7682 lines
200 KiB
Diff
7682 lines
200 KiB
Diff
From 7b0eefe88a023359f72dadc87a4d2449d765a38a Mon Sep 17 00:00:00 2001
|
|
From: Rong Qian <qianr@yunsilicon.com>
|
|
Date: Fri, 14 Mar 2025 14:17:42 +0800
|
|
Subject: [PATCH v4 1/1] net/xsc: add xsc PMD
|
|
|
|
---
|
|
drivers/net/meson.build | 1 +
|
|
drivers/net/xsc/meson.build | 56 ++
|
|
drivers/net/xsc/xsc_cmd.h | 478 +++++++++++
|
|
drivers/net/xsc/xsc_compat.c | 15 +
|
|
drivers/net/xsc/xsc_compat.h | 46 ++
|
|
drivers/net/xsc/xsc_defs.h | 102 +++
|
|
drivers/net/xsc/xsc_dev.c | 413 ++++++++++
|
|
drivers/net/xsc/xsc_dev.h | 200 +++++
|
|
drivers/net/xsc/xsc_ethdev.c | 966 +++++++++++++++++++++++
|
|
drivers/net/xsc/xsc_ethdev.h | 63 ++
|
|
drivers/net/xsc/xsc_log.h | 48 ++
|
|
drivers/net/xsc/xsc_np.c | 489 ++++++++++++
|
|
drivers/net/xsc/xsc_np.h | 156 ++++
|
|
drivers/net/xsc/xsc_rdma.c | 1304 +++++++++++++++++++++++++++++++
|
|
drivers/net/xsc/xsc_rx.c | 518 ++++++++++++
|
|
drivers/net/xsc/xsc_rx.h | 65 ++
|
|
drivers/net/xsc/xsc_rxtx.h | 193 +++++
|
|
drivers/net/xsc/xsc_tx.c | 353 +++++++++
|
|
drivers/net/xsc/xsc_tx.h | 62 ++
|
|
drivers/net/xsc/xsc_vfio.c | 1128 ++++++++++++++++++++++++++
|
|
drivers/net/xsc/xsc_vfio_mbox.c | 691 ++++++++++++++++
|
|
drivers/net/xsc/xsc_vfio_mbox.h | 142 ++++
|
|
22 files changed, 7489 insertions(+)
|
|
create mode 100644 drivers/net/xsc/meson.build
|
|
create mode 100644 drivers/net/xsc/xsc_cmd.h
|
|
create mode 100644 drivers/net/xsc/xsc_compat.c
|
|
create mode 100644 drivers/net/xsc/xsc_compat.h
|
|
create mode 100644 drivers/net/xsc/xsc_defs.h
|
|
create mode 100644 drivers/net/xsc/xsc_dev.c
|
|
create mode 100644 drivers/net/xsc/xsc_dev.h
|
|
create mode 100644 drivers/net/xsc/xsc_ethdev.c
|
|
create mode 100644 drivers/net/xsc/xsc_ethdev.h
|
|
create mode 100644 drivers/net/xsc/xsc_log.h
|
|
create mode 100644 drivers/net/xsc/xsc_np.c
|
|
create mode 100644 drivers/net/xsc/xsc_np.h
|
|
create mode 100644 drivers/net/xsc/xsc_rdma.c
|
|
create mode 100644 drivers/net/xsc/xsc_rx.c
|
|
create mode 100644 drivers/net/xsc/xsc_rx.h
|
|
create mode 100644 drivers/net/xsc/xsc_rxtx.h
|
|
create mode 100644 drivers/net/xsc/xsc_tx.c
|
|
create mode 100644 drivers/net/xsc/xsc_tx.h
|
|
create mode 100644 drivers/net/xsc/xsc_vfio.c
|
|
create mode 100644 drivers/net/xsc/xsc_vfio_mbox.c
|
|
create mode 100644 drivers/net/xsc/xsc_vfio_mbox.h
|
|
|
|
diff --git a/drivers/net/meson.build b/drivers/net/meson.build
|
|
index bd38b53..1c445f3 100644
|
|
--- a/drivers/net/meson.build
|
|
+++ b/drivers/net/meson.build
|
|
@@ -61,6 +61,7 @@ drivers = [
|
|
'vhost',
|
|
'virtio',
|
|
'vmxnet3',
|
|
+ 'xsc',
|
|
]
|
|
std_deps = ['ethdev', 'kvargs'] # 'ethdev' also pulls in mbuf, net, eal etc
|
|
std_deps += ['bus_pci'] # very many PMDs depend on PCI, so make std
|
|
diff --git a/drivers/net/xsc/meson.build b/drivers/net/xsc/meson.build
|
|
new file mode 100644
|
|
index 0000000..c72d001
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/meson.build
|
|
@@ -0,0 +1,56 @@
|
|
+# SPDX-License-Identifier: BSD-3-Clause
|
|
+# Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+
|
|
+if not is_linux or not dpdk_conf.get('RTE_ARCH_64')
|
|
+ build = false
|
|
+ reason = 'only supported on 64bit Linux'
|
|
+endif
|
|
+
|
|
+sources = files(
|
|
+ 'xsc_ethdev.c',
|
|
+ 'xsc_dev.c',
|
|
+ 'xsc_vfio_mbox.c',
|
|
+ 'xsc_vfio.c',
|
|
+ 'xsc_np.c',
|
|
+ 'xsc_rx.c',
|
|
+ 'xsc_tx.c',
|
|
+ 'xsc_compat.c',
|
|
+)
|
|
+
|
|
+libnames = ['ibverbs']
|
|
+foreach libname:libnames
|
|
+ lib = dependency('lib' + libname, required: false, method : 'pkg-config')
|
|
+ if lib.found()
|
|
+ build_rdma = true
|
|
+ ext_deps += lib
|
|
+ else
|
|
+ build_rdma = false
|
|
+ reason = 'missing dependency, "' + libname + '"'
|
|
+ endif
|
|
+endforeach
|
|
+
|
|
+lib = dependency('libxscale', required: false, method : 'pkg-config')
|
|
+if lib.found()
|
|
+ build_rdma = true
|
|
+ ext_deps += lib
|
|
+else
|
|
+ build_rdma = false
|
|
+ reason = 'missing dependency, "' + libname + '"'
|
|
+endif
|
|
+
|
|
+header_to_check = 'infiniband/xscdv.h'
|
|
+if cc.has_header(header_to_check)
|
|
+ build_rdma = true
|
|
+ cflags += '-DHAVE_XSC_DV_PROVIDER=1'
|
|
+ message(header_to_check + ' found, defining HAVE_XSC_DV_PROVIDER=1')
|
|
+else
|
|
+ build_rdma = false
|
|
+ cflags += '-DHAVE_XSC_DV_PROVIDER=0'
|
|
+ message(header_to_check + ' not found, defining HAVE_XSC_DV_PROVIDER=0')
|
|
+endif
|
|
+
|
|
+if build_rdma
|
|
+ sources += files('xsc_rdma.c')
|
|
+else
|
|
+ message('Some dependencies are missing, xsc_rdma.c will not be compiled.')
|
|
+endif
|
|
\ No newline at end of file
|
|
diff --git a/drivers/net/xsc/xsc_cmd.h b/drivers/net/xsc/xsc_cmd.h
|
|
new file mode 100644
|
|
index 0000000..b6b5021
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_cmd.h
|
|
@@ -0,0 +1,478 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#ifndef _XSC_CMD_H_
|
|
+#define _XSC_CMD_H_
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include <unistd.h>
|
|
+#include <string.h>
|
|
+#include <dirent.h>
|
|
+#include <net/if.h>
|
|
+
|
|
+#define XSC_BOARD_SN_LEN 32
|
|
+#define XSC_CMD_QUERY_HCA_CAP_V1 1
|
|
+
|
|
+enum xsc_cmd_opcode {
|
|
+ XSC_CMD_OP_QUERY_HCA_CAP = 0x100,
|
|
+ XSC_CMD_OP_FUNCTION_RESET = 0x10c,
|
|
+ XSC_CMD_OP_SET_QP_STATUS = 0x200,
|
|
+ XSC_CMD_OP_CREATE_CQ = 0x400,
|
|
+ XSC_CMD_OP_DESTROY_CQ = 0x401,
|
|
+ XSC_CMD_OP_CREATE_QP = 0x500,
|
|
+ XSC_CMD_OP_DESTROY_QP = 0x501,
|
|
+ XSC_CMD_OP_RTR2RTS_QP = 0x504,
|
|
+ XSC_CMD_OP_QP_2RST = 0x50A,
|
|
+ XSC_CMD_OP_CREATE_MULTI_QP = 0x515,
|
|
+ XSC_CMD_OP_MODIFY_NIC_HCA = 0x812,
|
|
+ XSC_CMD_OP_MODIFY_RAW_QP = 0x81f,
|
|
+ XSC_CMD_OP_QUERY_VPORT_STATE = 0x822,
|
|
+ XSC_CMD_OP_QUERY_EVENT_TYPE = 0x831,
|
|
+ XSC_CMD_OP_QUERY_LINK_INFO = 0x832,
|
|
+ XSC_CMD_OP_ENABLE_MSIX = 0x850,
|
|
+ XSC_CMD_OP_EXEC_NP = 0x900,
|
|
+ XSC_CMD_OP_SET_MTU = 0x1100,
|
|
+ XSC_CMD_OP_QUERY_ETH_MAC = 0X1101,
|
|
+ XSC_CMD_OP_SET_PORT_ADMIN_STATUS = 0x1801,
|
|
+ XSC_CMD_OP_MAX
|
|
+};
|
|
+
|
|
+enum xsc_cmd_status {
|
|
+ XSC_CMD_SUCC = 0,
|
|
+ XSC_CMD_FAIL,
|
|
+ XSC_CMD_TIMEOUT,
|
|
+};
|
|
+
|
|
+struct xsc_cmd_inbox_hdr {
|
|
+ rte_be16_t opcode;
|
|
+ uint8_t rsvd[4];
|
|
+ rte_be16_t ver;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_outbox_hdr {
|
|
+ uint8_t status;
|
|
+ uint8_t rsvd[5];
|
|
+ rte_be16_t ver;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_fw_version {
|
|
+ uint8_t major;
|
|
+ uint8_t minor;
|
|
+ rte_be16_t patch;
|
|
+ rte_be32_t tweak;
|
|
+ uint8_t extra_flag;
|
|
+ uint8_t rsv[7];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_hca_cap {
|
|
+ uint8_t rsvd1[12];
|
|
+ uint8_t send_seg_num;
|
|
+ uint8_t send_wqe_shift;
|
|
+ uint8_t recv_seg_num;
|
|
+ uint8_t recv_wqe_shift;
|
|
+ uint8_t log_max_srq_sz;
|
|
+ uint8_t log_max_qp_sz;
|
|
+ uint8_t log_max_mtt;
|
|
+ uint8_t log_max_qp;
|
|
+ uint8_t log_max_strq_sz;
|
|
+ uint8_t log_max_srqs;
|
|
+ uint8_t rsvd2[2];
|
|
+ uint8_t log_max_tso;
|
|
+ uint8_t log_max_cq_sz;
|
|
+ uint8_t rsvd3;
|
|
+ uint8_t log_max_cq;
|
|
+ uint8_t log_max_eq_sz;
|
|
+ uint8_t log_max_mkey;
|
|
+ uint8_t log_max_msix;
|
|
+ uint8_t log_max_eq;
|
|
+ uint8_t max_indirection;
|
|
+ uint8_t log_max_mrw_sz;
|
|
+ uint8_t log_max_bsf_list_sz;
|
|
+ uint8_t log_max_klm_list_sz;
|
|
+ uint8_t rsvd4;
|
|
+ uint8_t log_max_ra_req_dc;
|
|
+ uint8_t rsvd5;
|
|
+ uint8_t log_max_ra_res_dc;
|
|
+ uint8_t rsvd6;
|
|
+ uint8_t log_max_ra_req_qp;
|
|
+ uint8_t log_max_qp_depth;
|
|
+ uint8_t log_max_ra_res_qp;
|
|
+ rte_be16_t max_vfs;
|
|
+ rte_be16_t raweth_qp_id_end;
|
|
+ rte_be16_t raw_tpe_qp_num;
|
|
+ rte_be16_t max_qp_count;
|
|
+ rte_be16_t raweth_qp_id_base;
|
|
+ uint8_t rsvd7;
|
|
+ uint8_t local_ca_ack_delay;
|
|
+ uint8_t max_num_eqs;
|
|
+ uint8_t num_ports;
|
|
+ uint8_t log_max_msg;
|
|
+ uint8_t mac_port;
|
|
+ rte_be16_t raweth_rss_qp_id_base;
|
|
+ rte_be16_t stat_rate_support;
|
|
+ uint8_t rsvd8[2];
|
|
+ rte_be64_t flags;
|
|
+ uint8_t rsvd9;
|
|
+ uint8_t uar_sz;
|
|
+ uint8_t rsvd10;
|
|
+ uint8_t log_pg_sz;
|
|
+ rte_be16_t bf_log_bf_reg_size;
|
|
+ rte_be16_t msix_base;
|
|
+ rte_be16_t msix_num;
|
|
+ rte_be16_t max_desc_sz_sq;
|
|
+ uint8_t rsvd11[2];
|
|
+ rte_be16_t max_desc_sz_rq;
|
|
+ uint8_t rsvd12[2];
|
|
+ rte_be16_t max_desc_sz_sq_dc;
|
|
+ uint8_t rsvd13[4];
|
|
+ rte_be16_t max_qp_mcg;
|
|
+ uint8_t rsvd14;
|
|
+ uint8_t log_max_mcg;
|
|
+ uint8_t rsvd15;
|
|
+ uint8_t log_max_pd;
|
|
+ uint8_t rsvd16;
|
|
+ uint8_t log_max_xrcd;
|
|
+ uint8_t rsvd17[40];
|
|
+ rte_be32_t uar_page_sz;
|
|
+ uint8_t rsvd18[8];
|
|
+ rte_be32_t hw_feature_flag;
|
|
+ rte_be16_t pf0_vf_funcid_base;
|
|
+ rte_be16_t pf0_vf_funcid_top;
|
|
+ rte_be16_t pf1_vf_funcid_base;
|
|
+ rte_be16_t pf1_vf_funcid_top;
|
|
+ rte_be16_t pcie0_pf_funcid_base;
|
|
+ rte_be16_t pcie0_pf_funcid_top;
|
|
+ rte_be16_t pcie1_pf_funcid_base;
|
|
+ rte_be16_t pcie1_pf_funcid_top;
|
|
+ uint8_t log_msx_atomic_size_qp;
|
|
+ uint8_t pcie_host;
|
|
+ uint8_t rsvd19;
|
|
+ uint8_t log_msx_atomic_size_dc;
|
|
+ uint8_t board_sn[XSC_BOARD_SN_LEN];
|
|
+ uint8_t max_tc;
|
|
+ uint8_t mac_bit;
|
|
+ rte_be16_t funcid_to_logic_port;
|
|
+ uint8_t rsvd20[6];
|
|
+ uint8_t nif_port_num;
|
|
+ uint8_t reg_mr_via_cmdq;
|
|
+ rte_be32_t hca_core_clock;
|
|
+ rte_be32_t max_rwq_indirection_tables;
|
|
+ rte_be32_t max_rwq_indirection_table_size;
|
|
+ rte_be32_t chip_ver_h;
|
|
+ rte_be32_t chip_ver_m;
|
|
+ rte_be32_t chip_ver_l;
|
|
+ rte_be32_t hotfix_num;
|
|
+ rte_be32_t feature_flag;
|
|
+ rte_be32_t rx_pkt_len_max;
|
|
+ rte_be32_t glb_func_id;
|
|
+ rte_be64_t tx_db;
|
|
+ rte_be64_t rx_db;
|
|
+ rte_be64_t complete_db;
|
|
+ rte_be64_t complete_reg;
|
|
+ rte_be64_t event_db;
|
|
+ rte_be32_t qp_rate_limit_min;
|
|
+ rte_be32_t qp_rate_limit_max;
|
|
+ struct xsc_cmd_fw_version fw_ver;
|
|
+ uint8_t lag_logic_port_ofst;
|
|
+ rte_be64_t max_mr_size;
|
|
+ rte_be16_t max_cmd_in_len;
|
|
+ rte_be16_t max_cmd_out_len;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_query_hca_cap_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ rte_be16_t cpu_num;
|
|
+ uint8_t rsvd[6];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_query_hca_cap_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint8_t rsvd[8];
|
|
+ struct xsc_cmd_hca_cap hca_cap;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_cq_context {
|
|
+ uint16_t eqn;
|
|
+ uint16_t pa_num;
|
|
+ uint16_t glb_func_id;
|
|
+ uint8_t log_cq_sz;
|
|
+ uint8_t cq_type;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_create_cq_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ struct xsc_cmd_cq_context ctx;
|
|
+ uint64_t pas[];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_create_cq_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint32_t cqn;
|
|
+ uint8_t rsvd[4];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_destroy_cq_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ uint32_t cqn;
|
|
+ uint8_t rsvd[4];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_destroy_cq_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint8_t rsvd[8];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_create_qp_request {
|
|
+ rte_be16_t input_qpn;
|
|
+ rte_be16_t pa_num;
|
|
+ uint8_t qp_type;
|
|
+ uint8_t log_sq_sz;
|
|
+ uint8_t log_rq_sz;
|
|
+ uint8_t dma_direct;
|
|
+ rte_be32_t pdn;
|
|
+ rte_be16_t cqn_send;
|
|
+ rte_be16_t cqn_recv;
|
|
+ rte_be16_t glb_funcid;
|
|
+ uint8_t page_shift;
|
|
+ uint8_t rsvd;
|
|
+ rte_be64_t pas[];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_create_qp_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ struct xsc_cmd_create_qp_request req;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_create_qp_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint32_t qpn;
|
|
+ uint8_t rsvd[4];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_create_multiqp_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ rte_be16_t qp_num;
|
|
+ uint8_t qp_type;
|
|
+ uint8_t rsvd;
|
|
+ rte_be32_t req_len;
|
|
+ uint8_t data[];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_create_multiqp_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ rte_be32_t qpn_base;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_destroy_qp_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ rte_be32_t qpn;
|
|
+ uint8_t rsvd[4];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_destroy_qp_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint8_t rsvd[8];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_qp_context {
|
|
+ rte_be32_t remote_qpn;
|
|
+ rte_be32_t cqn_send;
|
|
+ rte_be32_t cqn_recv;
|
|
+ rte_be32_t next_send_psn;
|
|
+ rte_be32_t next_recv_psn;
|
|
+ rte_be32_t pdn;
|
|
+ rte_be16_t src_udp_port;
|
|
+ rte_be16_t path_id;
|
|
+ uint8_t mtu_mode;
|
|
+ uint8_t lag_sel;
|
|
+ uint8_t lag_sel_en;
|
|
+ uint8_t retry_cnt;
|
|
+ uint8_t rnr_retry;
|
|
+ uint8_t dscp;
|
|
+ uint8_t state;
|
|
+ uint8_t hop_limit;
|
|
+ uint8_t dmac[6];
|
|
+ uint8_t smac[6];
|
|
+ rte_be32_t dip[4];
|
|
+ rte_be32_t sip[4];
|
|
+ rte_be16_t ip_type;
|
|
+ rte_be16_t grp_id;
|
|
+ uint8_t vlan_valid;
|
|
+ uint8_t dci_cfi_prio_sl;
|
|
+ rte_be16_t vlan_id;
|
|
+ uint8_t qp_out_port;
|
|
+ uint8_t pcie_no;
|
|
+ rte_be16_t lag_id;
|
|
+ rte_be16_t func_id;
|
|
+ rte_be16_t rsvd;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_modify_qp_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ rte_be32_t qpn;
|
|
+ struct xsc_cmd_qp_context ctx;
|
|
+ uint8_t no_need_wait;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_modify_qp_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint8_t rsvd[8];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_modify_raw_qp_request {
|
|
+ uint16_t qpn;
|
|
+ uint16_t lag_id;
|
|
+ uint16_t func_id;
|
|
+ uint8_t dma_direct;
|
|
+ uint8_t prio;
|
|
+ uint8_t qp_out_port;
|
|
+ uint8_t rsvd[7];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_modify_raw_qp_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ uint8_t pcie_no;
|
|
+ uint8_t rsv[7];
|
|
+ struct xsc_cmd_modify_raw_qp_request req;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_modify_raw_qp_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint8_t rsvd[8];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_set_mtu_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ rte_be16_t mtu;
|
|
+ rte_be16_t rx_buf_sz_min;
|
|
+ uint8_t mac_port;
|
|
+ uint8_t rsvd;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_set_mtu_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_query_eth_mac_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ uint8_t index;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_query_eth_mac_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint8_t mac[6];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_nic_attr {
|
|
+ rte_be16_t caps;
|
|
+ rte_be16_t caps_mask;
|
|
+ uint8_t mac_addr[6];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_rss_modify_attr {
|
|
+ uint8_t caps_mask;
|
|
+ uint8_t rss_en;
|
|
+ rte_be16_t rqn_base;
|
|
+ rte_be16_t rqn_num;
|
|
+ uint8_t hfunc;
|
|
+ rte_be32_t hash_tmpl;
|
|
+ uint8_t hash_key[52];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_modify_nic_hca_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ struct xsc_cmd_nic_attr nic;
|
|
+ struct xsc_cmd_rss_modify_attr rss;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_modify_nic_hca_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint8_t rsvd[4];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_set_port_admin_status_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ uint16_t admin_status;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_set_port_admin_status_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint32_t status;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_linkinfo {
|
|
+ uint8_t status; /*link status: 0-down, 1-up */
|
|
+ uint8_t port;
|
|
+ uint8_t duplex;
|
|
+ uint8_t autoneg;
|
|
+ uint32_t linkspeed;
|
|
+ uint64_t supported;
|
|
+ uint64_t advertising;
|
|
+ uint64_t supported_fec;
|
|
+ uint64_t advertised_fec;
|
|
+ uint64_t supported_speed[2];
|
|
+ uint64_t advertising_speed[2];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_query_linkinfo_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_query_linkinfo_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ struct xsc_cmd_linkinfo ctx;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_query_vport_state_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ uint32_t other_vport:1;
|
|
+ uint32_t vport_number:16;
|
|
+ uint32_t rsv:15;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_query_vport_state_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint8_t admin_state:4;
|
|
+ uint8_t state:4;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_event_resp {
|
|
+ uint8_t resp_event_type;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_event_query_type_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ uint8_t rsvd[2];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_event_query_type_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ struct xsc_cmd_event_resp ctx;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_msix_table_info_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ uint16_t index;
|
|
+ uint8_t rsvd[6];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_msix_table_info_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint32_t addr_lo;
|
|
+ uint32_t addr_hi;
|
|
+ uint32_t data;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_function_reset_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ rte_be16_t glb_func_id;
|
|
+ uint8_t rsvd[6];
|
|
+};
|
|
+
|
|
+struct xsc_cmd_function_reset_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint8_t rsvd[8];
|
|
+};
|
|
+
|
|
+#endif /* _XSC_CMD_H_ */
|
|
diff --git a/drivers/net/xsc/xsc_compat.c b/drivers/net/xsc/xsc_compat.c
|
|
new file mode 100644
|
|
index 0000000..4913ec9
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_compat.c
|
|
@@ -0,0 +1,15 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#include "xsc_compat.h"
|
|
+
|
|
+#if RTE_VERSION_NUM(22, 0, 0, 0) > RTE_VERSION
|
|
+uint16_t
|
|
+rte_eth_pkt_burst_dummy(void *queue __rte_unused,
|
|
+ struct rte_mbuf **pkts __rte_unused,
|
|
+ uint16_t nb_pkts __rte_unused)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
diff --git a/drivers/net/xsc/xsc_compat.h b/drivers/net/xsc/xsc_compat.h
|
|
new file mode 100644
|
|
index 0000000..a57d817
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_compat.h
|
|
@@ -0,0 +1,46 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#ifndef _XSC_COMPAT_H_
|
|
+#define _XSC_COMPAT_H_
|
|
+
|
|
+#include <rte_mbuf_core.h>
|
|
+#include <rte_version.h>
|
|
+
|
|
+#if RTE_VERSION_NUM(22, 0, 0, 0) > RTE_VERSION
|
|
+#include <rte_bus_pci.h>
|
|
+#else
|
|
+#include <bus_pci_driver.h>
|
|
+#endif
|
|
+
|
|
+#if RTE_VERSION_NUM(25, 0, 0, 0) > RTE_VERSION
|
|
+#ifndef __rte_packed_begin
|
|
+#define __rte_packed_begin
|
|
+#endif
|
|
+
|
|
+#ifndef __rte_packed_end
|
|
+#define __rte_packed_end __rte_packed
|
|
+#endif
|
|
+#endif
|
|
+
|
|
+#if RTE_VERSION_NUM(22, 0, 0, 0) > RTE_VERSION
|
|
+/**
|
|
+ * @internal
|
|
+ * Dummy DPDK callback for Rx/Tx packet burst.
|
|
+ *
|
|
+ * @param queue
|
|
+ * Pointer to Rx/Tx queue
|
|
+ * @param pkts
|
|
+ * Packet array
|
|
+ * @param nb_pkts
|
|
+ * Number of packets in packet array
|
|
+ */
|
|
+__rte_internal
|
|
+uint16_t
|
|
+rte_eth_pkt_burst_dummy(void *queue __rte_unused,
|
|
+ struct rte_mbuf **pkts __rte_unused,
|
|
+ uint16_t nb_pkts __rte_unused);
|
|
+#endif
|
|
+
|
|
+#endif /* _XSC_COMPAT_H_ */
|
|
diff --git a/drivers/net/xsc/xsc_defs.h b/drivers/net/xsc/xsc_defs.h
|
|
new file mode 100644
|
|
index 0000000..78e4154
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_defs.h
|
|
@@ -0,0 +1,102 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#ifndef XSC_DEFS_H_
|
|
+#define XSC_DEFS_H_
|
|
+
|
|
+#define XSC_PAGE_SIZE 4096
|
|
+#define XSC_PHY_PORT_NUM 1
|
|
+
|
|
+#define XSC_PCI_VENDOR_ID 0x1f67
|
|
+#define XSC_PCI_DEV_ID_MS 0x1111
|
|
+#define XSC_PCI_DEV_ID_MSVF 0x1112
|
|
+#define XSC_PCI_DEV_ID_MVH 0x1151
|
|
+#define XSC_PCI_DEV_ID_MVHVF 0x1152
|
|
+#define XSC_PCI_DEV_ID_MVS 0x1153
|
|
+
|
|
+#define XSC_VFREP_BASE_LOGICAL_PORT 1081
|
|
+#define XSC_MAX_MAC_ADDRESSES 3
|
|
+
|
|
+#define XSC_RSS_HASH_KEY_LEN 52
|
|
+#define XSC_RSS_HASH_BIT_IPV4_SIP (1ULL << 0)
|
|
+#define XSC_RSS_HASH_BIT_IPV4_DIP (1ULL << 1)
|
|
+#define XSC_RSS_HASH_BIT_IPV6_SIP (1ULL << 2)
|
|
+#define XSC_RSS_HASH_BIT_IPV6_DIP (1ULL << 3)
|
|
+#define XSC_RSS_HASH_BIT_IPV4_SPORT (1ULL << 4)
|
|
+#define XSC_RSS_HASH_BIT_IPV4_DPORT (1ULL << 5)
|
|
+#define XSC_RSS_HASH_BIT_IPV6_SPORT (1ULL << 6)
|
|
+#define XSC_RSS_HASH_BIT_IPV6_DPORT (1ULL << 7)
|
|
+#define XSC_RSS_HASH_BIT_TNL_ID (1ULL << 8)
|
|
+#define XSC_RSS_HASH_BIT_NXT_PRO (1ULL << 9)
|
|
+
|
|
+#define XSC_EPAT_VLD_FLAG (1ULL)
|
|
+#define XSC_EPAT_RX_QP_ID_OFST_FLAG (1ULL << 2)
|
|
+#define XSC_EPAT_QP_NUM_FLAG (1ULL << 3)
|
|
+#define XSC_EPAT_RSS_EN_FLAG (1ULL << 4)
|
|
+#define XSC_EPAT_RSS_HASH_TEMPLATE_FLAG (1ULL << 5)
|
|
+#define XSC_EPAT_RSS_HASH_FUNC_FLAG (1ULL << 6)
|
|
+#define XSC_EPAT_HAS_PPH_FLAG (1ULL << 9)
|
|
+
|
|
+#define XSC_MAX_DESC_NUMBER 1024
|
|
+#define XSC_SEND_WQE_DS 3
|
|
+#define XSC_ESEG_EXTRA_DATA_SIZE 48u
|
|
+
|
|
+#define XSC_PF_TX_DB_ADDR 0x4802000
|
|
+#define XSC_PF_RX_DB_ADDR 0x4804000
|
|
+#define XSC_PF_CQ_DB_ADDR 0x2120000
|
|
+
|
|
+#define XSC_VF_RX_DB_ADDR 0x8d4
|
|
+#define XSC_VF_TX_DB_ADDR 0x8d0
|
|
+#define XSC_VF_CQ_DB_ADDR 0x8c4
|
|
+
|
|
+#define XSC_HIF_CMDQM_VECTOR_ID_MEM_ADDR 0x1034000
|
|
+
|
|
+enum xsc_nic_mode {
|
|
+ XSC_NIC_MODE_LEGACY,
|
|
+ XSC_NIC_MODE_SWITCHDEV,
|
|
+ XSC_NIC_MODE_SOC,
|
|
+};
|
|
+
|
|
+enum xsc_pph_type {
|
|
+ XSC_PPH_NONE = 0,
|
|
+ XSC_RX_PPH = 0x1,
|
|
+ XSC_TX_PPH = 0x2,
|
|
+ XSC_VFREP_PPH = 0x4,
|
|
+ XSC_UPLINK_PPH = 0x8,
|
|
+};
|
|
+
|
|
+enum xsc_funcid_type {
|
|
+ XSC_FUNCID_TYPE_INVAL = 0x0,
|
|
+ XSC_EMU_FUNCID = 0x1,
|
|
+ XSC_PHYPORT_MAC_FUNCID = 0x2,
|
|
+ XSC_VF_IOCTL_FUNCID = 0x3,
|
|
+ XSC_PHYPORT_LAG_FUNCID = 0x4,
|
|
+ XSC_FUNCID_TYPE_UNKNOWN = 0x5,
|
|
+};
|
|
+
|
|
+enum xsc_port_type {
|
|
+ XSC_PORT_TYPE_NONE = 0,
|
|
+ XSC_PORT_TYPE_UPLINK,
|
|
+ XSC_PORT_TYPE_UPLINK_BOND,
|
|
+ XSC_PORT_TYPE_PFVF,
|
|
+ XSC_PORT_TYPE_PFHPF,
|
|
+ XSC_PORT_TYPE_UNKNOWN,
|
|
+};
|
|
+
|
|
+enum xsc_tbm_cap {
|
|
+ XSC_TBM_CAP_HASH_PPH = 0,
|
|
+ XSC_TBM_CAP_RSS,
|
|
+ XSC_TBM_CAP_PP_BYPASS,
|
|
+ XSC_TBM_CAP_PCT_DROP_CONFIG,
|
|
+};
|
|
+
|
|
+enum xsc_rss_hf {
|
|
+ XSC_RSS_HASH_KEY_UPDATE = 0,
|
|
+ XSC_RSS_HASH_TEMP_UPDATE,
|
|
+ XSC_RSS_HASH_FUNC_UPDATE,
|
|
+ XSC_RSS_RXQ_UPDATE,
|
|
+ XSC_RSS_RXQ_DROP,
|
|
+};
|
|
+
|
|
+#endif /* XSC_DEFS_H_ */
|
|
diff --git a/drivers/net/xsc/xsc_dev.c b/drivers/net/xsc/xsc_dev.c
|
|
new file mode 100644
|
|
index 0000000..0562241
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_dev.c
|
|
@@ -0,0 +1,413 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <sys/stat.h>
|
|
+#include <fcntl.h>
|
|
+#include <limits.h>
|
|
+#include <sys/mman.h>
|
|
+
|
|
+#include <rte_pci.h>
|
|
+#include <rte_bus_pci.h>
|
|
+#include <rte_kvargs.h>
|
|
+#include <rte_eal_paging.h>
|
|
+#include <rte_bitops.h>
|
|
+
|
|
+#include "xsc_log.h"
|
|
+#include "xsc_defs.h"
|
|
+#include "xsc_dev.h"
|
|
+#include "xsc_cmd.h"
|
|
+
|
|
+#define XSC_DEV_DEF_FLOW_MODE 7
|
|
+
|
|
+TAILQ_HEAD(xsc_dev_ops_list, xsc_dev_ops);
|
|
+static struct xsc_dev_ops_list dev_ops_list = TAILQ_HEAD_INITIALIZER(dev_ops_list);
|
|
+
|
|
+static const struct xsc_dev_ops *
|
|
+xsc_dev_ops_get(enum rte_pci_kernel_driver kdrv)
|
|
+{
|
|
+ const struct xsc_dev_ops *ops;
|
|
+
|
|
+ TAILQ_FOREACH(ops, &dev_ops_list, entry) {
|
|
+ if (ops->kdrv & (1 << kdrv))
|
|
+ return ops;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+void
|
|
+xsc_dev_ops_register(struct xsc_dev_ops *new_ops)
|
|
+{
|
|
+ struct xsc_dev_ops *ops;
|
|
+
|
|
+ TAILQ_FOREACH(ops, &dev_ops_list, entry) {
|
|
+ if (ops->kdrv == new_ops->kdrv) {
|
|
+ PMD_DRV_LOG(ERR, "xsc dev ops exists, kdrv=%" PRIu64 "", new_ops->kdrv);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ TAILQ_INSERT_TAIL(&dev_ops_list, new_ops, entry);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_mailbox_exec(struct xsc_dev *xdev, void *data_in,
|
|
+ int in_len, void *data_out, int out_len)
|
|
+{
|
|
+ return xdev->dev_ops->mailbox_exec(xdev, data_in, in_len,
|
|
+ data_out, out_len);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_intr_event_get(struct xsc_dev *xdev)
|
|
+{
|
|
+ return xdev->dev_ops->intr_event_get(xdev);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_intr_handler_install(struct xsc_dev *xdev, rte_intr_callback_fn cb, void *cb_arg)
|
|
+{
|
|
+ return xdev->dev_ops->intr_handler_install(xdev, cb, cb_arg);
|
|
+}
|
|
+
|
|
+int xsc_dev_intr_handler_uninstall(struct xsc_dev *xdev)
|
|
+{
|
|
+ return xdev->dev_ops->intr_handler_uninstall(xdev);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_set_link_up(struct xsc_dev *xdev)
|
|
+{
|
|
+ if (xdev->dev_ops->set_link_up == NULL)
|
|
+ return -ENOTSUP;
|
|
+
|
|
+ return xdev->dev_ops->set_link_up(xdev);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_set_link_down(struct xsc_dev *xdev)
|
|
+{
|
|
+ if (xdev->dev_ops->set_link_down == NULL)
|
|
+ return -ENOTSUP;
|
|
+
|
|
+ return xdev->dev_ops->set_link_down(xdev);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_link_update(struct xsc_dev *xdev, int wait_to_complete)
|
|
+{
|
|
+ if (xdev->dev_ops->link_update == NULL)
|
|
+ return -ENOTSUP;
|
|
+
|
|
+ return xdev->dev_ops->link_update(xdev, wait_to_complete);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_set_mtu(struct xsc_dev *xdev, uint16_t mtu)
|
|
+{
|
|
+ return xdev->dev_ops->set_mtu(xdev, mtu);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_get_mac(struct xsc_dev *xdev, uint8_t *mac)
|
|
+{
|
|
+ return xdev->dev_ops->get_mac(xdev, mac);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_destroy_qp(struct xsc_dev *xdev, void *qp)
|
|
+{
|
|
+ return xdev->dev_ops->destroy_qp(qp);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_destroy_cq(struct xsc_dev *xdev, void *cq)
|
|
+{
|
|
+ return xdev->dev_ops->destroy_cq(cq);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_modify_qp_status(struct xsc_dev *xdev, uint32_t qpn, int num, int opcode)
|
|
+{
|
|
+ return xdev->dev_ops->modify_qp_status(xdev, qpn, num, opcode);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_modify_qp_qostree(struct xsc_dev *xdev, uint16_t qpn)
|
|
+{
|
|
+ return xdev->dev_ops->modify_qp_qostree(xdev, qpn);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_rx_cq_create(struct xsc_dev *xdev, struct xsc_rx_cq_params *cq_params,
|
|
+ struct xsc_rx_cq_info *cq_info)
|
|
+{
|
|
+ return xdev->dev_ops->rx_cq_create(xdev, cq_params, cq_info);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_tx_cq_create(struct xsc_dev *xdev, struct xsc_tx_cq_params *cq_params,
|
|
+ struct xsc_tx_cq_info *cq_info)
|
|
+{
|
|
+ return xdev->dev_ops->tx_cq_create(xdev, cq_params, cq_info);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_tx_qp_create(struct xsc_dev *xdev, struct xsc_tx_qp_params *qp_params,
|
|
+ struct xsc_tx_qp_info *qp_info)
|
|
+{
|
|
+ return xdev->dev_ops->tx_qp_create(xdev, qp_params, qp_info);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_close(struct xsc_dev *xdev, int repr_id)
|
|
+{
|
|
+ xsc_dev_clear_pct(xdev, repr_id);
|
|
+ return xdev->dev_ops->dev_close(xdev);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_rss_key_modify(struct xsc_dev *xdev, uint8_t *rss_key, uint8_t rss_key_len)
|
|
+{
|
|
+ struct xsc_cmd_modify_nic_hca_mbox_in in = {};
|
|
+ struct xsc_cmd_modify_nic_hca_mbox_out out = {};
|
|
+ uint8_t rss_caps_mask = 0;
|
|
+ int ret, key_len = 0;
|
|
+
|
|
+ in.hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_MODIFY_NIC_HCA);
|
|
+
|
|
+ key_len = RTE_MIN(rss_key_len, XSC_RSS_HASH_KEY_LEN);
|
|
+ rte_memcpy(in.rss.hash_key, rss_key, key_len);
|
|
+ rss_caps_mask |= RTE_BIT32(XSC_RSS_HASH_KEY_UPDATE);
|
|
+
|
|
+ in.rss.caps_mask = rss_caps_mask;
|
|
+ in.rss.rss_en = 1;
|
|
+ in.nic.caps_mask = rte_cpu_to_be_16(RTE_BIT32(XSC_TBM_CAP_RSS));
|
|
+ in.nic.caps = in.nic.caps_mask;
|
|
+
|
|
+ ret = xsc_dev_mailbox_exec(xdev, &in, sizeof(in), &out, sizeof(out));
|
|
+ if (ret != 0 || out.hdr.status != 0)
|
|
+ return -1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_dev_alloc_vfos_info(struct xsc_dev *xdev)
|
|
+{
|
|
+ struct xsc_hwinfo *hwinfo;
|
|
+ int base_lp = 0;
|
|
+
|
|
+ if (xsc_dev_is_vf(xdev))
|
|
+ return 0;
|
|
+
|
|
+ hwinfo = &xdev->hwinfo;
|
|
+ if (hwinfo->pcie_no == 1) {
|
|
+ xdev->vfrep_offset = hwinfo->func_id -
|
|
+ hwinfo->pcie1_pf_funcid_base +
|
|
+ hwinfo->pcie0_pf_funcid_top -
|
|
+ hwinfo->pcie0_pf_funcid_base + 1;
|
|
+ } else {
|
|
+ xdev->vfrep_offset = hwinfo->func_id - hwinfo->pcie0_pf_funcid_base;
|
|
+ }
|
|
+
|
|
+ base_lp = XSC_VFREP_BASE_LOGICAL_PORT;
|
|
+ if (xdev->devargs.nic_mode == XSC_NIC_MODE_LEGACY)
|
|
+ base_lp += xdev->vfrep_offset;
|
|
+ xdev->vfos_logical_in_port = base_lp;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_dev_args_parse(struct xsc_dev *xdev, struct rte_devargs *devargs)
|
|
+{
|
|
+ struct rte_kvargs *kvlist;
|
|
+ struct xsc_devargs *xdevargs = &xdev->devargs;
|
|
+ const char *tmp;
|
|
+
|
|
+ kvlist = rte_kvargs_parse(devargs->args, NULL);
|
|
+ if (kvlist == NULL)
|
|
+ return;
|
|
+
|
|
+ tmp = rte_kvargs_get(kvlist, XSC_PPH_MODE_ARG);
|
|
+ if (tmp != NULL)
|
|
+ xdevargs->pph_mode = atoi(tmp);
|
|
+ else
|
|
+ xdevargs->pph_mode = XSC_PPH_NONE;
|
|
+
|
|
+ tmp = rte_kvargs_get(kvlist, XSC_NIC_MODE_ARG);
|
|
+ if (tmp != NULL)
|
|
+ xdevargs->nic_mode = atoi(tmp);
|
|
+ else
|
|
+ xdevargs->nic_mode = XSC_NIC_MODE_LEGACY;
|
|
+
|
|
+ tmp = rte_kvargs_get(kvlist, XSC_FLOW_MODE_ARG);
|
|
+ if (tmp != NULL)
|
|
+ xdevargs->flow_mode = atoi(tmp);
|
|
+ else
|
|
+ xdevargs->flow_mode = XSC_DEV_DEF_FLOW_MODE;
|
|
+
|
|
+ rte_kvargs_free(kvlist);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_qp_set_id_get(struct xsc_dev *xdev, int repr_id)
|
|
+{
|
|
+ if (xsc_dev_is_vf(xdev))
|
|
+ return 0;
|
|
+
|
|
+ return (repr_id % 511 + 1);
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_repr_info_init(struct xsc_dev *xdev, struct xsc_repr_info *info,
|
|
+ enum xsc_port_type port_type,
|
|
+ enum xsc_funcid_type funcid_type, int32_t repr_id)
|
|
+{
|
|
+ int qp_set_id, logical_port;
|
|
+ struct xsc_hwinfo *hwinfo = &xdev->hwinfo;
|
|
+
|
|
+ info->repr_id = repr_id;
|
|
+ info->port_type = port_type;
|
|
+ if (port_type == XSC_PORT_TYPE_UPLINK_BOND) {
|
|
+ info->pf_bond = 1;
|
|
+ info->funcid = XSC_PHYPORT_LAG_FUNCID << 14;
|
|
+ } else if (port_type == XSC_PORT_TYPE_UPLINK) {
|
|
+ info->pf_bond = -1;
|
|
+ info->funcid = funcid_type << 14;
|
|
+ } else if (port_type == XSC_PORT_TYPE_PFVF) {
|
|
+ info->funcid = funcid_type << 14;
|
|
+ }
|
|
+
|
|
+ qp_set_id = xsc_dev_qp_set_id_get(xdev, repr_id);
|
|
+ if (xsc_dev_is_vf(xdev))
|
|
+ logical_port = xdev->hwinfo.func_id +
|
|
+ xdev->hwinfo.funcid_to_logic_port_off;
|
|
+ else
|
|
+ logical_port = xdev->vfos_logical_in_port + qp_set_id - 1;
|
|
+
|
|
+ info->logical_port = logical_port;
|
|
+ info->local_dstinfo = logical_port;
|
|
+ info->peer_logical_port = hwinfo->mac_phy_port;
|
|
+ info->peer_dstinfo = hwinfo->mac_phy_port;
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_repr_ports_probe(struct xsc_dev *xdev, int nb_repr_ports, int max_eth_ports)
|
|
+{
|
|
+ int funcid_type;
|
|
+ struct xsc_repr_port *repr_port;
|
|
+ int i;
|
|
+
|
|
+ PMD_INIT_FUNC_TRACE();
|
|
+
|
|
+ xdev->num_repr_ports = nb_repr_ports + XSC_PHY_PORT_NUM;
|
|
+ if (xdev->num_repr_ports > max_eth_ports) {
|
|
+ PMD_DRV_LOG(ERR, "Repr ports num %d, should be less than max %d",
|
|
+ xdev->num_repr_ports, max_eth_ports);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ xdev->repr_ports = rte_zmalloc(NULL,
|
|
+ sizeof(struct xsc_repr_port) * xdev->num_repr_ports,
|
|
+ RTE_CACHE_LINE_SIZE);
|
|
+ if (xdev->repr_ports == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to allocate memory for repr ports");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ funcid_type = (xdev->devargs.nic_mode == XSC_NIC_MODE_SWITCHDEV) ?
|
|
+ XSC_VF_IOCTL_FUNCID : XSC_PHYPORT_MAC_FUNCID;
|
|
+
|
|
+ /* PF representor use the last repr_ports */
|
|
+ repr_port = &xdev->repr_ports[xdev->num_repr_ports - 1];
|
|
+ xsc_repr_info_init(xdev, &repr_port->info, XSC_PORT_TYPE_UPLINK,
|
|
+ XSC_PHYPORT_MAC_FUNCID, xdev->num_repr_ports - 1);
|
|
+ repr_port->info.ifindex = xdev->ifindex;
|
|
+ repr_port->xdev = xdev;
|
|
+ LIST_INIT(&repr_port->def_pct_list);
|
|
+
|
|
+ /* VF representor start from 0 */
|
|
+ for (i = 0; i < nb_repr_ports; i++) {
|
|
+ repr_port = &xdev->repr_ports[i];
|
|
+ xsc_repr_info_init(xdev, &repr_port->info,
|
|
+ XSC_PORT_TYPE_PFVF, funcid_type, i);
|
|
+ repr_port->xdev = xdev;
|
|
+ LIST_INIT(&repr_port->def_pct_list);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void
|
|
+xsc_dev_uninit(struct xsc_dev *xdev)
|
|
+{
|
|
+ PMD_INIT_FUNC_TRACE();
|
|
+ xsc_dev_pct_uninit();
|
|
+ xsc_dev_close(xdev, XSC_DEV_REPR_ID_INVALID);
|
|
+ rte_free(xdev);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_init(struct rte_pci_device *pci_dev, struct xsc_dev **xdev)
|
|
+{
|
|
+ struct xsc_dev *d;
|
|
+ int ret;
|
|
+
|
|
+ PMD_INIT_FUNC_TRACE();
|
|
+
|
|
+ d = rte_zmalloc(NULL, sizeof(*d), RTE_CACHE_LINE_SIZE);
|
|
+ if (d == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc memory for xsc_dev");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ d->dev_ops = xsc_dev_ops_get(pci_dev->kdrv);
|
|
+ if (d->dev_ops == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Could not get dev_ops, kdrv=%d", pci_dev->kdrv);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ d->pci_dev = pci_dev;
|
|
+
|
|
+ if (d->dev_ops->dev_init)
|
|
+ d->dev_ops->dev_init(d);
|
|
+
|
|
+ xsc_dev_args_parse(d, pci_dev->device.devargs);
|
|
+
|
|
+ ret = xsc_dev_alloc_vfos_info(d);
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc vfos info");
|
|
+ ret = -EINVAL;
|
|
+ goto hwinfo_init_fail;
|
|
+ }
|
|
+
|
|
+ ret = xsc_dev_pct_init();
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to init xsc pct");
|
|
+ ret = -EINVAL;
|
|
+ goto hwinfo_init_fail;
|
|
+ }
|
|
+
|
|
+ *xdev = d;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+hwinfo_init_fail:
|
|
+ xsc_dev_uninit(d);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+bool
|
|
+xsc_dev_is_vf(struct xsc_dev *xdev)
|
|
+{
|
|
+ uint16_t device_id = xdev->pci_dev->id.device_id;
|
|
+
|
|
+ if (device_id == XSC_PCI_DEV_ID_MSVF ||
|
|
+ device_id == XSC_PCI_DEV_ID_MVHVF)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
diff --git a/drivers/net/xsc/xsc_dev.h b/drivers/net/xsc/xsc_dev.h
|
|
new file mode 100644
|
|
index 0000000..b8651c8
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_dev.h
|
|
@@ -0,0 +1,200 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#ifndef _XSC_DEV_H_
|
|
+#define _XSC_DEV_H_
|
|
+
|
|
+#include <rte_ethdev.h>
|
|
+#include <ethdev_driver.h>
|
|
+#include <rte_interrupts.h>
|
|
+#include <rte_bitmap.h>
|
|
+#include <rte_malloc.h>
|
|
+
|
|
+#include "xsc_defs.h"
|
|
+#include "xsc_log.h"
|
|
+#include "xsc_rxtx.h"
|
|
+#include "xsc_np.h"
|
|
+#include "xsc_compat.h"
|
|
+
|
|
+#define XSC_PPH_MODE_ARG "pph_mode"
|
|
+#define XSC_NIC_MODE_ARG "nic_mode"
|
|
+#define XSC_FLOW_MODE_ARG "flow_mode"
|
|
+
|
|
+#define XSC_FUNCID_TYPE_MASK 0x1c000
|
|
+#define XSC_FUNCID_MASK 0x3fff
|
|
+
|
|
+#define XSC_DEV_PCT_IDX_INVALID 0xFFFFFFFF
|
|
+#define XSC_DEV_REPR_ID_INVALID 0x7FFFFFFF
|
|
+
|
|
+enum xsc_queue_type {
|
|
+ XSC_QUEUE_TYPE_RDMA_RC = 0,
|
|
+ XSC_QUEUE_TYPE_RDMA_MAD = 1,
|
|
+ XSC_QUEUE_TYPE_RAW = 2,
|
|
+ XSC_QUEUE_TYPE_VIRTIO_NET = 3,
|
|
+ XSC_QUEUE_TYPE_VIRTIO_BLK = 4,
|
|
+ XSC_QUEUE_TYPE_RAW_TPE = 5,
|
|
+ XSC_QUEUE_TYPE_RAW_TSO = 6,
|
|
+ XSC_QUEUE_TYPE_RAW_TX = 7,
|
|
+ XSC_QUEUE_TYPE_INVALID = 0xFF,
|
|
+};
|
|
+
|
|
+struct xsc_hwinfo {
|
|
+ uint32_t pcie_no; /* pcie number , 0 or 1 */
|
|
+ uint32_t func_id; /* pf glb func id */
|
|
+ uint32_t pcie_host; /* host pcie number */
|
|
+ uint32_t mac_phy_port; /* mac port */
|
|
+ uint32_t funcid_to_logic_port_off; /* port func id offset */
|
|
+ uint32_t chip_version;
|
|
+ uint32_t hca_core_clock;
|
|
+ uint16_t lag_id;
|
|
+ uint16_t raw_qp_id_base;
|
|
+ uint16_t raw_rss_qp_id_base;
|
|
+ uint16_t pf0_vf_funcid_base;
|
|
+ uint16_t pf0_vf_funcid_top;
|
|
+ uint16_t pf1_vf_funcid_base;
|
|
+ uint16_t pf1_vf_funcid_top;
|
|
+ uint16_t pcie0_pf_funcid_base;
|
|
+ uint16_t pcie0_pf_funcid_top;
|
|
+ uint16_t pcie1_pf_funcid_base;
|
|
+ uint16_t pcie1_pf_funcid_top;
|
|
+ uint16_t lag_port_start;
|
|
+ uint16_t raw_tpe_qp_num;
|
|
+ uint16_t msix_base;
|
|
+ uint16_t msix_num;
|
|
+ uint8_t send_seg_num;
|
|
+ uint8_t recv_seg_num;
|
|
+ uint8_t valid; /* 1: current phy info is valid, 0 : invalid */
|
|
+ uint8_t on_chip_tbl_vld;
|
|
+ uint8_t dma_rw_tbl_vld;
|
|
+ uint8_t pct_compress_vld;
|
|
+ uint8_t mac_bit;
|
|
+ uint8_t esw_mode;
|
|
+};
|
|
+
|
|
+struct xsc_devargs {
|
|
+ int nic_mode;
|
|
+ int flow_mode;
|
|
+ int pph_mode;
|
|
+};
|
|
+
|
|
+struct xsc_repr_info {
|
|
+ int repr_id;
|
|
+ enum xsc_port_type port_type;
|
|
+ int pf_bond;
|
|
+
|
|
+ uint32_t ifindex;
|
|
+ const char *phys_dev_name;
|
|
+ uint32_t funcid;
|
|
+
|
|
+ uint16_t logical_port;
|
|
+ uint16_t local_dstinfo;
|
|
+ uint16_t peer_logical_port;
|
|
+ uint16_t peer_dstinfo;
|
|
+};
|
|
+
|
|
+struct xsc_repr_port {
|
|
+ struct xsc_dev *xdev;
|
|
+ struct xsc_repr_info info;
|
|
+ void *drv_data;
|
|
+ struct xsc_dev_pct_list def_pct_list;
|
|
+};
|
|
+
|
|
+struct xsc_dev_config {
|
|
+ uint8_t pph_flag;
|
|
+ uint8_t hw_csum;
|
|
+ uint8_t tso;
|
|
+ uint32_t tso_max_payload_sz;
|
|
+};
|
|
+
|
|
+struct xsc_dev {
|
|
+ struct rte_pci_device *pci_dev;
|
|
+ const struct xsc_dev_ops *dev_ops;
|
|
+ struct xsc_devargs devargs;
|
|
+ struct xsc_hwinfo hwinfo;
|
|
+ struct rte_eth_link pf_dev_link;
|
|
+ uint32_t link_speed_capa;
|
|
+ int vfos_logical_in_port;
|
|
+ int vfrep_offset;
|
|
+
|
|
+ struct rte_intr_handle *intr_handle;
|
|
+ struct xsc_repr_port *repr_ports;
|
|
+ int num_repr_ports; /* PF and VF representor ports num */
|
|
+ int ifindex;
|
|
+ int port_id; /* Probe dev */
|
|
+ void *dev_priv;
|
|
+ char name[PCI_PRI_STR_SIZE];
|
|
+ void *bar_addr;
|
|
+ void *jumbo_buffer_pa;
|
|
+ void *jumbo_buffer_va;
|
|
+ uint64_t bar_len;
|
|
+ int ctrl_fd;
|
|
+};
|
|
+
|
|
+enum xsc_intr_event_type {
|
|
+ XSC_EVENT_TYPE_NONE = 0x0,
|
|
+ XSC_EVENT_TYPE_CHANGE_LINK = 0x0001,
|
|
+ XSC_EVENT_TYPE_TEMP_WARN = 0x0002,
|
|
+ XSC_EVENT_TYPE_OVER_TEMP_PROTECTION = 0x0004,
|
|
+};
|
|
+
|
|
+struct xsc_dev_ops {
|
|
+ TAILQ_ENTRY(xsc_dev_ops) entry;
|
|
+ uint64_t kdrv;
|
|
+ int (*dev_init)(struct xsc_dev *xdev);
|
|
+ int (*dev_close)(struct xsc_dev *xdev);
|
|
+ int (*get_mac)(struct xsc_dev *xdev, uint8_t *mac);
|
|
+ int (*set_link_up)(struct xsc_dev *xdev);
|
|
+ int (*set_link_down)(struct xsc_dev *xdev);
|
|
+ int (*link_update)(struct xsc_dev *xdev, int wait_to_complete);
|
|
+ int (*set_mtu)(struct xsc_dev *xdev, uint16_t mtu);
|
|
+ int (*destroy_qp)(void *qp);
|
|
+ int (*destroy_cq)(void *cq);
|
|
+ int (*modify_qp_status)(struct xsc_dev *xdev,
|
|
+ uint32_t qpn, int num, int opcode);
|
|
+ int (*modify_qp_qostree)(struct xsc_dev *xdev, uint16_t qpn);
|
|
+
|
|
+ int (*rx_cq_create)(struct xsc_dev *xdev, struct xsc_rx_cq_params *cq_params,
|
|
+ struct xsc_rx_cq_info *cq_info);
|
|
+ int (*tx_cq_create)(struct xsc_dev *xdev, struct xsc_tx_cq_params *cq_params,
|
|
+ struct xsc_tx_cq_info *cq_info);
|
|
+ int (*tx_qp_create)(struct xsc_dev *xdev, struct xsc_tx_qp_params *qp_params,
|
|
+ struct xsc_tx_qp_info *qp_info);
|
|
+ int (*mailbox_exec)(struct xsc_dev *xdev, void *data_in,
|
|
+ int in_len, void *data_out, int out_len);
|
|
+ int (*intr_event_get)(struct xsc_dev *xdev);
|
|
+ int (*intr_handler_install)(struct xsc_dev *xdev, rte_intr_callback_fn cb, void *cb_arg);
|
|
+ int (*intr_handler_uninstall)(struct xsc_dev *xdev);
|
|
+};
|
|
+
|
|
+int xsc_dev_mailbox_exec(struct xsc_dev *xdev, void *data_in,
|
|
+ int in_len, void *data_out, int out_len);
|
|
+int xsc_dev_intr_event_get(struct xsc_dev *xdev);
|
|
+int xsc_dev_intr_handler_install(struct xsc_dev *xdev,
|
|
+ rte_intr_callback_fn cb, void *cb_arg);
|
|
+int xsc_dev_intr_handler_uninstall(struct xsc_dev *xdev);
|
|
+void xsc_dev_ops_register(struct xsc_dev_ops *new_ops);
|
|
+int xsc_dev_set_link_up(struct xsc_dev *xdev);
|
|
+int xsc_dev_set_link_down(struct xsc_dev *xde);
|
|
+int xsc_dev_link_update(struct xsc_dev *xdev, int wait_to_complete);
|
|
+int xsc_dev_destroy_qp(struct xsc_dev *xdev, void *qp);
|
|
+int xsc_dev_destroy_cq(struct xsc_dev *xdev, void *cq);
|
|
+int xsc_dev_modify_qp_status(struct xsc_dev *xdev, uint32_t qpn, int num, int opcode);
|
|
+int xsc_dev_modify_qp_qostree(struct xsc_dev *xdev, uint16_t qpn);
|
|
+int xsc_dev_rx_cq_create(struct xsc_dev *xdev, struct xsc_rx_cq_params *cq_params,
|
|
+ struct xsc_rx_cq_info *cq_info);
|
|
+int xsc_dev_tx_cq_create(struct xsc_dev *xdev, struct xsc_tx_cq_params *cq_params,
|
|
+ struct xsc_tx_cq_info *cq_info);
|
|
+int xsc_dev_tx_qp_create(struct xsc_dev *xdev, struct xsc_tx_qp_params *qp_params,
|
|
+ struct xsc_tx_qp_info *qp_info);
|
|
+int xsc_dev_init(struct rte_pci_device *pci_dev, struct xsc_dev **dev);
|
|
+void xsc_dev_uninit(struct xsc_dev *xdev);
|
|
+int xsc_dev_close(struct xsc_dev *xdev, int repr_id);
|
|
+int xsc_dev_repr_ports_probe(struct xsc_dev *xdev, int nb_repr_ports, int max_eth_ports);
|
|
+int xsc_dev_rss_key_modify(struct xsc_dev *xdev, uint8_t *rss_key, uint8_t rss_key_len);
|
|
+bool xsc_dev_is_vf(struct xsc_dev *xdev);
|
|
+int xsc_dev_qp_set_id_get(struct xsc_dev *xdev, int repr_id);
|
|
+int xsc_dev_set_mtu(struct xsc_dev *xdev, uint16_t mtu);
|
|
+int xsc_dev_get_mac(struct xsc_dev *xdev, uint8_t *mac);
|
|
+
|
|
+#endif /* _XSC_DEV_H_ */
|
|
diff --git a/drivers/net/xsc/xsc_ethdev.c b/drivers/net/xsc/xsc_ethdev.c
|
|
new file mode 100644
|
|
index 0000000..c63b603
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_ethdev.c
|
|
@@ -0,0 +1,966 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#include <ethdev_pci.h>
|
|
+#include <rte_interrupts.h>
|
|
+
|
|
+#include "xsc_log.h"
|
|
+#include "xsc_defs.h"
|
|
+#include "xsc_ethdev.h"
|
|
+#include "xsc_rx.h"
|
|
+#include "xsc_tx.h"
|
|
+#include "xsc_dev.h"
|
|
+#include "xsc_cmd.h"
|
|
+
|
|
+static int
|
|
+xsc_ethdev_rss_hash_conf_get(struct rte_eth_dev *dev,
|
|
+ struct rte_eth_rss_conf *rss_conf)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+
|
|
+ if (rss_conf->rss_key != NULL && rss_conf->rss_key_len >= priv->rss_conf.rss_key_len)
|
|
+ memcpy(rss_conf->rss_key, priv->rss_conf.rss_key, priv->rss_conf.rss_key_len);
|
|
+
|
|
+ rss_conf->rss_key_len = priv->rss_conf.rss_key_len;
|
|
+ rss_conf->rss_hf = priv->rss_conf.rss_hf;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_rss_hash_update(struct rte_eth_dev *dev,
|
|
+ struct rte_eth_rss_conf *rss_conf)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ int ret = 0;
|
|
+
|
|
+ ret = xsc_dev_rss_key_modify(priv->xdev, rss_conf->rss_key, rss_conf->rss_key_len);
|
|
+ if (ret == 0) {
|
|
+ memcpy(priv->rss_conf.rss_key, rss_conf->rss_key,
|
|
+ priv->rss_conf.rss_key_len);
|
|
+ priv->rss_conf.rss_key_len = rss_conf->rss_key_len;
|
|
+ priv->rss_conf.rss_hf = rss_conf->rss_hf;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_configure(struct rte_eth_dev *dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ int ret;
|
|
+ struct rte_eth_rss_conf *rss_conf;
|
|
+
|
|
+ priv->num_sq = dev->data->nb_tx_queues;
|
|
+ priv->num_rq = dev->data->nb_rx_queues;
|
|
+
|
|
+ if (dev->data->dev_conf.rxmode.mq_mode & RTE_ETH_MQ_RX_RSS_FLAG)
|
|
+ dev->data->dev_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_RSS_HASH;
|
|
+
|
|
+ if (priv->rss_conf.rss_key == NULL) {
|
|
+ priv->rss_conf.rss_key = rte_zmalloc(NULL, XSC_RSS_HASH_KEY_LEN,
|
|
+ RTE_CACHE_LINE_SIZE);
|
|
+ if (priv->rss_conf.rss_key == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc rss key");
|
|
+ rte_errno = ENOMEM;
|
|
+ ret = -rte_errno;
|
|
+ goto error;
|
|
+ }
|
|
+ priv->rss_conf.rss_key_len = XSC_RSS_HASH_KEY_LEN;
|
|
+ }
|
|
+
|
|
+ if (dev->data->dev_conf.rx_adv_conf.rss_conf.rss_key != NULL) {
|
|
+ rss_conf = &dev->data->dev_conf.rx_adv_conf.rss_conf;
|
|
+ ret = xsc_ethdev_rss_hash_update(dev, rss_conf);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Xsc pmd set rss key error!");
|
|
+ rte_errno = -ENOEXEC;
|
|
+ goto error;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ priv->txqs = (void *)dev->data->tx_queues;
|
|
+ priv->rxqs = (void *)dev->data->rx_queues;
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ return -rte_errno;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_ethdev_txq_release(struct rte_eth_dev *dev, uint16_t idx)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ struct xsc_txq_data *txq_data = xsc_txq_get(priv, idx);
|
|
+
|
|
+ if (txq_data == NULL)
|
|
+ return;
|
|
+
|
|
+ xsc_dev_set_qpsetid(priv->xdev, txq_data->qpn, 0);
|
|
+ xsc_txq_obj_release(priv->xdev, txq_data);
|
|
+ rte_free(txq_data->fcqs);
|
|
+ txq_data->fcqs = NULL;
|
|
+ xsc_txq_elts_free(txq_data);
|
|
+ rte_free(txq_data);
|
|
+ (*priv->txqs)[idx] = NULL;
|
|
+
|
|
+ dev->data->tx_queues[idx] = NULL;
|
|
+ dev->data->tx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STOPPED;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_ethdev_rxq_release(struct rte_eth_dev *dev, uint16_t idx)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ struct xsc_rxq_data *rxq_data = xsc_rxq_get(priv, idx);
|
|
+
|
|
+ if (rxq_data == NULL)
|
|
+ return;
|
|
+ xsc_rxq_rss_obj_release(priv->xdev, rxq_data);
|
|
+ xsc_rxq_elts_free(rxq_data);
|
|
+ rte_free(rxq_data);
|
|
+ (*priv->rxqs)[idx] = NULL;
|
|
+
|
|
+ dev->data->rx_queues[idx] = NULL;
|
|
+ dev->data->rx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STOPPED;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_enable(struct rte_eth_dev *dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ struct xsc_hwinfo *hwinfo;
|
|
+ int peer_dstinfo = 0;
|
|
+ int peer_logicalport = 0;
|
|
+ int logical_port = 0;
|
|
+ int local_dstinfo = 0;
|
|
+ int pcie_logic_port = 0;
|
|
+ int qp_set_id;
|
|
+ int repr_id;
|
|
+ struct xsc_rxq_data *rxq;
|
|
+ uint16_t rx_qpn;
|
|
+ int i, vld;
|
|
+ struct xsc_txq_data *txq;
|
|
+ struct xsc_repr_port *repr;
|
|
+ struct xsc_repr_info *repr_info;
|
|
+
|
|
+ if (priv->funcid_type != XSC_PHYPORT_MAC_FUNCID)
|
|
+ return -ENODEV;
|
|
+
|
|
+ rxq = xsc_rxq_get(priv, 0);
|
|
+ if (rxq == NULL)
|
|
+ return -EINVAL;
|
|
+
|
|
+ rx_qpn = (uint16_t)rxq->qpn;
|
|
+ hwinfo = &priv->xdev->hwinfo;
|
|
+ repr_id = priv->representor_id;
|
|
+ repr = &priv->xdev->repr_ports[repr_id];
|
|
+ repr_info = &repr->info;
|
|
+
|
|
+ qp_set_id = xsc_dev_qp_set_id_get(priv->xdev, repr_id);
|
|
+ logical_port = repr_info->logical_port;
|
|
+ local_dstinfo = repr_info->local_dstinfo;
|
|
+ peer_logicalport = repr_info->peer_logical_port;
|
|
+ peer_dstinfo = repr_info->peer_dstinfo;
|
|
+
|
|
+ pcie_logic_port = hwinfo->pcie_no + 8;
|
|
+
|
|
+ for (i = 0; i < priv->num_sq; i++) {
|
|
+ txq = xsc_txq_get(priv, i);
|
|
+ if (txq == NULL)
|
|
+ return -EINVAL;
|
|
+ xsc_dev_modify_qp_status(priv->xdev, txq->qpn, 1, XSC_CMD_OP_RTR2RTS_QP);
|
|
+ xsc_dev_modify_qp_qostree(priv->xdev, txq->qpn);
|
|
+ xsc_dev_set_qpsetid(priv->xdev, txq->qpn, qp_set_id);
|
|
+ }
|
|
+
|
|
+ if (!xsc_dev_is_vf(priv->xdev)) {
|
|
+ xsc_dev_create_ipat(priv->xdev, logical_port, peer_dstinfo);
|
|
+ xsc_dev_create_vfos_baselp(priv->xdev);
|
|
+ xsc_dev_create_epat(priv->xdev, local_dstinfo, pcie_logic_port,
|
|
+ rx_qpn - hwinfo->raw_rss_qp_id_base,
|
|
+ priv->num_rq, &priv->rss_conf);
|
|
+ xsc_dev_create_pct(priv->xdev, repr_id, logical_port, peer_dstinfo);
|
|
+ xsc_dev_create_pct(priv->xdev, repr_id, peer_logicalport, local_dstinfo);
|
|
+ } else {
|
|
+ vld = xsc_dev_get_ipat_vld(priv->xdev, logical_port);
|
|
+ if (vld == 0)
|
|
+ xsc_dev_create_ipat(priv->xdev, logical_port, peer_dstinfo);
|
|
+ xsc_dev_vf_modify_epat(priv->xdev, local_dstinfo,
|
|
+ rx_qpn - hwinfo->raw_rss_qp_id_base,
|
|
+ priv->num_rq, &priv->rss_conf);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_rxq_stop(struct rte_eth_dev *dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ uint16_t i;
|
|
+
|
|
+ for (i = 0; i != priv->num_rq; ++i)
|
|
+ xsc_ethdev_rxq_release(dev, i);
|
|
+ priv->rxqs = NULL;
|
|
+ priv->flags &= ~XSC_FLAG_RX_QUEUE_INIT;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_txq_stop(struct rte_eth_dev *dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ uint16_t i;
|
|
+
|
|
+ for (i = 0; i != priv->num_sq; ++i)
|
|
+ xsc_ethdev_txq_release(dev, i);
|
|
+ priv->txqs = NULL;
|
|
+ priv->flags &= ~XSC_FLAG_TX_QUEUE_INIT;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_txq_start(struct xsc_ethdev_priv *priv)
|
|
+{
|
|
+ struct xsc_txq_data *txq_data;
|
|
+ struct rte_eth_dev *dev = priv->eth_dev;
|
|
+ uint64_t offloads = dev->data->dev_conf.txmode.offloads;
|
|
+ uint16_t i;
|
|
+ int ret;
|
|
+ size_t size;
|
|
+
|
|
+ if (priv->flags & XSC_FLAG_TX_QUEUE_INIT) {
|
|
+ for (i = 0; i != priv->num_sq; ++i)
|
|
+ dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i != priv->num_sq; ++i) {
|
|
+ txq_data = xsc_txq_get(priv, i);
|
|
+ if (txq_data == NULL)
|
|
+ goto error;
|
|
+ xsc_txq_elts_alloc(txq_data);
|
|
+ ret = xsc_txq_obj_new(priv->xdev, txq_data, offloads, i);
|
|
+ if (ret < 0)
|
|
+ goto error;
|
|
+ dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
|
|
+ PMD_DRV_LOG(INFO, "Port %u create tx success", dev->data->port_id);
|
|
+
|
|
+ size = txq_data->cqe_s * sizeof(*txq_data->fcqs);
|
|
+ txq_data->fcqs = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
|
|
+ if (!txq_data->fcqs) {
|
|
+ PMD_DRV_LOG(ERR, "Port %u txq %u alloc fcqs memory failed",
|
|
+ dev->data->port_id, i);
|
|
+ rte_errno = ENOMEM;
|
|
+ goto error;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ priv->flags |= XSC_FLAG_TX_QUEUE_INIT;
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ /* Queue resources are released by xsc_ethdev_start calling the stop interface */
|
|
+ return -rte_errno;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rxq_start(struct xsc_ethdev_priv *priv)
|
|
+{
|
|
+ struct xsc_rxq_data *rxq_data;
|
|
+ struct rte_eth_dev *dev = priv->eth_dev;
|
|
+ uint16_t i;
|
|
+ int ret;
|
|
+
|
|
+ if (priv->flags & XSC_FLAG_RX_QUEUE_INIT) {
|
|
+ for (i = 0; i != priv->num_sq; ++i)
|
|
+ dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i != priv->num_rq; ++i) {
|
|
+ rxq_data = xsc_rxq_get(priv, i);
|
|
+ if (rxq_data == NULL)
|
|
+ goto error;
|
|
+ if (dev->data->rx_queue_state[i] != RTE_ETH_QUEUE_STATE_STARTED) {
|
|
+ ret = xsc_rxq_elts_alloc(rxq_data);
|
|
+ if (ret != 0)
|
|
+ goto error;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = xsc_rxq_rss_obj_new(priv, priv->dev_data->port_id);
|
|
+ if (ret != 0)
|
|
+ goto error;
|
|
+
|
|
+ priv->flags |= XSC_FLAG_RX_QUEUE_INIT;
|
|
+ return 0;
|
|
+error:
|
|
+ /* Queue resources are released by xsc_ethdev_start calling the stop interface */
|
|
+ return -rte_errno;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_start(struct rte_eth_dev *dev)
|
|
+{
|
|
+ int ret;
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+
|
|
+ ret = xsc_txq_start(priv);
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Port %u txq start failed: %s",
|
|
+ dev->data->port_id, strerror(rte_errno));
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ ret = xsc_rxq_start(priv);
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Port %u Rx queue start failed: %s",
|
|
+ dev->data->port_id, strerror(rte_errno));
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ dev->data->dev_started = 1;
|
|
+
|
|
+ dev->rx_pkt_burst = xsc_rx_burst;
|
|
+ dev->tx_pkt_burst = xsc_tx_burst;
|
|
+
|
|
+ ret = xsc_ethdev_enable(dev);
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to enable port: %u",
|
|
+ dev->data->port_id);
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ dev->data->dev_started = 0;
|
|
+ xsc_txq_stop(dev);
|
|
+ xsc_rxq_stop(dev);
|
|
+ return -rte_errno;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_stop(struct rte_eth_dev *dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ uint16_t i;
|
|
+
|
|
+ PMD_DRV_LOG(DEBUG, "Port %u stopping", dev->data->port_id);
|
|
+ dev->data->dev_started = 0;
|
|
+ dev->rx_pkt_burst = rte_eth_pkt_burst_dummy;
|
|
+ dev->tx_pkt_burst = rte_eth_pkt_burst_dummy;
|
|
+ rte_wmb();
|
|
+
|
|
+ rte_delay_us_sleep(1000 * priv->num_rq);
|
|
+ for (i = 0; i < priv->num_rq; ++i)
|
|
+ dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
|
|
+ for (i = 0; i < priv->num_sq; ++i)
|
|
+ dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_close(struct rte_eth_dev *dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+
|
|
+ PMD_DRV_LOG(DEBUG, "Port %u closing", dev->data->port_id);
|
|
+ dev->rx_pkt_burst = rte_eth_pkt_burst_dummy;
|
|
+ dev->tx_pkt_burst = rte_eth_pkt_burst_dummy;
|
|
+ rte_wmb();
|
|
+
|
|
+ xsc_txq_stop(dev);
|
|
+ xsc_rxq_stop(dev);
|
|
+
|
|
+ rte_free(priv->rss_conf.rss_key);
|
|
+ xsc_dev_close(priv->xdev, priv->representor_id);
|
|
+ dev->data->mac_addrs = NULL;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_set_link_up(struct rte_eth_dev *dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ struct xsc_dev *xdev = priv->xdev;
|
|
+
|
|
+ return xsc_dev_set_link_up(xdev);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_set_link_down(struct rte_eth_dev *dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ struct xsc_dev *xdev = priv->xdev;
|
|
+
|
|
+ return xsc_dev_set_link_down(xdev);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_link_update(struct rte_eth_dev *dev, int wait_to_complete)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ struct xsc_dev *xdev = priv->xdev;
|
|
+ int ret = 0;
|
|
+
|
|
+ ret = xsc_dev_link_update(xdev, wait_to_complete);
|
|
+ if (ret == 0) {
|
|
+ dev->data->dev_link = xdev->pf_dev_link;
|
|
+ dev->data->dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
|
|
+ RTE_ETH_LINK_SPEED_FIXED);
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static uint64_t
|
|
+xsc_get_rx_queue_offloads(struct rte_eth_dev *dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ struct xsc_dev_config *config = &priv->config;
|
|
+ uint64_t offloads = 0;
|
|
+
|
|
+ if (config->hw_csum)
|
|
+ offloads |= (RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
|
|
+ RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
|
|
+ RTE_ETH_RX_OFFLOAD_TCP_CKSUM);
|
|
+
|
|
+ return offloads;
|
|
+}
|
|
+
|
|
+static uint64_t
|
|
+xsc_get_tx_port_offloads(struct rte_eth_dev *dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ uint64_t offloads = 0;
|
|
+ struct xsc_dev_config *config = &priv->config;
|
|
+
|
|
+ if (config->hw_csum)
|
|
+ offloads |= (RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
|
|
+ RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
|
|
+ RTE_ETH_TX_OFFLOAD_TCP_CKSUM);
|
|
+ if (config->tso)
|
|
+ offloads |= RTE_ETH_TX_OFFLOAD_TCP_TSO;
|
|
+ return offloads;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+
|
|
+ info->min_rx_bufsize = 64;
|
|
+ info->max_rx_pktlen = 65536;
|
|
+ info->max_lro_pkt_size = 0;
|
|
+ info->max_rx_queues = 256;
|
|
+ info->max_tx_queues = 1024;
|
|
+ info->rx_desc_lim.nb_max = 4096;
|
|
+ info->rx_desc_lim.nb_min = 16;
|
|
+ info->tx_desc_lim.nb_max = 8192;
|
|
+ info->tx_desc_lim.nb_min = 128;
|
|
+
|
|
+ info->rx_queue_offload_capa = xsc_get_rx_queue_offloads(dev);
|
|
+ info->rx_offload_capa = info->rx_queue_offload_capa;
|
|
+ info->tx_offload_capa = xsc_get_tx_port_offloads(dev);
|
|
+
|
|
+ info->if_index = priv->ifindex;
|
|
+ info->speed_capa = priv->xdev->link_speed_capa;
|
|
+ info->hash_key_size = XSC_RSS_HASH_KEY_LEN;
|
|
+ info->tx_desc_lim.nb_seg_max = 8;
|
|
+ info->tx_desc_lim.nb_mtu_seg_max = 8;
|
|
+ info->switch_info.name = dev->data->name;
|
|
+ info->switch_info.port_id = priv->representor_id;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
|
|
+ uint32_t socket, const struct rte_eth_rxconf *conf,
|
|
+ struct rte_mempool *mp)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ struct xsc_rxq_data *rxq_data = NULL;
|
|
+ uint16_t desc_n;
|
|
+ uint16_t rx_free_thresh;
|
|
+ uint64_t offloads = conf->offloads | dev->data->dev_conf.rxmode.offloads;
|
|
+
|
|
+ desc = (desc > XSC_MAX_DESC_NUMBER) ? XSC_MAX_DESC_NUMBER : desc;
|
|
+ desc_n = desc;
|
|
+
|
|
+ if (!rte_is_power_of_2(desc))
|
|
+ desc_n = 1 << rte_log2_u32(desc);
|
|
+
|
|
+ rxq_data = rte_malloc_socket(NULL, sizeof(*rxq_data) + desc_n * sizeof(struct rte_mbuf *),
|
|
+ RTE_CACHE_LINE_SIZE, socket);
|
|
+ if (rxq_data == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Port %u create rxq idx %d failure",
|
|
+ dev->data->port_id, idx);
|
|
+ rte_errno = ENOMEM;
|
|
+ return -rte_errno;
|
|
+ }
|
|
+ rxq_data->idx = idx;
|
|
+ rxq_data->priv = priv;
|
|
+ (*priv->rxqs)[idx] = rxq_data;
|
|
+
|
|
+ rx_free_thresh = (conf->rx_free_thresh) ? conf->rx_free_thresh : XSC_RX_FREE_THRESH;
|
|
+ rxq_data->rx_free_thresh = rx_free_thresh;
|
|
+
|
|
+ rxq_data->elts = (struct rte_mbuf *(*)[desc_n])(rxq_data + 1);
|
|
+ rxq_data->mp = mp;
|
|
+ rxq_data->socket = socket;
|
|
+
|
|
+ rxq_data->csum = !!(offloads & RTE_ETH_RX_OFFLOAD_CHECKSUM);
|
|
+ rxq_data->hw_timestamp = !!(offloads & RTE_ETH_RX_OFFLOAD_TIMESTAMP);
|
|
+ rxq_data->crc_present = 0;
|
|
+
|
|
+ rxq_data->wqe_n = rte_log2_u32(desc_n);
|
|
+ rxq_data->wqe_s = desc_n;
|
|
+ rxq_data->wqe_m = desc_n - 1;
|
|
+
|
|
+ rxq_data->port_id = dev->data->port_id;
|
|
+ dev->data->rx_queues[idx] = rxq_data;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
|
|
+ uint32_t socket, const struct rte_eth_txconf *conf)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ struct xsc_txq_data *txq;
|
|
+ uint16_t desc_n;
|
|
+
|
|
+ desc = (desc > XSC_MAX_DESC_NUMBER) ? XSC_MAX_DESC_NUMBER : desc;
|
|
+ desc_n = desc;
|
|
+
|
|
+ if (!rte_is_power_of_2(desc))
|
|
+ desc_n = 1 << rte_log2_u32(desc);
|
|
+
|
|
+ txq = rte_malloc_socket(NULL, sizeof(*txq) + desc_n * sizeof(struct rte_mbuf *),
|
|
+ RTE_CACHE_LINE_SIZE, socket);
|
|
+ txq->offloads = conf->offloads | dev->data->dev_conf.txmode.offloads;
|
|
+ txq->priv = priv;
|
|
+ txq->socket = socket;
|
|
+
|
|
+ txq->elts_n = rte_log2_u32(desc_n);
|
|
+ txq->elts_s = desc_n;
|
|
+ txq->elts_m = desc_n - 1;
|
|
+ txq->port_id = dev->data->port_id;
|
|
+ txq->idx = idx;
|
|
+
|
|
+ (*priv->txqs)[idx] = txq;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ int ret = 0;
|
|
+
|
|
+ if (priv->eth_type != RTE_ETH_REPRESENTOR_PF) {
|
|
+ priv->mtu = mtu;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ ret = xsc_dev_set_mtu(priv->xdev, mtu);
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Mtu set to %u failure", mtu);
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ priv->mtu = mtu;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ uint32_t rxqs_n = priv->num_rq;
|
|
+ uint32_t txqs_n = priv->num_sq;
|
|
+ uint32_t i, idx;
|
|
+ struct xsc_rxq_data *rxq;
|
|
+ struct xsc_txq_data *txq;
|
|
+
|
|
+ for (i = 0; i < rxqs_n; ++i) {
|
|
+ rxq = xsc_rxq_get(priv, i);
|
|
+ if (unlikely(rxq == NULL))
|
|
+ continue;
|
|
+
|
|
+ idx = rxq->idx;
|
|
+ if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
|
|
+ stats->q_ipackets[idx] += rxq->stats.rx_pkts;
|
|
+ stats->q_ibytes[idx] += rxq->stats.rx_bytes;
|
|
+ stats->q_errors[idx] += rxq->stats.rx_errors +
|
|
+ rxq->stats.rx_nombuf;
|
|
+ }
|
|
+ stats->ipackets += rxq->stats.rx_pkts;
|
|
+ stats->ibytes += rxq->stats.rx_bytes;
|
|
+ stats->ierrors += rxq->stats.rx_errors;
|
|
+ stats->rx_nombuf += rxq->stats.rx_nombuf;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < txqs_n; ++i) {
|
|
+ txq = xsc_txq_get(priv, i);
|
|
+ if (unlikely(txq == NULL))
|
|
+ continue;
|
|
+
|
|
+ idx = txq->idx;
|
|
+ if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) {
|
|
+ stats->q_opackets[idx] += txq->stats.tx_pkts;
|
|
+ stats->q_obytes[idx] += txq->stats.tx_bytes;
|
|
+ stats->q_errors[idx] += txq->stats.tx_errors;
|
|
+ }
|
|
+ stats->opackets += txq->stats.tx_pkts;
|
|
+ stats->obytes += txq->stats.tx_bytes;
|
|
+ stats->oerrors += txq->stats.tx_errors;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_stats_reset(struct rte_eth_dev *dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(dev);
|
|
+ uint32_t rxqs_n = priv->num_rq;
|
|
+ uint32_t txqs_n = priv->num_sq;
|
|
+ uint32_t i;
|
|
+ struct xsc_rxq_data *rxq;
|
|
+ struct xsc_txq_data *txq;
|
|
+
|
|
+ for (i = 0; i < rxqs_n; ++i) {
|
|
+ rxq = xsc_rxq_get(priv, i);
|
|
+ if (unlikely(rxq == NULL))
|
|
+ continue;
|
|
+ memset(&rxq->stats, 0, sizeof(struct xsc_rxq_stats));
|
|
+ }
|
|
+ for (i = 0; i < txqs_n; ++i) {
|
|
+ txq = xsc_txq_get(priv, i);
|
|
+ if (unlikely(txq == NULL))
|
|
+ continue;
|
|
+ memset(&txq->stats, 0, sizeof(struct xsc_txq_stats));
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac, uint32_t index)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ rte_errno = EINVAL;
|
|
+ if (index > XSC_MAX_MAC_ADDRESSES)
|
|
+ return -rte_errno;
|
|
+
|
|
+ if (rte_is_zero_ether_addr(mac))
|
|
+ return -rte_errno;
|
|
+
|
|
+ for (i = 0; i != XSC_MAX_MAC_ADDRESSES; ++i) {
|
|
+ if (i == (int)index)
|
|
+ continue;
|
|
+ if (memcmp(&dev->data->mac_addrs[i], mac, sizeof(*mac)) != 0)
|
|
+ continue;
|
|
+ /* Address already configured elsewhere, return with error */
|
|
+ rte_errno = EADDRINUSE;
|
|
+ return -rte_errno;
|
|
+ }
|
|
+
|
|
+ dev->data->mac_addrs[index] = *mac;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+const struct eth_dev_ops xsc_eth_dev_ops = {
|
|
+ .dev_configure = xsc_ethdev_configure,
|
|
+ .dev_start = xsc_ethdev_start,
|
|
+ .dev_stop = xsc_ethdev_stop,
|
|
+ .dev_set_link_up = xsc_ethdev_set_link_up,
|
|
+ .dev_set_link_down = xsc_ethdev_set_link_down,
|
|
+ .dev_close = xsc_ethdev_close,
|
|
+ .link_update = xsc_ethdev_link_update,
|
|
+ .stats_get = xsc_ethdev_stats_get,
|
|
+ .stats_reset = xsc_ethdev_stats_reset,
|
|
+ .dev_infos_get = xsc_ethdev_infos_get,
|
|
+ .rx_queue_setup = xsc_ethdev_rx_queue_setup,
|
|
+ .tx_queue_setup = xsc_ethdev_tx_queue_setup,
|
|
+ .rx_queue_release = xsc_ethdev_rxq_release,
|
|
+ .tx_queue_release = xsc_ethdev_txq_release,
|
|
+ .mtu_set = xsc_ethdev_set_mtu,
|
|
+ .rss_hash_update = xsc_ethdev_rss_hash_update,
|
|
+ .rss_hash_conf_get = xsc_ethdev_rss_hash_conf_get,
|
|
+};
|
|
+
|
|
+static int
|
|
+xsc_ethdev_init_one_representor(struct rte_eth_dev *eth_dev, void *init_params)
|
|
+{
|
|
+ int ret;
|
|
+ struct xsc_repr_port *repr_port = (struct xsc_repr_port *)init_params;
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(eth_dev);
|
|
+ struct xsc_dev_config *config = &priv->config;
|
|
+ struct rte_ether_addr mac;
|
|
+
|
|
+ priv->repr_port = repr_port;
|
|
+ repr_port->drv_data = eth_dev;
|
|
+ priv->xdev = repr_port->xdev;
|
|
+ priv->mtu = RTE_ETHER_MTU;
|
|
+ priv->funcid_type = (repr_port->info.funcid & XSC_FUNCID_TYPE_MASK) >> 14;
|
|
+ priv->funcid = repr_port->info.funcid & XSC_FUNCID_MASK;
|
|
+ if (repr_port->info.port_type == XSC_PORT_TYPE_UPLINK ||
|
|
+ repr_port->info.port_type == XSC_PORT_TYPE_UPLINK_BOND)
|
|
+ priv->eth_type = RTE_ETH_REPRESENTOR_PF;
|
|
+ else
|
|
+ priv->eth_type = RTE_ETH_REPRESENTOR_VF;
|
|
+ priv->representor_id = repr_port->info.repr_id;
|
|
+ priv->dev_data = eth_dev->data;
|
|
+ priv->ifindex = repr_port->info.ifindex;
|
|
+
|
|
+ eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
|
|
+ eth_dev->data->mac_addrs = priv->mac;
|
|
+ if (rte_is_zero_ether_addr(eth_dev->data->mac_addrs)) {
|
|
+ ret = xsc_dev_get_mac(priv->xdev, mac.addr_bytes);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Port %u cannot get MAC address",
|
|
+ eth_dev->data->port_id);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ xsc_ethdev_mac_addr_add(eth_dev, &mac, 0);
|
|
+
|
|
+ config->hw_csum = 1;
|
|
+ config->pph_flag = priv->xdev->devargs.pph_mode;
|
|
+ if ((config->pph_flag & XSC_TX_PPH) != 0) {
|
|
+ config->tso = 0;
|
|
+ } else {
|
|
+ config->tso = 1;
|
|
+ config->tso_max_payload_sz = 1500;
|
|
+ }
|
|
+
|
|
+ priv->is_representor = 1;
|
|
+ eth_dev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR;
|
|
+ eth_dev->data->representor_id = priv->representor_id;
|
|
+ eth_dev->data->backer_port_id = eth_dev->data->port_id;
|
|
+
|
|
+ eth_dev->dev_ops = &xsc_eth_dev_ops;
|
|
+ eth_dev->rx_pkt_burst = rte_eth_pkt_burst_dummy;
|
|
+ eth_dev->tx_pkt_burst = rte_eth_pkt_burst_dummy;
|
|
+
|
|
+ rte_eth_dev_probing_finish(eth_dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_init_representors(struct rte_eth_dev *eth_dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(eth_dev);
|
|
+ struct rte_eth_devargs eth_da = { .nb_representor_ports = 0 };
|
|
+ struct rte_device *dev;
|
|
+ struct xsc_dev *xdev;
|
|
+ struct xsc_repr_port *repr_port;
|
|
+ char name[RTE_ETH_NAME_MAX_LEN];
|
|
+ int i;
|
|
+ int ret;
|
|
+
|
|
+ PMD_INIT_FUNC_TRACE();
|
|
+
|
|
+ dev = &priv->pci_dev->device;
|
|
+ if (dev->devargs != NULL) {
|
|
+#if RTE_VERSION_NUM(24, 0, 0, 0) > RTE_VERSION
|
|
+ ret = rte_eth_devargs_parse(dev->devargs->args, ð_da);
|
|
+#else
|
|
+ ret = rte_eth_devargs_parse(dev->devargs->args, ð_da, 1);
|
|
+#endif
|
|
+ if (ret < 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to parse device arguments: %s",
|
|
+ dev->devargs->args);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ xdev = priv->xdev;
|
|
+ ret = xsc_dev_repr_ports_probe(xdev, eth_da.nb_representor_ports, RTE_MAX_ETHPORTS);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to probe %d xsc device representors",
|
|
+ eth_da.nb_representor_ports);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* PF rep init */
|
|
+ repr_port = &xdev->repr_ports[xdev->num_repr_ports - 1];
|
|
+ ret = xsc_ethdev_init_one_representor(eth_dev, repr_port);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to init backing representor");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* VF rep init */
|
|
+ for (i = 0; i < eth_da.nb_representor_ports; i++) {
|
|
+ repr_port = &xdev->repr_ports[i];
|
|
+ snprintf(name, sizeof(name), "%s_rep_%d",
|
|
+ xdev->name, repr_port->info.repr_id);
|
|
+ ret = rte_eth_dev_create(dev,
|
|
+ name,
|
|
+ sizeof(struct xsc_ethdev_priv),
|
|
+ NULL, NULL,
|
|
+ xsc_ethdev_init_one_representor,
|
|
+ repr_port);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to create representor: %d", i);
|
|
+ goto destroy_reprs;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ret = xsc_ethdev_set_link_up(eth_dev);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to set mac link up");
|
|
+ goto destroy_reprs;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+destroy_reprs:
|
|
+ /* Destroy vf reprs */
|
|
+ while ((i--) > 1) {
|
|
+ repr_port = &xdev->repr_ports[i];
|
|
+ rte_eth_dev_destroy((struct rte_eth_dev *)repr_port->drv_data, NULL);
|
|
+ }
|
|
+
|
|
+ /* Destroy pf repr */
|
|
+ repr_port = &xdev->repr_ports[xdev->num_repr_ports - 1];
|
|
+ rte_eth_dev_destroy((struct rte_eth_dev *)repr_port->drv_data, NULL);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_ethdev_intr_handler(void *param)
|
|
+{
|
|
+ struct rte_eth_dev *eth_dev = param;
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(eth_dev);
|
|
+ int event_type;
|
|
+
|
|
+ event_type = xsc_dev_intr_event_get(priv->xdev);
|
|
+ switch (event_type) {
|
|
+ case XSC_EVENT_TYPE_CHANGE_LINK:
|
|
+ PMD_DRV_LOG(DEBUG, "Get intr event type=%04x", event_type);
|
|
+ xsc_ethdev_link_update(eth_dev, 0);
|
|
+ rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_INTR_LSC, NULL);
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_init(struct rte_eth_dev *eth_dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(eth_dev);
|
|
+ int ret;
|
|
+
|
|
+ PMD_INIT_FUNC_TRACE();
|
|
+
|
|
+ priv->eth_dev = eth_dev;
|
|
+ priv->pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
|
|
+
|
|
+ ret = xsc_dev_init(priv->pci_dev, &priv->xdev);
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to initialize xsc device");
|
|
+ return ret;
|
|
+ }
|
|
+ priv->xdev->port_id = eth_dev->data->port_id;
|
|
+
|
|
+ ret = xsc_ethdev_init_representors(eth_dev);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to initialize representors");
|
|
+ goto uninit_xsc_dev;
|
|
+ }
|
|
+
|
|
+ ret = xsc_dev_intr_handler_install(priv->xdev, xsc_ethdev_intr_handler, eth_dev);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to install intr handler");
|
|
+ goto uninit_xsc_dev;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+uninit_xsc_dev:
|
|
+ xsc_dev_uninit(priv->xdev);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_uninit(struct rte_eth_dev *eth_dev)
|
|
+{
|
|
+ struct xsc_ethdev_priv *priv = TO_XSC_ETHDEV_PRIV(eth_dev);
|
|
+
|
|
+ PMD_INIT_FUNC_TRACE();
|
|
+
|
|
+ xsc_dev_uninit(priv->xdev);
|
|
+ xsc_dev_intr_handler_uninstall(priv->xdev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
|
|
+ struct rte_pci_device *pci_dev)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ PMD_INIT_FUNC_TRACE();
|
|
+
|
|
+ ret = rte_eth_dev_pci_generic_probe(pci_dev,
|
|
+ sizeof(struct xsc_ethdev_priv),
|
|
+ xsc_ethdev_init);
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to probe ethdev: %s", pci_dev->name);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ethdev_pci_remove(struct rte_pci_device *pci_dev)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ PMD_INIT_FUNC_TRACE();
|
|
+
|
|
+ ret = rte_eth_dev_pci_generic_remove(pci_dev, xsc_ethdev_uninit);
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Could not remove ethdev: %s", pci_dev->name);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct rte_pci_id xsc_ethdev_pci_id_map[] = {
|
|
+ { RTE_PCI_DEVICE(XSC_PCI_VENDOR_ID, XSC_PCI_DEV_ID_MS) },
|
|
+ { RTE_PCI_DEVICE(XSC_PCI_VENDOR_ID, XSC_PCI_DEV_ID_MSVF) },
|
|
+ { RTE_PCI_DEVICE(XSC_PCI_VENDOR_ID, XSC_PCI_DEV_ID_MVH) },
|
|
+ { RTE_PCI_DEVICE(XSC_PCI_VENDOR_ID, XSC_PCI_DEV_ID_MVHVF) },
|
|
+ { RTE_PCI_DEVICE(XSC_PCI_VENDOR_ID, XSC_PCI_DEV_ID_MVS) },
|
|
+ { RTE_PCI_DEVICE(0, 0) },
|
|
+};
|
|
+
|
|
+static struct rte_pci_driver xsc_ethdev_pci_driver = {
|
|
+ .id_table = xsc_ethdev_pci_id_map,
|
|
+ .probe = xsc_ethdev_pci_probe,
|
|
+ .remove = xsc_ethdev_pci_remove,
|
|
+};
|
|
+
|
|
+RTE_PMD_REGISTER_PCI(net_xsc, xsc_ethdev_pci_driver);
|
|
+RTE_PMD_REGISTER_PCI_TABLE(net_xsc, xsc_ethdev_pci_id_map);
|
|
+RTE_PMD_REGISTER_PARAM_STRING(net_xsc,
|
|
+ XSC_PPH_MODE_ARG "=<x>"
|
|
+ XSC_NIC_MODE_ARG "=<x>"
|
|
+ XSC_FLOW_MODE_ARG "=<x>");
|
|
+
|
|
+RTE_LOG_REGISTER_SUFFIX(xsc_logtype_init, init, NOTICE);
|
|
+RTE_LOG_REGISTER_SUFFIX(xsc_logtype_driver, driver, NOTICE);
|
|
diff --git a/drivers/net/xsc/xsc_ethdev.h b/drivers/net/xsc/xsc_ethdev.h
|
|
new file mode 100644
|
|
index 0000000..0b307c2
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_ethdev.h
|
|
@@ -0,0 +1,63 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#ifndef _XSC_ETHDEV_H_
|
|
+#define _XSC_ETHDEV_H_
|
|
+
|
|
+#include "xsc_dev.h"
|
|
+
|
|
+#define XSC_FLAG_RX_QUEUE_INIT 0x1
|
|
+#define XSC_FLAG_TX_QUEUE_INIT 0x2
|
|
+
|
|
+struct xsc_ethdev_priv {
|
|
+ struct rte_eth_dev *eth_dev;
|
|
+ struct rte_pci_device *pci_dev;
|
|
+ struct xsc_dev *xdev;
|
|
+ struct xsc_repr_port *repr_port;
|
|
+ struct xsc_dev_config config;
|
|
+ struct rte_eth_dev_data *dev_data;
|
|
+ struct rte_ether_addr mac[XSC_MAX_MAC_ADDRESSES];
|
|
+ struct rte_eth_rss_conf rss_conf;
|
|
+
|
|
+ int representor_id;
|
|
+ uint32_t ifindex;
|
|
+ uint16_t mtu;
|
|
+ uint8_t isolated;
|
|
+ uint8_t is_representor;
|
|
+
|
|
+ uint32_t mode:7;
|
|
+ uint32_t member_bitmap:8;
|
|
+ uint32_t funcid_type:3;
|
|
+ uint32_t funcid:14;
|
|
+
|
|
+ uint16_t eth_type;
|
|
+ uint16_t qp_set_id;
|
|
+
|
|
+ uint16_t num_sq;
|
|
+ uint16_t num_rq;
|
|
+
|
|
+ uint16_t flags;
|
|
+ struct xsc_txq_data *(*txqs)[];
|
|
+ struct xsc_rxq_data *(*rxqs)[];
|
|
+};
|
|
+
|
|
+#define TO_XSC_ETHDEV_PRIV(dev) ((struct xsc_ethdev_priv *)(dev)->data->dev_private)
|
|
+
|
|
+static __rte_always_inline struct xsc_txq_data *
|
|
+xsc_txq_get(struct xsc_ethdev_priv *priv, uint16_t idx)
|
|
+{
|
|
+ if (priv->txqs != NULL && (*priv->txqs)[idx] != NULL)
|
|
+ return (*priv->txqs)[idx];
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static __rte_always_inline struct xsc_rxq_data *
|
|
+xsc_rxq_get(struct xsc_ethdev_priv *priv, uint16_t idx)
|
|
+{
|
|
+ if (priv->rxqs != NULL && (*priv->rxqs)[idx] != NULL)
|
|
+ return (*priv->rxqs)[idx];
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+#endif /* _XSC_ETHDEV_H_ */
|
|
diff --git a/drivers/net/xsc/xsc_log.h b/drivers/net/xsc/xsc_log.h
|
|
new file mode 100644
|
|
index 0000000..7fd16e2
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_log.h
|
|
@@ -0,0 +1,48 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#ifndef _XSC_LOG_H_
|
|
+#define _XSC_LOG_H_
|
|
+
|
|
+#include <rte_log.h>
|
|
+#include <rte_version.h>
|
|
+
|
|
+extern int xsc_logtype_init;
|
|
+extern int xsc_logtype_driver;
|
|
+#define RTE_LOGTYPE_XSC_INIT xsc_logtype_init
|
|
+#define RTE_LOGTYPE_XSC_DRV xsc_logtype_driver
|
|
+
|
|
+#if RTE_VERSION_NUM(25, 0, 0, 0) > RTE_VERSION
|
|
+
|
|
+#define PMD_INIT_LOG(level, fmt, args...) \
|
|
+ rte_log(RTE_LOG_ ## level, RTE_LOGTYPE_XSC_INIT, "%s(): " fmt "\n", \
|
|
+ __func__, ##args)
|
|
+#define PMD_INIT_FUNC_TRACE() PMD_INIT_LOG(DEBUG, " >>")
|
|
+
|
|
+
|
|
+#define PMD_DRV_LOG_RAW(level, fmt, args...) \
|
|
+ rte_log(RTE_LOG_ ## level, RTE_LOGTYPE_XSC_DRV, "%s(): " fmt, \
|
|
+ __func__, ## args)
|
|
+
|
|
+#define PMD_DRV_LOG(level, fmt, args...) \
|
|
+ PMD_DRV_LOG_RAW(level, fmt "\n", ## args)
|
|
+
|
|
+#else
|
|
+
|
|
+#define PMD_INIT_LOG(level, ...) \
|
|
+ RTE_LOG_LINE_PREFIX(level, XSC_INIT, "%s(): ", __func__, __VA_ARGS__)
|
|
+
|
|
+
|
|
+#define PMD_INIT_FUNC_TRACE() PMD_INIT_LOG(DEBUG, " >>")
|
|
+
|
|
+
|
|
+#define PMD_DRV_LOG_RAW(level, ...) \
|
|
+ RTE_LOG_LINE_PREFIX(level, XSC_DRV, "%s(): ", __func__, __VA_ARGS__)
|
|
+
|
|
+#define PMD_DRV_LOG(level, ...) \
|
|
+ PMD_DRV_LOG_RAW(level, __VA_ARGS__)
|
|
+
|
|
+#endif
|
|
+
|
|
+#endif /* _XSC_LOG_H_ */
|
|
diff --git a/drivers/net/xsc/xsc_np.c b/drivers/net/xsc/xsc_np.c
|
|
new file mode 100644
|
|
index 0000000..f96797b
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_np.c
|
|
@@ -0,0 +1,489 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#include <rte_bitmap.h>
|
|
+#include <rte_malloc.h>
|
|
+
|
|
+#include "xsc_log.h"
|
|
+#include "xsc_defs.h"
|
|
+#include "xsc_np.h"
|
|
+#include "xsc_cmd.h"
|
|
+#include "xsc_dev.h"
|
|
+
|
|
+#define XSC_RSS_HASH_FUNC_TOPELIZ 0x1
|
|
+#define XSC_LOGIC_PORT_MASK 0x07FF
|
|
+
|
|
+#define XSC_DEV_DEF_PCT_IDX_MIN 128
|
|
+#define XSC_DEV_DEF_PCT_IDX_MAX 138
|
|
+
|
|
+/* Each board has a PCT manager*/
|
|
+static struct xsc_dev_pct_mgr xsc_pct_mgr;
|
|
+
|
|
+enum xsc_np_type {
|
|
+ XSC_NP_IPAT = 0,
|
|
+ XSC_NP_PCT_V4 = 4,
|
|
+ XSC_NP_EPAT = 19,
|
|
+ XSC_NP_VFOS = 31,
|
|
+ XSC_NP_PG_QP_SET_ID = 41,
|
|
+ XSC_NP_MAX
|
|
+};
|
|
+
|
|
+enum xsc_np_opcode {
|
|
+ XSC_NP_OP_ADD,
|
|
+ XSC_NP_OP_DEL,
|
|
+ XSC_NP_OP_GET,
|
|
+ XSC_NP_OP_CLR,
|
|
+ XSC_NP_OP_MOD,
|
|
+ XSC_NP_OP_MAX
|
|
+};
|
|
+
|
|
+struct xsc_np_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ rte_be16_t len;
|
|
+ rte_be16_t rsvd;
|
|
+ uint8_t data[];
|
|
+};
|
|
+
|
|
+struct xsc_np_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ rte_be32_t error;
|
|
+ rte_be16_t len;
|
|
+ rte_be16_t rsvd;
|
|
+ uint8_t data[];
|
|
+};
|
|
+
|
|
+struct xsc_np_data_tl {
|
|
+ uint16_t table;
|
|
+ uint16_t opmod;
|
|
+ uint16_t length;
|
|
+ uint16_t rsvd;
|
|
+};
|
|
+
|
|
+enum xsc_hash_tmpl {
|
|
+ XSC_HASH_TMPL_IDX_IP_PORTS_IP6_PORTS = 0,
|
|
+ XSC_HASH_TMPL_IDX_IP_IP6,
|
|
+ XSC_HASH_TMPL_IDX_IP_PORTS_IP6,
|
|
+ XSC_HASH_TMPL_IDX_IP_IP6_PORTS,
|
|
+ XSC_HASH_TMPL_IDX_MAX,
|
|
+};
|
|
+
|
|
+static const int xsc_rss_hash_tmplate[XSC_HASH_TMPL_IDX_MAX] = {
|
|
+ XSC_RSS_HASH_BIT_IPV4_SIP | XSC_RSS_HASH_BIT_IPV4_DIP |
|
|
+ XSC_RSS_HASH_BIT_IPV6_SIP | XSC_RSS_HASH_BIT_IPV6_DIP |
|
|
+ XSC_RSS_HASH_BIT_IPV4_SPORT | XSC_RSS_HASH_BIT_IPV4_DPORT |
|
|
+ XSC_RSS_HASH_BIT_IPV6_SPORT | XSC_RSS_HASH_BIT_IPV6_DPORT,
|
|
+
|
|
+ XSC_RSS_HASH_BIT_IPV4_SIP | XSC_RSS_HASH_BIT_IPV4_DIP |
|
|
+ XSC_RSS_HASH_BIT_IPV6_SIP | XSC_RSS_HASH_BIT_IPV6_DIP,
|
|
+
|
|
+ XSC_RSS_HASH_BIT_IPV4_SIP | XSC_RSS_HASH_BIT_IPV4_DIP |
|
|
+ XSC_RSS_HASH_BIT_IPV6_SIP | XSC_RSS_HASH_BIT_IPV6_DIP |
|
|
+ XSC_RSS_HASH_BIT_IPV4_SPORT | XSC_RSS_HASH_BIT_IPV4_DPORT,
|
|
+
|
|
+ XSC_RSS_HASH_BIT_IPV4_SIP | XSC_RSS_HASH_BIT_IPV4_DIP |
|
|
+ XSC_RSS_HASH_BIT_IPV6_SIP | XSC_RSS_HASH_BIT_IPV6_DIP |
|
|
+ XSC_RSS_HASH_BIT_IPV6_SPORT | XSC_RSS_HASH_BIT_IPV6_DPORT,
|
|
+};
|
|
+
|
|
+static uint8_t
|
|
+xsc_rss_hash_template_get(struct rte_eth_rss_conf *rss_conf)
|
|
+{
|
|
+ int rss_hf = 0;
|
|
+ int i = 0;
|
|
+ uint8_t idx = 0;
|
|
+ uint8_t outer = 1;
|
|
+
|
|
+ if (rss_conf->rss_hf & RTE_ETH_RSS_IP) {
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV4_SIP;
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV4_DIP;
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV6_SIP;
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV6_DIP;
|
|
+ }
|
|
+
|
|
+ if ((rss_conf->rss_hf & RTE_ETH_RSS_UDP) ||
|
|
+ (rss_conf->rss_hf & RTE_ETH_RSS_TCP)) {
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV4_SPORT;
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV4_DPORT;
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV6_SPORT;
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV6_DPORT;
|
|
+ }
|
|
+
|
|
+ if (rss_conf->rss_hf & RTE_ETH_RSS_L3_SRC_ONLY) {
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV4_SIP;
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV6_SIP;
|
|
+ rss_hf &= ~XSC_RSS_HASH_BIT_IPV4_DIP;
|
|
+ rss_hf &= ~XSC_RSS_HASH_BIT_IPV6_DIP;
|
|
+ }
|
|
+
|
|
+ if (rss_conf->rss_hf & RTE_ETH_RSS_L3_DST_ONLY) {
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV4_DIP;
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV6_DIP;
|
|
+ rss_hf &= ~XSC_RSS_HASH_BIT_IPV4_SIP;
|
|
+ rss_hf &= ~XSC_RSS_HASH_BIT_IPV6_SIP;
|
|
+ }
|
|
+
|
|
+ if (rss_conf->rss_hf & RTE_ETH_RSS_L4_SRC_ONLY) {
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV4_SPORT;
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV6_SPORT;
|
|
+ rss_hf &= ~XSC_RSS_HASH_BIT_IPV4_DPORT;
|
|
+ rss_hf &= ~XSC_RSS_HASH_BIT_IPV6_DPORT;
|
|
+ }
|
|
+
|
|
+ if (rss_conf->rss_hf & RTE_ETH_RSS_L4_DST_ONLY) {
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV4_DPORT;
|
|
+ rss_hf |= XSC_RSS_HASH_BIT_IPV6_DPORT;
|
|
+ rss_hf &= ~XSC_RSS_HASH_BIT_IPV4_SPORT;
|
|
+ rss_hf &= ~XSC_RSS_HASH_BIT_IPV6_SPORT;
|
|
+ }
|
|
+
|
|
+ if (rss_conf->rss_hf & RTE_ETH_RSS_LEVEL_INNERMOST)
|
|
+ outer = 0;
|
|
+
|
|
+ for (i = 0; i < XSC_HASH_TMPL_IDX_MAX; i++) {
|
|
+ if (xsc_rss_hash_tmplate[i] == rss_hf) {
|
|
+ idx = i;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ idx = (idx << 1) | outer;
|
|
+ return idx;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_dev_np_exec(struct xsc_dev *xdev, void *cmd, int len, int table, int opmod)
|
|
+{
|
|
+ struct xsc_np_data_tl *tl;
|
|
+ struct xsc_np_mbox_in *in;
|
|
+ struct xsc_np_mbox_out *out;
|
|
+ int in_len;
|
|
+ int out_len;
|
|
+ int data_len;
|
|
+ int cmd_len;
|
|
+ int ret;
|
|
+ void *cmd_buf;
|
|
+
|
|
+ data_len = sizeof(struct xsc_np_data_tl) + len;
|
|
+ in_len = sizeof(struct xsc_np_mbox_in) + data_len;
|
|
+ out_len = sizeof(struct xsc_np_mbox_out) + data_len;
|
|
+ cmd_len = RTE_MAX(in_len, out_len);
|
|
+ cmd_buf = malloc(cmd_len);
|
|
+ if (cmd_buf == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc np cmd memory");
|
|
+ return -rte_errno;
|
|
+ }
|
|
+
|
|
+ in = cmd_buf;
|
|
+ memset(in, 0, cmd_len);
|
|
+ in->hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_EXEC_NP);
|
|
+ in->len = rte_cpu_to_be_16(data_len);
|
|
+
|
|
+ tl = (struct xsc_np_data_tl *)in->data;
|
|
+ tl->length = len;
|
|
+ tl->table = table;
|
|
+ tl->opmod = opmod;
|
|
+ if (cmd && len)
|
|
+ memcpy(tl + 1, cmd, len);
|
|
+
|
|
+ out = cmd_buf;
|
|
+ ret = xsc_dev_mailbox_exec(xdev, in, in_len, out, out_len);
|
|
+
|
|
+ free(cmd_buf);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_create_pct(struct xsc_dev *xdev, int repr_id,
|
|
+ uint16_t logical_in_port, uint16_t dst_info)
|
|
+{
|
|
+ int ret;
|
|
+ struct xsc_np_pct_v4_add add;
|
|
+ struct xsc_repr_port *repr = &xdev->repr_ports[repr_id];
|
|
+ struct xsc_dev_pct_list *pct_list = &repr->def_pct_list;
|
|
+
|
|
+ memset(&add, 0, sizeof(add));
|
|
+ add.key.logical_in_port = logical_in_port & XSC_LOGIC_PORT_MASK;
|
|
+ add.mask.logical_in_port = XSC_LOGIC_PORT_MASK;
|
|
+ add.action.dst_info = dst_info;
|
|
+ add.pct_idx = xsc_dev_pct_idx_alloc();
|
|
+ if (add.pct_idx == XSC_DEV_PCT_IDX_INVALID)
|
|
+ return -1;
|
|
+
|
|
+ ret = xsc_dev_np_exec(xdev, &add, sizeof(add), XSC_NP_PCT_V4, XSC_NP_OP_ADD);
|
|
+ if (unlikely(ret != 0)) {
|
|
+ xsc_dev_pct_idx_free(add.pct_idx);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ xsc_dev_pct_entry_insert(pct_list, add.key.logical_in_port, add.pct_idx);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_destroy_pct(struct xsc_dev *xdev, uint16_t logical_in_port, uint32_t pct_idx)
|
|
+{
|
|
+ struct xsc_np_pct_v4_del del;
|
|
+
|
|
+ memset(&del, 0, sizeof(del));
|
|
+ del.key.logical_in_port = logical_in_port & XSC_LOGIC_PORT_MASK;
|
|
+ del.mask.logical_in_port = XSC_LOGIC_PORT_MASK;
|
|
+ del.pct_idx = pct_idx;
|
|
+ return xsc_dev_np_exec(xdev, &del, sizeof(del), XSC_NP_PCT_V4, XSC_NP_OP_DEL);
|
|
+}
|
|
+
|
|
+void
|
|
+xsc_dev_clear_pct(struct xsc_dev *xdev, int repr_id)
|
|
+{
|
|
+ struct xsc_repr_port *repr;
|
|
+ struct xsc_dev_pct_entry *pct_entry;
|
|
+ struct xsc_dev_pct_list *pct_list;
|
|
+
|
|
+ if (repr_id == XSC_DEV_REPR_ID_INVALID)
|
|
+ return;
|
|
+
|
|
+ repr = &xdev->repr_ports[repr_id];
|
|
+ pct_list = &repr->def_pct_list;
|
|
+
|
|
+ while ((pct_entry = xsc_dev_pct_first_get(pct_list)) != NULL) {
|
|
+ xsc_dev_destroy_pct(xdev, pct_entry->logic_port, pct_entry->pct_idx);
|
|
+ xsc_dev_pct_entry_remove(pct_entry);
|
|
+ }
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_create_ipat(struct xsc_dev *xdev, uint16_t logic_in_port, uint16_t dst_info)
|
|
+{
|
|
+ struct xsc_np_ipat add;
|
|
+
|
|
+ memset(&add, 0, sizeof(add));
|
|
+ add.key.logical_in_port = logic_in_port;
|
|
+ add.action.dst_info = dst_info;
|
|
+ add.action.vld = 1;
|
|
+ return xsc_dev_np_exec(xdev, &add, sizeof(add), XSC_NP_IPAT, XSC_NP_OP_ADD);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_get_ipat_vld(struct xsc_dev *xdev, uint16_t logic_in_port)
|
|
+{
|
|
+ int ret;
|
|
+ struct xsc_np_ipat get;
|
|
+
|
|
+ memset(&get, 0, sizeof(get));
|
|
+ get.key.logical_in_port = logic_in_port;
|
|
+
|
|
+ ret = xsc_dev_np_exec(xdev, &get, sizeof(get), XSC_NP_IPAT, XSC_NP_OP_GET);
|
|
+ if (ret != 0)
|
|
+ PMD_DRV_LOG(ERR, "Get ipat vld failed, logic in port=%u", logic_in_port);
|
|
+
|
|
+ return get.action.vld;
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_destroy_ipat(struct xsc_dev *xdev, uint16_t logic_in_port)
|
|
+{
|
|
+ struct xsc_ipat_key del;
|
|
+
|
|
+ memset(&del, 0, sizeof(del));
|
|
+ del.logical_in_port = logic_in_port;
|
|
+ return xsc_dev_np_exec(xdev, &del, sizeof(del), XSC_NP_IPAT, XSC_NP_OP_DEL);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_create_epat(struct xsc_dev *xdev, uint16_t dst_info, uint8_t dst_port,
|
|
+ uint16_t qpn_ofst, uint8_t qp_num, struct rte_eth_rss_conf *rss_conf)
|
|
+{
|
|
+ struct xsc_np_epat_add add;
|
|
+
|
|
+ memset(&add, 0, sizeof(add));
|
|
+ add.key.dst_info = dst_info;
|
|
+ add.action.dst_port = dst_port;
|
|
+ add.action.vld = 1;
|
|
+ add.action.rx_qp_id_ofst = qpn_ofst;
|
|
+ add.action.qp_num = qp_num - 1;
|
|
+ add.action.rss_en = 1;
|
|
+ add.action.rss_hash_func = XSC_RSS_HASH_FUNC_TOPELIZ;
|
|
+ add.action.rss_hash_template = xsc_rss_hash_template_get(rss_conf);
|
|
+
|
|
+ return xsc_dev_np_exec(xdev, &add, sizeof(add), XSC_NP_EPAT, XSC_NP_OP_ADD);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_vf_modify_epat(struct xsc_dev *xdev, uint16_t dst_info, uint16_t qpn_ofst,
|
|
+ uint8_t qp_num, struct rte_eth_rss_conf *rss_conf)
|
|
+{
|
|
+ struct xsc_np_epat_mod mod;
|
|
+
|
|
+ memset(&mod, 0, sizeof(mod));
|
|
+ mod.flags = XSC_EPAT_VLD_FLAG | XSC_EPAT_RX_QP_ID_OFST_FLAG |
|
|
+ XSC_EPAT_QP_NUM_FLAG | XSC_EPAT_HAS_PPH_FLAG |
|
|
+ XSC_EPAT_RSS_EN_FLAG | XSC_EPAT_RSS_HASH_TEMPLATE_FLAG |
|
|
+ XSC_EPAT_RSS_HASH_FUNC_FLAG;
|
|
+
|
|
+ mod.key.dst_info = dst_info;
|
|
+ mod.action.vld = 1;
|
|
+ mod.action.rx_qp_id_ofst = qpn_ofst;
|
|
+ mod.action.qp_num = qp_num - 1;
|
|
+ mod.action.rss_en = 1;
|
|
+ mod.action.rss_hash_func = XSC_RSS_HASH_FUNC_TOPELIZ;
|
|
+ mod.action.rss_hash_template = xsc_rss_hash_template_get(rss_conf);
|
|
+
|
|
+ return xsc_dev_np_exec(xdev, &mod, sizeof(mod), XSC_NP_EPAT, XSC_NP_OP_MOD);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_set_qpsetid(struct xsc_dev *xdev, uint32_t txqpn, uint16_t qp_set_id)
|
|
+{
|
|
+ int ret;
|
|
+ struct xsc_pg_set_id add;
|
|
+ uint16_t qp_id_base = xdev->hwinfo.raw_qp_id_base;
|
|
+
|
|
+ memset(&add, 0, sizeof(add));
|
|
+ add.key.qp_id = txqpn - qp_id_base;
|
|
+ add.action.qp_set_id = qp_set_id;
|
|
+
|
|
+ ret = xsc_dev_np_exec(xdev, &add, sizeof(add), XSC_NP_PG_QP_SET_ID, XSC_NP_OP_ADD);
|
|
+ if (ret != 0)
|
|
+ PMD_DRV_LOG(ERR, "Failed to set qp %u setid %u", txqpn, qp_set_id);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_destroy_epat(struct xsc_dev *xdev, uint16_t dst_info)
|
|
+{
|
|
+ struct xsc_epat_key del;
|
|
+
|
|
+ memset(&del, 0, sizeof(del));
|
|
+
|
|
+ del.dst_info = dst_info;
|
|
+ return xsc_dev_np_exec(xdev, &del, sizeof(del), XSC_NP_EPAT, XSC_NP_OP_DEL);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_create_vfos_baselp(struct xsc_dev *xdev)
|
|
+{
|
|
+ int ret;
|
|
+ struct xsc_np_vfso add;
|
|
+
|
|
+ memset(&add, 0, sizeof(add));
|
|
+ add.key.src_port = xdev->vfrep_offset;
|
|
+ add.action.ofst = xdev->vfos_logical_in_port;
|
|
+
|
|
+ ret = xsc_dev_np_exec(xdev, &add, sizeof(add), XSC_NP_VFOS, XSC_NP_OP_ADD);
|
|
+ if (ret != 0)
|
|
+ PMD_DRV_LOG(ERR, "Failed to set vfos, port=%u, offset=%u",
|
|
+ add.key.src_port, add.action.ofst);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void
|
|
+xsc_dev_pct_uninit(void)
|
|
+{
|
|
+ rte_free(xsc_pct_mgr.bmp_mem);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_pct_init(void)
|
|
+{
|
|
+ int ret;
|
|
+ uint8_t *bmp_mem;
|
|
+ uint32_t pos, pct_sz, bmp_sz;
|
|
+
|
|
+ if (xsc_pct_mgr.bmp_mem != NULL)
|
|
+ return 0;
|
|
+
|
|
+ pct_sz = XSC_DEV_DEF_PCT_IDX_MAX - XSC_DEV_DEF_PCT_IDX_MIN + 1;
|
|
+ bmp_sz = rte_bitmap_get_memory_footprint(pct_sz);
|
|
+ bmp_mem = rte_zmalloc(NULL, bmp_sz, RTE_CACHE_LINE_SIZE);
|
|
+ if (bmp_mem == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc pct bitmap memory");
|
|
+ ret = -ENOMEM;
|
|
+ goto pct_init_fail;
|
|
+ }
|
|
+
|
|
+ xsc_pct_mgr.bmp_mem = bmp_mem;
|
|
+ xsc_pct_mgr.bmp_pct = rte_bitmap_init(pct_sz, bmp_mem, bmp_sz);
|
|
+ if (xsc_pct_mgr.bmp_pct == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to init pct bitmap");
|
|
+ ret = -EINVAL;
|
|
+ goto pct_init_fail;
|
|
+ }
|
|
+
|
|
+ /* Mark all pct bitmap available */
|
|
+ for (pos = 0; pos < pct_sz; pos++)
|
|
+ rte_bitmap_set(xsc_pct_mgr.bmp_pct, pos);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+pct_init_fail:
|
|
+ xsc_dev_pct_uninit();
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+uint32_t
|
|
+xsc_dev_pct_idx_alloc(void)
|
|
+{
|
|
+ int ret;
|
|
+ uint64_t slab = 0;
|
|
+ uint32_t pos = 0;
|
|
+
|
|
+ ret = rte_bitmap_scan(xsc_pct_mgr.bmp_pct, &pos, &slab);
|
|
+ if (ret != 0) {
|
|
+ pos += rte_bsf64(slab);
|
|
+ rte_bitmap_clear(xsc_pct_mgr.bmp_pct, pos);
|
|
+ return (pos + XSC_DEV_DEF_PCT_IDX_MIN);
|
|
+ }
|
|
+
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc xsc pct idx");
|
|
+ return XSC_DEV_PCT_IDX_INVALID;
|
|
+}
|
|
+
|
|
+void
|
|
+xsc_dev_pct_idx_free(uint32_t pct_idx)
|
|
+{
|
|
+ rte_bitmap_set(xsc_pct_mgr.bmp_pct, pct_idx - XSC_DEV_DEF_PCT_IDX_MIN);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_pct_entry_insert(struct xsc_dev_pct_list *pct_list,
|
|
+ uint32_t logic_port, uint32_t pct_idx)
|
|
+{
|
|
+ struct xsc_dev_pct_entry *pct_entry;
|
|
+
|
|
+ pct_entry = rte_zmalloc(NULL, sizeof(struct xsc_dev_pct_entry), RTE_CACHE_LINE_SIZE);
|
|
+ if (pct_entry == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc pct entry memory");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ pct_entry->logic_port = logic_port;
|
|
+ pct_entry->pct_idx = pct_idx;
|
|
+ LIST_INSERT_HEAD(pct_list, pct_entry, next);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+struct xsc_dev_pct_entry *
|
|
+xsc_dev_pct_first_get(struct xsc_dev_pct_list *pct_list)
|
|
+{
|
|
+ struct xsc_dev_pct_entry *pct_entry;
|
|
+
|
|
+ pct_entry = LIST_FIRST(pct_list);
|
|
+ return pct_entry;
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_dev_pct_entry_remove(struct xsc_dev_pct_entry *pct_entry)
|
|
+{
|
|
+ if (pct_entry == NULL)
|
|
+ return -1;
|
|
+
|
|
+ xsc_dev_pct_idx_free(pct_entry->pct_idx);
|
|
+ LIST_REMOVE(pct_entry, next);
|
|
+ rte_free(pct_entry);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/drivers/net/xsc/xsc_np.h b/drivers/net/xsc/xsc_np.h
|
|
new file mode 100644
|
|
index 0000000..02383b2
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_np.h
|
|
@@ -0,0 +1,156 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#ifndef _XSC_NP_H_
|
|
+#define _XSC_NP_H_
|
|
+
|
|
+#include <rte_byteorder.h>
|
|
+#include <rte_ethdev.h>
|
|
+
|
|
+#include "xsc_compat.h"
|
|
+
|
|
+struct xsc_dev;
|
|
+
|
|
+struct __rte_packed_begin xsc_ipat_key {
|
|
+ uint16_t logical_in_port:11;
|
|
+ uint16_t rsv:5;
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct __rte_packed_begin xsc_ipat_action {
|
|
+ uint64_t rsv0;
|
|
+ uint64_t rsv1:9;
|
|
+ uint64_t dst_info:11;
|
|
+ uint64_t rsv2:34;
|
|
+ uint64_t vld:1;
|
|
+ uint64_t rsv:1;
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct xsc_np_ipat {
|
|
+ struct xsc_ipat_key key;
|
|
+ struct xsc_ipat_action action;
|
|
+};
|
|
+
|
|
+struct __rte_packed_begin xsc_epat_key {
|
|
+ uint16_t dst_info:11;
|
|
+ uint16_t rsv:5;
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct __rte_packed_begin xsc_epat_action {
|
|
+ uint8_t rsv0[14];
|
|
+ uint8_t rsv1:4;
|
|
+ uint8_t dst_port:4;
|
|
+ uint8_t rss_hash_func:2;
|
|
+ uint8_t rss_hash_template:5;
|
|
+ uint8_t rss_en:1;
|
|
+ uint8_t qp_num;
|
|
+ uint16_t rx_qp_id_ofst:12;
|
|
+ uint16_t rsv3:4;
|
|
+ uint8_t rsv4:7;
|
|
+ uint8_t vld:1;
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct xsc_np_epat_add {
|
|
+ struct xsc_epat_key key;
|
|
+ struct xsc_epat_action action;
|
|
+};
|
|
+
|
|
+struct xsc_np_epat_mod {
|
|
+ uint64_t flags;
|
|
+ struct xsc_epat_key key;
|
|
+ struct xsc_epat_action action;
|
|
+};
|
|
+
|
|
+struct __rte_packed_begin xsc_pct_v4_key {
|
|
+ uint16_t rsv0[20];
|
|
+ uint32_t rsv1:13;
|
|
+ uint32_t logical_in_port:11;
|
|
+ uint32_t rsv2:8;
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct __rte_packed_begin xsc_pct_action {
|
|
+ uint64_t rsv0:29;
|
|
+ uint64_t dst_info:11;
|
|
+ uint64_t rsv1:8;
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct xsc_np_pct_v4_add {
|
|
+ struct xsc_pct_v4_key key;
|
|
+ struct xsc_pct_v4_key mask;
|
|
+ struct xsc_pct_action action;
|
|
+ uint32_t pct_idx;
|
|
+};
|
|
+
|
|
+struct xsc_np_pct_v4_del {
|
|
+ struct xsc_pct_v4_key key;
|
|
+ struct xsc_pct_v4_key mask;
|
|
+ uint32_t pct_idx;
|
|
+};
|
|
+
|
|
+struct __rte_packed_begin xsc_pg_qp_set_id_key {
|
|
+ uint16_t qp_id:13;
|
|
+ uint16_t rsv:3;
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct __rte_packed_begin xsc_pg_qp_set_id_action {
|
|
+ uint16_t qp_set_id:9;
|
|
+ uint16_t rsv:7;
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct xsc_pg_set_id {
|
|
+ struct xsc_pg_qp_set_id_key key;
|
|
+ struct xsc_pg_qp_set_id_action action;
|
|
+};
|
|
+
|
|
+struct __rte_packed_begin xsc_vfos_key {
|
|
+ uint16_t src_port:11;
|
|
+ uint16_t rsv:5;
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct __rte_packed_begin xsc_vfos_start_ofst_action {
|
|
+ uint16_t ofst:11;
|
|
+ uint16_t rsv:5;
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct xsc_np_vfso {
|
|
+ struct xsc_vfos_key key;
|
|
+ struct xsc_vfos_start_ofst_action action;
|
|
+};
|
|
+
|
|
+struct xsc_dev_pct_mgr {
|
|
+ uint8_t *bmp_mem;
|
|
+ struct rte_bitmap *bmp_pct;
|
|
+};
|
|
+
|
|
+struct xsc_dev_pct_entry {
|
|
+ LIST_ENTRY(xsc_dev_pct_entry) next;
|
|
+ uint32_t logic_port;
|
|
+ uint32_t pct_idx;
|
|
+};
|
|
+
|
|
+LIST_HEAD(xsc_dev_pct_list, xsc_dev_pct_entry);
|
|
+
|
|
+int xsc_dev_create_pct(struct xsc_dev *xdev, int repr_id,
|
|
+ uint16_t logical_in_port, uint16_t dst_info);
|
|
+int xsc_dev_destroy_pct(struct xsc_dev *xdev, uint16_t logical_in_port, uint32_t pct_idx);
|
|
+void xsc_dev_clear_pct(struct xsc_dev *xdev, int repr_id);
|
|
+int xsc_dev_create_ipat(struct xsc_dev *xdev, uint16_t logic_in_port, uint16_t dst_info);
|
|
+int xsc_dev_get_ipat_vld(struct xsc_dev *xdev, uint16_t logic_in_port);
|
|
+int xsc_dev_destroy_ipat(struct xsc_dev *xdev, uint16_t logic_in_port);
|
|
+int xsc_dev_create_epat(struct xsc_dev *xdev, uint16_t dst_info, uint8_t dst_port,
|
|
+ uint16_t qpn_ofst, uint8_t qp_num, struct rte_eth_rss_conf *rss_conf);
|
|
+int xsc_dev_vf_modify_epat(struct xsc_dev *xdev, uint16_t dst_info, uint16_t qpn_ofst,
|
|
+ uint8_t qp_num, struct rte_eth_rss_conf *rss_conf);
|
|
+int xsc_dev_destroy_epat(struct xsc_dev *xdev, uint16_t dst_info);
|
|
+int xsc_dev_set_qpsetid(struct xsc_dev *xdev, uint32_t txqpn, uint16_t qp_set_id);
|
|
+int xsc_dev_create_vfos_baselp(struct xsc_dev *xdev);
|
|
+void xsc_dev_pct_uninit(void);
|
|
+int xsc_dev_pct_init(void);
|
|
+uint32_t xsc_dev_pct_idx_alloc(void);
|
|
+void xsc_dev_pct_idx_free(uint32_t pct_idx);
|
|
+int xsc_dev_pct_entry_insert(struct xsc_dev_pct_list *pct_list,
|
|
+ uint32_t logic_port, uint32_t pct_idx);
|
|
+struct xsc_dev_pct_entry *xsc_dev_pct_first_get(struct xsc_dev_pct_list *pct_list);
|
|
+int xsc_dev_pct_entry_remove(struct xsc_dev_pct_entry *pct_entry);
|
|
+
|
|
+#endif /* _XSC_NP_H_ */
|
|
diff --git a/drivers/net/xsc/xsc_rdma.c b/drivers/net/xsc/xsc_rdma.c
|
|
new file mode 100644
|
|
index 0000000..956a01d
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_rdma.c
|
|
@@ -0,0 +1,1304 @@
|
|
+#include <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <sys/stat.h>
|
|
+#include <fcntl.h>
|
|
+#include <limits.h>
|
|
+#include <sys/mman.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <stdalign.h>
|
|
+
|
|
+#include <linux/ethtool.h>
|
|
+#include <linux/sockios.h>
|
|
+#include <rte_pci.h>
|
|
+#include <ethdev_pci.h>
|
|
+#include <rte_bus_pci.h>
|
|
+#include <rte_eal_paging.h>
|
|
+#include <rte_ethdev.h>
|
|
+
|
|
+#include <infiniband/xscdv.h>
|
|
+#include <infiniband/verbs.h>
|
|
+#include "xsc_log.h"
|
|
+#include "xsc_defs.h"
|
|
+#include "xsc_ethdev.h"
|
|
+#include "xsc_rxtx.h"
|
|
+#include "xsc_np.h"
|
|
+#include "xsc_cmd.h"
|
|
+
|
|
+struct xsc_ioctl_attr {
|
|
+ uint16_t opcode; /* ioctl cmd */
|
|
+ uint16_t length; /* data length */
|
|
+ uint32_t error; /* ioctl error info */
|
|
+ uint16_t ver;
|
|
+ uint16_t rsvd;
|
|
+ uint8_t data[]; /* specific table info */
|
|
+};
|
|
+
|
|
+struct xsc_ioctl_hdr {
|
|
+ uint32_t check_field;
|
|
+ uint32_t domain;
|
|
+ uint32_t bus;
|
|
+ uint32_t devfn;
|
|
+ struct xsc_ioctl_attr attr;
|
|
+};
|
|
+
|
|
+enum xsc_ioctl_opmod {
|
|
+ XSC_IOCTL_OP_GET_LOCAL,
|
|
+};
|
|
+
|
|
+struct xsc_ioctl_data_tl {
|
|
+ uint16_t table;
|
|
+ uint16_t opmod;
|
|
+ uint16_t length;
|
|
+ uint16_t rsvd;
|
|
+};
|
|
+
|
|
+struct xsc_ioctl_get_hwinfo {
|
|
+ uint32_t domain;
|
|
+ uint32_t bus;
|
|
+ uint32_t devfn;
|
|
+ uint32_t pcie_no;
|
|
+ uint32_t func_id;
|
|
+ uint32_t pcie_host;
|
|
+ uint32_t mac_phy_port;
|
|
+ uint32_t funcid_to_logic_port_off;
|
|
+ uint16_t lag_id;
|
|
+ uint16_t raw_qp_id_base;
|
|
+ uint16_t raw_rss_qp_id_base;
|
|
+ uint16_t pf0_vf_funcid_base;
|
|
+ uint16_t pf0_vf_funcid_top;
|
|
+ uint16_t pf1_vf_funcid_base;
|
|
+ uint16_t pf1_vf_funcid_top;
|
|
+ uint16_t pcie0_pf_funcid_base;
|
|
+ uint16_t pcie0_pf_funcid_top;
|
|
+ uint16_t pcie1_pf_funcid_base;
|
|
+ uint16_t pcie1_pf_funcid_top;
|
|
+ uint16_t lag_port_start;
|
|
+ uint16_t raw_tpe_qp_num;
|
|
+ int send_seg_num;
|
|
+ int recv_seg_num;
|
|
+ uint8_t on_chip_tbl_vld;
|
|
+ uint8_t dma_rw_tbl_vld;
|
|
+ uint8_t pct_compress_vld;
|
|
+ uint32_t chip_version;
|
|
+ uint32_t hca_core_clock;
|
|
+ uint8_t mac_bit;
|
|
+ uint8_t esw_mode;
|
|
+};
|
|
+
|
|
+struct xsc_ioctl_qp_range {
|
|
+ uint16_t opcode;
|
|
+ int num;
|
|
+ uint32_t qpn;
|
|
+};
|
|
+
|
|
+#define XSC_IOCTL_CHECK_FIELD 0x01234567
|
|
+#define XSC_IOCTL_MAGIC 0x1b
|
|
+#define XSC_IOCTL_CMDQ _IOWR(XSC_IOCTL_MAGIC, 1, struct xsc_ioctl_hdr)
|
|
+#define XSC_IOCTL_DRV_GET _IOR(XSC_IOCTL_MAGIC, 2, struct xsc_ioctl_hdr)
|
|
+#define XSC_IOCTL_CMDQ_RAW _IOWR(XSC_IOCTL_MAGIC, 5, struct xsc_ioctl_hdr)
|
|
+
|
|
+#define XSC_DEV_CTRL_FILE_FMT "/dev/yunsilicon/port_ctrl_" PCI_PRI_FMT
|
|
+
|
|
+#ifndef ETHTOOL_GLINKSETTINGS
|
|
+struct ethtool_link_settings {
|
|
+ uint32_t cmd;
|
|
+ uint32_t speed;
|
|
+ uint8_t duplex;
|
|
+ uint8_t port;
|
|
+ uint8_t phy_address;
|
|
+ uint8_t autoneg;
|
|
+ uint8_t mdio_support;
|
|
+ uint8_t eth_to_mdix;
|
|
+ uint8_t eth_tp_mdix_ctrl;
|
|
+ int8_t link_mode_masks_nwords;
|
|
+ uint32_t reserved[8];
|
|
+ uint32_t link_mode_masks[];
|
|
+};
|
|
+
|
|
+/* The kernel values can be found in /include/uapi/linux/ethtool.h */
|
|
+#define ETHTOOL_GLINKSETTINGS 0x0000004c
|
|
+#define ETHTOOL_LINK_MODE_1000baseT_Full_BIT 5
|
|
+#define ETHTOOL_LINK_MODE_Autoneg_BIT 6
|
|
+#define ETHTOOL_LINK_MODE_1000baseKX_Full_BIT 17
|
|
+#define ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT 18
|
|
+#define ETHTOOL_LINK_MODE_10000baseKR_Full_BIT 19
|
|
+#define ETHTOOL_LINK_MODE_10000baseR_FEC_BIT 20
|
|
+#define ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT 21
|
|
+#define ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT 22
|
|
+#define ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT 23
|
|
+#define ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT 24
|
|
+#define ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT 25
|
|
+#define ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT 26
|
|
+#define ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT 27
|
|
+#define ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT 28
|
|
+#define ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT 29
|
|
+#define ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT 30
|
|
+#endif
|
|
+#ifndef HAVE_ETHTOOL_LINK_MODE_25G
|
|
+#define ETHTOOL_LINK_MODE_25000baseCR_Full_BIT 31
|
|
+#define ETHTOOL_LINK_MODE_25000baseKR_Full_BIT 32
|
|
+#define ETHTOOL_LINK_MODE_25000baseSR_Full_BIT 33
|
|
+#endif
|
|
+#ifndef HAVE_ETHTOOL_LINK_MODE_50G
|
|
+#define ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT 34
|
|
+#define ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT 35
|
|
+#endif
|
|
+#ifndef HAVE_ETHTOOL_LINK_MODE_100G
|
|
+#define ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT 36
|
|
+#define ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT 37
|
|
+#define ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT 38
|
|
+#define ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT 39
|
|
+#endif
|
|
+#ifndef HAVE_ETHTOOL_LINK_MODE_200G
|
|
+#define ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT 62
|
|
+#define ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT 63
|
|
+#define ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT 64
|
|
+#define ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT 65
|
|
+#define ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT 66
|
|
+#endif
|
|
+
|
|
+#define XSC_CHECK_BIT(val, bit_shift) ((val) & (1UL << (bit_shift)))
|
|
+
|
|
+#if !HAVE_XSC_DV_PROVIDER
|
|
+enum xscdv_obj_type {
|
|
+ XSCDV_OBJ_QP = 1 << 0,
|
|
+ XSCDV_OBJ_CQ = 1 << 1,
|
|
+ XSCDV_OBJ_SRQ = 1 << 2,
|
|
+ XSCDV_OBJ_RWQ = 1 << 3,
|
|
+ XSCDV_OBJ_DM = 1 << 4,
|
|
+ XSCDV_OBJ_AH = 1 << 5,
|
|
+ XSCDV_OBJ_PD = 1 << 6,
|
|
+};
|
|
+
|
|
+enum xsc_qp_create_flags {
|
|
+ XSC_QP_CREATE_RAWPACKE_TSO = 1 << 0,
|
|
+ XSC_QP_CREATE_RAWPACKET_TSO = 1 << 0,
|
|
+ XSC_QP_CREATE_RAWPACKET_TX = 1 << 1,
|
|
+};
|
|
+
|
|
+struct xscdv_cq_init_attr {
|
|
+ uint64_t comp_mask; /* Use enum xscdv_cq_init_attr_mask */
|
|
+ uint8_t cqe_comp_res_format; /* Use enum xscdv_cqe_comp_res_format */
|
|
+ uint32_t flags;
|
|
+ uint16_t cqe_size; /* When XSCDV_CQ_INIT_ATTR_MASK_CQE_SIZE set */
|
|
+};
|
|
+
|
|
+struct xscdv_obj {
|
|
+ struct {
|
|
+ struct ibv_qp *in;
|
|
+ struct xscdv_qp *out;
|
|
+ } qp;
|
|
+ struct {
|
|
+ struct ibv_cq *in;
|
|
+ struct xscdv_cq *out;
|
|
+ } cq;
|
|
+};
|
|
+
|
|
+struct xscdv_qp {
|
|
+ rte_le32_t *dbrec;
|
|
+ struct {
|
|
+ void *buf;
|
|
+ uint32_t wqe_cnt;
|
|
+ uint32_t stride;
|
|
+ rte_le32_t *db;
|
|
+ } sq;
|
|
+ struct {
|
|
+ void *buf;
|
|
+ uint32_t wqe_cnt;
|
|
+ uint32_t stride;
|
|
+ rte_le32_t *db;
|
|
+ } rq;
|
|
+ uint64_t comp_mask;
|
|
+ uint32_t tirn;
|
|
+ uint32_t tisn;
|
|
+ uint32_t rqn;
|
|
+ uint32_t sqn;
|
|
+};
|
|
+
|
|
+struct xscdv_cq {
|
|
+ void *buf;
|
|
+ rte_le32_t *dbrec;
|
|
+ rte_le32_t *db;
|
|
+ uint32_t cqe_cnt;
|
|
+ uint32_t cqe_size;
|
|
+ uint32_t cqn;
|
|
+ uint64_t comp_mask;
|
|
+};
|
|
+
|
|
+#endif
|
|
+
|
|
+struct xsc_rdma_priv {
|
|
+ struct ibv_context *ibv_ctx;
|
|
+ struct ibv_pd *ibv_pd;
|
|
+};
|
|
+
|
|
+static int
|
|
+xsc_ioctl(struct xsc_dev *xdev, int cmd, int opcode,
|
|
+ void *data_in, int in_len, void *data_out, int out_len)
|
|
+{
|
|
+ struct xsc_ioctl_hdr *hdr;
|
|
+ int data_len = RTE_MAX(in_len, out_len);
|
|
+ int alloc_len = sizeof(struct xsc_ioctl_hdr) + data_len;
|
|
+ int ret = 0;
|
|
+
|
|
+ hdr = malloc(alloc_len);
|
|
+ memset(hdr, 0, alloc_len);
|
|
+ if (hdr == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to allocate xsc ioctl cmd memory");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ hdr->check_field = XSC_IOCTL_CHECK_FIELD;
|
|
+ hdr->attr.opcode = opcode;
|
|
+ hdr->attr.length = data_len;
|
|
+ hdr->attr.error = 0;
|
|
+
|
|
+ if (data_in != NULL && in_len > 0)
|
|
+ memcpy(hdr + 1, data_in, in_len);
|
|
+
|
|
+ ret = ioctl(xdev->ctrl_fd, cmd, hdr);
|
|
+ if (ret == 0) {
|
|
+ if (hdr->attr.error != 0)
|
|
+ ret = hdr->attr.error;
|
|
+ else if (data_out != NULL && out_len > 0)
|
|
+ memcpy(data_out, hdr + 1, out_len);
|
|
+ }
|
|
+
|
|
+ free(hdr);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_mailbox_exec(struct xsc_dev *xdev, void *data_in,
|
|
+ int in_len, void *data_out, int out_len)
|
|
+{
|
|
+ return xsc_ioctl(xdev, XSC_IOCTL_CMDQ_RAW, 0, data_in, in_len, data_out, out_len);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_fork_init(void)
|
|
+{
|
|
+ setenv("RDMAV_HUGEPAGES_SAFE", "1", 1);
|
|
+
|
|
+ if (RTE_CACHE_LINE_SIZE == 128)
|
|
+ setenv("XSC_CQE_SIZE", "128", 0);
|
|
+
|
|
+ setenv("XSC_DEVICE_FATAL_CLEANUP", "1", 1);
|
|
+
|
|
+ return ibv_fork_init();
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_hwinfo_init(struct xsc_dev *xdev)
|
|
+{
|
|
+ struct {
|
|
+ struct xsc_ioctl_data_tl tl;
|
|
+ struct xsc_ioctl_get_hwinfo hwinfo;
|
|
+ } data;
|
|
+ struct xsc_ioctl_get_hwinfo *info = &data.hwinfo;
|
|
+ int data_len;
|
|
+ int ret;
|
|
+
|
|
+ PMD_INIT_FUNC_TRACE();
|
|
+
|
|
+ data_len = sizeof(data);
|
|
+ data.tl.opmod = XSC_IOCTL_OP_GET_LOCAL;
|
|
+ ret = xsc_ioctl(xdev, XSC_IOCTL_DRV_GET, XSC_CMD_OP_QUERY_HCA_CAP,
|
|
+ &data, data_len, &data, data_len);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to get hardware info");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ xdev->hwinfo.valid = 1;
|
|
+ xdev->hwinfo.pcie_no = info->pcie_no;
|
|
+ xdev->hwinfo.func_id = info->func_id;
|
|
+ xdev->hwinfo.pcie_host = info->pcie_host;
|
|
+ xdev->hwinfo.mac_phy_port = info->mac_phy_port;
|
|
+ xdev->hwinfo.funcid_to_logic_port_off = info->funcid_to_logic_port_off;
|
|
+ xdev->hwinfo.lag_id = info->lag_id;
|
|
+ xdev->hwinfo.raw_qp_id_base = info->raw_qp_id_base;
|
|
+ xdev->hwinfo.raw_rss_qp_id_base = info->raw_rss_qp_id_base;
|
|
+ xdev->hwinfo.pf0_vf_funcid_base = info->pf0_vf_funcid_base;
|
|
+ xdev->hwinfo.pf0_vf_funcid_top = info->pf0_vf_funcid_top;
|
|
+ xdev->hwinfo.pf1_vf_funcid_base = info->pf1_vf_funcid_base;
|
|
+ xdev->hwinfo.pf1_vf_funcid_top = info->pf1_vf_funcid_top;
|
|
+ xdev->hwinfo.pcie0_pf_funcid_base = info->pcie0_pf_funcid_base;
|
|
+ xdev->hwinfo.pcie0_pf_funcid_top = info->pcie0_pf_funcid_top;
|
|
+ xdev->hwinfo.pcie1_pf_funcid_base = info->pcie1_pf_funcid_base;
|
|
+ xdev->hwinfo.pcie1_pf_funcid_top = info->pcie1_pf_funcid_top;
|
|
+ xdev->hwinfo.lag_port_start = info->lag_port_start;
|
|
+ xdev->hwinfo.raw_tpe_qp_num = info->raw_tpe_qp_num;
|
|
+ xdev->hwinfo.send_seg_num = info->send_seg_num;
|
|
+ xdev->hwinfo.recv_seg_num = info->recv_seg_num;
|
|
+ xdev->hwinfo.on_chip_tbl_vld = info->on_chip_tbl_vld;
|
|
+ xdev->hwinfo.dma_rw_tbl_vld = info->dma_rw_tbl_vld;
|
|
+ xdev->hwinfo.pct_compress_vld = info->pct_compress_vld;
|
|
+ xdev->hwinfo.chip_version = info->chip_version;
|
|
+ xdev->hwinfo.hca_core_clock = info->hca_core_clock;
|
|
+ xdev->hwinfo.mac_bit = info->mac_bit;
|
|
+ xdev->hwinfo.esw_mode = info->esw_mode;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_get_ibdev_pci_addr(const char *dev_path, struct rte_pci_addr *pci_addr)
|
|
+{
|
|
+ FILE *file;
|
|
+ char *line = NULL;
|
|
+ size_t len = 0;
|
|
+ char path[PATH_MAX];
|
|
+ int ret = -ENOENT;
|
|
+
|
|
+ ret = snprintf(path, sizeof(path), "%s/device/uevent", dev_path);
|
|
+ if (ret < 0 || ret >= (int)sizeof(path)) {
|
|
+ rte_errno = ENAMETOOLONG;
|
|
+ return -rte_errno;
|
|
+ }
|
|
+
|
|
+ file = fopen(path, "rb");
|
|
+ if (file == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to open file: (%s) ", path);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ while (getline(&line, &len, file) != -1) {
|
|
+ if (sscanf(line,
|
|
+ "PCI_SLOT_NAME=%04x:%hhx:%hhx.%hhx",
|
|
+ &pci_addr->domain,
|
|
+ &pci_addr->bus,
|
|
+ &pci_addr->devid,
|
|
+ &pci_addr->function) == 4) {
|
|
+ ret = 0;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ free(line);
|
|
+ fclose(file);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static struct ibv_device *
|
|
+xsc_rdma_get_ibv_device(const struct rte_pci_addr *addr)
|
|
+{
|
|
+ int ibv_num, i;
|
|
+ struct ibv_device **ibv_list;
|
|
+ struct ibv_device *ibv_match = NULL;
|
|
+ struct rte_pci_addr ibv_pci_addr;
|
|
+
|
|
+ ibv_list = ibv_get_device_list(&ibv_num);
|
|
+ if (ibv_list == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ for (i = 0; i < ibv_num; i++) {
|
|
+ if (xsc_get_ibdev_pci_addr(ibv_list[i]->ibdev_path, &ibv_pci_addr) != 0)
|
|
+ continue;
|
|
+ if (rte_pci_addr_cmp(addr, &ibv_pci_addr) != 0)
|
|
+ continue;
|
|
+ ibv_match = ibv_list[i];
|
|
+ PMD_DRV_LOG(DEBUG, "Finding device \"name:%s, %s, path:%s, %s\"..",
|
|
+ ibv_list[i]->name, ibv_list[i]->dev_name,
|
|
+ ibv_list[i]->dev_path, ibv_list[i]->ibdev_path);
|
|
+ break;
|
|
+ }
|
|
+ ibv_free_device_list(ibv_list);
|
|
+
|
|
+ if (ibv_match == NULL) {
|
|
+ PMD_DRV_LOG(WARNING,
|
|
+ "No verbs device matches PCI device " PCI_PRI_FMT,
|
|
+ addr->domain, addr->bus, addr->devid, addr->function);
|
|
+ }
|
|
+
|
|
+ return ibv_match;
|
|
+}
|
|
+
|
|
+#if HAVE_XSC_DV_PROVIDER
|
|
+static void *
|
|
+xsc_rdma_verbs_buf_alloc(size_t size, void *data)
|
|
+{
|
|
+ struct rte_device *dev = data;
|
|
+ size_t alignment = rte_mem_page_size();
|
|
+ void *addr;
|
|
+
|
|
+ if (size == 0)
|
|
+ return NULL;
|
|
+
|
|
+ if (alignment == (size_t)-1) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to get mem page size");
|
|
+ rte_errno = ENOMEM;
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ addr = rte_malloc_socket(NULL, size, alignment, dev->numa_node);
|
|
+ if (addr == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Alloc verbs buf memory failed");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return addr;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_rdma_verbs_buf_free(void *ptr, void *data __rte_unused)
|
|
+{
|
|
+ rte_free(ptr);
|
|
+}
|
|
+#endif
|
|
+
|
|
+static void
|
|
+xsc_rdma_context_attr_set(struct rte_device *dev, struct ibv_context *ctx)
|
|
+{
|
|
+#if HAVE_XSC_DV_PROVIDER
|
|
+ struct xscdv_ctx_allocators allocator = {
|
|
+ .alloc = &xsc_rdma_verbs_buf_alloc,
|
|
+ .free = &xsc_rdma_verbs_buf_free,
|
|
+ .data = dev,
|
|
+ };
|
|
+
|
|
+ /* Hint libxsc to use PMD allocator for data plane resources */
|
|
+ xscdv_set_context_attr(ctx, XSCDV_CTX_ATTR_BUF_ALLOCATORS,
|
|
+ (void *)((uintptr_t)&allocator));
|
|
+#else
|
|
+ (void)dev;
|
|
+ (void)ctx;
|
|
+ PMD_DRV_LOG(WARNING, "Huge page memory registration is not supported");
|
|
+#endif
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_dev_open(struct xsc_dev *xdev)
|
|
+{
|
|
+ struct ibv_device *ib_dev;
|
|
+ struct rte_pci_device *pci_dev = xdev->pci_dev;
|
|
+ struct rte_pci_addr *pci_addr = &xdev->pci_dev->addr;
|
|
+ struct xsc_rdma_priv *priv = xdev->dev_priv;
|
|
+ int ret;
|
|
+
|
|
+ priv = rte_zmalloc(NULL, sizeof(struct xsc_rdma_priv), RTE_CACHE_LINE_SIZE);
|
|
+ if (priv == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc xsc rdma priv");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ ib_dev = xsc_rdma_get_ibv_device(pci_addr);
|
|
+ if (ib_dev == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Could not get ibv device");
|
|
+ ret = -ENODEV;
|
|
+ goto aloc_priv_fail;
|
|
+ }
|
|
+
|
|
+ priv->ibv_ctx = ibv_open_device(ib_dev);
|
|
+ if (priv->ibv_ctx == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Could not open ibv device: %s", ib_dev->name);
|
|
+ ret = -ENODEV;
|
|
+ goto aloc_priv_fail;
|
|
+ }
|
|
+
|
|
+ xsc_rdma_context_attr_set(&pci_dev->device, priv->ibv_ctx);
|
|
+
|
|
+ priv->ibv_pd = ibv_alloc_pd(priv->ibv_ctx);
|
|
+ if (priv->ibv_pd == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to create pd:%s", ib_dev->name);
|
|
+ ret = -EINVAL;
|
|
+ goto alloc_pd_fail;
|
|
+ }
|
|
+
|
|
+ strcpy(xdev->name, ib_dev->name);
|
|
+
|
|
+ xdev->dev_priv = priv;
|
|
+ return 0;
|
|
+
|
|
+alloc_pd_fail:
|
|
+ ibv_close_device(priv->ibv_ctx);
|
|
+aloc_priv_fail:
|
|
+ rte_free(priv);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_bar_init(struct xsc_dev *xdev)
|
|
+{
|
|
+ struct rte_pci_addr *pci_addr = &xdev->pci_dev->addr;
|
|
+ char ctrl_file[PATH_MAX];
|
|
+ int ret;
|
|
+
|
|
+ snprintf(ctrl_file, PATH_MAX, XSC_DEV_CTRL_FILE_FMT,
|
|
+ pci_addr->domain, pci_addr->bus, pci_addr->devid, pci_addr->function);
|
|
+
|
|
+ ret = open(ctrl_file, O_RDWR);
|
|
+ if (ret < 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to open file: (%s) ", ctrl_file);
|
|
+ return ret;
|
|
+ }
|
|
+ xdev->ctrl_fd = ret;
|
|
+
|
|
+ xdev->bar_len = xdev->pci_dev->mem_resource[0].len;
|
|
+ xdev->bar_addr = mmap(NULL, xdev->bar_len, PROT_READ | PROT_WRITE,
|
|
+ MAP_SHARED, xdev->ctrl_fd, 0);
|
|
+ if (xdev->bar_addr == MAP_FAILED) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to mmap file: (%s) ", ctrl_file);
|
|
+ ret = -EINVAL;
|
|
+ goto mmap_fail;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+mmap_fail:
|
|
+ close(xdev->ctrl_fd);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_ifreq_by_ifname(const char *ifname, int req, struct ifreq *ifr)
|
|
+{
|
|
+ int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
|
|
+ int ret = 0;
|
|
+
|
|
+ if (sock == -1) {
|
|
+ rte_errno = errno;
|
|
+ return -rte_errno;
|
|
+ }
|
|
+ rte_strscpy(ifr->ifr_name, ifname, sizeof(ifr->ifr_name));
|
|
+ ret = ioctl(sock, req, ifr);
|
|
+ if (ret == -1) {
|
|
+ rte_errno = errno;
|
|
+ goto error;
|
|
+ }
|
|
+ close(sock);
|
|
+ return 0;
|
|
+error:
|
|
+ close(sock);
|
|
+ return -rte_errno;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_link_process(uint32_t ifindex, unsigned int flags)
|
|
+{
|
|
+ struct ifreq request;
|
|
+ struct ifreq *ifr = &request;
|
|
+ char ifname[sizeof(ifr->ifr_name)];
|
|
+ int ret;
|
|
+ unsigned int keep = ~IFF_UP;
|
|
+
|
|
+ if (if_indextoname(ifindex, ifname) == NULL)
|
|
+ return -rte_errno;
|
|
+
|
|
+ ret = xsc_ifreq_by_ifname(ifname, SIOCGIFFLAGS, &request);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ request.ifr_flags &= keep;
|
|
+ request.ifr_flags |= flags & ~keep;
|
|
+
|
|
+ return xsc_ifreq_by_ifname(ifname, SIOCSIFFLAGS, &request);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_set_link_up(struct xsc_dev *xdev)
|
|
+{
|
|
+ return xsc_rdma_link_process(xdev->ifindex, IFF_UP);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_set_link_down(struct xsc_dev *xdev)
|
|
+{
|
|
+ return xsc_rdma_link_process(xdev->ifindex, ~IFF_UP);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_link_status_get(struct xsc_dev *xdev, struct rte_eth_link *link, uint32_t *capa)
|
|
+{
|
|
+ struct rte_eth_link dev_link;
|
|
+ struct ethtool_link_settings settings = { .cmd = ETHTOOL_GLINKSETTINGS };
|
|
+ struct ifreq request;
|
|
+ uint64_t flags;
|
|
+ uint32_t link_speed_capa;
|
|
+ char ifname[sizeof(request.ifr_name)];
|
|
+ int ret;
|
|
+
|
|
+ if (if_indextoname(xdev->ifindex, ifname) == NULL)
|
|
+ return -rte_errno;
|
|
+
|
|
+ ret = xsc_ifreq_by_ifname(ifname, SIOCGIFFLAGS, &request);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if ((request.ifr_flags & IFF_UP) && (request.ifr_flags & IFF_RUNNING))
|
|
+ dev_link.link_status = 1;
|
|
+ else
|
|
+ dev_link.link_status = 0;
|
|
+
|
|
+ request.ifr_data = (void *)&settings;
|
|
+ ret = xsc_ifreq_by_ifname(ifname, SIOCETHTOOL, &request);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ settings.link_mode_masks_nwords = -settings.link_mode_masks_nwords;
|
|
+
|
|
+ alignas(struct ethtool_link_settings)
|
|
+ uint8_t data[offsetof(struct ethtool_link_settings, link_mode_masks) +
|
|
+ sizeof(uint32_t) * settings.link_mode_masks_nwords * 3];
|
|
+ struct ethtool_link_settings *ecmd = (void *)data;
|
|
+
|
|
+ *ecmd = settings;
|
|
+ request.ifr_data = (void *)ecmd;
|
|
+ ret = xsc_ifreq_by_ifname(ifname, SIOCETHTOOL, &request);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ dev_link.link_speed = (ecmd->speed == UINT32_MAX) ?
|
|
+ RTE_ETH_SPEED_NUM_UNKNOWN : ecmd->speed;
|
|
+
|
|
+ dev_link.link_duplex = ((ecmd->duplex == DUPLEX_HALF) ?
|
|
+ RTE_ETH_LINK_HALF_DUPLEX : RTE_ETH_LINK_FULL_DUPLEX);
|
|
+
|
|
+ link_speed_capa = 0;
|
|
+ flags = ecmd->link_mode_masks[0] |
|
|
+ ((uint64_t)ecmd->link_mode_masks[1] << 32);
|
|
+ if (XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_1000baseT_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_1000baseKX_Full_BIT))
|
|
+ link_speed_capa |= RTE_ETH_LINK_SPEED_1G;
|
|
+
|
|
+ if (XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_10000baseR_FEC_BIT))
|
|
+ link_speed_capa |= RTE_ETH_LINK_SPEED_10G;
|
|
+
|
|
+ if (XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT))
|
|
+ link_speed_capa |= RTE_ETH_LINK_SPEED_20G;
|
|
+
|
|
+ if (XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT))
|
|
+ link_speed_capa |= RTE_ETH_LINK_SPEED_40G;
|
|
+
|
|
+ if (XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT))
|
|
+ link_speed_capa |= RTE_ETH_LINK_SPEED_56G;
|
|
+
|
|
+ if (XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_25000baseCR_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_25000baseSR_Full_BIT))
|
|
+ link_speed_capa |= RTE_ETH_LINK_SPEED_25G;
|
|
+
|
|
+ if (XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT))
|
|
+ link_speed_capa |= RTE_ETH_LINK_SPEED_50G;
|
|
+
|
|
+ if (XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT))
|
|
+ link_speed_capa |= RTE_ETH_LINK_SPEED_100G;
|
|
+
|
|
+ if (XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT))
|
|
+ link_speed_capa |= RTE_ETH_LINK_SPEED_200G;
|
|
+
|
|
+ flags = ecmd->link_mode_masks[2] |
|
|
+ ((uint64_t)ecmd->link_mode_masks[3] << 32);
|
|
+ if (XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT - 64) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT - 64) ||
|
|
+ XSC_CHECK_BIT(flags, ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT - 64))
|
|
+ link_speed_capa |= RTE_ETH_LINK_SPEED_200G;
|
|
+
|
|
+
|
|
+ *link = dev_link;
|
|
+ *capa = link_speed_capa;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_link_update(struct xsc_dev *xdev, int wait_to_complete)
|
|
+{
|
|
+ int ret = 0;
|
|
+ struct rte_eth_link dev_link;
|
|
+ time_t start_time = time(NULL);
|
|
+ int retry = 3;
|
|
+ uint32_t link_speed_capa = 0;
|
|
+
|
|
+ do {
|
|
+ ret = xsc_rdma_link_status_get(xdev, &dev_link, &link_speed_capa);
|
|
+ if (ret == 0)
|
|
+ break;
|
|
+ /* Handle wait to complete situation. */
|
|
+ if ((wait_to_complete || retry) && ret == -EAGAIN) {
|
|
+ if (abs((int)difftime(time(NULL), start_time)) <
|
|
+ 10) {
|
|
+ usleep(0);
|
|
+ continue;
|
|
+ } else {
|
|
+ rte_errno = EBUSY;
|
|
+ return -rte_errno;
|
|
+ }
|
|
+ } else if (ret < 0) {
|
|
+ return ret;
|
|
+ }
|
|
+ } while (wait_to_complete || retry-- > 0);
|
|
+ ret = !memcmp(&xdev->pf_dev_link, &dev_link,
|
|
+ sizeof(struct rte_eth_link));
|
|
+ xdev->pf_dev_link = dev_link;
|
|
+ xdev->link_speed_capa = link_speed_capa;
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_event_get(struct xsc_dev *xdev)
|
|
+{
|
|
+ struct xsc_rdma_priv *priv = (struct xsc_rdma_priv *)xdev->dev_priv;
|
|
+ struct ibv_context *ibv_ctx = priv->ibv_ctx;
|
|
+ struct ibv_async_event event;
|
|
+
|
|
+ if (ibv_get_async_event(ibv_ctx, &event))
|
|
+ return XSC_EVENT_TYPE_NONE;
|
|
+
|
|
+ if ((event.event_type == IBV_EVENT_PORT_ACTIVE ||
|
|
+ event.event_type == IBV_EVENT_PORT_ERR)) {
|
|
+ ibv_ack_async_event(&event);
|
|
+ return XSC_EVENT_TYPE_CHANGE_LINK;
|
|
+ }
|
|
+
|
|
+ ibv_ack_async_event(&event);
|
|
+ return XSC_EVENT_TYPE_NONE;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_intr_handler_install(struct xsc_dev *xdev, rte_intr_callback_fn cb, void *cb_arg)
|
|
+{
|
|
+ int ret;
|
|
+ int flags;
|
|
+ struct xsc_rdma_priv *priv = (struct xsc_rdma_priv *)xdev->dev_priv;
|
|
+ struct ibv_context *ibv_ctx = priv->ibv_ctx;
|
|
+
|
|
+ xdev->intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
|
|
+ if (xdev->intr_handle == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ rte_intr_fd_set(xdev->intr_handle, -1);
|
|
+
|
|
+ flags = fcntl(ibv_ctx->async_fd, F_GETFL);
|
|
+ ret = fcntl(ibv_ctx->async_fd, F_SETFL, flags | O_NONBLOCK);
|
|
+ if (ret == 0) {
|
|
+ rte_intr_fd_set(xdev->intr_handle, ibv_ctx->async_fd);
|
|
+ rte_intr_type_set(xdev->intr_handle, RTE_INTR_HANDLE_EXT);
|
|
+ ret = rte_intr_callback_register(xdev->intr_handle, cb, cb_arg);
|
|
+ if (ret != 0)
|
|
+ rte_intr_fd_set(xdev->intr_handle, -1);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_intr_handler_uninstall(struct xsc_dev *xdev)
|
|
+{
|
|
+ rte_intr_instance_free(xdev->intr_handle);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_dev_close(struct xsc_dev *xdev)
|
|
+{
|
|
+ struct xsc_rdma_priv *rdma_priv = (struct xsc_rdma_priv *)xdev->dev_priv;
|
|
+
|
|
+ munmap(xdev->bar_addr, xdev->bar_len);
|
|
+ close(xdev->ctrl_fd);
|
|
+ ibv_close_device(rdma_priv->ibv_ctx);
|
|
+ rte_free(rdma_priv);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_init_obj(struct xscdv_obj *obj, uint64_t obj_type)
|
|
+{
|
|
+#if HAVE_XSC_DV_PROVIDER
|
|
+ return xscdv_init_obj(obj, obj_type);
|
|
+#else
|
|
+ (void)obj;
|
|
+ (void)obj_type;
|
|
+ return 0;
|
|
+#endif
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_destroy_qp(void *qp)
|
|
+{
|
|
+ return ibv_destroy_qp(qp);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_destroy_cq(void *cq)
|
|
+{
|
|
+ return ibv_destroy_cq(cq);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_set_mtu(uint16_t mtu, uint32_t ifindex)
|
|
+{
|
|
+ struct ifreq request = { .ifr_mtu = mtu, };
|
|
+ struct ifreq *ifr = &request;
|
|
+ char ifname[sizeof(ifr->ifr_name)];
|
|
+
|
|
+ if (if_indextoname(ifindex, ifname) == NULL)
|
|
+ return -rte_errno;
|
|
+
|
|
+ return xsc_ifreq_by_ifname(ifname, SIOCSIFMTU, &request);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_get_mtu(uint16_t *mtu, uint32_t ifindex)
|
|
+{
|
|
+ struct ifreq request;
|
|
+ struct ifreq *ifr = &request;
|
|
+ char ifname[sizeof(ifr->ifr_name)];
|
|
+ int ret;
|
|
+
|
|
+ if (if_indextoname(ifindex, ifname) == NULL)
|
|
+ return -rte_errno;
|
|
+
|
|
+ ret = xsc_ifreq_by_ifname(ifname, SIOCGIFMTU, &request);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ *mtu = request.ifr_mtu;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_set_mtu(struct xsc_dev *xdev, uint16_t mtu)
|
|
+{
|
|
+ uint16_t get_mtu = 0;
|
|
+ int ret = 0;
|
|
+
|
|
+ ret = xsc_set_mtu(mtu, xdev->ifindex);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = xsc_get_mtu(&get_mtu, xdev->ifindex);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if (get_mtu != mtu) {
|
|
+ PMD_DRV_LOG(ERR, "Mtu set to %u failure", mtu);
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_get_mac(struct xsc_dev *xdev, uint8_t *mac)
|
|
+{
|
|
+ struct ifreq request;
|
|
+ struct ifreq *ifr = &request;
|
|
+ char ifname[sizeof(ifr->ifr_name)];
|
|
+ int ret;
|
|
+
|
|
+ if (if_indextoname(xdev->ifindex, ifname) == NULL)
|
|
+ return -rte_errno;
|
|
+
|
|
+ ret = xsc_ifreq_by_ifname(ifname, SIOCGIFHWADDR, &request);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ memcpy(mac, request.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_rx_cq_create(struct xsc_dev *xdev, struct xsc_rx_cq_params *cq_params,
|
|
+ struct xsc_rx_cq_info *cq_info)
|
|
+{
|
|
+ struct xscdv_obj obj;
|
|
+ struct xscdv_cq cq = {0};
|
|
+ struct xsc_rdma_priv *priv = (struct xsc_rdma_priv *)xdev->dev_priv;
|
|
+ uint32_t cqe_s = cq_params->wqe_s;
|
|
+ int ret;
|
|
+
|
|
+ cq_info->cq = ibv_create_cq(priv->ibv_ctx, cqe_s, NULL, NULL, 0);
|
|
+ if (cq_info->cq == NULL) {
|
|
+ rte_errno = errno;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ obj.cq.in = cq_info->cq;
|
|
+ obj.cq.out = &cq;
|
|
+
|
|
+ ret = xsc_rdma_init_obj(&obj, XSCDV_OBJ_CQ);
|
|
+ if (ret) {
|
|
+ rte_errno = errno;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ cq_info->cqe_n = rte_log2_u32(cq.cqe_cnt);
|
|
+ cq_info->cqes = (void *)(uintptr_t)cq.buf;
|
|
+ cq_info->cq_db = cq.db;
|
|
+ cq_info->cqn = cq.cqn;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_tx_cq_create(struct xsc_dev *xdev, struct xsc_tx_cq_params *cq_params,
|
|
+ struct xsc_tx_cq_info *cq_info)
|
|
+{
|
|
+ struct xsc_rdma_priv *priv = (struct xsc_rdma_priv *)xdev->dev_priv;
|
|
+ const int cqe_n = 1 << cq_params->elts_n;
|
|
+ struct xscdv_obj obj = { };
|
|
+ struct xscdv_cq cq = { };
|
|
+ int ret;
|
|
+
|
|
+ cq_info->cq = ibv_create_cq(priv->ibv_ctx, cqe_n, NULL, NULL, 0);
|
|
+ if (cq_info->cq == NULL) {
|
|
+ rte_errno = errno;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ obj.cq.in = cq_info->cq;
|
|
+ obj.cq.out = (struct xscdv_cq *)&cq;
|
|
+ ret = xsc_rdma_init_obj(&obj, XSCDV_OBJ_CQ);
|
|
+ if (ret != 0) {
|
|
+ rte_errno = errno;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ cq_info->cqe_n = rte_log2_u32(cq.cqe_cnt);
|
|
+ cq_info->cqe_s = 1 << cq_info->cqe_n;
|
|
+ /* cqe doorbell */
|
|
+ cq_info->cq_db = cq.db;
|
|
+ cq_info->cqn = cq.cqn;
|
|
+ cq_info->cqes = cq.buf;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static struct ibv_qp *
|
|
+xsc_txq_ibv_qp_create(struct xsc_dev *xdev, struct xsc_tx_qp_params *qp_params,
|
|
+ struct xsc_tx_qp_info *qp_info)
|
|
+{
|
|
+ struct ibv_qp *qp_obj = NULL;
|
|
+ struct ibv_qp_init_attr_ex qp_attr = { 0 };
|
|
+ struct xsc_rdma_priv *priv = (struct xsc_rdma_priv *)xdev->dev_priv;
|
|
+ const int desc = 1 << qp_params->elts_n;
|
|
+
|
|
+ qp_attr.send_cq = qp_params->cq;
|
|
+ qp_attr.recv_cq = qp_params->cq;
|
|
+ qp_attr.cap.max_send_wr = desc;
|
|
+ qp_attr.cap.max_recv_wr = 0;
|
|
+ qp_attr.cap.max_send_sge = 1;
|
|
+ qp_attr.qp_type = IBV_QPT_RAW_PACKET;
|
|
+ qp_attr.pd = priv->ibv_pd;
|
|
+ qp_attr.sq_sig_all = 0;
|
|
+
|
|
+ if (qp_params->tx_offloads & (RTE_ETH_TX_OFFLOAD_TCP_TSO)) {
|
|
+ qp_attr.create_flags = XSC_QP_CREATE_RAWPACKET_TSO;
|
|
+ qp_attr.comp_mask = IBV_QP_INIT_ATTR_PD | IBV_QP_INIT_ATTR_CREATE_FLAGS;
|
|
+ qp_info->tso_en = 1;
|
|
+ PMD_DRV_LOG(DEBUG, "Port txq %u, create tso qp",
|
|
+ qp_params->qp_id);
|
|
+ } else {
|
|
+ qp_attr.create_flags = XSC_QP_CREATE_RAWPACKET_TX;
|
|
+ qp_attr.comp_mask = IBV_QP_INIT_ATTR_PD | IBV_QP_INIT_ATTR_CREATE_FLAGS;
|
|
+ PMD_DRV_LOG(DEBUG, "Port txq %u, create non-tso qp",
|
|
+ qp_params->qp_id);
|
|
+ }
|
|
+
|
|
+ qp_obj = ibv_create_qp_ex(priv->ibv_ctx, &qp_attr);
|
|
+ if (qp_obj == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Port txq %u, create %s qp fail, errno=%d",
|
|
+ qp_params->qp_id,
|
|
+ qp_attr.create_flags & XSC_QP_CREATE_RAWPACKET_TSO ?
|
|
+ "tso" : "non-tso", errno);
|
|
+
|
|
+ if (!(qp_params->tx_offloads & (RTE_ETH_TX_OFFLOAD_TCP_TSO))) {
|
|
+ qp_attr.create_flags = XSC_QP_CREATE_RAWPACKET_TSO;
|
|
+ qp_attr.comp_mask = IBV_QP_INIT_ATTR_PD |
|
|
+ IBV_QP_INIT_ATTR_CREATE_FLAGS;
|
|
+ PMD_DRV_LOG(DEBUG, "Port txq %u, recreate tso qp",
|
|
+ qp_params->qp_id);
|
|
+
|
|
+ qp_obj = ibv_create_qp_ex(priv->ibv_ctx, &qp_attr);
|
|
+ if (qp_obj == NULL)
|
|
+ PMD_DRV_LOG(ERR, "Port txq %u, recreate tso qp fail, errno=%d",
|
|
+ qp_params->qp_id, errno);
|
|
+ else
|
|
+ qp_info->tso_en = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return qp_obj;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_tx_qp_create(struct xsc_dev *xdev, struct xsc_tx_qp_params *qp_params,
|
|
+ struct xsc_tx_qp_info *qp_info)
|
|
+{
|
|
+ struct xscdv_obj obj = { };
|
|
+ struct xscdv_qp qp = { };
|
|
+ int ret;
|
|
+
|
|
+ qp_info->qp = xsc_txq_ibv_qp_create(xdev, qp_params, qp_info);
|
|
+ if (qp_info->qp == NULL) {
|
|
+ rte_errno = errno;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ obj.qp.in = qp_info->qp;
|
|
+ obj.qp.out = (struct xscdv_qp *)&qp;
|
|
+ ret = xsc_rdma_init_obj(&obj, XSCDV_OBJ_QP);
|
|
+ if (ret != 0) {
|
|
+ rte_errno = errno;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ qp_info->qpn = ((struct ibv_qp *)qp_info->qp)->qp_num;
|
|
+ qp_info->wqes = qp.sq.buf;
|
|
+ qp_info->wqe_n = rte_log2_u32(qp.sq.wqe_cnt);
|
|
+
|
|
+ qp_info->qp_db = qp.sq.db;
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_get_ifname_by_pci_addr(struct rte_pci_addr *addr, char *ifname)
|
|
+{
|
|
+ DIR *dir;
|
|
+ struct dirent *dent;
|
|
+ unsigned int dev_type = 0;
|
|
+ unsigned int dev_port_prev = ~0u;
|
|
+ char match[IF_NAMESIZE] = "";
|
|
+ char net_path[PATH_MAX];
|
|
+
|
|
+ snprintf(net_path, sizeof(net_path), "%s/" PCI_PRI_FMT "/net",
|
|
+ rte_pci_get_sysfs_path(), addr->domain, addr->bus,
|
|
+ addr->devid, addr->function);
|
|
+
|
|
+ dir = opendir(net_path);
|
|
+ if (dir == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Could not open %s", net_path);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ while ((dent = readdir(dir)) != NULL) {
|
|
+ char *name = dent->d_name;
|
|
+ FILE *file;
|
|
+ unsigned int dev_port;
|
|
+ int r;
|
|
+ char path[PATH_MAX];
|
|
+
|
|
+ if ((name[0] == '.') &&
|
|
+ ((name[1] == '\0') ||
|
|
+ ((name[1] == '.') && (name[2] == '\0'))))
|
|
+ continue;
|
|
+
|
|
+ snprintf(path, sizeof(path), "%s/%s/%s",
|
|
+ net_path, name, (dev_type ? "dev_id" : "dev_port"));
|
|
+
|
|
+ file = fopen(path, "rb");
|
|
+ if (file == NULL) {
|
|
+ if (errno != ENOENT)
|
|
+ continue;
|
|
+ /*
|
|
+ * Switch to dev_id when dev_port does not exist as
|
|
+ * is the case with Linux kernel versions < 3.15.
|
|
+ */
|
|
+try_dev_id:
|
|
+ match[0] = '\0';
|
|
+ if (dev_type)
|
|
+ break;
|
|
+ dev_type = 1;
|
|
+ dev_port_prev = ~0u;
|
|
+ rewinddir(dir);
|
|
+ continue;
|
|
+ }
|
|
+ r = fscanf(file, (dev_type ? "%x" : "%u"), &dev_port);
|
|
+ fclose(file);
|
|
+ if (r != 1)
|
|
+ continue;
|
|
+ /*
|
|
+ * Switch to dev_id when dev_port returns the same value for
|
|
+ * all ports. May happen when using a MOFED release older than
|
|
+ * 3.0 with a Linux kernel >= 3.15.
|
|
+ */
|
|
+ if (dev_port == dev_port_prev)
|
|
+ goto try_dev_id;
|
|
+ dev_port_prev = dev_port;
|
|
+ if (dev_port == 0)
|
|
+ snprintf(match, IF_NAMESIZE, "%s", name);
|
|
+ }
|
|
+ closedir(dir);
|
|
+ if (match[0] == '\0')
|
|
+ return -ENOENT;
|
|
+
|
|
+ snprintf(ifname, IF_NAMESIZE, "%s", match);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_get_ifindex_by_ifname(const char *ifname, int *ifindex)
|
|
+{
|
|
+ struct ifreq ifr;
|
|
+ int sockfd;
|
|
+
|
|
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
+ if (sockfd == -1)
|
|
+ return -EINVAL;
|
|
+
|
|
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
|
|
+ if (ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1) {
|
|
+ close(sockfd);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ *ifindex = ifr.ifr_ifindex;
|
|
+
|
|
+ close(sockfd);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_ifindex_init(struct xsc_dev *xdev)
|
|
+{
|
|
+ char ifname[IF_NAMESIZE];
|
|
+ struct rte_pci_addr *addr = &xdev->pci_dev->addr;
|
|
+ int *ifindex = &xdev->ifindex;
|
|
+ int ret;
|
|
+
|
|
+ ret = xsc_get_ifname_by_pci_addr(addr, ifname);
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Could not get ifname by pci address:" PCI_PRI_FMT,
|
|
+ addr->domain, addr->bus, addr->devid, addr->function);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = xsc_get_ifindex_by_ifname(ifname, ifindex);
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Could not get ifindex by ifname:%s", ifname);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_dev_init(struct xsc_dev *xdev)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = xsc_rdma_fork_init();
|
|
+ if (ret != 0)
|
|
+ goto init_fail;
|
|
+
|
|
+ ret = xsc_rdma_dev_open(xdev);
|
|
+ if (ret != 0)
|
|
+ goto init_fail;
|
|
+
|
|
+ ret = xsc_rdma_bar_init(xdev);
|
|
+ if (ret != 0)
|
|
+ goto init_fail;
|
|
+
|
|
+ ret = xsc_rdma_hwinfo_init(xdev);
|
|
+ if (ret != 0)
|
|
+ goto init_fail;
|
|
+
|
|
+ ret = xsc_rdma_ifindex_init(xdev);
|
|
+ if (ret != 0)
|
|
+ goto init_fail;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+init_fail:
|
|
+ xsc_rdma_dev_close(xdev);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_modify_qp_status(struct xsc_dev *xdev, uint32_t qpn, int num, int opcode)
|
|
+{
|
|
+ struct {
|
|
+ struct xsc_ioctl_data_tl tl;
|
|
+ struct xsc_ioctl_qp_range info;
|
|
+ } data_info;
|
|
+
|
|
+ int ret;
|
|
+
|
|
+ data_info.tl.opmod = XSC_CMD_OP_SET_QP_STATUS;
|
|
+ data_info.info.opcode = opcode;
|
|
+ data_info.info.qpn = qpn;
|
|
+ data_info.info.num = num;
|
|
+
|
|
+ ret = xsc_ioctl(xdev, XSC_IOCTL_DRV_GET, XSC_CMD_OP_SET_QP_STATUS,
|
|
+ &data_info, sizeof(data_info), NULL, 0);
|
|
+ if (ret != 0) {
|
|
+ rte_errno = ret;
|
|
+ PMD_DRV_LOG(ERR, "Modify qp status fail, ret = %d", ret);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rdma_modify_qp_qostree(struct xsc_dev *xdev, uint16_t qpn)
|
|
+{
|
|
+ int ret;
|
|
+ struct xsc_cmd_modify_raw_qp_request qos_request = { };
|
|
+
|
|
+ qos_request.prio = 0;
|
|
+ qos_request.qp_out_port = -1;
|
|
+ qos_request.lag_id = rte_cpu_to_be_16(xdev->hwinfo.lag_id);
|
|
+ qos_request.func_id = rte_cpu_to_be_16(xdev->hwinfo.func_id);
|
|
+ qos_request.dma_direct = 0;
|
|
+ qos_request.qpn = rte_cpu_to_be_16(qpn);
|
|
+ ret = xsc_ioctl(xdev, XSC_IOCTL_CMDQ, XSC_CMD_OP_MODIFY_RAW_QP,
|
|
+ &qos_request, sizeof(qos_request), NULL, 0);
|
|
+ if (ret != 0) {
|
|
+ rte_errno = ret;
|
|
+ PMD_DRV_LOG(ERR, "Modify qp qos fail, qpn=%u, ret=%d", qpn, ret);
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static struct xsc_dev_ops *xsc_rdma_ops = &(struct xsc_dev_ops) {
|
|
+ .kdrv = 1 << RTE_PCI_KDRV_UNKNOWN,
|
|
+ .dev_init = xsc_rdma_dev_init,
|
|
+ .dev_close = xsc_rdma_dev_close,
|
|
+ .set_mtu = xsc_rdma_set_mtu,
|
|
+ .get_mac = xsc_rdma_get_mac,
|
|
+ .set_link_up = xsc_rdma_set_link_up,
|
|
+ .set_link_down = xsc_rdma_set_link_down,
|
|
+ .link_update = xsc_rdma_link_update,
|
|
+ .destroy_qp = xsc_rdma_destroy_qp,
|
|
+ .destroy_cq = xsc_rdma_destroy_cq,
|
|
+ .modify_qp_status = xsc_rdma_modify_qp_status,
|
|
+ .modify_qp_qostree = xsc_rdma_modify_qp_qostree,
|
|
+ .rx_cq_create = xsc_rdma_rx_cq_create,
|
|
+ .tx_cq_create = xsc_rdma_tx_cq_create,
|
|
+ .tx_qp_create = xsc_rdma_tx_qp_create,
|
|
+ .mailbox_exec = xsc_rdma_mailbox_exec,
|
|
+ .intr_event_get = xsc_rdma_event_get,
|
|
+ .intr_handler_install = xsc_rdma_intr_handler_install,
|
|
+ .intr_handler_uninstall = xsc_rdma_intr_handler_uninstall,
|
|
+};
|
|
+
|
|
+RTE_INIT(xsc_rdma_ops_reg)
|
|
+{
|
|
+ xsc_dev_ops_register(xsc_rdma_ops);
|
|
+}
|
|
diff --git a/drivers/net/xsc/xsc_rx.c b/drivers/net/xsc/xsc_rx.c
|
|
new file mode 100644
|
|
index 0000000..c63d658
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_rx.c
|
|
@@ -0,0 +1,518 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#include <rte_io.h>
|
|
+
|
|
+#include "xsc_log.h"
|
|
+#include "xsc_defs.h"
|
|
+#include "xsc_dev.h"
|
|
+#include "xsc_ethdev.h"
|
|
+#include "xsc_cmd.h"
|
|
+#include "xsc_rx.h"
|
|
+
|
|
+#define XSC_MAX_RECV_LEN 9800
|
|
+
|
|
+static inline void
|
|
+xsc_cq_to_mbuf(struct xsc_rxq_data *rxq, struct rte_mbuf *pkt,
|
|
+ volatile struct xsc_cqe *cqe)
|
|
+{
|
|
+ uint32_t rss_hash_res = 0;
|
|
+
|
|
+ pkt->port = rxq->port_id;
|
|
+ if (rxq->rss_hash) {
|
|
+ rss_hash_res = rte_be_to_cpu_32(cqe->vni);
|
|
+ if (rss_hash_res) {
|
|
+ pkt->hash.rss = rss_hash_res;
|
|
+ pkt->ol_flags |= RTE_MBUF_F_RX_RSS_HASH;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline int
|
|
+xsc_rx_poll_len(struct xsc_rxq_data *rxq, volatile struct xsc_cqe *cqe)
|
|
+{
|
|
+ int len;
|
|
+
|
|
+ do {
|
|
+ len = 0;
|
|
+ int ret;
|
|
+
|
|
+ ret = xsc_check_cqe_own(cqe, rxq->cqe_n, rxq->cq_ci);
|
|
+ if (unlikely(ret != XSC_CQE_OWNER_SW)) {
|
|
+ if (unlikely(ret == XSC_CQE_OWNER_ERR))
|
|
+ ++rxq->stats.rx_errors;
|
|
+ else
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ rxq->cq_ci += 1;
|
|
+ len = rte_le_to_cpu_32(cqe->msg_len);
|
|
+ return len;
|
|
+ } while (1);
|
|
+}
|
|
+
|
|
+static __rte_always_inline void
|
|
+xsc_pkt_info_sync(struct rte_mbuf *rep, struct rte_mbuf *seg)
|
|
+{
|
|
+ if (rep != NULL && seg != NULL) {
|
|
+ rep->data_len = seg->data_len;
|
|
+ rep->pkt_len = seg->pkt_len;
|
|
+ rep->data_off = seg->data_off;
|
|
+ rep->port = seg->port;
|
|
+ }
|
|
+}
|
|
+
|
|
+uint16_t
|
|
+xsc_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
|
|
+{
|
|
+ struct xsc_rxq_data *rxq = dpdk_rxq;
|
|
+ const uint32_t wqe_m = rxq->wqe_m;
|
|
+ const uint32_t cqe_m = rxq->cqe_m;
|
|
+ const uint32_t sge_n = rxq->sge_n;
|
|
+ struct rte_mbuf *pkt = NULL;
|
|
+ struct rte_mbuf *seg = NULL;
|
|
+ volatile struct xsc_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_m];
|
|
+ uint32_t nb_pkts = 0;
|
|
+ uint64_t nb_bytes = 0;
|
|
+ uint32_t rq_ci = rxq->rq_ci;
|
|
+ int len = 0;
|
|
+ uint32_t cq_ci_two = 0;
|
|
+ int valid_cqe_num = 0;
|
|
+ int cqe_msg_len = 0;
|
|
+ volatile struct xsc_cqe_u64 *cqe_u64 = NULL;
|
|
+ struct rte_mbuf *rep;
|
|
+
|
|
+ while (pkts_n) {
|
|
+ uint32_t idx = rq_ci & wqe_m;
|
|
+ volatile struct xsc_wqe_data_seg *wqe =
|
|
+ &((volatile struct xsc_wqe_data_seg *)rxq->wqes)[idx << sge_n];
|
|
+
|
|
+ seg = (*rxq->elts)[idx];
|
|
+ rte_prefetch0(cqe);
|
|
+ rte_prefetch0(wqe);
|
|
+
|
|
+ rep = rte_mbuf_raw_alloc(seg->pool);
|
|
+ if (unlikely(rep == NULL)) {
|
|
+ ++rxq->stats.rx_nombuf;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (!pkt) {
|
|
+ if (valid_cqe_num) {
|
|
+ cqe = cqe + 1;
|
|
+ len = cqe_msg_len;
|
|
+ valid_cqe_num = 0;
|
|
+ } else if ((rxq->cq_ci % 2 == 0) && (pkts_n > 1)) {
|
|
+ cq_ci_two = (rxq->cq_ci & rxq->cqe_m) / 2;
|
|
+ cqe_u64 = &(*rxq->cqes_u64)[cq_ci_two];
|
|
+ cqe = (volatile struct xsc_cqe *)cqe_u64;
|
|
+ len = xsc_rx_poll_len(rxq, cqe);
|
|
+ if (len > 0) {
|
|
+ cqe_msg_len = xsc_rx_poll_len(rxq, cqe + 1);
|
|
+ if (cqe_msg_len > 0)
|
|
+ valid_cqe_num = 1;
|
|
+ }
|
|
+ } else {
|
|
+ cqe = &(*rxq->cqes)[rxq->cq_ci & rxq->cqe_m];
|
|
+ len = xsc_rx_poll_len(rxq, cqe);
|
|
+ }
|
|
+
|
|
+ if (!len) {
|
|
+ rte_mbuf_raw_free(rep);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (len > rte_pktmbuf_data_len(seg)) {
|
|
+ rte_mbuf_raw_free(rep);
|
|
+ pkt = NULL;
|
|
+ ++rq_ci;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ pkt = seg;
|
|
+ pkt->ol_flags &= RTE_MBUF_F_EXTERNAL;
|
|
+ xsc_cq_to_mbuf(rxq, pkt, cqe);
|
|
+
|
|
+ if (rxq->crc_present)
|
|
+ len -= RTE_ETHER_CRC_LEN;
|
|
+ rte_pktmbuf_pkt_len(pkt) = len;
|
|
+ }
|
|
+
|
|
+ xsc_pkt_info_sync(rep, seg);
|
|
+ (*rxq->elts)[idx] = rep;
|
|
+
|
|
+ /* Fill wqe */
|
|
+ wqe->va = rte_cpu_to_le_64(rte_pktmbuf_iova(rep));
|
|
+ rte_pktmbuf_data_len(seg) = len;
|
|
+ nb_bytes += rte_pktmbuf_pkt_len(pkt);
|
|
+
|
|
+ *(pkts++) = pkt;
|
|
+ pkt = NULL;
|
|
+ --pkts_n;
|
|
+ ++nb_pkts;
|
|
+ ++rq_ci;
|
|
+ }
|
|
+
|
|
+ if (unlikely(nb_pkts == 0 && rq_ci == rxq->rq_ci))
|
|
+ return 0;
|
|
+
|
|
+ rxq->rq_ci = rq_ci;
|
|
+ rxq->nb_rx_hold += nb_pkts;
|
|
+
|
|
+ if (rxq->nb_rx_hold >= rxq->rx_free_thresh) {
|
|
+ union xsc_cq_doorbell cq_db = {
|
|
+ .cq_data = 0
|
|
+ };
|
|
+ cq_db.next_cid = rxq->cq_ci;
|
|
+ cq_db.cq_num = rxq->cqn;
|
|
+
|
|
+ union xsc_recv_doorbell rq_db = {
|
|
+ .recv_data = 0
|
|
+ };
|
|
+ rq_db.next_pid = (rxq->rq_ci << sge_n);
|
|
+ rq_db.qp_num = rxq->qpn;
|
|
+
|
|
+ rte_write32(rte_cpu_to_le_32(cq_db.cq_data), rxq->cq_db);
|
|
+ rte_write32(rte_cpu_to_le_32(rq_db.recv_data), rxq->rq_db);
|
|
+ rxq->nb_rx_hold = 0;
|
|
+ }
|
|
+
|
|
+ rxq->stats.rx_pkts += nb_pkts;
|
|
+ rxq->stats.rx_bytes += nb_bytes;
|
|
+
|
|
+ return nb_pkts;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_rxq_initialize(struct xsc_dev *xdev, struct xsc_rxq_data *rxq_data)
|
|
+{
|
|
+ const uint32_t wqe_n = rxq_data->wqe_s;
|
|
+ uint32_t i;
|
|
+ uint32_t seg_len = 0;
|
|
+ struct xsc_hwinfo *hwinfo = &xdev->hwinfo;
|
|
+ uint32_t rx_ds_num = hwinfo->recv_seg_num;
|
|
+ uint32_t log2ds = rte_log2_u32(rx_ds_num);
|
|
+ uintptr_t addr;
|
|
+ struct rte_mbuf *mbuf;
|
|
+ void *jumbo_buffer_pa = xdev->jumbo_buffer_pa;
|
|
+ void *jumbo_buffer_va = xdev->jumbo_buffer_va;
|
|
+ volatile struct xsc_wqe_data_seg *seg;
|
|
+ volatile struct xsc_wqe_data_seg *seg_next;
|
|
+
|
|
+ for (i = 0; (i != wqe_n); ++i) {
|
|
+ mbuf = (*rxq_data->elts)[i];
|
|
+ seg = &((volatile struct xsc_wqe_data_seg *)rxq_data->wqes)[i * rx_ds_num];
|
|
+ addr = (uintptr_t)rte_pktmbuf_iova(mbuf);
|
|
+ if (rx_ds_num == 1)
|
|
+ seg_len = XSC_MAX_RECV_LEN;
|
|
+ else
|
|
+ seg_len = rte_pktmbuf_data_len(mbuf);
|
|
+ *seg = (struct xsc_wqe_data_seg){
|
|
+ .va = rte_cpu_to_le_64(addr),
|
|
+ .seg_len = rte_cpu_to_le_32(seg_len),
|
|
+ .lkey = 0,
|
|
+ };
|
|
+
|
|
+ if (rx_ds_num != 1) {
|
|
+ seg_next = seg + 1;
|
|
+ if (jumbo_buffer_va == NULL) {
|
|
+ jumbo_buffer_pa = rte_malloc(NULL, XSC_MAX_RECV_LEN, 0);
|
|
+ if (jumbo_buffer_pa == NULL) {
|
|
+ /* Rely on mtu */
|
|
+ seg->seg_len = XSC_MAX_RECV_LEN;
|
|
+ PMD_DRV_LOG(ERR, "Failed to malloc jumbo_buffer");
|
|
+ continue;
|
|
+ } else {
|
|
+ jumbo_buffer_va =
|
|
+ (void *)rte_malloc_virt2iova(jumbo_buffer_pa);
|
|
+ if ((rte_iova_t)jumbo_buffer_va == RTE_BAD_IOVA) {
|
|
+ seg->seg_len = XSC_MAX_RECV_LEN;
|
|
+ PMD_DRV_LOG(ERR, "Failed to turn jumbo_buffer");
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ xdev->jumbo_buffer_pa = jumbo_buffer_pa;
|
|
+ xdev->jumbo_buffer_va = jumbo_buffer_va;
|
|
+ }
|
|
+ *seg_next = (struct xsc_wqe_data_seg){
|
|
+ .va = rte_cpu_to_le_64((uint64_t)jumbo_buffer_va),
|
|
+ .seg_len = rte_cpu_to_le_32(XSC_MAX_RECV_LEN - seg_len),
|
|
+ .lkey = 0,
|
|
+ };
|
|
+ }
|
|
+ }
|
|
+
|
|
+ rxq_data->rq_ci = wqe_n;
|
|
+ rxq_data->sge_n = log2ds;
|
|
+
|
|
+ union xsc_recv_doorbell recv_db = {
|
|
+ .recv_data = 0
|
|
+ };
|
|
+
|
|
+ recv_db.next_pid = wqe_n << log2ds;
|
|
+ recv_db.qp_num = rxq_data->qpn;
|
|
+ rte_write32(rte_cpu_to_le_32(recv_db.recv_data), rxq_data->rq_db);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_rss_qp_create(struct xsc_ethdev_priv *priv, int port_id)
|
|
+{
|
|
+ struct xsc_cmd_create_multiqp_mbox_in *in;
|
|
+ struct xsc_cmd_create_qp_request *req;
|
|
+ struct xsc_cmd_create_multiqp_mbox_out *out;
|
|
+ uint8_t log_ele;
|
|
+ uint64_t iova;
|
|
+ int wqe_n;
|
|
+ int in_len, out_len, cmd_len;
|
|
+ int entry_total_len, entry_len;
|
|
+ uint8_t log_rq_sz, log_sq_sz = 0;
|
|
+ uint32_t wqe_total_len;
|
|
+ int j, ret;
|
|
+ uint16_t i, pa_num;
|
|
+ int rqn_base;
|
|
+ struct xsc_rxq_data *rxq_data;
|
|
+ struct xsc_dev *xdev = priv->xdev;
|
|
+ struct xsc_hwinfo *hwinfo = &xdev->hwinfo;
|
|
+ char name[RTE_ETH_NAME_MAX_LEN] = { 0 };
|
|
+ void *cmd_buf;
|
|
+
|
|
+ rxq_data = xsc_rxq_get(priv, 0);
|
|
+ if (rxq_data == NULL)
|
|
+ return -EINVAL;
|
|
+
|
|
+ log_ele = rte_log2_u32(sizeof(struct xsc_wqe_data_seg));
|
|
+ wqe_n = rxq_data->wqe_s;
|
|
+ log_rq_sz = rte_log2_u32(wqe_n * hwinfo->recv_seg_num);
|
|
+ wqe_total_len = 1 << (log_rq_sz + log_sq_sz + log_ele);
|
|
+
|
|
+ pa_num = (wqe_total_len + XSC_PAGE_SIZE - 1) / XSC_PAGE_SIZE;
|
|
+ entry_len = sizeof(struct xsc_cmd_create_qp_request) + sizeof(uint64_t) * pa_num;
|
|
+ entry_total_len = entry_len * priv->num_rq;
|
|
+
|
|
+ in_len = sizeof(struct xsc_cmd_create_multiqp_mbox_in) + entry_total_len;
|
|
+ out_len = sizeof(struct xsc_cmd_create_multiqp_mbox_out) + entry_total_len;
|
|
+ cmd_len = RTE_MAX(in_len, out_len);
|
|
+ cmd_buf = malloc(cmd_len);
|
|
+ if (cmd_buf == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Alloc rss qp create cmd memory failed");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ in = cmd_buf;
|
|
+ memset(in, 0, cmd_len);
|
|
+ in->qp_num = rte_cpu_to_be_16((uint16_t)priv->num_rq);
|
|
+ in->qp_type = XSC_QUEUE_TYPE_RAW;
|
|
+ in->req_len = rte_cpu_to_be_32(cmd_len);
|
|
+
|
|
+ for (i = 0; i < priv->num_rq; i++) {
|
|
+ rxq_data = xsc_rxq_get(priv, i);
|
|
+ if (rxq_data == NULL)
|
|
+ return -EINVAL;
|
|
+ req = (struct xsc_cmd_create_qp_request *)(&in->data[0] + entry_len * i);
|
|
+ req->input_qpn = rte_cpu_to_be_16(0); /* useless for eth */
|
|
+ req->pa_num = rte_cpu_to_be_16(pa_num);
|
|
+ req->qp_type = XSC_QUEUE_TYPE_RAW;
|
|
+ req->log_rq_sz = log_rq_sz;
|
|
+ req->cqn_recv = rte_cpu_to_be_16((uint16_t)rxq_data->cqn);
|
|
+ req->cqn_send = req->cqn_recv;
|
|
+ req->glb_funcid = rte_cpu_to_be_16((uint16_t)hwinfo->func_id);
|
|
+ /* Alloc pas addr */
|
|
+ snprintf(name, sizeof(name), "wqe_mem_rx_%d_%d", port_id, i);
|
|
+ rxq_data->rq_pas = rte_memzone_reserve_aligned(name,
|
|
+ (XSC_PAGE_SIZE * pa_num),
|
|
+ SOCKET_ID_ANY,
|
|
+ 0, XSC_PAGE_SIZE);
|
|
+ if (rxq_data->rq_pas == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Alloc rxq pas memory failed");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ iova = rxq_data->rq_pas->iova;
|
|
+ for (j = 0; j < pa_num; j++)
|
|
+ req->pas[j] = rte_cpu_to_be_64(iova + j * XSC_PAGE_SIZE);
|
|
+ }
|
|
+
|
|
+ in->hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_CREATE_MULTI_QP);
|
|
+ out = cmd_buf;
|
|
+ ret = xsc_dev_mailbox_exec(xdev, in, in_len, out, out_len);
|
|
+ if (ret != 0 || out->hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR,
|
|
+ "Create rss rq failed, port id=%d, qp_num=%d, ret=%d, out.status=%u",
|
|
+ port_id, priv->num_rq, ret, out->hdr.status);
|
|
+ rte_errno = ENOEXEC;
|
|
+ goto error;
|
|
+ }
|
|
+ rqn_base = rte_be_to_cpu_32(out->qpn_base) & 0xffffff;
|
|
+
|
|
+ for (i = 0; i < priv->num_rq; i++) {
|
|
+ rxq_data = xsc_rxq_get(priv, i);
|
|
+ if (rxq_data == NULL)
|
|
+ return -EINVAL;
|
|
+ rxq_data->wqes = rxq_data->rq_pas->addr;
|
|
+ if (!xsc_dev_is_vf(xdev))
|
|
+ rxq_data->rq_db = (uint32_t *)((uint8_t *)xdev->bar_addr +
|
|
+ XSC_PF_RX_DB_ADDR);
|
|
+ else
|
|
+ rxq_data->rq_db = (uint32_t *)((uint8_t *)xdev->bar_addr +
|
|
+ XSC_VF_RX_DB_ADDR);
|
|
+
|
|
+ rxq_data->qpn = rqn_base + i;
|
|
+ xsc_dev_modify_qp_status(xdev, rxq_data->qpn, 1, XSC_CMD_OP_RTR2RTS_QP);
|
|
+ xsc_rxq_initialize(xdev, rxq_data);
|
|
+ rxq_data->cq_ci = 0;
|
|
+ priv->dev_data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
|
|
+ PMD_DRV_LOG(INFO, "Port %d create rx qp, wqe_s:%d, wqe_n:%d, qp_db=%p, qpn:%u",
|
|
+ port_id,
|
|
+ rxq_data->wqe_s, rxq_data->wqe_n,
|
|
+ rxq_data->rq_db, rxq_data->qpn);
|
|
+ }
|
|
+
|
|
+ free(cmd_buf);
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ free(cmd_buf);
|
|
+ return -rte_errno;
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_rxq_rss_obj_new(struct xsc_ethdev_priv *priv, uint16_t port_id)
|
|
+{
|
|
+ int ret;
|
|
+ uint32_t i;
|
|
+ struct xsc_dev *xdev = priv->xdev;
|
|
+ struct xsc_rxq_data *rxq_data;
|
|
+ struct xsc_rx_cq_params cq_params = {0};
|
|
+ struct xsc_rx_cq_info cq_info = {0};
|
|
+
|
|
+ /* Create CQ */
|
|
+ for (i = 0; i < priv->num_rq; ++i) {
|
|
+ rxq_data = xsc_rxq_get(priv, i);
|
|
+ if (rxq_data == NULL)
|
|
+ return -EINVAL;
|
|
+
|
|
+ memset(&cq_params, 0, sizeof(cq_params));
|
|
+ memset(&cq_info, 0, sizeof(cq_info));
|
|
+ cq_params.port_id = rxq_data->port_id;
|
|
+ cq_params.qp_id = rxq_data->idx;
|
|
+ cq_params.wqe_s = rxq_data->wqe_s;
|
|
+
|
|
+ ret = xsc_dev_rx_cq_create(xdev, &cq_params, &cq_info);
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Port %u rxq %u create cq fail", port_id, i);
|
|
+ rte_errno = errno;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ rxq_data->cq = cq_info.cq;
|
|
+ rxq_data->cqe_n = cq_info.cqe_n;
|
|
+ rxq_data->cqe_s = 1 << rxq_data->cqe_n;
|
|
+ rxq_data->cqe_m = rxq_data->cqe_s - 1;
|
|
+ rxq_data->cqes = cq_info.cqes;
|
|
+ rxq_data->cq_db = cq_info.cq_db;
|
|
+ rxq_data->cqn = cq_info.cqn;
|
|
+
|
|
+ PMD_DRV_LOG(INFO, "Port %u create rx cq, cqe_s:%d, cqe_n:%d, cq_db=%p, cqn:%u",
|
|
+ port_id,
|
|
+ rxq_data->cqe_s, rxq_data->cqe_n,
|
|
+ rxq_data->cq_db, rxq_data->cqn);
|
|
+ }
|
|
+
|
|
+ ret = xsc_rss_qp_create(priv, port_id);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Port %u rss rxq create fail", port_id);
|
|
+ goto error;
|
|
+ }
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ return -rte_errno;
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_rxq_elts_alloc(struct xsc_rxq_data *rxq_data)
|
|
+{
|
|
+ uint32_t elts_s = rxq_data->wqe_s;
|
|
+ struct rte_mbuf *mbuf;
|
|
+ uint32_t i;
|
|
+
|
|
+ for (i = 0; (i != elts_s); ++i) {
|
|
+ mbuf = rte_pktmbuf_alloc(rxq_data->mp);
|
|
+ if (mbuf == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Port %u rxq %u empty mbuf pool",
|
|
+ rxq_data->port_id, rxq_data->idx);
|
|
+ rte_errno = ENOMEM;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ mbuf->port = rxq_data->port_id;
|
|
+ mbuf->nb_segs = 1;
|
|
+ rte_pktmbuf_data_len(mbuf) = mbuf->buf_len - mbuf->data_off;
|
|
+ rte_pktmbuf_pkt_len(mbuf) = rte_pktmbuf_data_len(mbuf);
|
|
+ (*rxq_data->elts)[i] = mbuf;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+error:
|
|
+ elts_s = i;
|
|
+ for (i = 0; (i != elts_s); ++i) {
|
|
+ if ((*rxq_data->elts)[i] != NULL)
|
|
+ rte_pktmbuf_free_seg((*rxq_data->elts)[i]);
|
|
+ (*rxq_data->elts)[i] = NULL;
|
|
+ }
|
|
+
|
|
+ PMD_DRV_LOG(ERR, "Port %u rxq %u start failed, free elts",
|
|
+ rxq_data->port_id, rxq_data->idx);
|
|
+
|
|
+ return -rte_errno;
|
|
+}
|
|
+
|
|
+void
|
|
+xsc_rxq_elts_free(struct xsc_rxq_data *rxq_data)
|
|
+{
|
|
+ uint16_t i;
|
|
+
|
|
+ if (rxq_data->elts == NULL)
|
|
+ return;
|
|
+ for (i = 0; i != rxq_data->wqe_s; ++i) {
|
|
+ if ((*rxq_data->elts)[i] != NULL)
|
|
+ rte_pktmbuf_free_seg((*rxq_data->elts)[i]);
|
|
+ (*rxq_data->elts)[i] = NULL;
|
|
+ }
|
|
+
|
|
+ PMD_DRV_LOG(DEBUG, "Port %u rxq %u free elts", rxq_data->port_id, rxq_data->idx);
|
|
+}
|
|
+
|
|
+void
|
|
+xsc_rxq_rss_obj_release(struct xsc_dev *xdev, struct xsc_rxq_data *rxq_data)
|
|
+{
|
|
+ struct xsc_cmd_destroy_qp_mbox_in in = { .hdr = { 0 } };
|
|
+ struct xsc_cmd_destroy_qp_mbox_out out = { .hdr = { 0 } };
|
|
+ int ret, in_len, out_len;
|
|
+ uint32_t qpn = rxq_data->qpn;
|
|
+
|
|
+ xsc_dev_modify_qp_status(xdev, qpn, 1, XSC_CMD_OP_QP_2RST);
|
|
+
|
|
+ in_len = sizeof(struct xsc_cmd_destroy_qp_mbox_in);
|
|
+ out_len = sizeof(struct xsc_cmd_destroy_qp_mbox_out);
|
|
+ in.hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_DESTROY_QP);
|
|
+ in.qpn = rte_cpu_to_be_32(rxq_data->qpn);
|
|
+
|
|
+ ret = xsc_dev_mailbox_exec(xdev, &in, in_len, &out, out_len);
|
|
+ if (ret != 0 || out.hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR,
|
|
+ "Release rss rq failed, port id=%d, qid=%d, err=%d, out.status=%u",
|
|
+ rxq_data->port_id, rxq_data->idx, ret, out.hdr.status);
|
|
+ rte_errno = ENOEXEC;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ rte_memzone_free(rxq_data->rq_pas);
|
|
+
|
|
+ if (rxq_data->cq != NULL)
|
|
+ xsc_dev_destroy_cq(xdev, rxq_data->cq);
|
|
+ rxq_data->cq = NULL;
|
|
+}
|
|
diff --git a/drivers/net/xsc/xsc_rx.h b/drivers/net/xsc/xsc_rx.h
|
|
new file mode 100644
|
|
index 0000000..90fbb89
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_rx.h
|
|
@@ -0,0 +1,65 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#ifndef _XSC_RX_H_
|
|
+#define _XSC_RX_H_
|
|
+
|
|
+#define XSC_RX_FREE_THRESH 32
|
|
+
|
|
+struct xsc_rxq_stats {
|
|
+ uint64_t rx_pkts; /* Total number of rx packets */
|
|
+ uint64_t rx_bytes; /* Total number of rx bytes */
|
|
+ uint64_t rx_errors; /* Total number of rx error packets */
|
|
+ uint64_t rx_nombuf; /* Total number of rx mbuf alloc failed */
|
|
+};
|
|
+
|
|
+struct __rte_cache_aligned xsc_rxq_data {
|
|
+ uint16_t idx; /*QP idx */
|
|
+ uint16_t port_id;
|
|
+ void *cq; /* CQ pointer */
|
|
+ void *qp; /* QP pointer */
|
|
+ uint32_t cqn; /* CQ serial number */
|
|
+ uint32_t qpn; /* QP serial number */
|
|
+ uint16_t wqe_s; /* Number of WQE */
|
|
+ uint16_t wqe_m; /* Mask of WQE number */
|
|
+ uint16_t cqe_s; /* Number of CQE */
|
|
+ uint16_t cqe_m; /* Mask of CQE number */
|
|
+ uint16_t wqe_n:4; /* Log 2 of WQE number */
|
|
+ uint16_t sge_n:4; /* Log 2 of each WQE DS number */
|
|
+ uint16_t cqe_n:4; /* Log 2 of CQE number */
|
|
+ uint16_t rsv0:4;
|
|
+ volatile uint32_t *rq_db;
|
|
+ volatile uint32_t *cq_db;
|
|
+ uint32_t rq_ci;
|
|
+ uint32_t rq_pi;
|
|
+ uint16_t cq_ci;
|
|
+ uint16_t rx_free_thresh;
|
|
+ uint16_t nb_rx_hold;
|
|
+ volatile void *wqes;
|
|
+ union {
|
|
+ volatile struct xsc_cqe(*cqes)[];
|
|
+ volatile struct xsc_cqe_u64(*cqes_u64)[];
|
|
+ };
|
|
+ struct rte_mbuf *(*elts)[]; /* Record the mbuf of wqe addr */
|
|
+ struct rte_mempool *mp;
|
|
+ const struct rte_memzone *rq_pas; /* Palist memory */
|
|
+ uint32_t socket;
|
|
+ struct xsc_ethdev_priv *priv;
|
|
+ struct xsc_rxq_stats stats;
|
|
+ /* attr */
|
|
+ uint16_t csum:1; /* Checksum offloading enable */
|
|
+ uint16_t hw_timestamp:1;
|
|
+ uint16_t vlan_strip:1;
|
|
+ uint16_t crc_present:1; /* CRC flag */
|
|
+ uint16_t rss_hash:1; /* RSS hash enabled */
|
|
+ uint16_t rsv1:11;
|
|
+};
|
|
+
|
|
+uint16_t xsc_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n);
|
|
+int xsc_rxq_elts_alloc(struct xsc_rxq_data *rxq_data);
|
|
+int xsc_rxq_rss_obj_new(struct xsc_ethdev_priv *priv, uint16_t port_id);
|
|
+void xsc_rxq_rss_obj_release(struct xsc_dev *xdev, struct xsc_rxq_data *rxq_data);
|
|
+void xsc_rxq_elts_free(struct xsc_rxq_data *rxq_data);
|
|
+
|
|
+#endif /* _XSC_RX_H_ */
|
|
diff --git a/drivers/net/xsc/xsc_rxtx.h b/drivers/net/xsc/xsc_rxtx.h
|
|
new file mode 100644
|
|
index 0000000..0b5a19a
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_rxtx.h
|
|
@@ -0,0 +1,193 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#ifndef _XSC_RXTX_H_
|
|
+#define _XSC_RXTX_H_
|
|
+
|
|
+#include <rte_byteorder.h>
|
|
+
|
|
+#include "xsc_compat.h"
|
|
+
|
|
+#define XSC_CQE_OWNER_MASK 0x1
|
|
+#define XSC_CQE_OWNER_HW 0x2
|
|
+#define XSC_CQE_OWNER_SW 0x4
|
|
+#define XSC_CQE_OWNER_ERR 0x8
|
|
+#define XSC_OPCODE_RAW 0x7
|
|
+
|
|
+struct __rte_packed_begin xsc_send_wqe_ctrl_seg {
|
|
+ rte_le32_t msg_opcode:8;
|
|
+ rte_le32_t with_immdt:1;
|
|
+ rte_le32_t csum_en:2;
|
|
+ rte_le32_t ds_data_num:5;
|
|
+ rte_le32_t wqe_id:16;
|
|
+ rte_le32_t msg_len;
|
|
+ union {
|
|
+ rte_le32_t opcode_data;
|
|
+ struct {
|
|
+ rte_le16_t has_pph:1;
|
|
+ rte_le16_t so_type:1;
|
|
+ rte_le16_t so_data_size:14;
|
|
+ rte_le16_t rsv1:8;
|
|
+ rte_le16_t so_hdr_len:8;
|
|
+ };
|
|
+ struct {
|
|
+ rte_le16_t desc_id;
|
|
+ rte_le16_t is_last_wqe:1;
|
|
+ rte_le16_t dst_qp_id:15;
|
|
+ };
|
|
+ };
|
|
+ rte_le32_t se:1;
|
|
+ rte_le32_t ce:1;
|
|
+ rte_le32_t rsv2:30;
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct __rte_packed_begin xsc_wqe_data_seg {
|
|
+ union {
|
|
+ struct {
|
|
+ uint8_t in_line:1;
|
|
+ uint8_t rsv0:7;
|
|
+ };
|
|
+ struct {
|
|
+ rte_le32_t rsv1:1;
|
|
+ rte_le32_t seg_len:31;
|
|
+ rte_le32_t lkey;
|
|
+ rte_le64_t va;
|
|
+ };
|
|
+ struct {
|
|
+ uint8_t rsv2:1;
|
|
+ uint8_t len:7;
|
|
+ uint8_t in_line_data[15];
|
|
+ };
|
|
+ };
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct __rte_packed_begin xsc_wqe {
|
|
+ union {
|
|
+ struct xsc_send_wqe_ctrl_seg cseg;
|
|
+ uint32_t ctrl[4];
|
|
+ };
|
|
+ union {
|
|
+ struct xsc_wqe_data_seg dseg[XSC_SEND_WQE_DS];
|
|
+ uint8_t data[XSC_ESEG_EXTRA_DATA_SIZE];
|
|
+ };
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct __rte_packed_begin xsc_cqe {
|
|
+ union {
|
|
+ uint8_t msg_opcode;
|
|
+ struct {
|
|
+ uint8_t error_code:7;
|
|
+ uint8_t is_error:1;
|
|
+ };
|
|
+ };
|
|
+ rte_le16_t qp_id:15;
|
|
+ rte_le16_t rsv:1;
|
|
+ uint8_t se:1;
|
|
+ uint8_t has_pph:1;
|
|
+ uint8_t type:1;
|
|
+ uint8_t with_immdt:1;
|
|
+ uint8_t csum_err:4;
|
|
+ rte_le32_t imm_data;
|
|
+ rte_le32_t msg_len;
|
|
+ rte_le32_t vni;
|
|
+ rte_le32_t tsl;
|
|
+ rte_le32_t tsh:16;
|
|
+ rte_le32_t wqe_id:16;
|
|
+ rte_le16_t rsv2[3];
|
|
+ rte_le16_t rsv3:15;
|
|
+ rte_le16_t owner:1;
|
|
+} __rte_packed_end;
|
|
+
|
|
+struct xsc_cqe_u64 {
|
|
+ struct xsc_cqe cqe0;
|
|
+ struct xsc_cqe cqe1;
|
|
+};
|
|
+
|
|
+union xsc_cq_doorbell {
|
|
+ struct {
|
|
+ uint32_t next_cid:16;
|
|
+ uint32_t cq_num:15;
|
|
+ uint32_t cq_sta:1;
|
|
+ };
|
|
+ uint32_t cq_data;
|
|
+};
|
|
+
|
|
+union xsc_send_doorbell {
|
|
+ struct {
|
|
+ uint32_t next_pid:16;
|
|
+ uint32_t qp_num:15;
|
|
+ uint32_t rsv:1;
|
|
+ };
|
|
+ uint32_t send_data;
|
|
+};
|
|
+
|
|
+struct xsc_tx_cq_params {
|
|
+ uint16_t port_id;
|
|
+ uint16_t qp_id;
|
|
+ uint16_t elts_n;
|
|
+};
|
|
+
|
|
+struct xsc_tx_cq_info {
|
|
+ void *cq;
|
|
+ void *cqes;
|
|
+ uint32_t *cq_db;
|
|
+ uint32_t cqn;
|
|
+ uint16_t cqe_s;
|
|
+ uint16_t cqe_n;
|
|
+};
|
|
+
|
|
+struct xsc_tx_qp_params {
|
|
+ void *cq;
|
|
+ uint64_t tx_offloads;
|
|
+ uint16_t port_id;
|
|
+ uint16_t qp_id;
|
|
+ uint16_t elts_n;
|
|
+};
|
|
+
|
|
+struct xsc_tx_qp_info {
|
|
+ void *qp;
|
|
+ void *wqes;
|
|
+ uint32_t *qp_db;
|
|
+ uint32_t qpn;
|
|
+ uint16_t tso_en;
|
|
+ uint16_t wqe_n;
|
|
+};
|
|
+
|
|
+union xsc_recv_doorbell {
|
|
+ struct {
|
|
+ uint32_t next_pid:13;
|
|
+ uint32_t qp_num:15;
|
|
+ uint32_t rsv:4;
|
|
+ };
|
|
+ uint32_t recv_data;
|
|
+};
|
|
+
|
|
+struct xsc_rx_cq_params {
|
|
+ uint16_t port_id;
|
|
+ uint16_t qp_id;
|
|
+ uint16_t wqe_s;
|
|
+};
|
|
+
|
|
+struct xsc_rx_cq_info {
|
|
+ void *cq;
|
|
+ void *cqes;
|
|
+ uint32_t *cq_db;
|
|
+ uint32_t cqn;
|
|
+ uint16_t cqe_n;
|
|
+};
|
|
+
|
|
+static __rte_always_inline int
|
|
+xsc_check_cqe_own(volatile struct xsc_cqe *cqe, const uint16_t cqe_n, const uint16_t ci)
|
|
+{
|
|
+ if (unlikely(((cqe->owner & XSC_CQE_OWNER_MASK) != ((ci >> cqe_n) & XSC_CQE_OWNER_MASK))))
|
|
+ return XSC_CQE_OWNER_HW;
|
|
+
|
|
+ rte_io_rmb();
|
|
+ if (cqe->msg_len <= 0 && cqe->is_error)
|
|
+ return XSC_CQE_OWNER_ERR;
|
|
+
|
|
+ return XSC_CQE_OWNER_SW;
|
|
+}
|
|
+
|
|
+#endif /* _XSC_RXTX_H_ */
|
|
diff --git a/drivers/net/xsc/xsc_tx.c b/drivers/net/xsc/xsc_tx.c
|
|
new file mode 100644
|
|
index 0000000..d1a0f32
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_tx.c
|
|
@@ -0,0 +1,353 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#include <rte_io.h>
|
|
+
|
|
+#include "xsc_log.h"
|
|
+#include "xsc_defs.h"
|
|
+#include "xsc_dev.h"
|
|
+#include "xsc_ethdev.h"
|
|
+#include "xsc_cmd.h"
|
|
+#include "xsc_tx.h"
|
|
+#include "xsc_np.h"
|
|
+
|
|
+void
|
|
+xsc_txq_elts_alloc(struct xsc_txq_data *txq_data)
|
|
+{
|
|
+ const uint32_t elts_s = 1 << txq_data->elts_n;
|
|
+ uint32_t i;
|
|
+
|
|
+ for (i = 0; i < elts_s; ++i)
|
|
+ txq_data->elts[i] = NULL;
|
|
+ txq_data->elts_head = 0;
|
|
+ txq_data->elts_tail = 0;
|
|
+ txq_data->elts_comp = 0;
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_txq_obj_new(struct xsc_dev *xdev, struct xsc_txq_data *txq_data,
|
|
+ uint64_t offloads, uint16_t idx)
|
|
+{
|
|
+ int ret = 0;
|
|
+ struct xsc_tx_cq_params cq_params = {0};
|
|
+ struct xsc_tx_cq_info cq_info = {0};
|
|
+ struct xsc_tx_qp_params qp_params = {0};
|
|
+ struct xsc_tx_qp_info qp_info = {0};
|
|
+
|
|
+ cq_params.port_id = txq_data->port_id;
|
|
+ cq_params.qp_id = txq_data->idx;
|
|
+ cq_params.elts_n = txq_data->elts_n;
|
|
+ ret = xsc_dev_tx_cq_create(xdev, &cq_params, &cq_info);
|
|
+ if (ret) {
|
|
+ rte_errno = errno;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ txq_data->cq = cq_info.cq;
|
|
+ txq_data->cqe_n = cq_info.cqe_n;
|
|
+ txq_data->cqe_s = cq_info.cqe_s;
|
|
+ txq_data->cq_db = cq_info.cq_db;
|
|
+ txq_data->cqn = cq_info.cqn;
|
|
+ txq_data->cqes = cq_info.cqes;
|
|
+ txq_data->cqe_m = (uint16_t)(1 << cq_info.cqe_n) - 1;
|
|
+
|
|
+ PMD_DRV_LOG(INFO, "Create tx cq, cqe_s:%d, cqe_n:%d, cq_db=%p, cqn:%u",
|
|
+ txq_data->cqe_s, txq_data->cqe_n,
|
|
+ txq_data->cq_db, txq_data->cqn);
|
|
+
|
|
+ qp_params.cq = txq_data->cq;
|
|
+ qp_params.tx_offloads = offloads;
|
|
+ qp_params.port_id = txq_data->port_id;
|
|
+ qp_params.qp_id = idx;
|
|
+ qp_params.elts_n = txq_data->elts_n;
|
|
+ ret = xsc_dev_tx_qp_create(xdev, &qp_params, &qp_info);
|
|
+
|
|
+ if (ret != 0) {
|
|
+ rte_errno = errno;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ txq_data->qp = qp_info.qp;
|
|
+ txq_data->qpn = qp_info.qpn;
|
|
+ txq_data->wqes = qp_info.wqes;
|
|
+ txq_data->wqe_n = qp_info.wqe_n;
|
|
+ txq_data->wqe_s = 1 << txq_data->wqe_n;
|
|
+ txq_data->wqe_m = txq_data->wqe_s - 1;
|
|
+ txq_data->wqe_ds_n = rte_log2_u32(xdev->hwinfo.send_seg_num);
|
|
+ txq_data->qp_db = qp_info.qp_db;
|
|
+
|
|
+ txq_data->cq_ci = 0;
|
|
+ txq_data->cq_pi = 0;
|
|
+ txq_data->wqe_ci = 0;
|
|
+ txq_data->wqe_pi = 0;
|
|
+ txq_data->wqe_comp = 0;
|
|
+
|
|
+ PMD_DRV_LOG(INFO, "Create tx qp, wqe_s:%d, wqe_n:%d, qp_db=%p, qpn:%u",
|
|
+ txq_data->wqe_s, txq_data->wqe_n,
|
|
+ txq_data->qp_db, txq_data->qpn);
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ return -rte_errno;
|
|
+}
|
|
+
|
|
+void
|
|
+xsc_txq_obj_release(struct xsc_dev *xdev, struct xsc_txq_data *txq_data)
|
|
+{
|
|
+ PMD_DRV_LOG(DEBUG, "Destroy tx queue %u, portid %u",
|
|
+ txq_data->idx, txq_data->port_id);
|
|
+ if (txq_data->qp != NULL)
|
|
+ xsc_dev_destroy_qp(xdev, txq_data->qp);
|
|
+ if (txq_data->cq != NULL)
|
|
+ xsc_dev_destroy_cq(xdev, txq_data->cq);
|
|
+}
|
|
+
|
|
+void
|
|
+xsc_txq_elts_free(struct xsc_txq_data *txq_data)
|
|
+{
|
|
+ const uint16_t elts_n = 1 << txq_data->elts_n;
|
|
+ const uint16_t elts_m = elts_n - 1;
|
|
+ uint16_t elts_head = txq_data->elts_head;
|
|
+ uint16_t elts_tail = txq_data->elts_tail;
|
|
+ struct rte_mbuf *(*elts)[elts_n] = &txq_data->elts;
|
|
+
|
|
+ txq_data->elts_head = 0;
|
|
+ txq_data->elts_tail = 0;
|
|
+ txq_data->elts_comp = 0;
|
|
+
|
|
+ while (elts_tail != elts_head) {
|
|
+ struct rte_mbuf *elt = (*elts)[elts_tail & elts_m];
|
|
+
|
|
+ rte_pktmbuf_free_seg(elt);
|
|
+ ++elts_tail;
|
|
+ }
|
|
+ PMD_DRV_LOG(DEBUG, "Port %u txq %u free elts", txq_data->port_id, txq_data->idx);
|
|
+}
|
|
+
|
|
+static __rte_always_inline void
|
|
+xsc_tx_elts_flush(struct xsc_txq_data *__rte_restrict txq, uint16_t tail)
|
|
+{
|
|
+ uint16_t elts_n = tail - txq->elts_tail;
|
|
+ uint32_t free_n;
|
|
+
|
|
+ do {
|
|
+ free_n = txq->elts_s - (txq->elts_tail & txq->elts_m);
|
|
+ free_n = RTE_MIN(free_n, elts_n);
|
|
+ rte_pktmbuf_free_bulk(&txq->elts[txq->elts_tail & txq->elts_m], free_n);
|
|
+ txq->elts_tail += free_n;
|
|
+ elts_n -= free_n;
|
|
+ } while (elts_n > 0);
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_tx_cqes_handle(struct xsc_txq_data *__rte_restrict txq)
|
|
+{
|
|
+ uint32_t count = XSC_TX_COMP_CQE_HANDLE_MAX;
|
|
+ volatile struct xsc_cqe *last_cqe = NULL;
|
|
+ volatile struct xsc_cqe *cqe;
|
|
+ bool doorbell = false;
|
|
+ int ret;
|
|
+ uint16_t tail;
|
|
+
|
|
+ do {
|
|
+ cqe = &txq->cqes[txq->cq_ci & txq->cqe_m];
|
|
+ ret = xsc_check_cqe_own(cqe, txq->cqe_n, txq->cq_ci);
|
|
+ if (unlikely(ret != XSC_CQE_OWNER_SW)) {
|
|
+ if (likely(ret != XSC_CQE_OWNER_ERR))
|
|
+ /* No new CQEs in completion queue. */
|
|
+ break;
|
|
+ doorbell = true;
|
|
+ ++txq->cq_ci;
|
|
+ txq->cq_pi = txq->cq_ci;
|
|
+ last_cqe = NULL;
|
|
+ ++txq->stats.tx_errors;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ doorbell = true;
|
|
+ ++txq->cq_ci;
|
|
+ last_cqe = cqe;
|
|
+ } while (--count > 0);
|
|
+
|
|
+ if (likely(doorbell)) {
|
|
+ union xsc_cq_doorbell cq_db = {
|
|
+ .cq_data = 0
|
|
+ };
|
|
+ cq_db.next_cid = txq->cq_ci;
|
|
+ cq_db.cq_num = txq->cqn;
|
|
+
|
|
+ /* Ring doorbell */
|
|
+ rte_write32(rte_cpu_to_le_32(cq_db.cq_data), txq->cq_db);
|
|
+
|
|
+ /* Release completed elts */
|
|
+ if (likely(last_cqe != NULL)) {
|
|
+ txq->wqe_pi = rte_le_to_cpu_16(last_cqe->wqe_id) >> txq->wqe_ds_n;
|
|
+ tail = txq->fcqs[(txq->cq_ci - 1) & txq->cqe_m];
|
|
+ if (likely(tail != txq->elts_tail))
|
|
+ xsc_tx_elts_flush(txq, tail);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static __rte_always_inline void
|
|
+xsc_tx_wqe_ctrl_seg_init(struct xsc_txq_data *__rte_restrict txq,
|
|
+ struct rte_mbuf *__rte_restrict mbuf,
|
|
+ struct xsc_wqe *__rte_restrict wqe)
|
|
+{
|
|
+ struct xsc_send_wqe_ctrl_seg *cs = &wqe->cseg;
|
|
+ int i = 0;
|
|
+ int ds_max = (1 << txq->wqe_ds_n) - 1;
|
|
+
|
|
+ cs->msg_opcode = XSC_OPCODE_RAW;
|
|
+ cs->wqe_id = rte_cpu_to_le_16(txq->wqe_ci << txq->wqe_ds_n);
|
|
+ cs->has_pph = 0;
|
|
+ /* Clear dseg's seg len */
|
|
+ if (cs->ds_data_num > 1 && cs->ds_data_num <= ds_max) {
|
|
+ for (i = 1; i < cs->ds_data_num; i++)
|
|
+ wqe->dseg[i].seg_len = 0;
|
|
+ }
|
|
+
|
|
+ cs->ds_data_num = mbuf->nb_segs;
|
|
+ if (mbuf->ol_flags & RTE_MBUF_F_TX_IP_CKSUM)
|
|
+ cs->csum_en = 0x2;
|
|
+ else
|
|
+ cs->csum_en = 0;
|
|
+
|
|
+ if (txq->tso_en == 1 && (mbuf->ol_flags & RTE_MBUF_F_TX_TCP_SEG)) {
|
|
+ cs->so_type = 1;
|
|
+ cs->so_hdr_len = mbuf->l2_len + mbuf->l3_len + mbuf->l4_len;
|
|
+ cs->so_data_size = rte_cpu_to_le_16(mbuf->tso_segsz);
|
|
+ }
|
|
+
|
|
+ cs->msg_len = rte_cpu_to_le_32(rte_pktmbuf_pkt_len(mbuf));
|
|
+ if (unlikely(cs->msg_len == 0))
|
|
+ cs->msg_len = rte_cpu_to_le_32(rte_pktmbuf_data_len(mbuf));
|
|
+
|
|
+ /* Do not generate cqe for every pkts */
|
|
+ cs->ce = 0;
|
|
+}
|
|
+
|
|
+static __rte_always_inline void
|
|
+xsc_tx_wqe_data_seg_init(struct rte_mbuf *mbuf, struct xsc_wqe *wqe)
|
|
+{
|
|
+ uint16_t i, nb_segs = mbuf->nb_segs;
|
|
+ uint32_t data_len;
|
|
+ rte_iova_t iova;
|
|
+ struct xsc_wqe_data_seg *dseg;
|
|
+
|
|
+ for (i = 0; i < nb_segs; ++i) {
|
|
+ dseg = &wqe->dseg[i];
|
|
+ iova = rte_pktmbuf_iova(mbuf);
|
|
+ data_len = rte_pktmbuf_data_len(mbuf);
|
|
+
|
|
+ dseg->in_line = 0;
|
|
+ dseg->seg_len = rte_cpu_to_le_32(data_len);
|
|
+ dseg->lkey = 0;
|
|
+ dseg->va = rte_cpu_to_le_64(iova);
|
|
+ mbuf = mbuf->next;
|
|
+ }
|
|
+}
|
|
+
|
|
+static __rte_always_inline struct xsc_wqe *
|
|
+xsc_tx_wqes_fill(struct xsc_txq_data *__rte_restrict txq,
|
|
+ struct rte_mbuf **__rte_restrict pkts,
|
|
+ uint32_t pkts_n)
|
|
+{
|
|
+ uint32_t i;
|
|
+ struct xsc_wqe *wqe = NULL;
|
|
+ struct rte_mbuf *mbuf;
|
|
+
|
|
+ for (i = 0; i < pkts_n; i++) {
|
|
+ rte_prefetch0(pkts[i]);
|
|
+ mbuf = pkts[i];
|
|
+ wqe = (struct xsc_wqe *)((struct xsc_send_wqe_ctrl_seg *)txq->wqes +
|
|
+ (txq->wqe_ci & txq->wqe_m) * (1 << txq->wqe_ds_n));
|
|
+
|
|
+ /* Init wqe ctrl seg */
|
|
+ xsc_tx_wqe_ctrl_seg_init(txq, mbuf, wqe);
|
|
+ /* Init wqe data segs */
|
|
+ xsc_tx_wqe_data_seg_init(mbuf, wqe);
|
|
+ ++txq->wqe_ci;
|
|
+ txq->stats.tx_bytes += rte_pktmbuf_pkt_len(mbuf);
|
|
+ }
|
|
+
|
|
+ return wqe;
|
|
+}
|
|
+
|
|
+static __rte_always_inline void
|
|
+xsc_tx_doorbell_ring(volatile uint32_t *db, uint32_t index,
|
|
+ uint32_t qpn, uint16_t ds_n)
|
|
+{
|
|
+ union xsc_send_doorbell tx_db;
|
|
+
|
|
+ tx_db.next_pid = index << ds_n;
|
|
+ tx_db.qp_num = qpn;
|
|
+
|
|
+ rte_write32(rte_cpu_to_le_32(tx_db.send_data), db);
|
|
+}
|
|
+
|
|
+static __rte_always_inline void
|
|
+xsc_tx_elts_store(struct xsc_txq_data *__rte_restrict txq,
|
|
+ struct rte_mbuf **__rte_restrict pkts,
|
|
+ uint32_t pkts_n)
|
|
+{
|
|
+ uint32_t part;
|
|
+ struct rte_mbuf **elts = (struct rte_mbuf **)txq->elts;
|
|
+
|
|
+ part = txq->elts_s - (txq->elts_head & txq->elts_m);
|
|
+ rte_memcpy((void *)(elts + (txq->elts_head & txq->elts_m)),
|
|
+ (void *)pkts,
|
|
+ RTE_MIN(part, pkts_n) * sizeof(struct rte_mbuf *));
|
|
+
|
|
+ if (unlikely(part < pkts_n))
|
|
+ rte_memcpy((void *)elts, (void *)(pkts + part),
|
|
+ (pkts_n - part) * sizeof(struct rte_mbuf *));
|
|
+}
|
|
+
|
|
+uint16_t
|
|
+xsc_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
|
|
+{
|
|
+ struct xsc_txq_data *txq = dpdk_txq;
|
|
+ uint32_t tx_n, remain_n = pkts_n;
|
|
+ uint16_t idx, elts_free, wqe_free;
|
|
+ uint16_t elts_head;
|
|
+ struct xsc_wqe *last_wqe;
|
|
+
|
|
+ if (unlikely(!pkts_n))
|
|
+ return 0;
|
|
+
|
|
+ do {
|
|
+ xsc_tx_cqes_handle(txq);
|
|
+
|
|
+ elts_free = txq->elts_s - (uint16_t)(txq->elts_head - txq->elts_tail);
|
|
+ wqe_free = txq->wqe_s - ((uint16_t)((txq->wqe_ci << txq->wqe_ds_n) -
|
|
+ (txq->wqe_pi << txq->wqe_ds_n)) >> txq->wqe_ds_n);
|
|
+ if (unlikely(elts_free == 0 || wqe_free == 0))
|
|
+ break;
|
|
+
|
|
+ /* Fill in WQEs */
|
|
+ tx_n = RTE_MIN(remain_n, wqe_free);
|
|
+ idx = pkts_n - remain_n;
|
|
+ last_wqe = xsc_tx_wqes_fill(txq, &pkts[idx], tx_n);
|
|
+ remain_n -= tx_n;
|
|
+ last_wqe->cseg.ce = 1;
|
|
+
|
|
+ /* Update free-cqs, elts_comp */
|
|
+ elts_head = txq->elts_head;
|
|
+ elts_head += tx_n;
|
|
+ if ((uint16_t)(elts_head - txq->elts_comp) > 0) {
|
|
+ txq->elts_comp = elts_head;
|
|
+ txq->fcqs[txq->cq_pi++ & txq->cqe_m] = elts_head;
|
|
+ }
|
|
+
|
|
+ /* Ring tx doorbell */
|
|
+ xsc_tx_doorbell_ring(txq->qp_db, txq->wqe_ci, txq->qpn, txq->wqe_ds_n);
|
|
+
|
|
+ xsc_tx_elts_store(txq, &pkts[idx], tx_n);
|
|
+ txq->elts_head += tx_n;
|
|
+ } while (remain_n > 0);
|
|
+
|
|
+ txq->stats.tx_pkts += (pkts_n - remain_n);
|
|
+ return pkts_n - remain_n;
|
|
+}
|
|
diff --git a/drivers/net/xsc/xsc_tx.h b/drivers/net/xsc/xsc_tx.h
|
|
new file mode 100644
|
|
index 0000000..88419dd
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_tx.h
|
|
@@ -0,0 +1,62 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#ifndef _XSC_TX_H_
|
|
+#define _XSC_TX_H_
|
|
+
|
|
+#define XSC_TX_COMP_CQE_HANDLE_MAX 2
|
|
+
|
|
+struct xsc_txq_stats {
|
|
+ uint64_t tx_pkts; /* Total number of tx packets */
|
|
+ uint64_t tx_bytes; /* Total number of tx bytes */
|
|
+ uint64_t tx_errors; /* Total number of tx error packets */
|
|
+};
|
|
+
|
|
+struct __rte_cache_aligned xsc_txq_data {
|
|
+ uint16_t idx; /*QP idx */
|
|
+ uint16_t port_id;
|
|
+ void *cq; /* CQ pointer */
|
|
+ void *qp; /* QP pointer */
|
|
+ uint32_t cqn; /* CQ serial number */
|
|
+ uint32_t qpn; /* QP serial number */
|
|
+ uint16_t elts_head; /* Current pos in (*elts)[] */
|
|
+ uint16_t elts_tail; /* Counter of first element awaiting completion */
|
|
+ uint16_t elts_comp; /* Elts index since last completion request */
|
|
+ uint16_t elts_s; /* Number of (*elts)[] */
|
|
+ uint16_t elts_m; /* Mask of (*elts)[] number */
|
|
+ uint16_t wqe_ci; /* Consumer index for TXQ */
|
|
+ uint16_t wqe_pi; /* Producer index for TXQ */
|
|
+ uint16_t wqe_s; /* Number of WQE */
|
|
+ uint16_t wqe_m; /* Mask of WQE number */
|
|
+ uint16_t wqe_comp; /* WQE index since last completion request */
|
|
+ uint16_t cq_ci; /* Consumer index for CQ */
|
|
+ uint16_t cq_pi; /* Production index for CQ */
|
|
+ uint16_t cqe_s; /* Number of CQE */
|
|
+ uint16_t cqe_m; /* Mask of CQE number */
|
|
+ uint16_t elts_n:4; /* Log 2 of (*elts)[] number */
|
|
+ uint16_t cqe_n:4; /* Log 2 of CQE number */
|
|
+ uint16_t wqe_n:4; /* Log 2 of WQE number */
|
|
+ uint16_t wqe_ds_n:4; /* Log 2 of each WQE DS number */
|
|
+ uint64_t offloads; /* TXQ offloads */
|
|
+ struct xsc_wqe *wqes;
|
|
+ volatile struct xsc_cqe *cqes;
|
|
+ volatile uint32_t *qp_db;
|
|
+ volatile uint32_t *cq_db;
|
|
+ struct xsc_ethdev_priv *priv;
|
|
+ struct xsc_txq_stats stats;
|
|
+ uint32_t socket;
|
|
+ uint8_t tso_en:1; /* TSO enable 0-off 1-on */
|
|
+ uint8_t rsv:7;
|
|
+ uint16_t *fcqs; /* Free completion queue. */
|
|
+ struct rte_mbuf *elts[]; /* Storage for queued packets, for free */
|
|
+};
|
|
+
|
|
+uint16_t xsc_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n);
|
|
+int xsc_txq_obj_new(struct xsc_dev *xdev, struct xsc_txq_data *txq_data,
|
|
+ uint64_t offloads, uint16_t idx);
|
|
+void xsc_txq_elts_alloc(struct xsc_txq_data *txq_data);
|
|
+void xsc_txq_obj_release(struct xsc_dev *xdev, struct xsc_txq_data *txq_data);
|
|
+void xsc_txq_elts_free(struct xsc_txq_data *txq_data);
|
|
+
|
|
+#endif /* _XSC_TX_H_ */
|
|
diff --git a/drivers/net/xsc/xsc_vfio.c b/drivers/net/xsc/xsc_vfio.c
|
|
new file mode 100644
|
|
index 0000000..d030019
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_vfio.c
|
|
@@ -0,0 +1,1128 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#include <sys/mman.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <fcntl.h>
|
|
+#include <linux/vfio.h>
|
|
+#include <sys/eventfd.h>
|
|
+#include <sys/ioctl.h>
|
|
+
|
|
+#include <rte_pci.h>
|
|
+#include <ethdev_pci.h>
|
|
+#include <rte_bus_pci.h>
|
|
+#include <rte_bitops.h>
|
|
+#include <rte_interrupts.h>
|
|
+
|
|
+#include "xsc_defs.h"
|
|
+#include "xsc_vfio_mbox.h"
|
|
+#include "xsc_ethdev.h"
|
|
+#include "xsc_rxtx.h"
|
|
+
|
|
+#define XSC_FEATURE_ONCHIP_FT_MASK RTE_BIT32(4)
|
|
+#define XSC_FEATURE_DMA_RW_TBL_MASK RTE_BIT32(8)
|
|
+#define XSC_FEATURE_PCT_EXP_MASK RTE_BIT32(19)
|
|
+#define XSC_HOST_PCIE_NO_DEFAULT 0
|
|
+#define XSC_SOC_PCIE_NO_DEFAULT 1
|
|
+
|
|
+#define XSC_SW2HW_MTU(mtu) ((mtu) + 14 + 4)
|
|
+#define XSC_SW2HW_RX_PKT_LEN(mtu) ((mtu) + 14 + 256)
|
|
+
|
|
+#define MAX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
|
|
+#define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \
|
|
+ sizeof(int) * (MAX_INTR_VEC_ID))
|
|
+
|
|
+enum xsc_port_status {
|
|
+ XSC_PORT_DOWN = 0,
|
|
+ XSC_PORT_UP = 1,
|
|
+};
|
|
+
|
|
+enum xsc_vector {
|
|
+ XSC_VEC_CMD = 0,
|
|
+ XSC_VEC_CMD_EVENT = 1,
|
|
+ XSC_EQ_VEC_COMP_BASE,
|
|
+};
|
|
+
|
|
+enum xsc_cq_type {
|
|
+ XSC_CQ_TYPE_NORMAL = 0,
|
|
+ XSC_CQ_TYPE_VIRTIO = 1,
|
|
+};
|
|
+
|
|
+struct xsc_vfio_cq {
|
|
+ const struct rte_memzone *mz;
|
|
+ struct xsc_dev *xdev;
|
|
+ uint32_t cqn;
|
|
+};
|
|
+
|
|
+struct xsc_vfio_qp {
|
|
+ const struct rte_memzone *mz;
|
|
+ struct xsc_dev *xdev;
|
|
+ uint32_t qpn;
|
|
+};
|
|
+
|
|
+static void
|
|
+xsc_vfio_pcie_no_init(struct xsc_hwinfo *hwinfo)
|
|
+{
|
|
+ uint func_id = hwinfo->func_id;
|
|
+
|
|
+ if (func_id >= hwinfo->pf0_vf_funcid_base &&
|
|
+ func_id <= hwinfo->pf0_vf_funcid_top)
|
|
+ hwinfo->pcie_no = hwinfo->pcie_host;
|
|
+ else if (func_id >= hwinfo->pf1_vf_funcid_base &&
|
|
+ func_id <= hwinfo->pf1_vf_funcid_top)
|
|
+ hwinfo->pcie_no = hwinfo->pcie_host;
|
|
+ else if (func_id >= hwinfo->pcie0_pf_funcid_base &&
|
|
+ func_id <= hwinfo->pcie0_pf_funcid_top)
|
|
+ hwinfo->pcie_no = XSC_HOST_PCIE_NO_DEFAULT;
|
|
+ else
|
|
+ hwinfo->pcie_no = XSC_SOC_PCIE_NO_DEFAULT;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_hwinfo_init(struct xsc_dev *xdev)
|
|
+{
|
|
+ int ret;
|
|
+ uint32_t feature;
|
|
+ int in_len, out_len, cmd_len;
|
|
+ struct xsc_cmd_query_hca_cap_mbox_in *in;
|
|
+ struct xsc_cmd_query_hca_cap_mbox_out *out;
|
|
+ struct xsc_cmd_hca_cap *hca_cap;
|
|
+ void *cmd_buf;
|
|
+
|
|
+ in_len = sizeof(struct xsc_cmd_query_hca_cap_mbox_in);
|
|
+ out_len = sizeof(struct xsc_cmd_query_hca_cap_mbox_out);
|
|
+ cmd_len = RTE_MAX(in_len, out_len);
|
|
+
|
|
+ cmd_buf = malloc(cmd_len);
|
|
+ if (cmd_buf == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc dev hwinfo cmd memory");
|
|
+ rte_errno = ENOMEM;
|
|
+ return -rte_errno;
|
|
+ }
|
|
+
|
|
+ in = cmd_buf;
|
|
+ memset(in, 0, cmd_len);
|
|
+ in->hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_QUERY_HCA_CAP);
|
|
+ in->hdr.ver = rte_cpu_to_be_16(XSC_CMD_QUERY_HCA_CAP_V1);
|
|
+ in->cpu_num = rte_cpu_to_be_16(2);
|
|
+ out = cmd_buf;
|
|
+
|
|
+ ret = xsc_vfio_mbox_exec(xdev, in, in_len, out, out_len);
|
|
+ if (ret != 0 || out->hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to get dev hwinfo, err=%d, out.status=%u",
|
|
+ ret, out->hdr.status);
|
|
+ rte_errno = ENOEXEC;
|
|
+ ret = -rte_errno;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ hca_cap = &out->hca_cap;
|
|
+ xdev->hwinfo.valid = 1;
|
|
+ xdev->hwinfo.func_id = rte_be_to_cpu_32(hca_cap->glb_func_id);
|
|
+ xdev->hwinfo.pcie_host = hca_cap->pcie_host;
|
|
+ xdev->hwinfo.mac_phy_port = hca_cap->mac_port;
|
|
+ xdev->hwinfo.funcid_to_logic_port_off = rte_be_to_cpu_16(hca_cap->funcid_to_logic_port);
|
|
+ xdev->hwinfo.raw_qp_id_base = rte_be_to_cpu_16(hca_cap->raweth_qp_id_base);
|
|
+ xdev->hwinfo.raw_rss_qp_id_base = rte_be_to_cpu_16(hca_cap->raweth_rss_qp_id_base);
|
|
+ xdev->hwinfo.pf0_vf_funcid_base = rte_be_to_cpu_16(hca_cap->pf0_vf_funcid_base);
|
|
+ xdev->hwinfo.pf0_vf_funcid_top = rte_be_to_cpu_16(hca_cap->pf0_vf_funcid_top);
|
|
+ xdev->hwinfo.pf1_vf_funcid_base = rte_be_to_cpu_16(hca_cap->pf1_vf_funcid_base);
|
|
+ xdev->hwinfo.pf1_vf_funcid_top = rte_be_to_cpu_16(hca_cap->pf1_vf_funcid_top);
|
|
+ xdev->hwinfo.pcie0_pf_funcid_base = rte_be_to_cpu_16(hca_cap->pcie0_pf_funcid_base);
|
|
+ xdev->hwinfo.pcie0_pf_funcid_top = rte_be_to_cpu_16(hca_cap->pcie0_pf_funcid_top);
|
|
+ xdev->hwinfo.pcie1_pf_funcid_base = rte_be_to_cpu_16(hca_cap->pcie1_pf_funcid_base);
|
|
+ xdev->hwinfo.pcie1_pf_funcid_top = rte_be_to_cpu_16(hca_cap->pcie1_pf_funcid_top);
|
|
+ xdev->hwinfo.lag_port_start = hca_cap->lag_logic_port_ofst;
|
|
+ xdev->hwinfo.raw_tpe_qp_num = rte_be_to_cpu_16(hca_cap->raw_tpe_qp_num);
|
|
+ xdev->hwinfo.send_seg_num = hca_cap->send_seg_num;
|
|
+ xdev->hwinfo.recv_seg_num = hca_cap->recv_seg_num;
|
|
+ feature = rte_be_to_cpu_32(hca_cap->feature_flag);
|
|
+ xdev->hwinfo.on_chip_tbl_vld = (feature & XSC_FEATURE_ONCHIP_FT_MASK) ? 1 : 0;
|
|
+ xdev->hwinfo.dma_rw_tbl_vld = (feature & XSC_FEATURE_DMA_RW_TBL_MASK) ? 1 : 0;
|
|
+ xdev->hwinfo.pct_compress_vld = (feature & XSC_FEATURE_PCT_EXP_MASK) ? 1 : 0;
|
|
+ xdev->hwinfo.chip_version = rte_be_to_cpu_32(hca_cap->chip_ver_l);
|
|
+ xdev->hwinfo.hca_core_clock = rte_be_to_cpu_32(hca_cap->hca_core_clock);
|
|
+ xdev->hwinfo.mac_bit = hca_cap->mac_bit;
|
|
+ xdev->hwinfo.msix_base = rte_be_to_cpu_16(hca_cap->msix_base);
|
|
+ xdev->hwinfo.msix_num = rte_be_to_cpu_16(hca_cap->msix_num);
|
|
+ xsc_vfio_pcie_no_init(&xdev->hwinfo);
|
|
+
|
|
+exit:
|
|
+ free(in);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_dev_open(struct xsc_dev *xdev)
|
|
+{
|
|
+ struct rte_pci_addr *addr = &xdev->pci_dev->addr;
|
|
+ struct xsc_vfio_priv *priv;
|
|
+
|
|
+ snprintf(xdev->name, PCI_PRI_STR_SIZE, PCI_PRI_FMT,
|
|
+ addr->domain, addr->bus, addr->devid, addr->function);
|
|
+
|
|
+ priv = rte_zmalloc(NULL, sizeof(*priv), RTE_CACHE_LINE_SIZE);
|
|
+ if (priv == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc xsc vfio priv");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ xdev->dev_priv = (void *)priv;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_bar_init(struct xsc_dev *xdev)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = rte_pci_map_device(xdev->pci_dev);
|
|
+ if (ret) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to map pci device");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ xdev->bar_len = xdev->pci_dev->mem_resource[0].len;
|
|
+ xdev->bar_addr = (void *)xdev->pci_dev->mem_resource[0].addr;
|
|
+ if (xdev->bar_addr == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to attach dev(%s) bar", xdev->pci_dev->device.name);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_dev_close(struct xsc_dev *xdev)
|
|
+{
|
|
+ struct xsc_vfio_priv *vfio_priv = (struct xsc_vfio_priv *)xdev->dev_priv;
|
|
+
|
|
+ xsc_vfio_mbox_destroy(vfio_priv->cmdq);
|
|
+ rte_free(vfio_priv);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_modify_link_status(struct xsc_dev *xdev, enum xsc_port_status status)
|
|
+{
|
|
+ struct xsc_cmd_set_port_admin_status_mbox_in in = { };
|
|
+ struct xsc_cmd_set_port_admin_status_mbox_out out = { };
|
|
+ int ret = 0;
|
|
+
|
|
+ in.hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_SET_PORT_ADMIN_STATUS);
|
|
+ in.admin_status = rte_cpu_to_be_16(status);
|
|
+
|
|
+ ret = xsc_vfio_mbox_exec(xdev, &in, sizeof(in), &out, sizeof(out));
|
|
+ if (ret != 0 || out.hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to set link status, ret=%d, status=%d",
|
|
+ ret, out.hdr.status);
|
|
+ return -ENOEXEC;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_set_link_up(struct xsc_dev *xdev)
|
|
+{
|
|
+ return xsc_vfio_modify_link_status(xdev, XSC_PORT_UP);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_set_link_down(struct xsc_dev *xdev)
|
|
+{
|
|
+ return xsc_vfio_modify_link_status(xdev, XSC_PORT_DOWN);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_get_link_info(struct xsc_dev *xdev, struct rte_eth_link *link)
|
|
+{
|
|
+ struct xsc_cmd_query_linkinfo_mbox_in in = { };
|
|
+ struct xsc_cmd_query_linkinfo_mbox_out out = { };
|
|
+ struct xsc_cmd_linkinfo linkinfo;
|
|
+ int ret;
|
|
+
|
|
+ in.hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_QUERY_LINK_INFO);
|
|
+ ret = xsc_vfio_mbox_exec(xdev, &in, sizeof(in), &out, sizeof(out));
|
|
+ if (ret != 0 || out.hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to get link info, ret=%d, status=%d",
|
|
+ ret, out.hdr.status);
|
|
+ return -ENOEXEC;
|
|
+ }
|
|
+
|
|
+ memcpy(&linkinfo, &out.ctx, sizeof(struct xsc_cmd_linkinfo));
|
|
+
|
|
+ link->link_speed = rte_be_to_cpu_32(linkinfo.linkspeed);
|
|
+ link->link_duplex = linkinfo.duplex;
|
|
+ link->link_autoneg = linkinfo.autoneg;
|
|
+
|
|
+ return 0;
|
|
+};
|
|
+
|
|
+static int
|
|
+xsc_vfio_link_update(struct xsc_dev *xdev, __rte_unused int wait_to_complete)
|
|
+{
|
|
+ int ret;
|
|
+ uint8_t linkup;
|
|
+ struct xsc_cmd_query_vport_state_in in = { };
|
|
+ struct xsc_cmd_query_vport_state_out out = { };
|
|
+ struct rte_eth_link *origin_link = &xdev->pf_dev_link;
|
|
+ struct rte_eth_link link;
|
|
+ uint16_t vport = 0;
|
|
+
|
|
+ in.hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_QUERY_VPORT_STATE);
|
|
+ in.vport_number = rte_cpu_to_be_16(vport);
|
|
+ ret = xsc_vfio_mbox_exec(xdev, &in, sizeof(in), &out, sizeof(out));
|
|
+ if (ret != 0 || out.hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to get port state, ret=%d, status=%d",
|
|
+ ret, out.hdr.status);
|
|
+ return -ENOEXEC;
|
|
+ }
|
|
+
|
|
+ linkup = out.state;
|
|
+ link.link_status = linkup ? XSC_PORT_UP : XSC_PORT_DOWN;
|
|
+
|
|
+ ret = xsc_vfio_get_link_info(xdev, &link);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = !memcmp(origin_link, &link, sizeof(struct rte_eth_link));
|
|
+ xdev->pf_dev_link = link;
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_destroy_qp(void *qp)
|
|
+{
|
|
+ int ret;
|
|
+ int in_len, out_len, cmd_len;
|
|
+ struct xsc_cmd_destroy_qp_mbox_in *in;
|
|
+ struct xsc_cmd_destroy_qp_mbox_out *out;
|
|
+ struct xsc_vfio_qp *data = (struct xsc_vfio_qp *)qp;
|
|
+ void *cmd_buf;
|
|
+
|
|
+ in_len = sizeof(struct xsc_cmd_destroy_qp_mbox_in);
|
|
+ out_len = sizeof(struct xsc_cmd_destroy_qp_mbox_out);
|
|
+ cmd_len = RTE_MAX(in_len, out_len);
|
|
+
|
|
+ cmd_buf = malloc(cmd_len);
|
|
+ if (cmd_buf == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc qp destroy cmd memory");
|
|
+ return -rte_errno;
|
|
+ }
|
|
+
|
|
+ in = cmd_buf;
|
|
+ memset(in, 0, cmd_len);
|
|
+ in->hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_DESTROY_QP);
|
|
+ in->qpn = rte_cpu_to_be_32(data->qpn);
|
|
+ out = cmd_buf;
|
|
+ ret = xsc_vfio_mbox_exec(data->xdev, in, in_len, out, out_len);
|
|
+ if (ret != 0 || out->hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to destroy qp, type=%d, err=%d, out.status=%u",
|
|
+ XSC_QUEUE_TYPE_RAW, ret, out->hdr.status);
|
|
+ rte_errno = ENOEXEC;
|
|
+ ret = -rte_errno;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ rte_memzone_free(data->mz);
|
|
+ rte_free(qp);
|
|
+
|
|
+exit:
|
|
+ free(cmd_buf);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_destroy_cq(void *cq)
|
|
+{
|
|
+ int ret;
|
|
+ int in_len, out_len, cmd_len;
|
|
+ struct xsc_cmd_destroy_cq_mbox_in *in;
|
|
+ struct xsc_cmd_destroy_cq_mbox_out *out;
|
|
+ struct xsc_vfio_cq *data = (struct xsc_vfio_cq *)cq;
|
|
+ void *cmd_buf;
|
|
+
|
|
+ in_len = sizeof(struct xsc_cmd_destroy_cq_mbox_in);
|
|
+ out_len = sizeof(struct xsc_cmd_destroy_cq_mbox_out);
|
|
+ cmd_len = RTE_MAX(in_len, out_len);
|
|
+
|
|
+ cmd_buf = malloc(cmd_len);
|
|
+ if (cmd_buf == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc cq destroy cmd memory");
|
|
+ return -rte_errno;
|
|
+ }
|
|
+
|
|
+ in = cmd_buf;
|
|
+ memset(in, 0, cmd_len);
|
|
+
|
|
+ in->hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_DESTROY_CQ);
|
|
+ in->cqn = rte_cpu_to_be_32(data->cqn);
|
|
+ out = cmd_buf;
|
|
+ ret = xsc_vfio_mbox_exec(data->xdev, in, in_len, out, out_len);
|
|
+ if (ret != 0 || out->hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to destroy cq, type=%d, err=%d, out.status=%u",
|
|
+ XSC_QUEUE_TYPE_RAW, ret, out->hdr.status);
|
|
+ rte_errno = ENOEXEC;
|
|
+ ret = -rte_errno;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ rte_memzone_free(data->mz);
|
|
+ rte_free(cq);
|
|
+
|
|
+exit:
|
|
+ free(cmd_buf);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_set_mtu(struct xsc_dev *xdev, uint16_t mtu)
|
|
+{
|
|
+ struct xsc_cmd_set_mtu_mbox_in in = { };
|
|
+ struct xsc_cmd_set_mtu_mbox_out out = { };
|
|
+ int ret;
|
|
+
|
|
+ in.hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_SET_MTU);
|
|
+ in.mtu = rte_cpu_to_be_16(XSC_SW2HW_MTU(mtu));
|
|
+ in.rx_buf_sz_min = rte_cpu_to_be_16(XSC_SW2HW_RX_PKT_LEN(mtu));
|
|
+ in.mac_port = (uint8_t)xdev->hwinfo.mac_phy_port;
|
|
+
|
|
+ ret = xsc_vfio_mbox_exec(xdev, &in, sizeof(in), &out, sizeof(out));
|
|
+ if (ret != 0 || out.hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to set mtu, port=%d, err=%d, out.status=%u",
|
|
+ xdev->port_id, ret, out.hdr.status);
|
|
+ rte_errno = ENOEXEC;
|
|
+ ret = -rte_errno;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_get_mac(struct xsc_dev *xdev, uint8_t *mac)
|
|
+{
|
|
+ struct xsc_cmd_query_eth_mac_mbox_in in = { };
|
|
+ struct xsc_cmd_query_eth_mac_mbox_out out = { };
|
|
+ int ret;
|
|
+
|
|
+ in.hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_QUERY_ETH_MAC);
|
|
+ ret = xsc_vfio_mbox_exec(xdev, &in, sizeof(in), &out, sizeof(out));
|
|
+ if (ret != 0 || out.hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to get mtu, port=%d, err=%d, out.status=%u",
|
|
+ xdev->port_id, ret, out.hdr.status);
|
|
+ rte_errno = ENOEXEC;
|
|
+ return -rte_errno;
|
|
+ }
|
|
+
|
|
+ memcpy(mac, out.mac, RTE_ETHER_ADDR_LEN);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_modify_qp_status(struct xsc_dev *xdev, uint32_t qpn, int num, int opcode)
|
|
+{
|
|
+ int i, ret;
|
|
+ int in_len, out_len, cmd_len;
|
|
+ struct xsc_cmd_modify_qp_mbox_in *in;
|
|
+ struct xsc_cmd_modify_qp_mbox_out *out;
|
|
+ void *cmd_buf;
|
|
+
|
|
+ in_len = sizeof(struct xsc_cmd_modify_qp_mbox_in);
|
|
+ out_len = sizeof(struct xsc_cmd_modify_qp_mbox_out);
|
|
+ cmd_len = RTE_MAX(in_len, out_len);
|
|
+
|
|
+ cmd_buf = malloc(cmd_len);
|
|
+ if (cmd_buf == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc cmdq qp modify status");
|
|
+ rte_errno = ENOMEM;
|
|
+ return -rte_errno;
|
|
+ }
|
|
+
|
|
+ in = cmd_buf;
|
|
+ memset(in, 0, cmd_len);
|
|
+ out = cmd_buf;
|
|
+
|
|
+ for (i = 0; i < num; i++) {
|
|
+ in->hdr.opcode = rte_cpu_to_be_16(opcode);
|
|
+ in->hdr.ver = 0;
|
|
+ in->qpn = rte_cpu_to_be_32(qpn + i);
|
|
+ in->no_need_wait = 1;
|
|
+
|
|
+ ret = xsc_vfio_mbox_exec(xdev, in, in_len, out, out_len);
|
|
+ if (ret != 0 || out->hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Modify qp status failed, qpn=%u, err=%d, out.status=%u",
|
|
+ qpn + i, ret, out->hdr.status);
|
|
+ rte_errno = ENOEXEC;
|
|
+ ret = -rte_errno;
|
|
+ goto exit;
|
|
+ }
|
|
+ }
|
|
+
|
|
+exit:
|
|
+ free(cmd_buf);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_modify_qp_qostree(struct xsc_dev *xdev, uint16_t qpn)
|
|
+{
|
|
+ int ret;
|
|
+ int in_len, out_len, cmd_len;
|
|
+ struct xsc_cmd_modify_raw_qp_mbox_in *in;
|
|
+ struct xsc_cmd_modify_raw_qp_mbox_out *out;
|
|
+ void *cmd_buf;
|
|
+
|
|
+ in_len = sizeof(struct xsc_cmd_modify_raw_qp_mbox_in);
|
|
+ out_len = sizeof(struct xsc_cmd_modify_raw_qp_mbox_out);
|
|
+ cmd_len = RTE_MAX(in_len, out_len);
|
|
+
|
|
+ cmd_buf = malloc(cmd_len);
|
|
+ if (cmd_buf == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc cmdq qp modify qostree");
|
|
+ rte_errno = ENOMEM;
|
|
+ return -rte_errno;
|
|
+ }
|
|
+
|
|
+ in = cmd_buf;
|
|
+ memset(in, 0, cmd_len);
|
|
+ in->hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_MODIFY_RAW_QP);
|
|
+ in->req.prio = 0;
|
|
+ in->req.qp_out_port = 0xFF;
|
|
+ in->req.lag_id = rte_cpu_to_be_16(xdev->hwinfo.lag_id);
|
|
+ in->req.func_id = rte_cpu_to_be_16(xdev->hwinfo.func_id);
|
|
+ in->req.dma_direct = 0;
|
|
+ in->req.qpn = rte_cpu_to_be_16(qpn);
|
|
+ out = cmd_buf;
|
|
+
|
|
+ ret = xsc_vfio_mbox_exec(xdev, in, in_len, out, out_len);
|
|
+ if (ret != 0 || out->hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Filed to modify qp qostree, qpn=%d, err=%d, out.status=%u",
|
|
+ qpn, ret, out->hdr.status);
|
|
+ rte_errno = ENOEXEC;
|
|
+ ret = -rte_errno;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+exit:
|
|
+ free(cmd_buf);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_rx_cq_create(struct xsc_dev *xdev, struct xsc_rx_cq_params *cq_params,
|
|
+ struct xsc_rx_cq_info *cq_info)
|
|
+{
|
|
+ int ret;
|
|
+ int pa_len;
|
|
+ uint16_t i;
|
|
+ uint16_t pa_num;
|
|
+ uint8_t log_cq_sz;
|
|
+ uint16_t cqe_n;
|
|
+ uint32_t cqe_total_sz;
|
|
+ int in_len, out_len, cmd_len;
|
|
+ char name[RTE_ETH_NAME_MAX_LEN] = { 0 };
|
|
+ uint16_t port_id = cq_params->port_id;
|
|
+ uint16_t idx = cq_params->qp_id;
|
|
+ struct xsc_vfio_cq *cq;
|
|
+ const struct rte_memzone *cq_pas = NULL;
|
|
+ struct xsc_cqe *cqes;
|
|
+ struct xsc_cmd_create_cq_mbox_in *in = NULL;
|
|
+ struct xsc_cmd_create_cq_mbox_out *out = NULL;
|
|
+ void *cmd_buf;
|
|
+
|
|
+ cqe_n = cq_params->wqe_s;
|
|
+ log_cq_sz = rte_log2_u32(cqe_n);
|
|
+ cqe_total_sz = cqe_n * sizeof(struct xsc_cqe);
|
|
+ pa_num = (cqe_total_sz + XSC_PAGE_SIZE - 1) / XSC_PAGE_SIZE;
|
|
+ pa_len = sizeof(uint64_t) * pa_num;
|
|
+ in_len = sizeof(struct xsc_cmd_create_cq_mbox_in) + pa_len;
|
|
+ out_len = sizeof(struct xsc_cmd_create_cq_mbox_out);
|
|
+ cmd_len = RTE_MAX(in_len, out_len);
|
|
+
|
|
+ cq = rte_zmalloc(NULL, sizeof(struct xsc_vfio_cq), 0);
|
|
+ if (cq == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc rx cq memory");
|
|
+ return -rte_errno;
|
|
+ }
|
|
+
|
|
+ cmd_buf = malloc(cmd_len);
|
|
+ if (cmd_buf == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc rx cq exec cmd memory");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ in = cmd_buf;
|
|
+ memset(in, 0, cmd_len);
|
|
+ in->hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_CREATE_CQ);
|
|
+ in->ctx.eqn = 0;
|
|
+ in->ctx.pa_num = rte_cpu_to_be_16(pa_num);
|
|
+ in->ctx.glb_func_id = rte_cpu_to_be_16((uint16_t)xdev->hwinfo.func_id);
|
|
+ in->ctx.log_cq_sz = log_cq_sz;
|
|
+ in->ctx.cq_type = XSC_CQ_TYPE_NORMAL;
|
|
+
|
|
+ snprintf(name, sizeof(name), "mz_cqe_mem_rx_%u_%u", port_id, idx);
|
|
+ cq_pas = rte_memzone_reserve_aligned(name,
|
|
+ (XSC_PAGE_SIZE * pa_num),
|
|
+ SOCKET_ID_ANY,
|
|
+ 0, XSC_PAGE_SIZE);
|
|
+ if (cq_pas == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc rx cq pas memory");
|
|
+ goto error;
|
|
+ }
|
|
+ cq->mz = cq_pas;
|
|
+
|
|
+ for (i = 0; i < pa_num; i++)
|
|
+ in->pas[i] = rte_cpu_to_be_64(cq_pas->iova + i * XSC_PAGE_SIZE);
|
|
+
|
|
+ out = cmd_buf;
|
|
+ ret = xsc_vfio_mbox_exec(xdev, in, in_len, out, out_len);
|
|
+ if (ret != 0 || out->hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR,
|
|
+ "Failed to exec rx cq create cmd, port id=%d, err=%d, out.status=%u",
|
|
+ port_id, ret, out->hdr.status);
|
|
+ rte_errno = ENOEXEC;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ cq_info->cq = (void *)cq;
|
|
+ cq_info->cqe_n = log_cq_sz;
|
|
+ cqes = (struct xsc_cqe *)cq_pas->addr;
|
|
+ for (i = 0; i < (1 << cq_info->cqe_n); i++)
|
|
+ ((volatile struct xsc_cqe *)(cqes + i))->owner = 1;
|
|
+ cq_info->cqes = cqes;
|
|
+ if (xsc_dev_is_vf(xdev))
|
|
+ cq_info->cq_db = (uint32_t *)((uint8_t *)xdev->bar_addr + XSC_VF_CQ_DB_ADDR);
|
|
+ else
|
|
+ cq_info->cq_db = (uint32_t *)((uint8_t *)xdev->bar_addr + XSC_PF_CQ_DB_ADDR);
|
|
+ cq_info->cqn = rte_be_to_cpu_32(out->cqn);
|
|
+ cq->cqn = cq_info->cqn;
|
|
+ cq->xdev = xdev;
|
|
+ PMD_DRV_LOG(INFO, "Port id=%d, Rx cqe_n:%d, cqn:%u",
|
|
+ port_id, cq_info->cqe_n, cq_info->cqn);
|
|
+
|
|
+ free(cmd_buf);
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ free(cmd_buf);
|
|
+ rte_memzone_free(cq_pas);
|
|
+ rte_free(cq);
|
|
+ return -rte_errno;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_tx_cq_create(struct xsc_dev *xdev, struct xsc_tx_cq_params *cq_params,
|
|
+ struct xsc_tx_cq_info *cq_info)
|
|
+{
|
|
+ struct xsc_vfio_cq *cq = NULL;
|
|
+ char name[RTE_ETH_NAME_MAX_LEN] = {0};
|
|
+ struct xsc_cmd_create_cq_mbox_in *in = NULL;
|
|
+ struct xsc_cmd_create_cq_mbox_out *out = NULL;
|
|
+ const struct rte_memzone *cq_pas = NULL;
|
|
+ struct xsc_cqe *cqes;
|
|
+ int in_len, out_len, cmd_len;
|
|
+ uint16_t pa_num;
|
|
+ uint16_t log_cq_sz;
|
|
+ int ret = 0;
|
|
+ int cqe_s = 1 << cq_params->elts_n;
|
|
+ uint64_t iova;
|
|
+ int i;
|
|
+ void *cmd_buf = NULL;
|
|
+
|
|
+ cq = rte_zmalloc(NULL, sizeof(struct xsc_vfio_cq), 0);
|
|
+ if (cq == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc tx cq memory");
|
|
+ return -rte_errno;
|
|
+ }
|
|
+
|
|
+ log_cq_sz = rte_log2_u32(cqe_s);
|
|
+ pa_num = (((1 << log_cq_sz) * sizeof(struct xsc_cqe)) / XSC_PAGE_SIZE);
|
|
+
|
|
+ snprintf(name, sizeof(name), "mz_cqe_mem_tx_%u_%u", cq_params->port_id, cq_params->qp_id);
|
|
+ cq_pas = rte_memzone_reserve_aligned(name,
|
|
+ (XSC_PAGE_SIZE * pa_num),
|
|
+ SOCKET_ID_ANY,
|
|
+ 0, XSC_PAGE_SIZE);
|
|
+ if (cq_pas == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc tx cq pas memory");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ cq->mz = cq_pas;
|
|
+ in_len = (sizeof(struct xsc_cmd_create_cq_mbox_in) + (pa_num * sizeof(uint64_t)));
|
|
+ out_len = sizeof(struct xsc_cmd_create_cq_mbox_out);
|
|
+ cmd_len = RTE_MAX(in_len, out_len);
|
|
+ cmd_buf = malloc(cmd_len);
|
|
+ if (cmd_buf == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc tx cq exec cmd memory");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ in = cmd_buf;
|
|
+ memset(in, 0, cmd_len);
|
|
+
|
|
+ in->hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_CREATE_CQ);
|
|
+ in->ctx.eqn = 0;
|
|
+ in->ctx.pa_num = rte_cpu_to_be_16(pa_num);
|
|
+ in->ctx.glb_func_id = rte_cpu_to_be_16((uint16_t)xdev->hwinfo.func_id);
|
|
+ in->ctx.log_cq_sz = rte_log2_u32(cqe_s);
|
|
+ in->ctx.cq_type = XSC_CQ_TYPE_NORMAL;
|
|
+ iova = cq->mz->iova;
|
|
+ for (i = 0; i < pa_num; i++)
|
|
+ in->pas[i] = rte_cpu_to_be_64(iova + i * XSC_PAGE_SIZE);
|
|
+
|
|
+ out = cmd_buf;
|
|
+ ret = xsc_vfio_mbox_exec(xdev, in, in_len, out, out_len);
|
|
+ if (ret != 0 || out->hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to create tx cq, port id=%u, err=%d, out.status=%u",
|
|
+ cq_params->port_id, ret, out->hdr.status);
|
|
+ rte_errno = ENOEXEC;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ cq->cqn = rte_be_to_cpu_32(out->cqn);
|
|
+ cq->xdev = xdev;
|
|
+
|
|
+ cq_info->cq = cq;
|
|
+ cqes = (struct xsc_cqe *)((uint8_t *)cq->mz->addr);
|
|
+ if (xsc_dev_is_vf(xdev))
|
|
+ cq_info->cq_db = (uint32_t *)((uint8_t *)xdev->bar_addr + XSC_VF_CQ_DB_ADDR);
|
|
+ else
|
|
+ cq_info->cq_db = (uint32_t *)((uint8_t *)xdev->bar_addr + XSC_PF_CQ_DB_ADDR);
|
|
+ cq_info->cqn = cq->cqn;
|
|
+ cq_info->cqe_s = cqe_s;
|
|
+ cq_info->cqe_n = log_cq_sz;
|
|
+
|
|
+ for (i = 0; i < cq_info->cqe_s; i++)
|
|
+ ((volatile struct xsc_cqe *)(cqes + i))->owner = 1;
|
|
+ cq_info->cqes = cqes;
|
|
+
|
|
+ free(cmd_buf);
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ free(cmd_buf);
|
|
+ rte_memzone_free(cq_pas);
|
|
+ rte_free(cq);
|
|
+ return -rte_errno;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_tx_qp_create(struct xsc_dev *xdev, struct xsc_tx_qp_params *qp_params,
|
|
+ struct xsc_tx_qp_info *qp_info)
|
|
+{
|
|
+ struct xsc_cmd_create_qp_mbox_in *in = NULL;
|
|
+ struct xsc_cmd_create_qp_mbox_out *out = NULL;
|
|
+ const struct rte_memzone *qp_pas = NULL;
|
|
+ struct xsc_vfio_cq *cq = (struct xsc_vfio_cq *)qp_params->cq;
|
|
+ struct xsc_vfio_qp *qp = NULL;
|
|
+ int in_len, out_len, cmd_len;
|
|
+ int ret = 0;
|
|
+ uint32_t send_ds_num = xdev->hwinfo.send_seg_num;
|
|
+ int wqe_s = 1 << qp_params->elts_n;
|
|
+ uint16_t pa_num;
|
|
+ uint8_t log_ele = 0;
|
|
+ uint32_t log_rq_sz = 0;
|
|
+ uint32_t log_sq_sz = 0;
|
|
+ int i;
|
|
+ uint64_t iova;
|
|
+ char name[RTE_ETH_NAME_MAX_LEN] = {0};
|
|
+ void *cmd_buf = NULL;
|
|
+
|
|
+ qp = rte_zmalloc(NULL, sizeof(struct xsc_vfio_qp), 0);
|
|
+ if (qp == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc tx qp memory");
|
|
+ return -rte_errno;
|
|
+ }
|
|
+
|
|
+ log_sq_sz = rte_log2_u32(wqe_s * send_ds_num);
|
|
+ log_ele = rte_log2_u32(sizeof(struct xsc_wqe_data_seg));
|
|
+ pa_num = ((1 << (log_rq_sz + log_sq_sz + log_ele))) / XSC_PAGE_SIZE;
|
|
+
|
|
+ snprintf(name, sizeof(name), "mz_wqe_mem_tx_%u_%u", qp_params->port_id, qp_params->qp_id);
|
|
+ qp_pas = rte_memzone_reserve_aligned(name,
|
|
+ (XSC_PAGE_SIZE * pa_num),
|
|
+ SOCKET_ID_ANY,
|
|
+ 0, XSC_PAGE_SIZE);
|
|
+ if (qp_pas == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc tx qp pas memory");
|
|
+ goto error;
|
|
+ }
|
|
+ qp->mz = qp_pas;
|
|
+
|
|
+ in_len = (sizeof(struct xsc_cmd_create_qp_mbox_in) + (pa_num * sizeof(uint64_t)));
|
|
+ out_len = sizeof(struct xsc_cmd_create_qp_mbox_out);
|
|
+ cmd_len = RTE_MAX(in_len, out_len);
|
|
+ cmd_buf = malloc(cmd_len);
|
|
+ if (cmd_buf == NULL) {
|
|
+ rte_errno = ENOMEM;
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc tx qp exec cmd memory");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ in = cmd_buf;
|
|
+ memset(in, 0, cmd_len);
|
|
+
|
|
+ in->hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_CREATE_QP);
|
|
+ in->req.input_qpn = 0;
|
|
+ in->req.pa_num = rte_cpu_to_be_16(pa_num);
|
|
+ in->req.qp_type = XSC_QUEUE_TYPE_RAW_TX;
|
|
+ in->req.log_sq_sz = log_sq_sz;
|
|
+ in->req.log_rq_sz = log_rq_sz;
|
|
+ in->req.dma_direct = 0;
|
|
+ in->req.pdn = 0;
|
|
+ in->req.cqn_send = rte_cpu_to_be_16((uint16_t)cq->cqn);
|
|
+ in->req.cqn_recv = 0;
|
|
+ in->req.glb_funcid = rte_cpu_to_be_16((uint16_t)xdev->hwinfo.func_id);
|
|
+ iova = qp->mz->iova;
|
|
+ for (i = 0; i < pa_num; i++)
|
|
+ in->req.pas[i] = rte_cpu_to_be_64(iova + i * XSC_PAGE_SIZE);
|
|
+
|
|
+ out = cmd_buf;
|
|
+ ret = xsc_vfio_mbox_exec(xdev, in, in_len, out, out_len);
|
|
+ if (ret != 0 || out->hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to create tx qp, port id=%u, err=%d, out.status=%u",
|
|
+ qp_params->port_id, ret, out->hdr.status);
|
|
+ rte_errno = ENOEXEC;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ qp->qpn = rte_be_to_cpu_32(out->qpn);
|
|
+ qp->xdev = xdev;
|
|
+
|
|
+ qp_info->qp = qp;
|
|
+ qp_info->qpn = qp->qpn;
|
|
+ qp_info->wqes = (struct xsc_wqe *)qp->mz->addr;
|
|
+ qp_info->wqe_n = rte_log2_u32(wqe_s);
|
|
+
|
|
+ if (xsc_dev_is_vf(xdev))
|
|
+ qp_info->qp_db = (uint32_t *)((uint8_t *)xdev->bar_addr + XSC_VF_TX_DB_ADDR);
|
|
+ else
|
|
+ qp_info->qp_db = (uint32_t *)((uint8_t *)xdev->bar_addr + XSC_PF_TX_DB_ADDR);
|
|
+
|
|
+ free(cmd_buf);
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ free(cmd_buf);
|
|
+ rte_memzone_free(qp_pas);
|
|
+ rte_free(qp);
|
|
+ return -rte_errno;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_irq_info_get(struct rte_intr_handle *intr_handle)
|
|
+{
|
|
+ struct vfio_irq_info irq = { .argsz = sizeof(irq) };
|
|
+ int rc, vfio_dev_fd;
|
|
+
|
|
+ irq.index = VFIO_PCI_MSIX_IRQ_INDEX;
|
|
+
|
|
+ vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
|
|
+ rc = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
|
|
+ if (rc < 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to get IRQ info rc=%d errno=%d", rc, errno);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ PMD_DRV_LOG(INFO, "Flags=0x%x index=0x%x count=0x%x max_intr_vec_id=0x%x",
|
|
+ irq.flags, irq.index, irq.count, MAX_INTR_VEC_ID);
|
|
+
|
|
+ if (rte_intr_max_intr_set(intr_handle, irq.count))
|
|
+ return -1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_irq_init(struct rte_intr_handle *intr_handle)
|
|
+{
|
|
+ char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
|
|
+ struct vfio_irq_set *irq_set;
|
|
+ int len, rc, vfio_dev_fd;
|
|
+ int32_t *fd_ptr;
|
|
+ uint32_t i;
|
|
+
|
|
+ if (rte_intr_max_intr_get(intr_handle) > MAX_INTR_VEC_ID) {
|
|
+ PMD_DRV_LOG(ERR, "Max_intr=%d greater than MAX_INTR_VEC_ID=%d",
|
|
+ rte_intr_max_intr_get(intr_handle),
|
|
+ MAX_INTR_VEC_ID);
|
|
+ return -ERANGE;
|
|
+ }
|
|
+
|
|
+ len = sizeof(struct vfio_irq_set) +
|
|
+ sizeof(int32_t) * rte_intr_max_intr_get(intr_handle);
|
|
+
|
|
+ irq_set = (struct vfio_irq_set *)irq_set_buf;
|
|
+ irq_set->argsz = len;
|
|
+ irq_set->start = 0;
|
|
+ irq_set->count = 10;
|
|
+ irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
|
|
+ VFIO_IRQ_SET_ACTION_TRIGGER;
|
|
+ irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
|
|
+
|
|
+ fd_ptr = (int32_t *)&irq_set->data[0];
|
|
+ for (i = 0; i < irq_set->count; i++)
|
|
+ fd_ptr[i] = -1;
|
|
+
|
|
+ vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
|
|
+ rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
|
|
+ if (rc)
|
|
+ PMD_DRV_LOG(ERR, "Failed to set irqs vector rc=%d", rc);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_irq_config(struct rte_intr_handle *intr_handle, unsigned int vec)
|
|
+{
|
|
+ char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
|
|
+ struct vfio_irq_set *irq_set;
|
|
+ int len, rc, vfio_dev_fd;
|
|
+ int32_t *fd_ptr;
|
|
+
|
|
+ if (vec > (uint32_t)rte_intr_max_intr_get(intr_handle)) {
|
|
+ PMD_DRV_LOG(INFO, "Vector=%d greater than max_intr=%d", vec,
|
|
+ rte_intr_max_intr_get(intr_handle));
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ len = sizeof(struct vfio_irq_set) + sizeof(int32_t);
|
|
+
|
|
+ irq_set = (struct vfio_irq_set *)irq_set_buf;
|
|
+ irq_set->argsz = len;
|
|
+
|
|
+ irq_set->start = vec;
|
|
+ irq_set->count = 1;
|
|
+ irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
|
|
+ VFIO_IRQ_SET_ACTION_TRIGGER;
|
|
+ irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
|
|
+
|
|
+ /* Use vec fd to set interrupt vectors */
|
|
+ fd_ptr = (int32_t *)&irq_set->data[0];
|
|
+ fd_ptr[0] = rte_intr_efds_index_get(intr_handle, vec);
|
|
+
|
|
+ vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
|
|
+ rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
|
|
+ if (rc)
|
|
+ PMD_DRV_LOG(INFO, "Failed to set_irqs vector=0x%x rc=%d", vec, rc);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_irq_register(struct rte_intr_handle *intr_handle,
|
|
+ rte_intr_callback_fn cb, void *data, unsigned int vec)
|
|
+{
|
|
+ struct rte_intr_handle *tmp_handle;
|
|
+ uint32_t nb_efd, tmp_nb_efd;
|
|
+ int rc, fd;
|
|
+
|
|
+ if (rte_intr_max_intr_get(intr_handle) == 0) {
|
|
+ xsc_vfio_irq_info_get(intr_handle);
|
|
+ xsc_vfio_irq_init(intr_handle);
|
|
+ }
|
|
+
|
|
+ if (vec > (uint32_t)rte_intr_max_intr_get(intr_handle)) {
|
|
+ PMD_DRV_LOG(INFO, "Vector=%d greater than max_intr=%d", vec,
|
|
+ rte_intr_max_intr_get(intr_handle));
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ tmp_handle = intr_handle;
|
|
+ /* Create new eventfd for interrupt vector */
|
|
+ fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
|
+ if (fd == -1)
|
|
+ return -ENODEV;
|
|
+
|
|
+ if (rte_intr_fd_set(tmp_handle, fd))
|
|
+ return errno;
|
|
+
|
|
+ /* Register vector interrupt callback */
|
|
+ rc = rte_intr_callback_register(tmp_handle, cb, data);
|
|
+ if (rc) {
|
|
+ PMD_DRV_LOG(INFO, "Failed to register vector:0x%x irq callback.", vec);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ rte_intr_efds_index_set(intr_handle, vec, fd);
|
|
+ nb_efd = (vec > (uint32_t)rte_intr_nb_efd_get(intr_handle)) ?
|
|
+ vec : (uint32_t)rte_intr_nb_efd_get(intr_handle);
|
|
+ rte_intr_nb_efd_set(intr_handle, nb_efd);
|
|
+
|
|
+ tmp_nb_efd = rte_intr_nb_efd_get(intr_handle) + 1;
|
|
+ if (tmp_nb_efd > (uint32_t)rte_intr_max_intr_get(intr_handle))
|
|
+ rte_intr_max_intr_set(intr_handle, tmp_nb_efd);
|
|
+
|
|
+ PMD_DRV_LOG(INFO, "Enable vector:0x%x for vfio (efds: %d, max:%d)", vec,
|
|
+ rte_intr_nb_efd_get(intr_handle),
|
|
+ rte_intr_max_intr_get(intr_handle));
|
|
+
|
|
+ /* Enable MSIX vectors to VFIO */
|
|
+ return xsc_vfio_irq_config(intr_handle, vec);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_msix_enable(struct xsc_dev *xdev)
|
|
+{
|
|
+ struct xsc_cmd_msix_table_info_mbox_in in = { };
|
|
+ struct xsc_cmd_msix_table_info_mbox_out out = { };
|
|
+ int ret;
|
|
+
|
|
+ in.hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_ENABLE_MSIX);
|
|
+ ret = xsc_vfio_mbox_exec(xdev, &in, sizeof(in), &out, sizeof(out));
|
|
+ if (ret != 0 || out.hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to enable msix, ret=%d, stats=%d",
|
|
+ ret, out.hdr.status);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ rte_write32(xdev->hwinfo.msix_base,
|
|
+ (uint8_t *)xdev->bar_addr + XSC_HIF_CMDQM_VECTOR_ID_MEM_ADDR);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_event_get(struct xsc_dev *xdev)
|
|
+{
|
|
+ int ret;
|
|
+ struct xsc_cmd_event_query_type_mbox_in in = { };
|
|
+ struct xsc_cmd_event_query_type_mbox_out out = { };
|
|
+
|
|
+ in.hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_QUERY_EVENT_TYPE);
|
|
+ ret = xsc_vfio_mbox_exec(xdev, &in, sizeof(in), &out, sizeof(out));
|
|
+ if (ret != 0 || out.hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to query event type, ret=%d, stats=%d",
|
|
+ ret, out.hdr.status);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return out.ctx.resp_event_type;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_intr_handler_install(struct xsc_dev *xdev, rte_intr_callback_fn cb, void *cb_arg)
|
|
+{
|
|
+ int ret;
|
|
+ struct rte_intr_handle *intr_handle = xdev->pci_dev->intr_handle;
|
|
+
|
|
+ /* xsc_register_irq(intr_handle, xsc_vfio_dummy_handler, xdev, XSC_VEC_CMD); */
|
|
+ ret = xsc_vfio_irq_register(intr_handle, cb, cb_arg, XSC_VEC_CMD_EVENT);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to register vfio irq, ret=%d", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = xsc_vfio_msix_enable(xdev);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to enable vfio msix, ret=%d", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_intr_handler_uninstall(struct xsc_dev *xdev)
|
|
+{
|
|
+ rte_intr_instance_free(xdev->intr_handle);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_function_reset(struct xsc_dev *xdev)
|
|
+{
|
|
+ struct xsc_cmd_function_reset_mbox_in in = { };
|
|
+ struct xsc_cmd_function_reset_mbox_out out = { };
|
|
+ uint16_t func_id = (uint16_t)xdev->hwinfo.func_id;
|
|
+ int ret;
|
|
+
|
|
+ in.hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_FUNCTION_RESET);
|
|
+ in.glb_func_id = rte_cpu_to_be_16(func_id);
|
|
+
|
|
+ ret = xsc_vfio_mbox_exec(xdev, &in, sizeof(in), &out, sizeof(out));
|
|
+ if (ret != 0 || out.hdr.status != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to reset function, funcid=%u, ret=%d, stats=%d",
|
|
+ func_id, ret, out.hdr.status);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_vfio_dev_init(struct xsc_dev *xdev)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = xsc_vfio_dev_open(xdev);
|
|
+ if (ret != 0)
|
|
+ goto open_fail;
|
|
+
|
|
+ ret = xsc_vfio_bar_init(xdev);
|
|
+ if (ret != 0)
|
|
+ goto init_fail;
|
|
+
|
|
+ if (xsc_vfio_mbox_init(xdev) != 0)
|
|
+ goto init_fail;
|
|
+
|
|
+ ret = xsc_vfio_hwinfo_init(xdev);
|
|
+ if (ret != 0)
|
|
+ goto init_fail;
|
|
+
|
|
+ ret = xsc_vfio_function_reset(xdev);
|
|
+ if (ret != 0)
|
|
+ goto init_fail;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+init_fail:
|
|
+ xsc_vfio_dev_close(xdev);
|
|
+
|
|
+open_fail:
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static struct xsc_dev_ops *xsc_vfio_ops = &(struct xsc_dev_ops) {
|
|
+ .kdrv = (1 << RTE_PCI_KDRV_VFIO) | (1 << RTE_PCI_KDRV_IGB_UIO),
|
|
+ .dev_init = xsc_vfio_dev_init,
|
|
+ .dev_close = xsc_vfio_dev_close,
|
|
+ .set_link_up = xsc_vfio_set_link_up,
|
|
+ .set_link_down = xsc_vfio_set_link_down,
|
|
+ .link_update = xsc_vfio_link_update,
|
|
+ .set_mtu = xsc_vfio_set_mtu,
|
|
+ .get_mac = xsc_vfio_get_mac,
|
|
+ .destroy_qp = xsc_vfio_destroy_qp,
|
|
+ .destroy_cq = xsc_vfio_destroy_cq,
|
|
+ .modify_qp_status = xsc_vfio_modify_qp_status,
|
|
+ .modify_qp_qostree = xsc_vfio_modify_qp_qostree,
|
|
+ .rx_cq_create = xsc_vfio_rx_cq_create,
|
|
+ .tx_cq_create = xsc_vfio_tx_cq_create,
|
|
+ .tx_qp_create = xsc_vfio_tx_qp_create,
|
|
+ .mailbox_exec = xsc_vfio_mbox_exec,
|
|
+ .intr_event_get = xsc_vfio_event_get,
|
|
+ .intr_handler_install = xsc_vfio_intr_handler_install,
|
|
+ .intr_handler_uninstall = xsc_vfio_intr_handler_uninstall,
|
|
+};
|
|
+
|
|
+RTE_INIT(xsc_vfio_ops_reg)
|
|
+{
|
|
+ xsc_dev_ops_register(xsc_vfio_ops);
|
|
+}
|
|
diff --git a/drivers/net/xsc/xsc_vfio_mbox.c b/drivers/net/xsc/xsc_vfio_mbox.c
|
|
new file mode 100644
|
|
index 0000000..ec1311a
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_vfio_mbox.c
|
|
@@ -0,0 +1,691 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+#include <rte_malloc.h>
|
|
+#include <rte_version.h>
|
|
+
|
|
+#include "xsc_vfio_mbox.h"
|
|
+#include "xsc_log.h"
|
|
+
|
|
+#define XSC_MBOX_BUF_NUM 2048
|
|
+#define XSC_MBOX_BUF_CACHE_SIZE 256
|
|
+#define XSC_CMDQ_DEPTH_LOG 5
|
|
+#define XSC_CMDQ_ELEMENT_SIZE_LOG 6
|
|
+#define XSC_CMDQ_REQ_TYPE 7
|
|
+#define XSC_CMDQ_WAIT_TIMEOUT 10
|
|
+#define XSC_CMDQ_WAIT_DELAY_MS 100
|
|
+#define XSC_CMD_OP_DUMMY 0x10d
|
|
+
|
|
+#define XSC_PF_CMDQ_ELEMENT_SZ 0x1020020
|
|
+#define XSC_PF_CMDQ_REQ_BASE_H_ADDR 0x1022000
|
|
+#define XSC_PF_CMDQ_REQ_BASE_L_ADDR 0x1024000
|
|
+#define XSC_PF_CMDQ_RSP_BASE_H_ADDR 0x102a000
|
|
+#define XSC_PF_CMDQ_RSP_BASE_L_ADDR 0x102c000
|
|
+#define XSC_PF_CMDQ_REQ_PID 0x1026000
|
|
+#define XSC_PF_CMDQ_REQ_CID 0x1028000
|
|
+#define XSC_PF_CMDQ_RSP_PID 0x102e000
|
|
+#define XSC_PF_CMDQ_RSP_CID 0x1030000
|
|
+#define XSC_PF_CMDQ_DEPTH 0x1020028
|
|
+
|
|
+#define XSC_VF_CMDQ_REQ_BASE_H_ADDR 0x0
|
|
+#define XSC_VF_CMDQ_REQ_BASE_L_ADDR 0x4
|
|
+#define XSC_VF_CMDQ_RSP_BASE_H_ADDR 0x10
|
|
+#define XSC_VF_CMDQ_RSP_BASE_L_ADDR 0x14
|
|
+#define XSC_VF_CMDQ_REQ_PID 0x8
|
|
+#define XSC_VF_CMDQ_REQ_CID 0xc
|
|
+#define XSC_VF_CMDQ_RSP_PID 0x18
|
|
+#define XSC_VF_CMDQ_RSP_CID 0x1c
|
|
+#define XSC_VF_CMDQ_ELEMENT_SZ 0x28
|
|
+#define XSC_VF_CMDQ_DEPTH 0x2c
|
|
+
|
|
+static const char * const xsc_cmd_error[] = {
|
|
+ "xsc cmd success",
|
|
+ "xsc cmd fail",
|
|
+ "xsc cmd timeout"
|
|
+};
|
|
+
|
|
+static struct xsc_cmdq_config xsc_pf_config = {
|
|
+ .req_pid_addr = XSC_PF_CMDQ_REQ_PID,
|
|
+ .req_cid_addr = XSC_PF_CMDQ_REQ_CID,
|
|
+ .rsp_pid_addr = XSC_PF_CMDQ_RSP_PID,
|
|
+ .rsp_cid_addr = XSC_PF_CMDQ_RSP_CID,
|
|
+ .req_h_addr = XSC_PF_CMDQ_REQ_BASE_H_ADDR,
|
|
+ .req_l_addr = XSC_PF_CMDQ_REQ_BASE_L_ADDR,
|
|
+ .rsp_h_addr = XSC_PF_CMDQ_RSP_BASE_H_ADDR,
|
|
+ .rsp_l_addr = XSC_PF_CMDQ_RSP_BASE_L_ADDR,
|
|
+ .elt_sz_addr = XSC_PF_CMDQ_ELEMENT_SZ,
|
|
+ .depth_addr = XSC_PF_CMDQ_DEPTH,
|
|
+};
|
|
+
|
|
+static struct xsc_cmdq_config xsc_vf_config = {
|
|
+ .req_pid_addr = XSC_VF_CMDQ_REQ_PID,
|
|
+ .req_cid_addr = XSC_VF_CMDQ_REQ_CID,
|
|
+ .rsp_pid_addr = XSC_VF_CMDQ_RSP_PID,
|
|
+ .rsp_cid_addr = XSC_VF_CMDQ_RSP_CID,
|
|
+ .req_h_addr = XSC_VF_CMDQ_REQ_BASE_H_ADDR,
|
|
+ .req_l_addr = XSC_VF_CMDQ_REQ_BASE_L_ADDR,
|
|
+ .rsp_h_addr = XSC_VF_CMDQ_RSP_BASE_H_ADDR,
|
|
+ .rsp_l_addr = XSC_VF_CMDQ_RSP_BASE_L_ADDR,
|
|
+ .elt_sz_addr = XSC_VF_CMDQ_ELEMENT_SZ,
|
|
+ .depth_addr = XSC_VF_CMDQ_DEPTH,
|
|
+};
|
|
+
|
|
+static void
|
|
+xsc_cmdq_config_init(struct xsc_dev *xdev, struct xsc_cmd_queue *cmdq)
|
|
+{
|
|
+ if (!xsc_dev_is_vf(xdev))
|
|
+ cmdq->config = &xsc_pf_config;
|
|
+ else
|
|
+ cmdq->config = &xsc_vf_config;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_cmdq_rsp_cid_update(struct xsc_dev *xdev, struct xsc_cmd_queue *cmdq)
|
|
+{
|
|
+ uint32_t rsp_pid;
|
|
+
|
|
+ cmdq->rsp_cid = rte_read32((uint8_t *)xdev->bar_addr + cmdq->config->rsp_cid_addr);
|
|
+ rsp_pid = rte_read32((uint8_t *)xdev->bar_addr + cmdq->config->rsp_pid_addr);
|
|
+ if (rsp_pid != cmdq->rsp_cid) {
|
|
+ PMD_DRV_LOG(INFO, "Update cid(%u) to latest pid(%u)",
|
|
+ cmdq->rsp_cid, rsp_pid);
|
|
+ cmdq->rsp_cid = rsp_pid;
|
|
+ rte_write32(cmdq->rsp_cid, (uint8_t *)xdev->bar_addr + cmdq->config->rsp_cid_addr);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_cmdq_depth_set(struct xsc_dev *xdev, struct xsc_cmd_queue *cmdq)
|
|
+{
|
|
+ cmdq->depth_n = XSC_CMDQ_DEPTH_LOG;
|
|
+ cmdq->depth_m = (1 << XSC_CMDQ_DEPTH_LOG) - 1;
|
|
+ rte_write32(1 << cmdq->depth_n, (uint8_t *)xdev->bar_addr + cmdq->config->depth_addr);
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_cmdq_elt_size_check(struct xsc_dev *xdev, struct xsc_cmd_queue *cmdq)
|
|
+{
|
|
+ uint32_t elts_n;
|
|
+
|
|
+ elts_n = rte_read32((uint8_t *)xdev->bar_addr + cmdq->config->elt_sz_addr);
|
|
+ if (elts_n != XSC_CMDQ_ELEMENT_SIZE_LOG) {
|
|
+ PMD_DRV_LOG(ERR, "The cmdq elt size log(%u) is error, should be %u",
|
|
+ elts_n, XSC_CMDQ_ELEMENT_SIZE_LOG);
|
|
+ rte_errno = ENODEV;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_cmdq_req_base_addr_set(struct xsc_dev *xdev, struct xsc_cmd_queue *cmdq)
|
|
+{
|
|
+ uint32_t h_addr, l_addr;
|
|
+
|
|
+ h_addr = (uint32_t)(cmdq->req_mz->iova >> 32);
|
|
+ l_addr = (uint32_t)(cmdq->req_mz->iova);
|
|
+ rte_write32(h_addr, (uint8_t *)xdev->bar_addr + cmdq->config->req_h_addr);
|
|
+ rte_write32(l_addr, (uint8_t *)xdev->bar_addr + cmdq->config->req_l_addr);
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_cmdq_rsp_base_addr_set(struct xsc_dev *xdev, struct xsc_cmd_queue *cmdq)
|
|
+{
|
|
+ uint32_t h_addr, l_addr;
|
|
+
|
|
+ h_addr = (uint32_t)(cmdq->rsp_mz->iova >> 32);
|
|
+ l_addr = (uint32_t)(cmdq->rsp_mz->iova);
|
|
+ rte_write32(h_addr, (uint8_t *)xdev->bar_addr + cmdq->config->rsp_h_addr);
|
|
+ rte_write32(l_addr, (uint8_t *)xdev->bar_addr + cmdq->config->rsp_l_addr);
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_cmdq_mbox_free(struct xsc_dev *xdev, struct xsc_cmdq_mbox *mbox)
|
|
+{
|
|
+ struct xsc_cmdq_mbox *next, *head;
|
|
+ struct xsc_vfio_priv *priv = xdev->dev_priv;
|
|
+
|
|
+ head = mbox;
|
|
+ while (head != NULL) {
|
|
+ next = head->next;
|
|
+ if (head->buf != NULL)
|
|
+ rte_mempool_put(priv->cmdq->mbox_buf_pool, head->buf);
|
|
+ free(head);
|
|
+ head = next;
|
|
+ }
|
|
+}
|
|
+
|
|
+static struct xsc_cmdq_mbox *
|
|
+xsc_cmdq_mbox_alloc(struct xsc_dev *xdev)
|
|
+{
|
|
+ struct xsc_cmdq_mbox *mbox;
|
|
+ int ret;
|
|
+ struct xsc_vfio_priv *priv = (struct xsc_vfio_priv *)xdev->dev_priv;
|
|
+
|
|
+ mbox = malloc(sizeof(*mbox));
|
|
+ if (mbox == NULL) {
|
|
+ rte_errno = -ENOMEM;
|
|
+ goto error;
|
|
+ }
|
|
+ memset(mbox, 0, sizeof(struct xsc_cmdq_mbox));
|
|
+
|
|
+ ret = rte_mempool_get(priv->cmdq->mbox_buf_pool, (void **)&mbox->buf);
|
|
+ if (ret != 0)
|
|
+ goto error;
|
|
+ mbox->buf_dma = rte_mempool_virt2iova(mbox->buf);
|
|
+ memset(mbox->buf, 0, sizeof(struct xsc_cmdq_mbox_buf));
|
|
+ mbox->next = NULL;
|
|
+
|
|
+ return mbox;
|
|
+
|
|
+error:
|
|
+ xsc_cmdq_mbox_free(xdev, mbox);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static struct xsc_cmdq_mbox *
|
|
+xsc_cmdq_mbox_alloc_bulk(struct xsc_dev *xdev, int n)
|
|
+{
|
|
+ int i;
|
|
+ struct xsc_cmdq_mbox *head = NULL;
|
|
+ struct xsc_cmdq_mbox *mbox;
|
|
+ struct xsc_cmdq_mbox_buf *mbox_buf;
|
|
+
|
|
+ for (i = 0; i < n; i++) {
|
|
+ mbox = xsc_cmdq_mbox_alloc(xdev);
|
|
+ if (mbox == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc mailbox");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ mbox_buf = mbox->buf;
|
|
+ mbox->next = head;
|
|
+ mbox_buf->next = rte_cpu_to_be_64(mbox->next ? mbox->next->buf_dma : 0);
|
|
+ mbox_buf->block_num = rte_cpu_to_be_32(n - i - 1);
|
|
+ head = mbox;
|
|
+ }
|
|
+
|
|
+ return head;
|
|
+
|
|
+error:
|
|
+ xsc_cmdq_mbox_free(xdev, head);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_cmdq_req_msg_free(struct xsc_dev *xdev, struct xsc_cmdq_req_msg *msg)
|
|
+{
|
|
+ struct xsc_cmdq_mbox *head;
|
|
+
|
|
+ if (msg == NULL)
|
|
+ return;
|
|
+
|
|
+ head = msg->next;
|
|
+ xsc_cmdq_mbox_free(xdev, head);
|
|
+ free(msg);
|
|
+}
|
|
+
|
|
+static struct xsc_cmdq_req_msg *
|
|
+xsc_cmdq_req_msg_alloc(struct xsc_dev *xdev, int len)
|
|
+{
|
|
+ struct xsc_cmdq_req_msg *msg;
|
|
+ struct xsc_cmdq_mbox *head = NULL;
|
|
+ int cmd_len, nb_mbox;
|
|
+
|
|
+ msg = malloc(sizeof(*msg));
|
|
+ if (msg == NULL) {
|
|
+ rte_errno = -ENOMEM;
|
|
+ goto error;
|
|
+ }
|
|
+ memset(msg, 0, sizeof(*msg));
|
|
+
|
|
+ cmd_len = len - RTE_MIN(sizeof(msg->hdr.data), (uint32_t)len);
|
|
+ nb_mbox = (cmd_len + XSC_CMDQ_DATA_SIZE - 1) / XSC_CMDQ_DATA_SIZE;
|
|
+ head = xsc_cmdq_mbox_alloc_bulk(xdev, nb_mbox);
|
|
+ if (head == NULL && nb_mbox != 0)
|
|
+ goto error;
|
|
+
|
|
+ msg->next = head;
|
|
+ msg->len = len;
|
|
+
|
|
+ return msg;
|
|
+
|
|
+error:
|
|
+ xsc_cmdq_req_msg_free(xdev, msg);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_cmdq_rsp_msg_free(struct xsc_dev *xdev, struct xsc_cmdq_rsp_msg *msg)
|
|
+{
|
|
+ struct xsc_cmdq_mbox *head;
|
|
+
|
|
+ if (msg == NULL)
|
|
+ return;
|
|
+
|
|
+ head = msg->next;
|
|
+ xsc_cmdq_mbox_free(xdev, head);
|
|
+ free(msg);
|
|
+}
|
|
+
|
|
+static struct xsc_cmdq_rsp_msg *
|
|
+xsc_cmdq_rsp_msg_alloc(struct xsc_dev *xdev, int len)
|
|
+{
|
|
+ struct xsc_cmdq_rsp_msg *msg;
|
|
+ struct xsc_cmdq_mbox *head = NULL;
|
|
+ int cmd_len, nb_mbox;
|
|
+
|
|
+ msg = malloc(sizeof(*msg));
|
|
+ if (msg == NULL) {
|
|
+ rte_errno = -ENOMEM;
|
|
+ goto error;
|
|
+ }
|
|
+ memset(msg, 0, sizeof(*msg));
|
|
+
|
|
+ cmd_len = len - RTE_MIN(sizeof(msg->hdr.data), (uint32_t)len);
|
|
+ nb_mbox = (cmd_len + XSC_CMDQ_DATA_SIZE - 1) / XSC_CMDQ_DATA_SIZE;
|
|
+ head = xsc_cmdq_mbox_alloc_bulk(xdev, nb_mbox);
|
|
+ if (head == NULL && nb_mbox != 0)
|
|
+ goto error;
|
|
+
|
|
+ msg->next = head;
|
|
+ msg->len = len;
|
|
+
|
|
+ return msg;
|
|
+
|
|
+error:
|
|
+ xsc_cmdq_rsp_msg_free(xdev, msg);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static void
|
|
+xsc_cmdq_msg_destruct(struct xsc_dev *xdev,
|
|
+ struct xsc_cmdq_req_msg **req_msg,
|
|
+ struct xsc_cmdq_rsp_msg **rsp_msg)
|
|
+{
|
|
+ xsc_cmdq_req_msg_free(xdev, *req_msg);
|
|
+ xsc_cmdq_rsp_msg_free(xdev, *rsp_msg);
|
|
+ *req_msg = NULL;
|
|
+ *rsp_msg = NULL;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_cmdq_msg_construct(struct xsc_dev *xdev,
|
|
+ struct xsc_cmdq_req_msg **req_msg, int in_len,
|
|
+ struct xsc_cmdq_rsp_msg **rsp_msg, int out_len)
|
|
+{
|
|
+ *req_msg = xsc_cmdq_req_msg_alloc(xdev, in_len);
|
|
+ if (*req_msg == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc xsc cmd request msg");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ *rsp_msg = xsc_cmdq_rsp_msg_alloc(xdev, out_len);
|
|
+ if (*rsp_msg == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc xsc cmd response msg");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ xsc_cmdq_msg_destruct(xdev, req_msg, rsp_msg);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_cmdq_req_msg_copy(struct xsc_cmdq_req_msg *req_msg, void *data_in, int in_len)
|
|
+{
|
|
+ struct xsc_cmdq_mbox_buf *mbox_buf;
|
|
+ struct xsc_cmdq_mbox *mbox;
|
|
+ int copy;
|
|
+ uint8_t *data = data_in;
|
|
+
|
|
+ if (req_msg == NULL || data == NULL)
|
|
+ return -1;
|
|
+
|
|
+ copy = RTE_MIN((uint32_t)in_len, sizeof(req_msg->hdr.data));
|
|
+ memcpy(req_msg->hdr.data, data, copy);
|
|
+
|
|
+ in_len -= copy;
|
|
+ data += copy;
|
|
+
|
|
+ mbox = req_msg->next;
|
|
+ while (in_len > 0) {
|
|
+ if (mbox == NULL)
|
|
+ return -1;
|
|
+
|
|
+ copy = RTE_MIN(in_len, XSC_CMDQ_DATA_SIZE);
|
|
+ mbox_buf = mbox->buf;
|
|
+ memcpy(mbox_buf->data, data, copy);
|
|
+ mbox_buf->owner_status = 0;
|
|
+ data += copy;
|
|
+ in_len -= copy;
|
|
+ mbox = mbox->next;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_cmdq_rsp_msg_copy(void *data_out, struct xsc_cmdq_rsp_msg *rsp_msg, int out_len)
|
|
+{
|
|
+ struct xsc_cmdq_mbox_buf *mbox_buf;
|
|
+ struct xsc_cmdq_mbox *mbox;
|
|
+ int copy;
|
|
+ uint8_t *data = data_out;
|
|
+
|
|
+ if (data == NULL || rsp_msg == NULL)
|
|
+ return -1;
|
|
+
|
|
+ copy = RTE_MIN((uint32_t)out_len, sizeof(rsp_msg->hdr.data));
|
|
+ memcpy(data, rsp_msg->hdr.data, copy);
|
|
+ out_len -= copy;
|
|
+ data += copy;
|
|
+
|
|
+ mbox = rsp_msg->next;
|
|
+ while (out_len > 0) {
|
|
+ if (mbox == NULL)
|
|
+ return -1;
|
|
+ copy = RTE_MIN(out_len, XSC_CMDQ_DATA_SIZE);
|
|
+ mbox_buf = mbox->buf;
|
|
+ if (!mbox_buf->owner_status)
|
|
+ PMD_DRV_LOG(ERR, "Failed to check cmd owner");
|
|
+ memcpy(data, mbox_buf->data, copy);
|
|
+ data += copy;
|
|
+ out_len -= copy;
|
|
+ mbox = mbox->next;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static enum xsc_cmd_status
|
|
+xsc_cmdq_wait_completion(struct xsc_dev *xdev, struct xsc_cmdq_rsp_msg *rsp_msg)
|
|
+{
|
|
+ struct xsc_vfio_priv *priv = (struct xsc_vfio_priv *)xdev->dev_priv;
|
|
+ struct xsc_cmd_queue *cmdq = priv->cmdq;
|
|
+ volatile struct xsc_cmdq_rsp_layout *rsp_lay;
|
|
+ struct xsc_cmd_outbox_hdr *out_hdr = (struct xsc_cmd_outbox_hdr *)rsp_msg->hdr.data;
|
|
+ int count = (XSC_CMDQ_WAIT_TIMEOUT * 1000) / XSC_CMDQ_WAIT_DELAY_MS;
|
|
+ uint32_t rsp_pid;
|
|
+ uint8_t cmd_status;
|
|
+ uint32_t i;
|
|
+
|
|
+ while (count-- > 0) {
|
|
+ rsp_pid = rte_read32((uint8_t *)xdev->bar_addr + cmdq->config->rsp_pid_addr);
|
|
+ if (rsp_pid == cmdq->rsp_cid) {
|
|
+ rte_delay_ms(XSC_CMDQ_WAIT_DELAY_MS);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ rsp_lay = cmdq->rsp_lay + cmdq->rsp_cid;
|
|
+ if (cmdq->owner_learn == 0) {
|
|
+ /* First time learning owner_bit from hardware */
|
|
+ cmdq->owner_bit = rsp_lay->owner_bit;
|
|
+ cmdq->owner_learn = 1;
|
|
+ }
|
|
+
|
|
+ /* Waiting for dma to complete */
|
|
+ if (cmdq->owner_bit != rsp_lay->owner_bit)
|
|
+ continue;
|
|
+
|
|
+ for (i = 0; i < XSC_CMDQ_RSP_INLINE_SIZE; i++)
|
|
+ rsp_msg->hdr.data[i] = rsp_lay->out[i];
|
|
+
|
|
+ cmdq->rsp_cid = (cmdq->rsp_cid + 1) & cmdq->depth_m;
|
|
+ rte_write32(cmdq->rsp_cid, (uint8_t *)xdev->bar_addr + cmdq->config->rsp_cid_addr);
|
|
+
|
|
+ /* Change owner bit */
|
|
+ if (cmdq->rsp_cid == 0)
|
|
+ cmdq->owner_bit = !cmdq->owner_bit;
|
|
+
|
|
+ cmd_status = out_hdr->status;
|
|
+ if (cmd_status != 0)
|
|
+ return XSC_CMD_FAIL;
|
|
+ return XSC_CMD_SUCC;
|
|
+ }
|
|
+
|
|
+ return XSC_CMD_TIMEOUT;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_cmdq_dummy_invoke(struct xsc_dev *xdev, struct xsc_cmd_queue *cmdq, uint32_t start, int num)
|
|
+{
|
|
+ struct xsc_cmdq_dummy_mbox_in in;
|
|
+ struct xsc_cmdq_dummy_mbox_out out;
|
|
+ struct xsc_cmdq_req_msg *req_msg = NULL;
|
|
+ struct xsc_cmdq_rsp_msg *rsp_msg = NULL;
|
|
+ struct xsc_cmdq_req_layout *req_lay;
|
|
+ int in_len = sizeof(in);
|
|
+ int out_len = sizeof(out);
|
|
+ int ret, i;
|
|
+ uint32_t start_pid = start;
|
|
+
|
|
+ memset(&in, 0, sizeof(in));
|
|
+ in.hdr.opcode = rte_cpu_to_be_16(XSC_CMD_OP_DUMMY);
|
|
+
|
|
+ ret = xsc_cmdq_msg_construct(xdev, &req_msg, in_len, &rsp_msg, out_len);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to construct cmd msg for dummy exec");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ ret = xsc_cmdq_req_msg_copy(req_msg, &in, in_len);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to copy cmd buf to request msg for dummy exec");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ rte_spinlock_lock(&cmdq->lock);
|
|
+
|
|
+ for (i = 0; i < num; i++) {
|
|
+ req_lay = cmdq->req_lay + start_pid;
|
|
+ memset(req_lay, 0, sizeof(*req_lay));
|
|
+ memcpy(req_lay->in, req_msg->hdr.data, sizeof(req_lay->in));
|
|
+ req_lay->inlen = rte_cpu_to_be_32(req_msg->len);
|
|
+ req_lay->outlen = rte_cpu_to_be_32(rsp_msg->len);
|
|
+ req_lay->sig = 0xff;
|
|
+ req_lay->idx = 0;
|
|
+ req_lay->type = XSC_CMDQ_REQ_TYPE;
|
|
+ start_pid = (start_pid + 1) & cmdq->depth_m;
|
|
+ }
|
|
+
|
|
+ /* Ring doorbell after the descriptor is valid */
|
|
+ rte_write32(cmdq->req_pid, (uint8_t *)xdev->bar_addr + cmdq->config->req_pid_addr);
|
|
+
|
|
+ ret = xsc_cmdq_wait_completion(xdev, rsp_msg);
|
|
+ rte_spinlock_unlock(&cmdq->lock);
|
|
+
|
|
+error:
|
|
+ xsc_cmdq_msg_destruct(xdev, &req_msg, &rsp_msg);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+xsc_cmdq_req_status_restore(struct xsc_dev *xdev, struct xsc_cmd_queue *cmdq)
|
|
+{
|
|
+ uint32_t req_pid, req_cid;
|
|
+ uint32_t cnt;
|
|
+
|
|
+ req_pid = rte_read32((uint8_t *)xdev->bar_addr + cmdq->config->req_pid_addr);
|
|
+ req_cid = rte_read32((uint8_t *)xdev->bar_addr + cmdq->config->req_cid_addr);
|
|
+
|
|
+ if (req_pid >= (uint32_t)(1 << cmdq->depth_n) ||
|
|
+ req_cid >= (uint32_t)(1 << cmdq->depth_n)) {
|
|
+ PMD_DRV_LOG(ERR, "Request pid %u and cid %u must be less than %u",
|
|
+ req_pid, req_cid, (uint32_t)(1 << cmdq->depth_n));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ cmdq->req_pid = req_pid;
|
|
+ if (req_pid == req_cid)
|
|
+ return 0;
|
|
+
|
|
+ cnt = (req_pid > req_cid) ? (req_pid - req_cid) :
|
|
+ ((1 << cmdq->depth_n) + req_pid - req_cid);
|
|
+ if (xsc_cmdq_dummy_invoke(xdev, cmdq, req_cid, cnt) != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to dummy invoke xsc cmd");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void
|
|
+xsc_vfio_mbox_destroy(struct xsc_cmd_queue *cmdq)
|
|
+{
|
|
+ if (cmdq == NULL)
|
|
+ return;
|
|
+
|
|
+ rte_memzone_free(cmdq->req_mz);
|
|
+ rte_memzone_free(cmdq->rsp_mz);
|
|
+ rte_mempool_free(cmdq->mbox_buf_pool);
|
|
+ rte_free(cmdq);
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_vfio_mbox_init(struct xsc_dev *xdev)
|
|
+{
|
|
+ struct xsc_cmd_queue *cmdq;
|
|
+ struct xsc_vfio_priv *priv = (struct xsc_vfio_priv *)xdev->dev_priv;
|
|
+ char name[RTE_MEMZONE_NAMESIZE] = { 0 };
|
|
+ uint32_t size;
|
|
+
|
|
+ cmdq = rte_zmalloc(NULL, sizeof(*cmdq), RTE_CACHE_LINE_SIZE);
|
|
+ if (cmdq == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc memory for xsc_cmd_queue");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ snprintf(name, RTE_MEMZONE_NAMESIZE, "%s_cmdq", xdev->pci_dev->device.name);
|
|
+ size = (1 << XSC_CMDQ_DEPTH_LOG) * sizeof(struct xsc_cmdq_req_layout);
|
|
+ cmdq->req_mz = rte_memzone_reserve_aligned(name,
|
|
+ size, SOCKET_ID_ANY,
|
|
+ RTE_MEMZONE_IOVA_CONTIG,
|
|
+ XSC_PAGE_SIZE);
|
|
+ if (cmdq->req_mz == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc memory for cmd queue");
|
|
+ goto error;
|
|
+ }
|
|
+ cmdq->req_lay = cmdq->req_mz->addr;
|
|
+
|
|
+ snprintf(name, RTE_MEMZONE_NAMESIZE, "%s_cmd_cq", xdev->pci_dev->device.name);
|
|
+ size = (1 << XSC_CMDQ_DEPTH_LOG) * sizeof(struct xsc_cmdq_rsp_layout); /* -V1048 */
|
|
+ cmdq->rsp_mz = rte_memzone_reserve_aligned(name,
|
|
+ size, SOCKET_ID_ANY,
|
|
+ RTE_MEMZONE_IOVA_CONTIG,
|
|
+ XSC_PAGE_SIZE);
|
|
+ if (cmdq->rsp_mz == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to alloc memory for cmd cq");
|
|
+ goto error;
|
|
+ }
|
|
+ cmdq->rsp_lay = cmdq->rsp_mz->addr;
|
|
+
|
|
+ snprintf(name, RTE_MEMZONE_NAMESIZE, "%s_mempool", xdev->pci_dev->device.name);
|
|
+ cmdq->mbox_buf_pool = rte_mempool_create(name, XSC_MBOX_BUF_NUM,
|
|
+ sizeof(struct xsc_cmdq_mbox_buf),
|
|
+ XSC_MBOX_BUF_CACHE_SIZE, 0,
|
|
+ NULL, NULL, NULL, NULL,
|
|
+ SOCKET_ID_ANY, 0);
|
|
+ if (cmdq->mbox_buf_pool == NULL) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to create mailbox buf pool");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ xsc_cmdq_config_init(xdev, cmdq);
|
|
+ xsc_cmdq_rsp_cid_update(xdev, cmdq);
|
|
+ xsc_cmdq_depth_set(xdev, cmdq);
|
|
+ if (xsc_cmdq_elt_size_check(xdev, cmdq) != 0)
|
|
+ goto error;
|
|
+
|
|
+ xsc_cmdq_req_base_addr_set(xdev, cmdq);
|
|
+ xsc_cmdq_rsp_base_addr_set(xdev, cmdq);
|
|
+ /* Check request status and restore it */
|
|
+ if (xsc_cmdq_req_status_restore(xdev, cmdq) != 0)
|
|
+ goto error;
|
|
+
|
|
+ rte_spinlock_init(&cmdq->lock);
|
|
+ priv->cmdq = cmdq;
|
|
+ return 0;
|
|
+
|
|
+error:
|
|
+ xsc_vfio_mbox_destroy(cmdq);
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static enum xsc_cmd_status
|
|
+xsc_cmdq_invoke(struct xsc_dev *xdev, struct xsc_cmdq_req_msg *req_msg,
|
|
+ struct xsc_cmdq_rsp_msg *rsp_msg)
|
|
+{
|
|
+ struct xsc_vfio_priv *priv = (struct xsc_vfio_priv *)xdev->dev_priv;
|
|
+ struct xsc_cmd_queue *cmdq = priv->cmdq;
|
|
+ struct xsc_cmdq_req_layout *req_lay;
|
|
+ enum xsc_cmd_status status = XSC_CMD_FAIL;
|
|
+
|
|
+ rte_spinlock_lock(&cmdq->lock);
|
|
+ req_lay = cmdq->req_lay + cmdq->req_pid;
|
|
+ memset(req_lay, 0, sizeof(*req_lay));
|
|
+ memcpy(req_lay->in, req_msg->hdr.data, sizeof(req_lay->in));
|
|
+ if (req_msg->next != NULL)
|
|
+ req_lay->in_ptr = rte_cpu_to_be_64(req_msg->next->buf_dma);
|
|
+ req_lay->inlen = rte_cpu_to_be_32(req_msg->len);
|
|
+
|
|
+ if (rsp_msg->next != NULL)
|
|
+ req_lay->out_ptr = rte_cpu_to_be_64(rsp_msg->next->buf_dma);
|
|
+ req_lay->outlen = rte_cpu_to_be_32(rsp_msg->len);
|
|
+
|
|
+ req_lay->sig = 0xff;
|
|
+ req_lay->idx = 0;
|
|
+ req_lay->type = XSC_CMDQ_REQ_TYPE;
|
|
+
|
|
+ /* Ring doorbell after the descriptor is valid */
|
|
+ cmdq->req_pid = (cmdq->req_pid + 1) & cmdq->depth_m;
|
|
+ rte_write32(cmdq->req_pid, (uint8_t *)xdev->bar_addr + cmdq->config->req_pid_addr);
|
|
+
|
|
+ status = xsc_cmdq_wait_completion(xdev, rsp_msg);
|
|
+ rte_spinlock_unlock(&cmdq->lock);
|
|
+
|
|
+ return status;
|
|
+}
|
|
+
|
|
+int
|
|
+xsc_vfio_mbox_exec(struct xsc_dev *xdev, void *data_in,
|
|
+ int in_len, void *data_out, int out_len)
|
|
+{
|
|
+ struct xsc_cmdq_req_msg *req_msg = NULL;
|
|
+ struct xsc_cmdq_rsp_msg *rsp_msg = NULL;
|
|
+ int ret;
|
|
+ enum xsc_cmd_status status;
|
|
+
|
|
+ ret = xsc_cmdq_msg_construct(xdev, &req_msg, in_len, &rsp_msg, out_len);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to construct cmd msg");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ ret = xsc_cmdq_req_msg_copy(req_msg, data_in, in_len);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to copy cmd buf to request msg");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ status = xsc_cmdq_invoke(xdev, req_msg, rsp_msg);
|
|
+ if (status != XSC_CMD_SUCC) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to invoke xsc cmd, %s",
|
|
+ xsc_cmd_error[status]);
|
|
+ ret = -1;
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ ret = xsc_cmdq_rsp_msg_copy(data_out, rsp_msg, out_len);
|
|
+ if (ret != 0) {
|
|
+ PMD_DRV_LOG(ERR, "Failed to copy response msg to out data");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+error:
|
|
+ xsc_cmdq_msg_destruct(xdev, &req_msg, &rsp_msg);
|
|
+ return ret;
|
|
+}
|
|
diff --git a/drivers/net/xsc/xsc_vfio_mbox.h b/drivers/net/xsc/xsc_vfio_mbox.h
|
|
new file mode 100644
|
|
index 0000000..49ca84f
|
|
--- /dev/null
|
|
+++ b/drivers/net/xsc/xsc_vfio_mbox.h
|
|
@@ -0,0 +1,142 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause
|
|
+ * Copyright 2025 Yunsilicon Technology Co., Ltd.
|
|
+ */
|
|
+
|
|
+#ifndef _XSC_CMDQ_H_
|
|
+#define _XSC_CMDQ_H_
|
|
+
|
|
+#include <rte_common.h>
|
|
+#include <rte_mempool.h>
|
|
+#include <rte_memzone.h>
|
|
+#include <rte_spinlock.h>
|
|
+#include <rte_byteorder.h>
|
|
+#include <rte_io.h>
|
|
+
|
|
+#include "xsc_dev.h"
|
|
+#include "xsc_cmd.h"
|
|
+
|
|
+#define XSC_CMDQ_DATA_SIZE 512
|
|
+#define XSC_CMDQ_REQ_INLINE_SIZE 8
|
|
+#define XSC_CMDQ_RSP_INLINE_SIZE 14
|
|
+
|
|
+struct xsc_cmdq_config {
|
|
+ uint32_t req_pid_addr;
|
|
+ uint32_t req_cid_addr;
|
|
+ uint32_t rsp_pid_addr;
|
|
+ uint32_t rsp_cid_addr;
|
|
+ uint32_t req_h_addr;
|
|
+ uint32_t req_l_addr;
|
|
+ uint32_t rsp_h_addr;
|
|
+ uint32_t rsp_l_addr;
|
|
+ uint32_t elt_sz_addr;
|
|
+ uint32_t depth_addr;
|
|
+};
|
|
+
|
|
+struct xsc_cmd_queue {
|
|
+ struct xsc_cmdq_req_layout *req_lay;
|
|
+ struct xsc_cmdq_rsp_layout *rsp_lay;
|
|
+ const struct rte_memzone *req_mz;
|
|
+ const struct rte_memzone *rsp_mz;
|
|
+ uint32_t req_pid;
|
|
+ uint32_t rsp_cid;
|
|
+ uint8_t owner_bit; /* CMDQ owner bit */
|
|
+ uint8_t owner_learn; /* Learn ownerbit from hw */
|
|
+ uint8_t depth_n; /* Log 2 of CMDQ depth */
|
|
+ uint8_t depth_m; /* CMDQ depth mask */
|
|
+ struct rte_mempool *mbox_buf_pool; /* CMDQ data pool */
|
|
+ struct xsc_cmdq_config *config;
|
|
+ rte_spinlock_t lock;
|
|
+};
|
|
+
|
|
+struct xsc_cmdq_mbox_buf {
|
|
+ uint8_t data[XSC_CMDQ_DATA_SIZE];
|
|
+ uint8_t rsv0[48];
|
|
+ rte_be64_t next; /* Next buf dma addr */
|
|
+ rte_be32_t block_num;
|
|
+ uint8_t owner_status;
|
|
+ uint8_t token;
|
|
+ uint8_t ctrl_sig;
|
|
+ uint8_t sig;
|
|
+};
|
|
+
|
|
+struct xsc_cmdq_mbox {
|
|
+ struct xsc_cmdq_mbox_buf *buf;
|
|
+ rte_iova_t buf_dma;
|
|
+ struct xsc_cmdq_mbox *next;
|
|
+};
|
|
+
|
|
+/* CMDQ request msg inline */
|
|
+struct xsc_cmdq_req_hdr {
|
|
+ rte_be32_t data[XSC_CMDQ_REQ_INLINE_SIZE];
|
|
+};
|
|
+
|
|
+struct xsc_cmdq_req_msg {
|
|
+ uint32_t len;
|
|
+ struct xsc_cmdq_req_hdr hdr;
|
|
+ struct xsc_cmdq_mbox *next;
|
|
+};
|
|
+
|
|
+/* CMDQ response msg inline */
|
|
+struct xsc_cmdq_rsp_hdr {
|
|
+ rte_be32_t data[XSC_CMDQ_RSP_INLINE_SIZE];
|
|
+};
|
|
+
|
|
+struct xsc_cmdq_rsp_msg {
|
|
+ uint32_t len;
|
|
+ struct xsc_cmdq_rsp_hdr hdr;
|
|
+ struct xsc_cmdq_mbox *next;
|
|
+};
|
|
+
|
|
+/* HW will use this for some records(e.g. vf_id) */
|
|
+struct xsc_cmdq_rsv {
|
|
+ uint16_t vf_id;
|
|
+ uint8_t rsv[2];
|
|
+};
|
|
+
|
|
+/* CMDQ request entry layout */
|
|
+struct xsc_cmdq_req_layout {
|
|
+ struct xsc_cmdq_rsv rsv0;
|
|
+ rte_be32_t inlen;
|
|
+ rte_be64_t in_ptr;
|
|
+ rte_be32_t in[XSC_CMDQ_REQ_INLINE_SIZE];
|
|
+ rte_be64_t out_ptr;
|
|
+ rte_be32_t outlen;
|
|
+ uint8_t token;
|
|
+ uint8_t sig;
|
|
+ uint8_t idx;
|
|
+ uint8_t type:7;
|
|
+ uint8_t owner_bit:1;
|
|
+};
|
|
+
|
|
+/* CMDQ response entry layout */
|
|
+struct xsc_cmdq_rsp_layout {
|
|
+ struct xsc_cmdq_rsv rsv0;
|
|
+ rte_be32_t out[XSC_CMDQ_RSP_INLINE_SIZE];
|
|
+ uint8_t token;
|
|
+ uint8_t sig;
|
|
+ uint8_t idx;
|
|
+ uint8_t type:7;
|
|
+ uint8_t owner_bit:1;
|
|
+};
|
|
+
|
|
+struct xsc_cmdq_dummy_mbox_in {
|
|
+ struct xsc_cmd_inbox_hdr hdr;
|
|
+ uint8_t rsv[8];
|
|
+};
|
|
+
|
|
+struct xsc_cmdq_dummy_mbox_out {
|
|
+ struct xsc_cmd_outbox_hdr hdr;
|
|
+ uint8_t rsv[8];
|
|
+};
|
|
+
|
|
+struct xsc_vfio_priv {
|
|
+ struct xsc_cmd_queue *cmdq;
|
|
+};
|
|
+
|
|
+int xsc_vfio_mbox_init(struct xsc_dev *xdev);
|
|
+void xsc_vfio_mbox_destroy(struct xsc_cmd_queue *cmdq);
|
|
+int xsc_vfio_mbox_exec(struct xsc_dev *xdev,
|
|
+ void *data_in, int in_len,
|
|
+ void *data_out, int out_len);
|
|
+
|
|
+#endif /* _XSC_CMDQ_H_ */
|
|
--
|
|
2.25.1
|
|
|