未验证 提交 04988a23 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!1724 Net: ethernet: Support management channel of the host tool in 3snic 3s9xx network driver

Merge Pull Request from: @steven-song3 
 
3snic inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I7MVPN
CVE:NA

--------------------------------

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: NChen Mou <chenmou@3snic.com>
Reviewed-by: NWan Renyong <wanry@3snic.com>
Reviewed-by: NYang Gan <yanggan@3snic.com>
Reviewed-by: NWen Liang <wenliang@3snic.com>
Signed-off-by: NSteven Song <steven.song@3snic.com>

==================================

Test:
compille: pass
insmod/rmmod: pass
iperf: Pass 
 
Link:https://gitee.com/openeuler/kernel/pulls/1724 

Reviewed-by: Jialin Zhang <zhangjialin11@huawei.com> 
Signed-off-by: Jialin Zhang <zhangjialin11@huawei.com> 
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2023 3SNIC # 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
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
ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/include/hw 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/include/kernel
...@@ -45,4 +48,8 @@ sssdk-y := sss_hw_main.o \ ...@@ -45,4 +48,8 @@ sssdk-y := sss_hw_main.o \
sss_common.o \ sss_common.o \
sss_wq.o \ sss_wq.o \
sss_hwif_ceq.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
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include "sss_hw_svc_cap.h" #include "sss_hw_svc_cap.h"
#include "sss_sriov_info.h" #include "sss_sriov_info.h"
#define SSS_MAX_FUNCTION_NUM 4096 #define SSS_MAX_FUNC 4096
struct sss_card_node { struct sss_card_node {
struct list_head node; struct list_head node;
...@@ -23,7 +23,10 @@ struct sss_card_node { ...@@ -23,7 +23,10 @@ struct sss_card_node {
char chip_name[IFNAMSIZ]; char chip_name[IFNAMSIZ];
u8 bus_id; u8 bus_id;
u8 resvd[7]; u8 resvd[7];
u16 func_num;
atomic_t channel_timeout_cnt; atomic_t channel_timeout_cnt;
void *func_handle_array[SSS_MAX_FUNC];
void *dbgtool_info;
}; };
/* Structure pcidev private */ /* Structure pcidev private */
...@@ -57,6 +60,11 @@ struct sss_pci_adapter { ...@@ -57,6 +60,11 @@ struct sss_pci_adapter {
struct sss_sriov_info sriov_info; 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 */ /* set when uld driver processing event */
unsigned long uld_run_state; unsigned long uld_run_state;
...@@ -65,7 +73,6 @@ struct sss_pci_adapter { ...@@ -65,7 +73,6 @@ struct sss_pci_adapter {
/* lock for attach/detach uld */ /* lock for attach/detach uld */
struct mutex uld_attach_mutex; struct mutex uld_attach_mutex;
/* spin lock for uld_attach_state access */ spinlock_t dettach_uld_lock; /* spin lock for uld_attach_state access */
spinlock_t dettach_uld_lock;
}; };
#endif #endif
...@@ -93,7 +93,7 @@ struct sss_adm_msg { ...@@ -93,7 +93,7 @@ struct sss_adm_msg {
u32 ci; u32 ci;
struct semaphore sem; struct semaphore sem;
spinlock_t async_lock; /* protect adm msg async and sync */
dma_addr_t wb_state_paddr; dma_addr_t wb_state_paddr;
dma_addr_t head_elem_paddr; dma_addr_t head_elem_paddr;
......
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
#ifndef SSS_CSR_H #ifndef SSS_CSR_H
#define 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_MGMT_FLAG 0xC0000000
#define SSS_CSR_FLAG_MASK 0x3FFFFFFF #define SSS_CSR_FLAG_MASK 0x3FFFFFFF
#define SSS_VF_CFG_REG_OFFSET 0x2000 #define SSS_VF_CFG_REG_OFFSET 0x2000
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#define SSS_CSR_HW_ATTR6_ADDR (SSS_CSR_CFG_FLAG + 0x18) #define SSS_CSR_HW_ATTR6_ADDR (SSS_CSR_CFG_FLAG + 0x18)
#define SSS_HW_CSR_MBX_DATA_OFF 0x80 #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_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_H_OFF (SSS_CSR_CFG_FLAG + 0x0108)
#define SSS_HW_CSR_MBX_RES_L_OFF (SSS_CSR_CFG_FLAG + 0x010C) #define SSS_HW_CSR_MBX_RES_L_OFF (SSS_CSR_CFG_FLAG + 0x010C)
...@@ -46,27 +46,41 @@ ...@@ -46,27 +46,41 @@
(SSS_CSR_HW_PPF_ELECT_BASE_ADDR + \ (SSS_CSR_HW_PPF_ELECT_BASE_ADDR + \
(host_id) * SSS_CSR_HW_PPF_ELECT_PORT_STRIDE) (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) #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 */ /* MSI-X registers */
#define SSS_CSR_MSIX_INDIR_ID_ADDR (SSS_CSR_CFG_FLAG + 0x310) #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_CTRL_ADDR (SSS_CSR_CFG_FLAG + 0x300)
#define SSS_CSR_MSIX_CNT_ADDR (SSS_CSR_CFG_FLAG + 0x304) #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_RESEND_TIMER_CLR_SHIFT 0
#define SSS_MSI_CLR_INDIR_INT_MSK_SET_SHIFT 1 #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_CLR_SHIFT 2
#define SSS_MSI_CLR_INDIR_AUTO_MSK_SET_SHIFT 3 #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_AUTO_MSK_CLR_SHIFT 4
#define SSS_MSI_CLR_INDIR_SIMPLE_INDIR_ID_SHIFT 22 #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_RESEND_TIMER_CLR_MASK 0x1U
#define SSS_MSI_CLR_INDIR_INT_MSK_SET_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_INT_MSK_CLR_MASK 0x1U
#define SSS_MSI_CLR_INDIR_AUTO_MSK_SET_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_AUTO_MSK_CLR_MASK 0x1U
#define SSS_MSI_CLR_INDIR_SIMPLE_INDIR_ID_MASK 0x3FFU #define SSS_MSI_CLR_INDIR_SIMPLE_INDIR_ID_MASK 0x3FFU
#define SSS_SET_MSI_CLR_INDIR(val, member) \ #define SSS_SET_MSI_CLR_INDIR(val, member) \
...@@ -80,8 +94,8 @@ ...@@ -80,8 +94,8 @@
#define SSS_EQ_INDIR_ID_ADDR(type) \ #define SSS_EQ_INDIR_ID_ADDR(type) \
((type == SSS_AEQ) ? SSS_AEQ_INDIR_ID_ADDR : SSS_CEQ_INDIR_ID_ADDR) ((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_AEQ_MTT_OFF_BASE_ADDR (SSS_CSR_CFG_FLAG + 0x240)
#define SSS_CEQ_MTT_OFF_BASE_ADDR (SSS_CSR_CFG_FLAG + 0x2C0) #define SSS_CEQ_MTT_OFF_BASE_ADDR (SSS_CSR_CFG_FLAG + 0x2C0)
#define SSS_CSR_EQ_PAGE_OFF_STRIDE 8 #define SSS_CSR_EQ_PAGE_OFF_STRIDE 8
...@@ -98,20 +112,20 @@ ...@@ -98,20 +112,20 @@
(SSS_CEQ_MTT_OFF_BASE_ADDR + \ (SSS_CEQ_MTT_OFF_BASE_ADDR + \
(pg_num) * SSS_CSR_EQ_PAGE_OFF_STRIDE + 4) (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_0_ADDR (SSS_CSR_CFG_FLAG + 0x200)
#define SSS_CSR_AEQ_CTRL_1_ADDR (SSS_CSR_CFG_FLAG + 0x204) #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_CI_ADDR (SSS_CSR_CFG_FLAG + 0x208)
#define SSS_CSR_AEQ_PI_ADDR (SSS_CSR_CFG_FLAG + 0x20C) #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_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_0_ADDR (SSS_CSR_CFG_FLAG + 0x280)
#define SSS_CSR_CEQ_CTRL_1_ADDR (SSS_CSR_CFG_FLAG + 0x284) #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_CI_ADDR (SSS_CSR_CFG_FLAG + 0x288)
#define SSS_CSR_CEQ_PI_ADDR (SSS_CSR_CFG_FLAG + 0x28c) #define SSS_CSR_CEQ_PI_ADDR (SSS_CSR_CFG_FLAG + 0x28c)
#define SSS_CSR_CEQ_CI_SIMPLE_INDIR_ADDR (SSS_CSR_CFG_FLAG + 0x54) #define SSS_CSR_CEQ_CI_SIMPLE_INDIR_ADDR (SSS_CSR_CFG_FLAG + 0x54)
/* ADM MSG registers */ /* 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 #define SSS_CSR_ADM_MSG_STRIDE 0x80
...@@ -143,12 +157,12 @@ ...@@ -143,12 +157,12 @@
(SSS_CSR_ADM_MSG_BASE + 0x30 + (id) * SSS_CSR_ADM_MSG_STRIDE) (SSS_CSR_ADM_MSG_BASE + 0x30 + (id) * SSS_CSR_ADM_MSG_STRIDE)
/* self test register */ /* 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_STATUS0_ADDR (SSS_MGMT_FLAG + 0xC0EC)
#define SSS_CHIP_ERR_STATUS1_ADDR (SSS_MGMT_FLAG + 0xC0F0) #define SSS_CHIP_ERR_STATUS1_ADDR (SSS_MGMT_FLAG + 0xC0F0)
#define SSS_ERR_INFO0_ADDR (SSS_MGMT_FLAG + 0xC0F4) #define SSS_ERR_INFO0_ADDR (SSS_MGMT_FLAG + 0xC0F4)
#define SSS_ERR_INFO1_ADDR (SSS_MGMT_FLAG + 0xC0F8) #define SSS_ERR_INFO1_ADDR (SSS_MGMT_FLAG + 0xC0F8)
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include "sss_mbx_info.h" #include "sss_mbx_info.h"
#include "sss_mgmt_channel.h" #include "sss_mgmt_channel.h"
#define SSSNIC_CHANNEL_DETECT_PERIOD (5 * 1000)
enum sss_func_mode { enum sss_func_mode {
SSS_FUNC_MOD_MIN, SSS_FUNC_MOD_MIN,
...@@ -81,6 +83,11 @@ struct sss_aeq_stat { ...@@ -81,6 +83,11 @@ struct sss_aeq_stat {
u64 last_recv_cnt; u64 last_recv_cnt;
}; };
struct sss_clp_pf_to_mgmt {
struct semaphore clp_msg_lock;
void *clp_msg_buf;
};
struct sss_hwdev { struct sss_hwdev {
void *adapter_hdl; /* pointer to sss_pci_adapter or NDIS_Adapter */ void *adapter_hdl; /* pointer to sss_pci_adapter or NDIS_Adapter */
void *pcidev_hdl; /* pointer to pcidev or Handler */ void *pcidev_hdl; /* pointer to pcidev or Handler */
...@@ -108,6 +115,7 @@ struct sss_hwdev { ...@@ -108,6 +115,7 @@ struct sss_hwdev {
struct sss_ceq_info *ceq_info; struct sss_ceq_info *ceq_info;
struct sss_mbx *mbx; // mbx struct sss_mbx *mbx; // mbx
struct sss_msg_pf_to_mgmt *pf_to_mgmt; // adm 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; struct sss_hw_stats hw_stats;
u8 *chip_fault_stats; u8 *chip_fault_stats;
...@@ -132,6 +140,8 @@ struct sss_hwdev { ...@@ -132,6 +140,8 @@ struct sss_hwdev {
enum sss_func_mode func_mode; enum sss_func_mode func_mode;
struct sss_aeq_stat aeq_stat; struct sss_aeq_stat aeq_stat;
u16 aeq_busy_cnt;
}; };
#define SSS_TO_HWDEV(ptr) ((struct sss_hwdev *)(ptr)->hwdev) #define SSS_TO_HWDEV(ptr) ((struct sss_hwdev *)(ptr)->hwdev)
...@@ -220,6 +230,8 @@ enum sss_servic_bit_define { ...@@ -220,6 +230,8 @@ enum sss_servic_bit_define {
#define SSS_IS_PPF(dev) \ #define SSS_IS_PPF(dev) \
(SSS_GET_FUNC_TYPE(dev) == SSS_FUNC_TYPE_PPF) (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) \ #define SSS_IS_BMGW_MASTER_HOST(hwdev) \
((hwdev)->func_mode == SSS_FUNC_MOD_MULTI_BM_MASTER) ((hwdev)->func_mode == SSS_FUNC_MOD_MULTI_BM_MASTER)
#define SSS_IS_BMGW_SLAVE_HOST(hwdev) \ #define SSS_IS_BMGW_SLAVE_HOST(hwdev) \
...@@ -248,6 +260,10 @@ enum sss_servic_bit_define { ...@@ -248,6 +260,10 @@ enum sss_servic_bit_define {
((hwdev)->features[0] & SSS_COMM_F_CTRLQ_NUM) ((hwdev)->features[0] & SSS_COMM_F_CTRLQ_NUM)
#define SSS_SUPPORT_VIRTIO_VQ_SIZE(hwdev) \ #define SSS_SUPPORT_VIRTIO_VQ_SIZE(hwdev) \
((hwdev)->features[0] & SSS_COMM_F_VIRTIO_VQ_SIZE) ((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 { enum {
SSS_CFG_FREE = 0, SSS_CFG_FREE = 0,
......
...@@ -109,29 +109,33 @@ struct sss_recv_msg { ...@@ -109,29 +109,33 @@ struct sss_recv_msg {
}; };
struct sss_msg_pf_to_mgmt { 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 *sync_buf;
void *ack_buf; void *ack_buf;
struct sss_recv_msg recv_msg; struct sss_recv_msg recv_msg;
struct sss_recv_msg recv_resp_msg; struct sss_recv_msg recv_resp_msg;
u16 rsvd; u16 rsvd;
u16 sync_msg_id; u16 async_msg_id;
struct sss_adm_msg adm_msg; 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]; sss_mgmt_msg_handler_t recv_handler[SSS_MOD_TYPE_HW_MAX];
void *recv_data[SSS_MOD_TYPE_HW_MAX]; void *recv_data[SSS_MOD_TYPE_HW_MAX];
unsigned long recv_handler_state[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 */ /* lock when sending msg */
spinlock_t sync_event_lock; spinlock_t sync_event_lock; /* protect event async and sync */
enum sss_pf_to_mgmt_event_state event_state; enum sss_pf_to_mgmt_event_state event_state;
}; };
#endif #endif
...@@ -107,6 +107,11 @@ struct sss_service_cap { ...@@ -107,6 +107,11 @@ struct sss_service_cap {
struct sss_vbs_service_cap vbs_cap; /* VBS capability */ 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 { struct sss_mgmt_info {
void *hwdev; void *hwdev;
struct sss_service_cap svc_cap; struct sss_service_cap svc_cap;
......
...@@ -17,21 +17,31 @@ ...@@ -17,21 +17,31 @@
#include "sss_kernel.h" #include "sss_kernel.h"
#include "sss_hw.h" #include "sss_hw.h"
#include "sss_hwdev.h"
#include "sss_pci_sriov.h" #include "sss_pci_sriov.h"
#include "sss_pci_id_tbl.h" #include "sss_pci_id_tbl.h"
#include "sss_adapter.h"
#include "sss_adapter_mgmt.h" #include "sss_adapter_mgmt.h"
#include "sss_pci_global.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_ADAPTER_CNT_TIMEOUT 10000
#define SSS_WAIT_ADAPTER_USLEEP_MIN 9900 #define SSS_WAIT_ADAPTER_USLEEP_MIN 9900
#define SSS_WAIT_ADAPTER_USLEEP_MAX 10000 #define SSS_WAIT_ADAPTER_USLEEP_MAX 10000
#define SSS_CHIP_NODE_HOLD_TIMEOUT (10 * 60 * 1000) #define SSS_CHIP_NODE_HOLD_TIMEOUT (10 * 60 * 1000)
#define SSS_WAIT_CHIP_NODE_CHANGED (10 * 60 * 1000) #define SSS_WAIT_CHIP_NODE_CHANGED (10 * 60 * 1000)
#define SSS_PRINT_TIMEOUT_INTERVAL 10000 #define SSS_PRINT_TIMEOUT_INTERVAL 10000
#define SSS_MICRO_SECOND 1000 #define SSS_MICRO_SECOND 1000
#define SSS_CHIP_NODE_USLEEP_MIN 900 #define SSS_CHIP_NODE_USLEEP_MIN 900
#define SSS_CHIP_NODE_USLEEP_MAX 1000 #define SSS_CHIP_NODE_USLEEP_MAX 1000
#define SSS_CARD_CNT_MAX 64 #define SSS_CARD_CNT_MAX 64
...@@ -42,10 +52,9 @@ enum sss_node_state { ...@@ -42,10 +52,9 @@ enum sss_node_state {
}; };
struct sss_chip_node_lock { struct sss_chip_node_lock {
/* lock for chip list */ struct mutex chip_mutex; /* lock for chip list */
struct mutex chip_mutex; unsigned long state;
unsigned long state; atomic_t ref_cnt;
atomic_t ref_cnt;
}; };
static struct sss_chip_node_lock g_chip_node_lock; static struct sss_chip_node_lock g_chip_node_lock;
...@@ -59,7 +68,21 @@ struct list_head *sss_get_chip_list(void) ...@@ -59,7 +68,21 @@ struct list_head *sss_get_chip_list(void)
return &g_chip_list; 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; unsigned long end;
bool timeout = true; bool timeout = true;
...@@ -81,8 +104,7 @@ static void sss_chip_node_lock(void) ...@@ -81,8 +104,7 @@ static void sss_chip_node_lock(void)
loop_cnt / SSS_MICRO_SECOND); loop_cnt / SSS_MICRO_SECOND);
/* if sleep 1ms, use usleep_range to be more precise */ /* if sleep 1ms, use usleep_range to be more precise */
usleep_range(SSS_CHIP_NODE_USLEEP_MIN, usleep_range(SSS_CHIP_NODE_USLEEP_MIN, SSS_CHIP_NODE_USLEEP_MAX);
SSS_CHIP_NODE_USLEEP_MAX);
} while (time_before(jiffies, end)); } while (time_before(jiffies, end));
if (timeout && test_and_set_bit(SSS_NODE_CHANGE, &g_chip_node_lock.state)) 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) ...@@ -113,7 +135,7 @@ static void sss_chip_node_lock(void)
mutex_unlock(&g_chip_node_lock.chip_mutex); 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); clear_bit(SSS_NODE_CHANGE, &g_chip_node_lock.state);
} }
...@@ -136,8 +158,7 @@ void sss_hold_chip_node(void) ...@@ -136,8 +158,7 @@ void sss_hold_chip_node(void)
pr_warn("Wait adapter change complete for %us\n", pr_warn("Wait adapter change complete for %us\n",
loop_cnt / SSS_MICRO_SECOND); loop_cnt / SSS_MICRO_SECOND);
/* if sleep 1ms, use usleep_range to be more precise */ /* if sleep 1ms, use usleep_range to be more precise */
usleep_range(SSS_CHIP_NODE_USLEEP_MIN, usleep_range(SSS_CHIP_NODE_USLEEP_MIN, SSS_CHIP_NODE_USLEEP_MAX);
SSS_CHIP_NODE_USLEEP_MAX);
} while (time_before(jiffies, end)); } while (time_before(jiffies, end));
if (test_bit(SSS_NODE_CHANGE, &g_chip_node_lock.state)) 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) ...@@ -295,8 +316,7 @@ void sss_free_chip_node(struct sss_pci_adapter *adapter)
if (ret < 0) if (ret < 0)
sdk_err(&adapter->pcidev->dev, "Fail to get nic id\n"); 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); kfree(chip_node);
} }
sss_chip_node_unlock(); sss_chip_node_unlock();
...@@ -315,3 +335,390 @@ void sss_del_func_list(struct sss_pci_adapter *adapter) ...@@ -315,3 +335,390 @@ void sss_del_func_list(struct sss_pci_adapter *adapter)
list_del(&adapter->node); list_del(&adapter->node);
sss_chip_node_unlock(); 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;
}
...@@ -7,8 +7,11 @@ ...@@ -7,8 +7,11 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include "sss_version.h"
#include "sss_adapter.h" #include "sss_adapter.h"
#define SSS_DRV_VERSION SSS_VERSION_STR
#define SSS_DRV_NAME "sssdk" #define SSS_DRV_NAME "sssdk"
#define SSS_CHIP_NAME "sssnic" #define SSS_CHIP_NAME "sssnic"
...@@ -21,6 +24,30 @@ ...@@ -21,6 +24,30 @@
#define SSS_IS_VF_DEV(pdev) ((pdev)->device == SSS_DEV_ID_VF) #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 { enum {
SSS_NO_PROBE = 1, SSS_NO_PROBE = 1,
SSS_PROBE_START = 2, SSS_PROBE_START = 2,
...@@ -40,4 +67,34 @@ void sss_put_chip_node(void); ...@@ -40,4 +67,34 @@ void sss_put_chip_node(void);
void sss_set_adapter_probe_state(struct sss_pci_adapter *adapter, int state); 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 #endif
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include "sss_pci_shutdown.h" #include "sss_pci_shutdown.h"
#include "sss_pci_error.h" #include "sss_pci_error.h"
#define SSS_DRV_VERSION SSS_VERSION_STR
#define SSS_DRV_DESC "Intelligent Network Interface Card Driver" #define SSS_DRV_DESC "Intelligent Network Interface Card Driver"
MODULE_AUTHOR("steven.song@3snic.com"); MODULE_AUTHOR("steven.song@3snic.com");
......
...@@ -280,7 +280,7 @@ static void sss_print_pubic_cap(void *dev_hdl, const struct sss_service_cap *svc ...@@ -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); 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_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; 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, ...@@ -346,7 +346,7 @@ static void sss_parse_pubic_cap(struct sss_hwdev *hwdev,
svc_cap->sf_en = (type == SSS_FUNC_TYPE_PPF) ? svc_cap->sf_en = (type == SSS_FUNC_TYPE_PPF) ?
(!!cmd_cap->host_sf_en) : (!!cmd_cap->func_sf_en); (!!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); sss_print_pubic_cap(hwdev->dev_hdl, svc_cap);
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "sss_hwdev.h" #include "sss_hwdev.h"
#include "sss_csr.h" #include "sss_csr.h"
#include "sss_hwif_api.h" #include "sss_hwif_api.h"
#include "sss_hw_svc_cap.h"
#define SSS_DEFAULT_RX_BUF_SIZE_LEVEL ((u16)0xB) #define SSS_DEFAULT_RX_BUF_SIZE_LEVEL ((u16)0xB)
...@@ -287,6 +288,23 @@ bool sss_support_nic(void *hwdev) ...@@ -287,6 +288,23 @@ bool sss_support_nic(void *hwdev)
} }
EXPORT_SYMBOL(sss_support_nic); 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) u16 sss_get_max_sq_num(void *hwdev)
{ {
if (!hwdev) { if (!hwdev) {
...@@ -320,6 +338,19 @@ u16 sss_get_max_vf_num(void *hwdev) ...@@ -320,6 +338,19 @@ u16 sss_get_max_vf_num(void *hwdev)
} }
EXPORT_SYMBOL(sss_get_max_vf_num); 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) int sss_get_cos_valid_bitmap(void *hwdev, u8 *func_cos_bitmap, u8 *port_cos_bitmap)
{ {
if (!hwdev) { if (!hwdev) {
...@@ -561,8 +592,8 @@ void sss_update_link_stats(void *hwdev, bool link_state) ...@@ -561,8 +592,8 @@ void sss_update_link_stats(void *hwdev, bool link_state)
return; return;
if (link_state) 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 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); EXPORT_SYMBOL(sss_update_link_stats);
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "sss_hw_common.h" #include "sss_hw_common.h"
#include "sss_hwdev_api.h" #include "sss_hwdev_api.h"
#include "sss_hwif_adm.h" #include "sss_hwif_adm.h"
#include "sss_hwif_adm_common.h"
#define SSS_FW_MAGIC_NUM 0x5a5a1100 #define SSS_FW_MAGIC_NUM 0x5a5a1100
#define SSS_FW_IMAGE_HEAD_SIZE 4096 #define SSS_FW_IMAGE_HEAD_SIZE 4096
......
...@@ -318,10 +318,10 @@ static void sss_print_chip_fault(struct sss_hwdev *hwdev, ...@@ -318,10 +318,10 @@ static void sss_print_chip_fault(struct sss_hwdev *hwdev,
level_str = SSS_FAULT_LEVEL_STR_UNKNOWN; level_str = SSS_FAULT_LEVEL_STR_UNKNOWN;
if (err_level == SSS_FAULT_LEVEL_SERIOUS_FLR) 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); 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, fault_event->info.chip.node_id, fault_event->info.chip.err_type,
err_level, level_str, err_level, level_str,
fault_event->info.chip.err_csr_addr, fault_event->info.chip.err_csr_value); 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, ...@@ -362,7 +362,7 @@ static void sss_print_phy_err(struct sss_hwdev *hwdev,
static void sss_print_fault_info(struct sss_hwdev *hwdev, static void sss_print_fault_info(struct sss_hwdev *hwdev,
struct sss_fault_event *fault_event) 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 *type = NULL;
char *fault_type[SSS_FAULT_TYPE_MAX] = { char *fault_type[SSS_FAULT_TYPE_MAX] = {
SSS_FAULT_TYPE_STR_CHIP, SSS_FAULT_TYPE_STR_NPU, SSS_FAULT_TYPE_STR_CHIP, SSS_FAULT_TYPE_STR_NPU,
......
...@@ -25,63 +25,12 @@ ...@@ -25,63 +25,12 @@
#define SSS_ADM_MSG_ELEM_DESC_SIZE 8 #define SSS_ADM_MSG_ELEM_DESC_SIZE 8
#define SSS_ADM_MSG_ELEM_DATA_ADDR_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_ELEM_ALIGNMENT 8
#define SSS_ADM_MSG_STATE_TIMEOUT 10000 #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 */ /* adm_msg_state header */
#define SSS_ADM_MSG_STATE_HEAD_VALID_SHIFT 0 #define SSS_ADM_MSG_STATE_HEAD_VALID_SHIFT 0
#define SSS_ADM_MSG_STATE_HEAD_MSG_ID_SHIFT 16 #define SSS_ADM_MSG_STATE_HEAD_MSG_ID_SHIFT 16
...@@ -89,6 +38,9 @@ ...@@ -89,6 +38,9 @@
#define SSS_ADM_MSG_STATE_HEAD_VALID_MASK 0xFFU #define SSS_ADM_MSG_STATE_HEAD_VALID_MASK 0xFFU
#define SSS_ADM_MSG_STATE_HEAD_MSG_ID_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) \ #define SSS_ADM_MSG_STATE_HEAD_GET(val, member) \
(((val) >> SSS_ADM_MSG_STATE_HEAD_##member##_SHIFT) & \ (((val) >> SSS_ADM_MSG_STATE_HEAD_##member##_SHIFT) & \
SSS_ADM_MSG_STATE_HEAD_##member##_MASK) SSS_ADM_MSG_STATE_HEAD_##member##_MASK)
...@@ -130,8 +82,6 @@ struct sss_msg_head { ...@@ -130,8 +82,6 @@ struct sss_msg_head {
u8 rsvd0[5]; u8 rsvd0[5];
}; };
#define SSS_ADM_MSG_AEQ_ID 2
#define SSS_MGMT_MSG_SIZE_MIN 20 #define SSS_MGMT_MSG_SIZE_MIN 20
#define SSS_MGMT_MSG_SIZE_STEP 16 #define SSS_MGMT_MSG_SIZE_STEP 16
#define SSS_MGMT_MSG_RSVD_FOR_DEV 8 #define SSS_MGMT_MSG_RSVD_FOR_DEV 8
...@@ -164,6 +114,36 @@ struct sss_msg_head { ...@@ -164,6 +114,36 @@ struct sss_msg_head {
SSS_SET_MSG_HEADER(func_id, SRC_GLB_FUNC_ID) | \ SSS_SET_MSG_HEADER(func_id, SRC_GLB_FUNC_ID) | \
SSS_SET_MSG_HEADER(msg_id, MSG_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) static u8 sss_xor_chksum_set(void *data)
{ {
int id; int id;
...@@ -223,23 +203,65 @@ static void sss_dump_adm_msg_reg(struct sss_adm_msg *adm_msg) ...@@ -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) static int sss_adm_msg_busy(struct sss_adm_msg *adm_msg)
{ {
adm_msg->ci = sss_chip_get_ci(adm_msg); void *dev = SSS_TO_HWDEV(adm_msg)->dev_hdl;
if (adm_msg->ci == SSS_MASK_ID(adm_msg, adm_msg->pi + 1)) { struct sss_adm_msg_elem_ctx *ctx = &adm_msg->elem_ctx[adm_msg->pi];
sdk_err(SSS_TO_HWDEV(adm_msg)->dev_hdl, "Adm cmd is busy, ci = %u, pi = %u\n", u64 resp_header;
adm_msg->ci, adm_msg->pi);
sss_dump_adm_msg_reg(adm_msg); switch (adm_msg->msg_type) {
return -EBUSY; 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; 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; u64 control;
u8 chksum; u8 chksum;
u16 elem_len = ALIGN(SSS_ADM_MSG_ELEM_DESC_SIZE + u16 elem_len = 0;
SSS_ADM_MSG_ELEM_DATA_ADDR_SIZE, SSS_ADM_MSG_ELEM_ALIGNMENT);
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) | 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) | 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, ...@@ -258,13 +280,41 @@ static void sss_prepare_elem_desc(struct sss_adm_msg *adm_msg,
{ {
u32 priv; u32 priv;
struct sss_adm_msg_elem *elem = adm_msg->now_node; 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) | 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); 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, ...@@ -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; 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_desc(adm_msg, node_id, cmd_size);
sss_prepare_elem_ctx(adm_msg, cmd, 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) ...@@ -345,21 +395,87 @@ static enum sss_process_ret sss_wait_for_state_poll_handler(void *priv_data)
return SSS_PROCESS_DOING; 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) 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, return sss_check_handler_timeout(adm_msg, sss_wait_for_state_poll_handler,
SSS_ADM_MSG_STATE_TIMEOUT, 100); /* wait 100 us once */ 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, 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; int ret = 0;
ret = sss_wait_for_state_poll(adm_msg); switch (adm_msg->msg_type) {
if (ret != 0) { case SSS_ADM_MSG_POLL_READ:
sdk_err(SSS_TO_HWDEV(adm_msg)->dev_hdl, "Adm msg poll state timeout\n"); 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); 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; return ret;
...@@ -381,25 +497,25 @@ static inline void sss_update_adm_msg_ctx(struct sss_adm_msg *adm_msg) ...@@ -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) 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) 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, static int sss_adm_msg_io(struct sss_adm_msg *adm_msg, u8 node_id,
const void *cmd, u16 cmd_size) const void *cmd, u16 cmd_size, void *ack, u16 ack_size)
{ {
struct sss_adm_msg_elem_ctx *ctx = NULL; 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); sss_adm_msg_lock(adm_msg);
ctx = &adm_msg->elem_ctx[adm_msg->pi]; 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, ...@@ -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); 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, 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, ...@@ -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); 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, 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) u8 mod, u16 cmd, const void *msg_body, u16 msg_body_len)
{ {
struct sss_hwif *hwif = SSS_TO_HWDEV(pf_to_mgmt)->hwif; 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); u16 adm_msg_len = sss_align_adm_msg_len(msg_body_len);
u32 func_id = SSS_GET_HWIF_GLOBAL_ID(hwif); u32 func_id = SSS_GET_HWIF_GLOBAL_ID(hwif);
u8 node_id = SSS_MGMT_CPU_NODE_ID(SSS_TO_HWDEV(pf_to_mgmt)); u8 node_id = SSS_MGMT_CPU_NODE_ID(SSS_TO_HWDEV(pf_to_mgmt));
u64 header; u64 header;
struct sss_adm_msg *adm_mag;
if (sss_get_dev_present_flag(pf_to_mgmt->hwdev) == 0) if (sss_get_dev_present_flag(pf_to_mgmt->hwdev) == 0)
return -EFAULT; return -EFAULT;
...@@ -481,13 +655,15 @@ static int sss_send_adm_msg(struct sss_msg_pf_to_mgmt *pf_to_mgmt, ...@@ -481,13 +655,15 @@ static int sss_send_adm_msg(struct sss_msg_pf_to_mgmt *pf_to_mgmt,
return -EFAULT; return -EFAULT;
sss_set_adm_event_flag(pf_to_mgmt, SSS_ADM_EVENT_START); 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, header = SSS_ENCAPSULATE_ADM_MSG_HEAD(func_id, msg_body_len, mod,
cmd, SSS_SYNC_MSG_ID(pf_to_mgmt)); cmd, SSS_INCREASE_SYNC_MSG_ID(pf_to_mgmt));
sss_encapsulate_adm_msg((u8 *)adm_msg, &header, msg_body, msg_body_len);
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) static inline void sss_check_msg_body(u8 mod, void *buf_in)
......
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
#define SSS_HWIF_ADM_H #define SSS_HWIF_ADM_H
#include <linux/types.h> #include <linux/types.h>
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, 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); u16 in_size, void *buf_out, u16 *out_size, u32 timeout);
......
...@@ -4,6 +4,19 @@ ...@@ -4,6 +4,19 @@
#ifndef SSS_HWIF_ADM_COMMON_H #ifndef SSS_HWIF_ADM_COMMON_H
#define 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 */ /* ADM_STATUS_0 CSR: 0x0030+adm msg id*0x080 */
#define SSS_ADM_MSG_STATE_CI_MASK 0xFFFFFFU #define SSS_ADM_MSG_STATE_CI_MASK 0xFFFFFFU
#define SSS_ADM_MSG_STATE_CI_SHIFT 0 #define SSS_ADM_MSG_STATE_CI_SHIFT 0
...@@ -20,4 +33,47 @@ ...@@ -20,4 +33,47 @@
#define SSS_GET_ADM_MSG_STATE(val, member) \ #define SSS_GET_ADM_MSG_STATE(val, member) \
(((val) >> SSS_ADM_MSG_STATE_##member##_SHIFT) & \ (((val) >> SSS_ADM_MSG_STATE_##member##_SHIFT) & \
SSS_ADM_MSG_STATE_##member##_MASK) 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 #endif
...@@ -310,9 +310,28 @@ static void sss_init_ctx_buf_reply_addr(struct sss_adm_msg *adm_msg, ...@@ -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); 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) 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_ctx *ctx = NULL;
struct sss_adm_msg_elem *elem;
sss_alloc_elem_buf_handler_t handler[] = { sss_alloc_elem_buf_handler_t handler[] = {
NULL, NULL,
NULL, NULL,
...@@ -322,6 +341,11 @@ static int sss_init_elem_ctx(struct sss_adm_msg *adm_msg, u32 elem_id) ...@@ -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_reply_addr,
sss_init_ctx_buf_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 = &adm_msg->elem_ctx[elem_id];
ctx->elem_vaddr = ctx->elem_vaddr =
...@@ -379,17 +403,6 @@ static int sss_init_adm_msg_elem(struct sss_adm_msg *adm_msg) ...@@ -379,17 +403,6 @@ static int sss_init_adm_msg_elem(struct sss_adm_msg *adm_msg)
return 0; 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) static int sss_alloc_adm_msg_ctx(struct sss_adm_msg *adm_msg)
{ {
size_t ctx_size; size_t ctx_size;
...@@ -512,46 +525,105 @@ static void sss_free_adm_msg_buf(struct sss_adm_msg *adm_msg) ...@@ -512,46 +525,105 @@ static void sss_free_adm_msg_buf(struct sss_adm_msg *adm_msg)
sss_free_adm_msg_ctx(adm_msg); sss_free_adm_msg_ctx(adm_msg);
} }
static int sss_init_adm_msg(struct sss_hwdev *hwdev, static void sss_init_adm_msg_param(struct sss_adm_msg *adm_msg,
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; int ret;
if (!SSS_SUPPORT_ADM_MSG(hwdev)) msg = kzalloc(sizeof(*msg), GFP_KERNEL);
return 0; 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) { if (ret != 0) {
sdk_err(hwdev->dev_hdl, "Fail to init adm msg buf\n"); sdk_err(hwdev->dev_hdl, "Fail to init adm msg buf\n");
return ret; return ret;
} }
ret = sss_init_adm_msg_elem(adm_msg); ret = sss_init_adm_msg_elem(msg);
if (ret != 0) { if (ret != 0) {
sdk_err(hwdev->dev_hdl, "Fail to init adm msg elem\n"); 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; return ret;
} }
ret = sss_chip_init_adm_msg(adm_msg); ret = sss_chip_init_adm_msg(msg);
if (ret != 0) { if (ret != 0) {
sdk_err(hwdev->dev_hdl, "Fail to init adm msg\n"); 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; return ret;
} }
*adm_msg = msg;
return 0; 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, 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)) if (!SSS_SUPPORT_ADM_MSG(hwdev))
return; 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) 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) ...@@ -578,8 +650,15 @@ static int sss_alloc_msg_buf(struct sss_msg_pf_to_mgmt *mgmt_msg)
if (!mgmt_msg->sync_buf) if (!mgmt_msg->sync_buf)
goto alloc_sync_buf_err; 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; return 0;
alloc_async_msg_buf_err:
kfree(mgmt_msg->sync_buf);
mgmt_msg->sync_buf = NULL;
alloc_sync_buf_err: alloc_sync_buf_err:
kfree(mgmt_msg->ack_buf); kfree(mgmt_msg->ack_buf);
mgmt_msg->ack_buf = NULL; mgmt_msg->ack_buf = NULL;
...@@ -600,6 +679,7 @@ static void sss_free_msg_buf(struct sss_msg_pf_to_mgmt *mgmt_msg) ...@@ -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 *recv_msg = &mgmt_msg->recv_msg;
struct sss_recv_msg *resp_msg = &mgmt_msg->recv_resp_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->sync_buf);
kfree(mgmt_msg->ack_buf); kfree(mgmt_msg->ack_buf);
kfree(resp_msg->buf); kfree(resp_msg->buf);
...@@ -615,6 +695,7 @@ int sss_hwif_init_adm(struct sss_hwdev *hwdev) ...@@ -615,6 +695,7 @@ int sss_hwif_init_adm(struct sss_hwdev *hwdev)
if (!mgmt_msg) if (!mgmt_msg)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&mgmt_msg->async_msg_lock);
spin_lock_init(&mgmt_msg->sync_event_lock); spin_lock_init(&mgmt_msg->sync_event_lock);
sema_init(&mgmt_msg->sync_lock, 1); sema_init(&mgmt_msg->sync_lock, 1);
mgmt_msg->hwdev = hwdev; mgmt_msg->hwdev = hwdev;
...@@ -633,7 +714,7 @@ int sss_hwif_init_adm(struct sss_hwdev *hwdev) ...@@ -633,7 +714,7 @@ int sss_hwif_init_adm(struct sss_hwdev *hwdev)
goto alloc_msg_buf_err; 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) { if (ret != 0) {
sdk_err(hwdev->dev_hdl, "Fail to init adm msg\n"); sdk_err(hwdev->dev_hdl, "Fail to init adm msg\n");
goto init_all_adm_err; goto init_all_adm_err;
...@@ -660,7 +741,7 @@ void sss_hwif_deinit_adm(struct sss_hwdev *hwdev) ...@@ -660,7 +741,7 @@ void sss_hwif_deinit_adm(struct sss_hwdev *hwdev)
destroy_workqueue(mgmt_msg->workq); 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); sss_free_msg_buf(mgmt_msg);
......
...@@ -261,7 +261,7 @@ struct sss_ctrlq_wqe { ...@@ -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); struct sss_ctrlq_wqe *wqe, u16 ci);
void *sss_ctrlq_read_wqe(struct sss_wq *wq, 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, ...@@ -801,58 +801,66 @@ static void sss_ctrlq_update_cmd_info(struct sss_ctrlq *ctrlq,
spin_unlock(&ctrlq->ctrlq_lock); spin_unlock(&ctrlq->ctrlq_lock);
} }
static void sss_ctrlq_arm_ceq_handler(struct sss_ctrlq *ctrlq, static int sss_ctrlq_arm_ceq_handler(struct sss_ctrlq *ctrlq,
struct sss_ctrlq_wqe *wqe, u16 ci) struct sss_ctrlq_wqe *wqe, u16 ci)
{ {
struct sss_wqe_ctrl *ctrl = &wqe->inline_wqe.wqe_scmd.ctrl; struct sss_wqe_ctrl *ctrl = &wqe->inline_wqe.wqe_scmd.ctrl;
u32 info = sss_hw_cpu32((ctrl)->info); u32 info = sss_hw_cpu32((ctrl)->info);
if (!SSS_WQE_COMPLETE(info)) if (!SSS_WQE_COMPLETE(info))
return; return -EBUSY;
sss_erase_wqe_complete_bit(ctrlq, wqe, ci); sss_erase_wqe_complete_bit(ctrlq, wqe, ci);
return 0;
} }
static void sss_ctrlq_default_handler(struct sss_ctrlq *ctrlq, static int sss_ctrlq_default_handler(struct sss_ctrlq *ctrlq,
struct sss_ctrlq_wqe *wqe, u16 ci) struct sss_ctrlq_wqe *wqe, u16 ci)
{ {
struct sss_wqe_ctrl *ctrl = &wqe->wqe_lcmd.ctrl; struct sss_wqe_ctrl *ctrl = &wqe->wqe_lcmd.ctrl;
u32 info = sss_hw_cpu32((ctrl)->info); u32 info = sss_hw_cpu32((ctrl)->info);
if (!SSS_WQE_COMPLETE(info)) if (!SSS_WQE_COMPLETE(info))
return; return -EBUSY;
dma_rmb(); dma_rmb();
sss_ctrlq_update_cmd_info(ctrlq, wqe, ci); sss_ctrlq_update_cmd_info(ctrlq, wqe, ci);
sss_free_ctrlq_cmd_buf(SSS_TO_HWDEV(ctrlq), &ctrlq->cmd_info[ci]); sss_free_ctrlq_cmd_buf(SSS_TO_HWDEV(ctrlq), &ctrlq->cmd_info[ci]);
sss_erase_wqe_complete_bit(ctrlq, wqe, ci); sss_erase_wqe_complete_bit(ctrlq, wqe, ci);
return 0;
} }
static void sss_ctrlq_async_cmd_handler(struct sss_ctrlq *ctrlq, static int sss_ctrlq_async_cmd_handler(struct sss_ctrlq *ctrlq,
struct sss_ctrlq_wqe *wqe, u16 ci) struct sss_ctrlq_wqe *wqe, u16 ci)
{ {
struct sss_wqe_ctrl *ctrl = &wqe->wqe_lcmd.ctrl; struct sss_wqe_ctrl *ctrl = &wqe->wqe_lcmd.ctrl;
u32 info = sss_hw_cpu32((ctrl)->info); u32 info = sss_hw_cpu32((ctrl)->info);
if (!SSS_WQE_COMPLETE(info)) if (!SSS_WQE_COMPLETE(info))
return; return -EBUSY;
dma_rmb(); dma_rmb();
sss_free_ctrlq_cmd_buf(SSS_TO_HWDEV(ctrlq), &ctrlq->cmd_info[ci]); sss_free_ctrlq_cmd_buf(SSS_TO_HWDEV(ctrlq), &ctrlq->cmd_info[ci]);
sss_erase_wqe_complete_bit(ctrlq, wqe, ci); sss_erase_wqe_complete_bit(ctrlq, wqe, ci);
return 0;
} }
static void sss_ctrlq_pseudo_timeout_handler(struct sss_ctrlq *ctrlq, static int sss_ctrlq_pseudo_timeout_handler(struct sss_ctrlq *ctrlq,
struct sss_ctrlq_wqe *wqe, u16 ci) struct sss_ctrlq_wqe *wqe, u16 ci)
{ {
sss_free_ctrlq_cmd_buf(SSS_TO_HWDEV(ctrlq), &ctrlq->cmd_info[ci]); sss_free_ctrlq_cmd_buf(SSS_TO_HWDEV(ctrlq), &ctrlq->cmd_info[ci]);
sss_erase_wqe_complete_bit(ctrlq, wqe, ci); sss_erase_wqe_complete_bit(ctrlq, wqe, ci);
return 0;
} }
static void sss_ctrlq_timeout_handler(struct sss_ctrlq *ctrlq, static int sss_ctrlq_timeout_handler(struct sss_ctrlq *ctrlq,
struct sss_ctrlq_wqe *wqe, u16 ci) struct sss_ctrlq_wqe *wqe, u16 ci)
{ {
u32 i; u32 i;
u32 *data = (u32 *)wqe; u32 *data = (u32 *)wqe;
...@@ -868,17 +876,20 @@ static void sss_ctrlq_timeout_handler(struct sss_ctrlq *ctrlq, ...@@ -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_free_ctrlq_cmd_buf(SSS_TO_HWDEV(ctrlq), &ctrlq->cmd_info[ci]);
sss_erase_wqe_complete_bit(ctrlq, wqe, ci); sss_erase_wqe_complete_bit(ctrlq, wqe, ci);
return 0;
} }
static void sss_ctrlq_force_stop_handler(struct sss_ctrlq *ctrlq, static int sss_ctrlq_force_stop_handler(struct sss_ctrlq *ctrlq,
struct sss_ctrlq_wqe *wqe, u16 ci) 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) void sss_ctrlq_ceq_handler(void *dev, u32 data)
{ {
u16 ci; u16 ci;
int ret;
enum sss_ctrlq_type type = SSS_GET_CEQE_CTRLQ(data, TYPE); 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 *ctrlq = &SSS_TO_CTRLQ_INFO(dev)->ctrlq[type];
struct sss_ctrlq_wqe *ctrlq_wqe = NULL; struct sss_ctrlq_wqe *ctrlq_wqe = NULL;
...@@ -895,17 +906,23 @@ void sss_ctrlq_ceq_handler(void *dev, u32 data) ...@@ -895,17 +906,23 @@ void sss_ctrlq_ceq_handler(void *dev, u32 data)
sss_ctrlq_force_stop_handler, sss_ctrlq_force_stop_handler,
}; };
ctrlq_wqe = sss_ctrlq_read_wqe(&ctrlq->wq, &ci); while ((ctrlq_wqe = sss_ctrlq_read_wqe(&ctrlq->wq, &ci)) != NULL) {
if (!ctrlq_wqe) info = &ctrlq->cmd_info[ci];
return;
info = &ctrlq->cmd_info[ci]; if (info->msg_type < SSS_MSG_TYPE_NONE ||
if (info->msg_type < SSS_MSG_TYPE_NONE || info->msg_type >= SSS_MSG_TYPE_MAX) {
info->msg_type >= SSS_MSG_TYPE_MAX) { ret = sss_ctrlq_default_handler(ctrlq, ctrlq_wqe, ci);
sss_ctrlq_default_handler(ctrlq, ctrlq_wqe, ci); if (ret)
return; break;
}
continue;
}
if (!handler[info->msg_type])
break;
if (handler[info->msg_type]) ret = handler[info->msg_type](ctrlq, ctrlq_wqe, ci);
handler[info->msg_type](ctrlq, ctrlq_wqe, ci); if (ret)
break;
}
} }
...@@ -119,6 +119,15 @@ enum sss_func_type sss_get_func_type(void *hwdev) ...@@ -119,6 +119,15 @@ enum sss_func_type sss_get_func_type(void *hwdev)
} }
EXPORT_SYMBOL(sss_get_func_type); 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) u16 sss_get_glb_pf_vf_offset(void *hwdev)
{ {
if (!hwdev) if (!hwdev)
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "sss_hwif_mbx.h" #include "sss_hwif_mbx.h"
#include "sss_csr.h" #include "sss_csr.h"
#include "sss_common.h" #include "sss_common.h"
#include "sss_adapter_mgmt.h"
#define SSS_MBX_WB_STATUS_SIZE 16UL #define SSS_MBX_WB_STATUS_SIZE 16UL
...@@ -25,8 +26,6 @@ ...@@ -25,8 +26,6 @@
#define SSS_MBX_WQ_NAME "sss_mbx" #define SSS_MBX_WQ_NAME "sss_mbx"
#define SSS_MAX_FUNC 4096
#define SSS_MBX_AREA(hwif) \ #define SSS_MBX_AREA(hwif) \
((hwif)->cfg_reg_base + SSS_HW_CSR_MBX_DATA_OFF) ((hwif)->cfg_reg_base + SSS_HW_CSR_MBX_DATA_OFF)
...@@ -449,18 +448,21 @@ int sss_hwif_init_mbx(struct sss_hwdev *hwdev) ...@@ -449,18 +448,21 @@ int sss_hwif_init_mbx(struct sss_hwdev *hwdev)
void sss_hwif_deinit_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); destroy_workqueue(mbx->workq);
mdx->workq = NULL; 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, static bool sss_check_mbx_msg_header(void *dev_hdl,
...@@ -725,7 +727,7 @@ static void sss_recv_mbx_handler(struct sss_mbx *mbx, ...@@ -725,7 +727,7 @@ static void sss_recv_mbx_handler(struct sss_mbx *mbx,
int ret = 0; int ret = 0;
void *resp_buf = recv_mbx->resp_buf; void *resp_buf = recv_mbx->resp_buf;
u16 size = SSS_MBX_DATA_SIZE; 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); struct sss_hwdev *hwdev = SSS_TO_HWDEV(mbx);
if (SSS_IS_VF(hwdev)) { if (SSS_IS_VF(hwdev)) {
...@@ -733,7 +735,6 @@ static void sss_recv_mbx_handler(struct sss_mbx *mbx, ...@@ -733,7 +735,6 @@ static void sss_recv_mbx_handler(struct sss_mbx *mbx,
goto out; goto out;
} }
src_func_id = recv_mbx->src_func_id;
if (SSS_SRC_IS_PF_OR_PPF(hwdev, src_func_id)) { if (SSS_SRC_IS_PF_OR_PPF(hwdev, src_func_id)) {
if (SSS_IS_PPF(hwdev)) if (SSS_IS_PPF(hwdev))
ret = sss_recv_ppf_mbx_handler(mbx, recv_mbx, ret = sss_recv_ppf_mbx_handler(mbx, recv_mbx,
......
...@@ -28,7 +28,7 @@ static void sss_record_pcie_error(void *dev) ...@@ -28,7 +28,7 @@ static void sss_record_pcie_error(void *dev)
{ {
struct sss_hwdev *hwdev = (struct sss_hwdev *)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, pci_ers_result_t sss_detect_pci_error(struct pci_dev *pdev,
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "sss_hwdev_api.h" #include "sss_hwdev_api.h"
#include "sss_pci_remove.h" #include "sss_pci_remove.h"
#include "sss_pci_global.h" #include "sss_pci_global.h"
#include "sss_tool.h"
#define SSS_SYNC_YEAR_OFFSET 1900 #define SSS_SYNC_YEAR_OFFSET 1900
#define SSS_SYNC_MONTH_OFFSET 1 #define SSS_SYNC_MONTH_OFFSET 1
...@@ -448,6 +449,15 @@ static int sss_init_function(struct pci_dev *pdev, struct sss_pci_adapter *adapt ...@@ -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_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); sss_add_func_list(adapter);
ret = sss_attach_uld_dev(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 ...@@ -461,6 +471,10 @@ static int sss_init_function(struct pci_dev *pdev, struct sss_pci_adapter *adapt
attach_uld_err: attach_uld_err:
sss_del_func_list(adapter); 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_unregister_dev_event(adapter->hwdev);
sss_deinit_hwdev(adapter->hwdev); sss_deinit_hwdev(adapter->hwdev);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "sss_hwdev_api.h" #include "sss_hwdev_api.h"
#include "sss_hwif_mgmt_init.h" #include "sss_hwif_mgmt_init.h"
#include "sss_pci_global.h" #include "sss_pci_global.h"
#include "sss_tool.h"
#define SSS_WAIT_SRIOV_CFG_TIMEOUT 15000 #define SSS_WAIT_SRIOV_CFG_TIMEOUT 15000
#define SSS_EVENT_PROCESS_TIMEOUT 10000 #define SSS_EVENT_PROCESS_TIMEOUT 10000
...@@ -185,6 +186,10 @@ void sss_deinit_function(struct pci_dev *pdev) ...@@ -185,6 +186,10 @@ void sss_deinit_function(struct pci_dev *pdev)
sss_del_func_list(adapter); 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_dettach_uld_dev(adapter);
sss_unregister_dev_event(adapter->hwdev); sss_unregister_dev_event(adapter->hwdev);
......
/* 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
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2021 3snic Technologies Co., Ltd */
#define pr_fmt(fmt) KBUILD_MODNAME ": [TOOL]" fmt
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/completion.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/semaphore.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
#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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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;
}
/* 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
/* 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 */
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2021 3snic Technologies Co., Ltd */
#define pr_fmt(fmt) KBUILD_MODNAME ": [TOOL]" fmt
#include <net/sock.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/time.h>
#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(&param, (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(&param, 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();
}
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2021 3snic Technologies Co., Ltd */
#define pr_fmt(fmt) KBUILD_MODNAME ": [TOOL]" fmt
#include <net/sock.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/time.h>
#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;
}
/* 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
// 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;
}
/* 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
...@@ -85,6 +85,8 @@ bool sss_get_nic_capability(void *hwdev, struct sss_nic_service_cap *capability) ...@@ -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_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 * @brief sss_get_max_sq_num - get max queue number
* @param hwdev: device pointer to hwdev * @param hwdev: device pointer to hwdev
...@@ -163,6 +165,8 @@ int sss_get_dev_present_flag(const void *hwdev); ...@@ -163,6 +165,8 @@ int sss_get_dev_present_flag(const void *hwdev);
*/ */
u8 sss_get_max_pf_num(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 * @brief sss_get_chip_present_state - get card present state
* @param hwdev: device pointer to hwdev * @param hwdev: device pointer to hwdev
......
...@@ -171,7 +171,7 @@ enum sss_mod_type { ...@@ -171,7 +171,7 @@ enum sss_mod_type {
SSS_MOD_TYPE_FLR = 5, SSS_MOD_TYPE_FLR = 5,
SSS_MOD_TYPE_RSVD1 = 6, SSS_MOD_TYPE_RSVD1 = 6,
SSS_MOD_TYPE_CFGM = 7, /* Configuration module */ SSS_MOD_TYPE_CFGM = 7, /* Configuration module */
SSS_MOD_TYPE_CQM = 8, SSS_MOD_TYPE_QMM = 8,
SSS_MOD_TYPE_RSVD2 = 9, SSS_MOD_TYPE_RSVD2 = 9,
COMM_MOD_FC = 10, COMM_MOD_FC = 10,
SSS_MOD_TYPE_OVS = 11, SSS_MOD_TYPE_OVS = 11,
......
...@@ -10,20 +10,26 @@ ...@@ -10,20 +10,26 @@
#include "sss_hw_event.h" #include "sss_hw_event.h"
#include "sss_hw_aeq.h" #include "sss_hw_aeq.h"
struct sss_qmm_stats {
atomic_t qmm_rsv_cnt[134];
};
struct sss_link_event_stats { struct sss_link_event_stats {
atomic_t link_down_stats; atomic_t link_down_stats;
atomic_t link_up_stats; atomic_t link_up_stats;
}; };
struct sss_fault_event_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 fault_type_stat[SSS_FAULT_TYPE_MAX];
atomic_t pcie_fault_stats; atomic_t pcie_fault_stats;
}; };
struct sss_hw_stats { struct sss_hw_stats {
atomic_t heart_lost_stats; atomic_t heart_lost_stats;
struct sss_link_event_stats sss_link_event_stats; struct sss_qmm_stats qmm_stats;
struct sss_fault_event_stats sss_fault_event_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]; atomic_t nic_ucode_event_stats[SSS_ERR_MAX];
}; };
......
...@@ -23,7 +23,7 @@ enum sss_service_type { ...@@ -23,7 +23,7 @@ enum sss_service_type {
SSS_SERVICE_TYPE_MAX, SSS_SERVICE_TYPE_MAX,
SSS_SERVICE_TYPE_INTF = (1 << 15), SSS_SERVICE_TYPE_INTF = (1 << 15),
SSS_SERVICE_TYPE_CQM = (1 << 16), SSS_SERVICE_TYPE_QMM = (1 << 16),
}; };
/* RDMA service capability */ /* RDMA service capability */
......
...@@ -71,6 +71,8 @@ u8 sss_get_pcie_itf_id(void *hwdev); ...@@ -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_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 * @brief sss_get_glb_pf_vf_offset - get vf offset id of pf
* @param hwdev: device pointer to hwdev * @param hwdev: device pointer to hwdev
......
/* 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_ */
...@@ -2,10 +2,14 @@ ...@@ -2,10 +2,14 @@
# Copyright (c) 2023 3SNIC # 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
ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/include/hw 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/include/kernel
ccflags-y += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/nic 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 += -I$(srctree)/drivers/net/ethernet/3snic/sssnic/nic/include
ccflags-y += -Werror ccflags-y += -Werror
...@@ -33,4 +37,9 @@ sssnic-y := sss_nic_main.o \ ...@@ -33,4 +37,9 @@ sssnic-y := sss_nic_main.o \
sss_nic_rss_cfg.o \ sss_nic_rss_cfg.o \
sss_nic_event.o \ sss_nic_event.o \
sss_nic_io.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
...@@ -455,4 +455,6 @@ struct sss_nic_mag_cfg { ...@@ -455,4 +455,6 @@ struct sss_nic_mag_cfg {
struct mutex sfp_mutex; /* mutex used for copy sfp info */ struct mutex sfp_mutex; /* mutex used for copy sfp info */
}; };
#define SSSNIC_PF_LIMIT_BW_MAX 100
#endif #endif
...@@ -45,9 +45,9 @@ struct sss_nic_sq_stats { ...@@ -45,9 +45,9 @@ struct sss_nic_sq_stats {
u64 dma_map_err; u64 dma_map_err;
u64 unknown_tunnel_proto; u64 unknown_tunnel_proto;
u64 frag_size_zero; u64 frag_size_zero;
u64 frag_len_overflow;
u64 rsvd1; u64 rsvd1;
u64 rsvd2; u64 rsvd2;
u64 rsvd3;
#ifdef HAVE_NDO_GET_STATS64 #ifdef HAVE_NDO_GET_STATS64
struct u64_stats_sync stats_sync; struct u64_stats_sync stats_sync;
......
...@@ -1100,3 +1100,42 @@ int sss_nic_rq_hw_pc_info(struct sss_nic_dev *nic_dev, ...@@ -1100,3 +1100,42 @@ int sss_nic_rq_hw_pc_info(struct sss_nic_dev *nic_dev,
return ret; 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;
}
...@@ -99,5 +99,7 @@ void sss_nic_io_deinit(struct sss_nic_dev *nic_dev); ...@@ -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, 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); 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 #endif
...@@ -158,8 +158,8 @@ static u8 sss_nic_get_cos_num(u8 cos_bitmap) ...@@ -158,8 +158,8 @@ static u8 sss_nic_get_cos_num(u8 cos_bitmap)
return cos_count; return cos_count;
} }
static void sss_nic_sync_dcb_cfg(struct sss_nic_dev *nic_dev, void sss_nic_sync_dcb_cfg(struct sss_nic_dev *nic_dev,
const struct sss_nic_dcb_config *dcb_config) const struct sss_nic_dcb_config *dcb_config)
{ {
struct sss_nic_dcb_config *hw_config = &nic_dev->hw_dcb_cfg; struct sss_nic_dcb_config *hw_config = &nic_dev->hw_dcb_cfg;
......
...@@ -7,6 +7,11 @@ ...@@ -7,6 +7,11 @@
#include "sss_kernel.h" #include "sss_kernel.h"
#include "sss_nic_dcb_define.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 { enum sss_nic_dcb_trust {
DCB_PCP, DCB_PCP,
DCB_DSCP, DCB_DSCP,
...@@ -18,5 +23,7 @@ int sss_nic_dcb_init(struct sss_nic_dev *nic_dev); ...@@ -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); 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_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_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 #endif
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include "sss_nic_tx.h" #include "sss_nic_tx.h"
#include "sss_nic_rx.h" #include "sss_nic_rx.h"
#include "sss_nic_ethtool_stats_api.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_SUPPORTED_MODE 0
#define SSSNIC_SET_ADVERTISED_MODE 1 #define SSSNIC_SET_ADVERTISED_MODE 1
...@@ -89,6 +91,35 @@ do { \ ...@@ -89,6 +91,35 @@ do { \
(len) == sizeof(u16) ? *(u16 *)(ptr) : *(u8 *)(ptr) \ (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_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_STRING(autoneg) ((autoneg) ? ("autong enable") : ("autong disable"))
#define SSSNIC_AUTONEG_ENABLE(autoneg) ((autoneg) ? SSSNIC_PORT_CFG_AN_ON : SSSNIC_PORT_CFG_AN_OFF) #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[] = { ...@@ -127,6 +158,17 @@ static struct sss_nic_stats g_nic_sq_stats[] = {
SSSNIC_SQ_STATS(tx_dropped), 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[] = { static struct sss_nic_stats g_nic_rq_stats[] = {
SSSNIC_RQ_STATS(rx_packets), SSSNIC_RQ_STATS(rx_packets),
SSSNIC_RQ_STATS(rx_bytes), SSSNIC_RQ_STATS(rx_bytes),
...@@ -140,6 +182,14 @@ static struct sss_nic_stats g_nic_rq_stats[] = { ...@@ -140,6 +182,14 @@ static struct sss_nic_stats g_nic_rq_stats[] = {
SSSNIC_RQ_STATS(rx_buf_errors), 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[] = { static struct sss_nic_stats g_netdev_stats[] = {
SSSNIC_NETDEV_STATS(rx_packets), SSSNIC_NETDEV_STATS(rx_packets),
SSSNIC_NETDEV_STATS(tx_packets), SSSNIC_NETDEV_STATS(tx_packets),
...@@ -167,6 +217,13 @@ static struct sss_nic_stats g_dev_stats[] = { ...@@ -167,6 +217,13 @@ static struct sss_nic_stats g_dev_stats[] = {
SSSNIC_TX_STATS(tx_timeout), 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[] = { static struct sss_nic_stats g_function_stats[] = {
SSSNIC_FUNCTION_STATS(tx_unicast_pkts), SSSNIC_FUNCTION_STATS(tx_unicast_pkts),
SSSNIC_FUNCTION_STATS(tx_unicast_bytes), SSSNIC_FUNCTION_STATS(tx_unicast_bytes),
...@@ -432,6 +489,20 @@ static sss_nic_port_type_handler_t g_link_port_set_handler[] = { ...@@ -432,6 +489,20 @@ static sss_nic_port_type_handler_t g_link_port_set_handler[] = {
sss_nic_set_none_port 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) int sss_nic_eth_ss_test(struct sss_nic_dev *nic_dev)
{ {
return ARRAY_LEN(g_test_strings); return ARRAY_LEN(g_test_strings);
...@@ -959,3 +1030,29 @@ int sssnic_set_link_settings(struct net_device *netdev, ...@@ -959,3 +1030,29 @@ int sssnic_set_link_settings(struct net_device *netdev,
return 0; 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);
}
}
...@@ -104,4 +104,6 @@ int sss_nic_set_settings_to_hw(struct sss_nic_dev *nic_dev, ...@@ -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, int sssnic_set_link_settings(struct net_device *netdev,
u8 autoneg, u32 speed); u8 autoneg, u32 speed);
void sss_nic_get_io_stats(const struct sss_nic_dev *nic_dev, void *stats);
#endif #endif
...@@ -543,7 +543,7 @@ static int _sss_nic_event_handler(void *hwdev, u16 cmd, void *in_buf, u16 in_siz ...@@ -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; ((struct sss_mgmt_msg_head *)out_buf)->state = SSS_MGMT_CMD_UNSUPPORTED;
*out_size = sizeof(struct sss_mgmt_msg_head); *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; return 0;
} }
......
...@@ -161,6 +161,15 @@ int sss_nic_set_loopback_mode(struct sss_nic_dev *nic_dev, u8 lp_mode, u8 enable ...@@ -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); 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, 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) 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, ...@@ -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_event_info event_info = {0};
struct sss_nic_event_link_info *link_info = (void *)event_info.event_data; 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_get_global_func_id(nic_io->hwdev), in_link_state->status);
sss_update_link_stats(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, ...@@ -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; struct sss_nic_cache_port_sfp *routine_cmd = NULL;
if (in_size != sizeof(*in_xsfp_info)) { 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)); in_size, sizeof(*in_xsfp_info));
return; return;
} }
...@@ -435,7 +444,7 @@ static void sss_nic_port_sfp_absent_event_handler(struct sss_nic_io *nic_io, ...@@ -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; struct sss_nic_cache_port_sfp *routine_cmd = NULL;
if (in_size != sizeof(*in_xsfp_present)) { 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)); in_size, sizeof(*in_xsfp_present));
return; return;
} }
...@@ -447,7 +456,7 @@ static void sss_nic_port_sfp_absent_event_handler(struct sss_nic_io *nic_io, ...@@ -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); 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; int ret;
bool sfp_abs_state; bool sfp_abs_state;
...@@ -484,8 +493,8 @@ static bool sss_nic_if_sfp_absent(struct sss_nic_dev *nic_dev) ...@@ -484,8 +493,8 @@ static bool sss_nic_if_sfp_absent(struct sss_nic_dev *nic_dev)
return !!xsfp_present.abs_status; return !!xsfp_present.abs_status;
} }
static int sss_nic_get_sfp_info(struct sss_nic_dev *nic_dev, int sss_nic_get_sfp_info(struct sss_nic_dev *nic_dev,
struct sss_nic_mbx_get_xsfp_info *xsfp_info) struct sss_nic_mbx_get_xsfp_info *xsfp_info)
{ {
int ret; int ret;
u16 out_len = sizeof(*xsfp_info); u16 out_len = sizeof(*xsfp_info);
...@@ -709,7 +718,7 @@ static int _sss_nic_mag_event_handler(void *hwdev, u16 cmd, ...@@ -709,7 +718,7 @@ static int _sss_nic_mag_event_handler(void *hwdev, u16 cmd,
out_msg_head->state = SSS_MGMT_CMD_UNSUPPORTED; out_msg_head->state = SSS_MGMT_CMD_UNSUPPORTED;
*out_size = sizeof(*out_msg_head); *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; return 0;
} }
......
...@@ -69,4 +69,11 @@ int sss_nic_pf_mag_mbx_handler(void *hwdev, ...@@ -69,4 +69,11 @@ int sss_nic_pf_mag_mbx_handler(void *hwdev,
u16 vf_id, u16 cmd, void *buf_in, u16 in_size, u16 vf_id, u16 cmd, void *buf_in, u16 in_size,
void *buf_out, u16 *out_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 #endif
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#include "sss_nic_netdev_ops_api.h" #include "sss_nic_netdev_ops_api.h"
#include "sss_nic_ntuple.h" #include "sss_nic_ntuple.h"
#include "sss_nic_event.h" #include "sss_nic_event.h"
#include "sss_tool_nic_func.h"
#define DEFAULT_POLL_BUDGET 64 #define DEFAULT_POLL_BUDGET 64
static u32 poll_budget = DEFAULT_POLL_BUDGET; static u32 poll_budget = DEFAULT_POLL_BUDGET;
...@@ -1021,6 +1023,7 @@ struct sss_uld_info g_nic_uld_info = { ...@@ -1021,6 +1023,7 @@ struct sss_uld_info g_nic_uld_info = {
.suspend = NULL, .suspend = NULL,
.resume = NULL, .resume = NULL,
.event = sss_nic_event, .event = sss_nic_event,
.ioctl = sss_tool_ioctl,
}; };
struct sss_uld_info *get_nic_uld_info(void) struct sss_uld_info *get_nic_uld_info(void)
......
...@@ -603,7 +603,7 @@ static int sss_nic_ndo_set_vf_tx_rate(struct net_device *netdev, int vf_id, ...@@ -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), 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) { if (ret != 0) {
nicif_err(nic_dev, drv, netdev, nicif_err(nic_dev, drv, netdev,
"Fail to set VF %d max rate %d min rate %d%s\n", "Fail to set VF %d max rate %d min rate %d%s\n",
......
...@@ -64,4 +64,6 @@ void sss_nic_get_tx_stats(struct sss_nic_dev *nic_dev, ...@@ -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, void sss_nic_get_rx_stats(struct sss_nic_dev *nic_dev,
struct rtnl_link_stats64 *stats); struct rtnl_link_stats64 *stats);
u32 sss_nic_get_io_stats_size(const struct sss_nic_dev *nic_dev);
#endif #endif
/* 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 */
// 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;
}
/* 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
// 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);
}
/* 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
// 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;
}
/* 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
// 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;
}
/* 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
// 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;
}
/* 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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册