[PATCH 01/15] yunsilicon: add PCI core driver skeleton

From: Xin Tian

Date: Mon Oct 12 2026 - 07:48:51 EST


Add the Yunsilicon XSC PCI core driver skeleton: Kconfig and Makefile
plumbing, the register definitions and the PCI probe/remove path that
enables the device, maps BAR 0 and allocates the per-function resource
structure.

Signed-off-by: Xin Tian <tianx@xxxxxxxxxxxxxx>
---
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/yunsilicon/Kconfig | 26 +
drivers/net/ethernet/yunsilicon/Makefile | 8 +
.../ethernet/yunsilicon/xsc/common/xsc_cmd.h | 1022 +++++++++++++++++
.../yunsilicon/xsc/common/xsc_cmd_api.h | 25 +
.../ethernet/yunsilicon/xsc/common/xsc_cmdq.h | 192 ++++
.../ethernet/yunsilicon/xsc/common/xsc_core.h | 707 ++++++++++++
.../yunsilicon/xsc/common/xsc_device.h | 94 ++
.../ethernet/yunsilicon/xsc/common/xsc_hsi.h | 123 ++
.../ethernet/yunsilicon/xsc/common/xsc_reg.h | 28 +
.../net/ethernet/yunsilicon/xsc/pci/Kconfig | 15 +
.../net/ethernet/yunsilicon/xsc/pci/Makefile | 9 +
.../net/ethernet/yunsilicon/xsc/pci/main.c | 253 ++++
14 files changed, 2504 insertions(+)
create mode 100644 drivers/net/ethernet/yunsilicon/Kconfig
create mode 100644 drivers/net/ethernet/yunsilicon/Makefile
create mode 100644 drivers/net/ethernet/yunsilicon/xsc/common/xsc_cmd.h
create mode 100644 drivers/net/ethernet/yunsilicon/xsc/common/xsc_cmd_api.h
create mode 100644 drivers/net/ethernet/yunsilicon/xsc/common/xsc_cmdq.h
create mode 100644 drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h
create mode 100644 drivers/net/ethernet/yunsilicon/xsc/common/xsc_device.h
create mode 100644 drivers/net/ethernet/yunsilicon/xsc/common/xsc_hsi.h
create mode 100644 drivers/net/ethernet/yunsilicon/xsc/common/xsc_reg.h
create mode 100644 drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
create mode 100644 drivers/net/ethernet/yunsilicon/xsc/pci/Makefile
create mode 100644 drivers/net/ethernet/yunsilicon/xsc/pci/main.c

diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 8581ccba1..3f357b773 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -70,6 +70,7 @@ source "drivers/net/ethernet/i825xx/Kconfig"
source "drivers/net/ethernet/ibm/Kconfig"
source "drivers/net/ethernet/intel/Kconfig"
source "drivers/net/ethernet/xscale/Kconfig"
+source "drivers/net/ethernet/yunsilicon/Kconfig"

config JME
tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 2b1153d35..4ad89b36b 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_NET_VENDOR_INTEL) += intel/
obj-$(CONFIG_NET_VENDOR_I825XX) += i825xx/
obj-$(CONFIG_NET_VENDOR_MICROSOFT) += microsoft/
obj-$(CONFIG_NET_VENDOR_XSCALE) += xscale/
+obj-$(CONFIG_NET_VENDOR_YUNSILICON) += yunsilicon/
obj-$(CONFIG_JME) += jme.o
obj-$(CONFIG_KORINA) += korina.o
obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
diff --git a/drivers/net/ethernet/yunsilicon/Kconfig b/drivers/net/ethernet/yunsilicon/Kconfig
new file mode 100644
index 000000000..ffdfdf4bf
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/Kconfig
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021-2026, Shanghai Yunsilicon Technology Co., Ltd.
+# All rights reserved.
+#
+# Yunsilicon driver configuration
+#
+
+config NET_VENDOR_YUNSILICON
+ bool "Yunsilicon devices"
+ default y
+ depends on PCI
+ depends on 64BIT || COMPILE_TEST
+ help
+ If you have a network (Ethernet) device belonging to this class,
+ say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Yunsilicon cards. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_YUNSILICON
+
+source "drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig"
+
+endif # NET_VENDOR_YUNSILICON
diff --git a/drivers/net/ethernet/yunsilicon/Makefile b/drivers/net/ethernet/yunsilicon/Makefile
new file mode 100644
index 000000000..b2924ccaf
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021-2026, Shanghai Yunsilicon Technology Co., Ltd.
+# All rights reserved.
+#
+# Makefile for the Yunsilicon device drivers.
+#
+
+obj-$(CONFIG_YUNSILICON_XSC_PCI) += xsc/pci/
diff --git a/drivers/net/ethernet/yunsilicon/xsc/common/xsc_cmd.h b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_cmd.h
new file mode 100644
index 000000000..0b8f669b5
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_cmd.h
@@ -0,0 +1,1022 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021-2026, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#ifndef __XSC_CMD_H
+#define __XSC_CMD_H
+
+#include <linux/if_ether.h>
+
+#define XSC_CMDQ_VERSION 0x32
+
+#define XSC_BOARD_SN_LEN 32
+#define DSCP_PCP_UNSET 255
+#define XSC_MAX_NUM_PCIE_INTF 2
+#define XSC_MAX_PF_NUM_PER_PCIE 8
+
+/* hca_cap mbox version */
+#define CMD_QUERY_HCA_CAP_V1 1
+#define CMD_QUERY_HCA_CAP_V2 2
+#define CMD_QUERY_HCA_CAP_V3 3
+#define CMD_QUERY_HCA_CAP_V4 4
+#define CMD_QUERY_HCA_CAP_V5 5
+#define CMD_QUERY_HCA_CAP_V6 6
+#define CMD_QUERY_HCA_CAP_V7 7
+#define CMD_QUERY_HCA_CAP_V8 8
+#define CMD_QUERY_HCA_CAP_V9 9
+
+#define CMD_SET_CQ_CONTEXT_V1 1
+
+enum {
+ XSC_CMDQ_GET_HW_STATS_RDMA_V0 = 0,
+ XSC_CMDQ_GET_HW_STATS_RDMA_V1 = 1,
+
+ XSC_CMDQ_GET_HW_STATS_RDMA_UNKNOW,
+};
+
+enum {
+ XSC_CMD_STAT_OK = 0x0,
+ XSC_CMD_STAT_INT_ERR = 0x1,
+ XSC_CMD_STAT_BAD_OP_ERR = 0x2,
+ XSC_CMD_STAT_BAD_PARAM_ERR = 0x3,
+ XSC_CMD_STAT_BAD_SYS_STATE_ERR = 0x4,
+ XSC_CMD_STAT_BAD_RES_ERR = 0x5,
+ XSC_CMD_STAT_RES_BUSY = 0x6,
+ XSC_CMD_STAT_LIM_ERR = 0x8,
+ XSC_CMD_STAT_BAD_RES_STATE_ERR = 0x9,
+ XSC_CMD_STAT_IX_ERR = 0xa,
+ XSC_CMD_STAT_NO_RES_ERR = 0xf,
+ XSC_CMD_STAT_BAD_QP_STATE_ERR = 0x10,
+ XSC_CMD_STAT_BAD_PKT_ERR = 0x30,
+ XSC_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR = 0x40,
+ XSC_CMD_STAT_BAD_INP_LEN_ERR = 0x50,
+ XSC_CMD_STAT_BAD_OUTP_LEN_ERR = 0x51,
+};
+
+/* status aliases used by the RDMA driver (same protocol values) */
+#define XSC_CMD_STATUS_OK XSC_CMD_STAT_OK
+#define XSC_CMD_STATUS_FAIL XSC_CMD_STAT_INT_ERR
+#define XSC_CMD_STATUS_NOT_SUPPORTED XSC_CMD_STAT_BAD_OP_ERR
+#define XSC_CMD_STATUS_BAD_PARAM XSC_CMD_STAT_BAD_PARAM_ERR
+#define XSC_CMD_STATUS_INVAL_RES XSC_CMD_STAT_BAD_RES_ERR
+#define XSC_CMD_STATUS_BUSY XSC_CMD_STAT_RES_BUSY
+#define XSC_CMD_STATUS_INVAL_DATA XSC_CMD_STAT_LIM_ERR
+#define XSC_CMD_STATUS_NOT_FOUND XSC_CMD_STAT_IX_ERR
+#define XSC_CMD_STATUS_NO_RES XSC_CMD_STAT_NO_RES_ERR
+#define XSC_CMD_STATUS_BAD_INBUF XSC_CMD_STAT_BAD_INP_LEN_ERR
+#define XSC_CMD_STATUS_BAD_OUTBUF XSC_CMD_STAT_BAD_OUTP_LEN_ERR
+
+/* extended status codes */
+#define XSC_CMD_STATUS_INVAL_FUNC 0x41
+#define XSC_CMD_STATUS_NO_MPT_RES 0x42
+#define XSC_CMD_STATUS_NO_MTT_RES 0x43
+#define XSC_CMD_STATUS_NO_EQN_RES 0x44
+#define XSC_CMD_STATUS_NO_EQ_PA_RES 0x45
+#define XSC_CMD_STATUS_NO_CQN_RES 0x46
+#define XSC_CMD_STATUS_NO_CQ_PA_RES 0x47
+#define XSC_CMD_STATUS_NO_QPN_RES 0x48
+#define XSC_CMD_STATUS_NO_QP_PA_RES 0x49
+#define XSC_CMD_STATUS_NO_PDN_RES 0x4a
+#define XSC_CMD_STATUS_QP_FLUSH_BUSY 0x4b
+#define XSC_CMD_STATUS_QP_FLUSH_PENDING 0x4c
+#define XSC_CMD_STATUS_INVAL_OPCODE 0x52
+
+enum {
+ XSC_CMD_OP_QUERY_HCA_CAP = 0x100,
+ XSC_CMD_OP_QUERY_CMDQ_VERSION = 0x10a,
+ XSC_CMD_OP_FUNCTION_RESET = 0x10c,
+ XSC_CMD_OP_DUMMY = 0x10d,
+ XSC_CMD_OP_QUERY_GUID = 0x113,
+ XSC_CMD_OP_ACTIVATE_HW_CONFIG = 0x114,
+
+ XSC_CMD_OP_QUERY_HW_STATS = 0x1200,
+ XSC_CMD_OP_QUERY_HW_STATS_RDMA = 0x1203,
+ XSC_CMD_OP_QUERY_HW_GLOBAL_STATS = 0x1210,
+
+ XSC_CMD_OP_CREATE_MKEY = 0x200,
+ XSC_CMD_OP_DESTROY_MKEY = 0x202,
+ XSC_CMD_OP_REG_MR = 0x204,
+ XSC_CMD_OP_DEREG_MR = 0x205,
+ XSC_CMD_OP_SET_MPT = 0x206,
+ XSC_CMD_OP_SET_MTT = 0x207,
+
+ XSC_CMD_OP_CREATE_EQ = 0x301,
+ XSC_CMD_OP_DESTROY_EQ = 0x302,
+
+ XSC_CMD_OP_CREATE_CQ = 0x400,
+ XSC_CMD_OP_DESTROY_CQ = 0x401,
+ XSC_CMD_OP_SET_CQ_CONTEXT = 0x406,
+ XSC_CMD_OP_SET_CQ_BUF_PA = 0x407,
+ XSC_CMD_OP_CREATE_CQ_EX = 0x408,
+
+ XSC_CMD_OP_CREATE_QP = 0x500,
+ XSC_CMD_OP_DESTROY_QP = 0x501,
+ XSC_CMD_OP_RST2INIT_QP = 0x502,
+ XSC_CMD_OP_INIT2RTR_QP = 0x503,
+ XSC_CMD_OP_RTR2RTS_QP = 0x504,
+ XSC_CMD_OP_RTS2RTS_QP = 0x505,
+ XSC_CMD_OP_SQERR2RTS_QP = 0x506,
+ XSC_CMD_OP_2ERR_QP = 0x507,
+ XSC_CMD_OP_RTS2SQD_QP = 0x508,
+ XSC_CMD_OP_SQD2RTS_QP = 0x509,
+ XSC_CMD_OP_2RST_QP = 0x50a,
+ XSC_CMD_OP_QUERY_QP = 0x50b,
+ XSC_CMD_OP_INIT2INIT_QP = 0x50e,
+ XSC_CMD_OP_SQD2SQD_QP = 0x511,
+ XSC_CMD_OP_CREATE_MULTI_QP = 0x515,
+
+ XSC_CMD_OP_ALLOC_PD = 0x800,
+ XSC_CMD_OP_DEALLOC_PD = 0x801,
+
+ XSC_CMD_OP_MODIFY_RAW_QP = 0x81f,
+
+ XSC_CMD_OP_ENABLE_NIC_HCA = 0x810,
+ XSC_CMD_OP_DISABLE_NIC_HCA = 0x811,
+
+ XSC_CMD_OP_QUERY_VPORT_STATE = 0x822,
+ XSC_CMD_OP_QUERY_LINK_INFO = 0x832,
+ XSC_CMD_OP_MODIFY_LINK_INFO = 0x834,
+ XSC_CMD_OP_QUERY_EVENT_TYPE = 0x831,
+
+ XSC_CMD_OP_ENABLE_MSIX = 0x850,
+
+ 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_dma_direct {
+ XSC_DMA_DIR_TO_MAC,
+ XSC_DMA_DIR_READ,
+ XSC_DMA_DIR_WRITE,
+ XSC_DMA_DIR_LOOPBACK,
+ XSC_DMA_DIR_MAX
+};
+
+/* hw feature bitmap, 32bit */
+enum xsc_hw_feature_flag {
+ XSC_HW_RDMA_SUPPORT = BIT(0),
+ XSC_HW_PFC_PRIO_STATISTIC_SUPPORT = BIT(1),
+ XSC_HW_PFC_STALL_STATS_SUPPORT = BIT(3),
+ XSC_HW_RDMA_CM_SUPPORT = BIT(5),
+ XSC_HW_MTU_8192_SUPPORT = BIT(11),
+ XSC_HW_RDMA_ATOMIC_SUPPORT = BIT(17),
+ XSC_HW_MULTIDOORBELL_SUPPORT = BIT(18),
+ XSC_HW_CQE64_SUPPORT = BIT(21),
+
+ XSC_HW_LAST_FEATURE = BIT(31)
+};
+
+struct xsc_inbox_hdr {
+ __be16 opcode;
+ u8 rsvd[4];
+ __be16 ver; /* cmd version */
+};
+
+struct xsc_outbox_hdr {
+ u8 status;
+ u8 rsvd[5];
+ __be16 ver;
+};
+
+/*CQ mbox*/
+struct xsc_cq_context {
+ __be16 eqn; /* event queue number */
+ __be16 pa_num; /* physical address count in the ctx */
+ __be16 glb_func_id;
+ u8 log_cq_sz;
+ u8 cq_type;
+};
+
+struct xsc_cq_context_ex {
+ struct xsc_cq_context ctx;
+ u8 page_shift;
+ u8 overrun_ignore;
+ u8 rsvd[2];
+ u32 pa_num_ex;
+};
+
+struct xsc_create_cq_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ struct xsc_cq_context ctx;
+ __be64 pas[]; /* physical address list */
+};
+
+struct xsc_create_cq_ex_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ struct xsc_cq_context_ex ctx_ex;
+ __be64 pas[];
+};
+
+struct xsc_create_cq_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ __be32 cqn; /* completion queue number */
+ u8 rsvd[4];
+};
+
+struct xsc_destroy_cq_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be32 cqn;
+ u8 rsvd[4];
+};
+
+struct xsc_destroy_cq_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct xsc_set_cq_context_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ struct xsc_cq_context_ex ctx_ex;
+};
+
+struct xsc_set_cq_context_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ __be32 cqn;
+ __be32 cq_pa_list_base;
+};
+
+struct xsc_set_cq_buf_pa_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be32 pa_list_start;
+ __be32 pa_num;
+ __be64 pas[];
+};
+
+struct xsc_set_cq_buf_pa_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+/* MKey / MPT / MTT mbox */
+struct xsc_create_mkey_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ u8 rsvd[4];
+};
+
+struct xsc_create_mkey_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ __be32 mkey;
+};
+
+struct xsc_destroy_mkey_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be32 mkey;
+};
+
+struct xsc_destroy_mkey_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd;
+};
+
+struct xsc_mpt_item {
+ __be32 pdn;
+ __be32 pa_num;
+ __be32 len;
+ __be32 mkey;
+ __be32 len_h;
+ u8 is_gpu;
+ u8 acc;
+ u8 page_mode;
+ u8 map_en;
+ __be64 va_base;
+};
+
+struct xsc_set_mpt_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ struct xsc_mpt_item mpt_item;
+};
+
+struct xsc_set_mpt_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ __be32 mtt_base;
+ u8 rsvd[4];
+};
+
+struct xsc_mtt_setting {
+ __be32 mtt_base;
+ __be32 pa_num;
+ __be64 pas[];
+};
+
+struct xsc_set_mtt_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ struct xsc_mtt_setting mtt_setting;
+};
+
+struct xsc_set_mtt_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+/*QP mbox*/
+enum {
+ MODULE_SPEED_UNKNOWN,
+ MODULE_SPEED_10G,
+ MODULE_SPEED_25G,
+ MODULE_SPEED_40G_R4,
+ MODULE_SPEED_50G_R,
+ MODULE_SPEED_50G_R2,
+ MODULE_SPEED_100G_R2,
+ MODULE_SPEED_100G_R4,
+ MODULE_SPEED_200G_R4,
+ MODULE_SPEED_200G_R8,
+ MODULE_SPEED_400G_R8,
+ MODULE_SPEED_400G_R4,
+};
+
+struct xsc_create_qp_request {
+ __be16 input_qpn;
+ __be16 pa_num;
+ u8 qp_type;
+ u8 log_sq_sz;
+ u8 log_rq_sz;
+ u8 dma_direct;
+ __be32 pdn; /* protect domain number */
+ __be16 cqn_send;
+ __be16 cqn_recv;
+ __be16 glb_funcid;
+ /*rsvd, the old logic_port */
+ u8 page_shift;
+ u8 rsvd;
+ __be64 pas[];
+};
+
+struct xsc_create_qp_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ struct xsc_create_qp_request req;
+};
+
+struct xsc_create_qp_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ __be32 qpn; /* queue pair number */
+ u8 rsvd[4];
+};
+
+struct xsc_destroy_qp_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be32 qpn;
+ u8 rsvd[4];
+};
+
+struct xsc_destroy_qp_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+/* MR mbox */
+struct xsc_register_mr_request {
+ __be32 pdn;
+ __be32 pa_num;
+ __be64 len;
+ __be32 mkey;
+ u8 is_gpu;
+ u8 acc;
+ u8 page_mode;
+ u8 map_en;
+ __be64 va_base;
+ __be64 pas[];
+};
+
+struct xsc_register_mr_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ struct xsc_register_mr_request req;
+};
+
+struct xsc_unregister_mr_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be32 mkey;
+ u8 rsvd[4];
+};
+
+struct xsc_unregister_mr_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+enum qp_access_flag {
+ QP_ACCESS_REMOTE_READ = (1 << 0),
+ QP_ACCESS_REMOTE_WRITE = (1 << 1),
+ QP_ACCESS_REMOTE_ATOMIC = (1 << 2),
+ QP_ACCESS_MODIFY_QP_TYPE = (1 << 3),
+};
+
+#define XSC_QP_CONTEXT_V1 1
+#define XSC_QP_CONTEXT_V2 2
+
+struct xsc_qp_context {
+ __be32 remote_qpn;
+ __be32 cqn_send;
+ __be32 cqn_recv;
+ __be32 next_send_psn;
+ __be32 next_recv_psn;
+ __be32 pdn;
+ __be16 src_udp_port;
+ __be16 path_id;
+ u8 mtu_mode;
+ u8 lag_sel;
+ u8 lag_sel_en;
+ u8 retry_cnt;
+ u8 rnr_retry;
+ u8 dscp;
+ u8 state;
+ u8 hop_limit;
+ u8 dmac[6];
+ u8 smac[6];
+ __be32 dip[4];
+ __be32 sip[4];
+ __be16 ip_type;
+ __be16 grp_id;
+ u8 vlan_valid;
+ u8 dci_cfi_prio_sl;
+ __be16 vlan_id;
+ u8 qp_out_port;
+ u8 pcie_no;
+ __be16 lag_id;
+ __be16 func_id;
+ u8 max_sra;
+ u8 max_rra;
+ u8 no_need_wait;
+ u8 swith_qp_type;
+ u8 rsvd0[2];
+ __be32 qp_access_flags;
+};
+
+struct xsc_modify_qp_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be32 qpn;
+ struct xsc_qp_context ctx;
+ u8 no_need_wait;
+};
+
+struct xsc_modify_qp_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct xsc_query_qp_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be32 qpn;
+ u8 rsvd[4];
+};
+
+struct xsc_query_qp_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ struct xsc_qp_context ctx;
+};
+
+struct xsc_create_multiqp_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be16 qp_num;
+ u8 qp_type;
+ u8 rsvd;
+ __be32 req_len;
+ u8 data[];
+};
+
+struct xsc_create_multiqp_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ __be32 qpn_base;
+};
+
+/* PD mbox */
+struct xsc_alloc_pd_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct xsc_alloc_pd_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ __be32 pdn;
+ u8 rsvd[4];
+};
+
+struct xsc_dealloc_pd_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be32 pdn;
+ u8 rsvd[4];
+};
+
+struct xsc_dealloc_pd_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+/* MSIX TABLE mbox */
+struct xsc_msix_table_info_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be16 index;
+ u8 rsvd[6];
+};
+
+struct xsc_msix_table_info_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ __be32 addr_lo;
+ __be32 addr_hi;
+ __be32 data;
+};
+
+/*EQ mbox*/
+struct xsc_eq_context {
+ __be16 vecidx;
+ __be16 pa_num;
+ u8 log_eq_sz;
+ __be16 glb_func_id;
+ u8 is_async_eq;
+ u8 rsvd;
+};
+
+struct xsc_create_eq_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ struct xsc_eq_context ctx;
+ __be64 pas[];
+};
+
+struct xsc_create_eq_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ __be32 eqn;
+ u8 rsvd[4];
+};
+
+struct xsc_destroy_eq_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be32 eqn;
+ u8 rsvd[4];
+};
+
+struct xsc_destroy_eq_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct xsc_cmd_query_cmdq_ver_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct xsc_cmd_query_cmdq_ver_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ __be16 cmdq_ver;
+ u8 rsvd[6];
+};
+
+struct xsc_fw_version {
+ u8 fw_version_major;
+ u8 fw_version_minor;
+ __be16 fw_version_patch;
+ __be32 fw_version_tweak;
+ u8 fw_version_extra_flag;
+ u8 rsvd[7];
+};
+
+struct xsc_hca_cap {
+ u8 rsvd1[12];
+ u8 send_seg_num;
+ u8 send_wqe_shift;
+ u8 recv_seg_num;
+ u8 recv_wqe_shift;
+ u8 log_max_srq_sz;
+ u8 log_max_qp_sz;
+ u8 log_max_mtt;
+ u8 log_max_qp;
+ u8 log_max_strq_sz;
+ u8 log_max_srqs;
+ u8 rsvd4[2];
+ u8 log_max_tso;
+ u8 log_max_cq_sz;
+ u8 rsvd6;
+ u8 log_max_cq;
+ u8 log_max_eq_sz;
+ u8 log_max_mkey;
+ u8 log_max_msix;
+ u8 log_max_eq;
+ u8 max_indirection;
+ u8 log_max_mrw_sz;
+ u8 log_max_bsf_list_sz;
+ u8 log_max_klm_list_sz;
+ u8 rsvd_8_0;
+ u8 log_max_ra_req_dc;
+ u8 rsvd_8_1;
+ u8 log_max_ra_res_dc;
+ u8 rsvd9;
+ u8 log_max_ra_req_qp;
+ u8 log_max_qp_depth;
+ u8 log_max_ra_res_qp;
+ __be16 max_vfs;
+ __be16 raweth_qp_id_end;
+ __be16 raw_tpe_qp_num;
+ __be16 max_qp_count;
+ __be16 raweth_qp_id_base;
+ u8 rsvd13;
+ u8 local_ca_ack_delay;
+ u8 max_num_eqs;
+ u8 num_ports;
+ u8 log_max_msg;
+ u8 mac_port;
+ __be16 raweth_rss_qp_id_base;
+ __be16 stat_rate_support;
+ u8 rsvd16[2];
+ __be64 flags;
+ u8 rsvd17;
+ u8 uar_sz;
+ u8 rsvd18;
+ u8 log_pg_sz;
+ __be16 bf_log_bf_reg_size;
+ __be16 msix_base;
+ __be16 msix_num;
+ __be16 max_desc_sz_sq;
+ u8 rsvd20[2];
+ __be16 max_desc_sz_rq;
+ u8 rsvd21[2];
+ __be16 max_desc_sz_sq_dc;
+ u8 rsvd22[4];
+ __be16 max_qp_mcg;
+ u8 rsvd23;
+ u8 log_max_mcg;
+ u8 rsvd24;
+ u8 log_max_pd;
+ u8 rsvd25;
+ u8 log_max_xrcd;
+ u8 rsvd26[40];
+ __be32 uar_page_sz;
+ u8 rsvd27[8];
+ __be32 hw_feature_flag; /* enum xsc_hw_feature_flag */
+ __be16 pf0_vf_funcid_base;
+ __be16 pf0_vf_funcid_top;
+ __be16 pf1_vf_funcid_base;
+ __be16 pf1_vf_funcid_top;
+ __be16 pcie0_pf_funcid_base;
+ __be16 pcie0_pf_funcid_top;
+ __be16 pcie1_pf_funcid_base;
+ __be16 pcie1_pf_funcid_top;
+ u8 log_msx_atomic_size_qp;
+ u8 pcie_host;
+ u8 rsvd28;
+ u8 log_msx_atomic_size_dc;
+ u8 board_sn[XSC_BOARD_SN_LEN];
+ u8 max_tc;
+ u8 mac_bit;
+ __be16 funcid_to_logic_port;
+ u8 rsvd29[6];
+ u8 nif_port_num;
+ u8 reg_mr_via_cmdq;
+ __be32 hca_core_clock;
+ __be32 max_rwq_indirection_tables; /* rss_caps */
+ __be32 max_rwq_indirection_table_size; /* rss_caps */
+ __be32 chip_ver_h;
+ __be32 chip_ver_m;
+ __be32 chip_ver_l;
+ __be32 hotfix_num;
+ __be32 feature_flag;
+ __be32 rx_pkt_len_max;
+ __be32 glb_func_id;
+ __be64 tx_db;
+ __be64 rx_db;
+ __be64 complete_db;
+ __be64 complete_reg;
+ __be64 event_db;
+ __be32 qp_rate_limit_min;
+ __be32 qp_rate_limit_max;
+ struct xsc_fw_version fw_ver;
+ u8 lag_logic_port_ofst;
+ /* V1 */
+ __be64 max_mr_size;
+ __be16 max_cmd_in_len;
+ __be16 max_cmd_out_len;
+ /* V2 */
+ __be32 max_qp;
+ __be32 max_cq;
+ __be32 max_pd;
+ __be32 max_mtt;
+ /* V3 */
+ __be32 mpt_tbl_addr;
+ __be32 mpt_tbl_depth;
+ __be32 mpt_tbl_width;
+ __be32 mtt_inst_base_addr;
+ __be32 mtt_inst_stride;
+ __be32 mtt_inst_num_log;
+ __be32 mtt_inst_depth;
+ /* V4 */
+ __be16 vf_funcid_base[XSC_MAX_NUM_PCIE_INTF][XSC_MAX_PF_NUM_PER_PCIE];
+ __be16 vf_funcid_top[XSC_MAX_NUM_PCIE_INTF][XSC_MAX_PF_NUM_PER_PCIE];
+ __be16 pf_funcid_base[XSC_MAX_NUM_PCIE_INTF];
+ __be16 pf_funcid_top[XSC_MAX_NUM_PCIE_INTF];
+ u8 pcie_no;
+ u8 pf_id;
+ __be16 vf_id;
+ u8 pcie_host_num;
+ u8 pf_num_per_pcie;
+ /* V6 */
+ u16 ft_support;
+ /* V7 */
+ __be16 total_dynamic_vf_msix;
+ __be16 min_dynamic_vf_msix;
+ __be16 max_dynamic_vf_msix;
+ /* V8 */
+ u8 max_sgl_rd;
+ u8 rsvd30;
+ /* V9 */
+ __be32 mdb_num;
+ u8 rsvd31[4];
+ __be64 mdb_base;
+};
+
+struct xsc_cmd_query_hca_cap_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be16 cpu_num;
+ u8 rsvd[6];
+};
+
+struct xsc_cmd_query_hca_cap_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd0[8];
+ struct xsc_hca_cap hca_cap;
+};
+
+struct xsc_query_vport_state_out {
+ struct xsc_outbox_hdr hdr;
+ u8 admin_state:4;
+ u8 state:4;
+};
+
+struct xsc_query_vport_state_in {
+ struct xsc_inbox_hdr hdr;
+ __be32 data0;
+#define XSC_QUERY_VPORT_OTHER_VPORT BIT(0)
+#define XSC_QUERY_VPORT_VPORT_NUM_MASK GENMASK(16, 1)
+};
+
+enum {
+ XSC_CMD_EVENT_RESP_CHANGE_LINK = BIT(0),
+ XSC_CMD_EVENT_RESP_TEMP_WARN = BIT(1),
+ XSC_CMD_EVENT_RESP_OVER_TEMP_PROTECTION = BIT(2),
+};
+
+struct xsc_event_resp {
+ u8 resp_cmd_type;
+};
+
+struct xsc_event_query_type_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ u8 rsvd[2];
+};
+
+struct xsc_event_query_type_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ struct xsc_event_resp ctx;
+};
+
+struct xsc_modify_raw_qp_request {
+ __be16 qpn;
+ __be16 lag_id;
+ __be16 func_id;
+ u8 dma_direct;
+ u8 prio;
+ u8 qp_out_port;
+ u8 rsvd[7];
+};
+
+struct xsc_modify_raw_qp_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ u8 pcie_no;
+ u8 rsvd[7];
+ struct xsc_modify_raw_qp_request req;
+};
+
+struct xsc_modify_raw_qp_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct xsc_set_mtu_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be16 mtu;
+ __be16 rx_buf_sz_min;
+ u8 mac_port;
+ u8 rsvd;
+};
+
+struct xsc_set_mtu_mbox_out {
+ struct xsc_outbox_hdr hdr;
+};
+
+struct xsc_query_eth_mac_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ u8 index;
+};
+
+struct xsc_query_eth_mac_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 mac[ETH_ALEN];
+};
+
+enum {
+ XSC_TBM_CAP_HASH_PPH = 0,
+ XSC_TBM_CAP_RSS,
+ XSC_TBM_CAP_PP_BYPASS,
+ XSC_TBM_CAP_PCT_DROP_CONFIG,
+};
+
+struct xsc_nic_attr {
+ __be16 caps;
+ __be16 caps_mask;
+ u8 mac_addr[ETH_ALEN];
+};
+
+struct xsc_rss_attr {
+ u8 rss_en;
+ u8 hfunc;
+ __be16 rqn_base;
+ __be16 rqn_num;
+ __be32 hash_tmpl;
+};
+
+struct xsc_cmd_enable_nic_hca_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ struct xsc_nic_attr nic;
+ struct xsc_rss_attr rss;
+};
+
+struct xsc_cmd_enable_nic_hca_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd0[2];
+};
+
+struct xsc_nic_dis_attr {
+ __be16 caps;
+};
+
+struct xsc_cmd_disable_nic_hca_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ struct xsc_nic_dis_attr nic;
+};
+
+struct xsc_cmd_disable_nic_hca_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd0[4];
+};
+
+struct xsc_function_reset_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be16 glb_func_id;
+ u8 rsvd[6];
+};
+
+struct xsc_function_reset_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct xsc_cmd_query_guid_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct xsc_cmd_query_guid_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ __be64 guid;
+};
+
+struct xsc_cmd_activate_hw_config_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct xsc_cmd_activate_hw_config_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ u8 rsvd[8];
+};
+
+struct xsc_event_linkinfo {
+ u8 linkstatus; /*0:down, 1:up*/
+ u8 port;
+ u8 duplex;
+ u8 autoneg;
+ u32 linkspeed;
+ u64 supported;
+ u64 advertising;
+ u64 supported_fec; /* reserved, not support currently */
+ u64 advertised_fec; /* reserved, not support currently */
+ u64 supported_speed[2];
+ u64 advertising_speed[2];
+};
+
+struct xsc_event_query_linkinfo_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ struct xsc_event_linkinfo ctx;
+};
+
+struct xsc_event_set_port_admin_status_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ __be16 status;
+};
+
+struct xsc_event_set_port_admin_status_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ __be32 status;
+};
+
+/* HW stats mbox */
+struct xsc_hw_stats_rdma_pf {
+ /*by mac port*/
+ u64 rdma_tx_pkts;
+ u64 rdma_tx_bytes;
+ u64 rdma_rx_pkts;
+ u64 rdma_rx_bytes;
+ u64 np_cnp_sent;
+ u64 rp_cnp_handled;
+ u64 np_ecn_marked_roce_packets;
+ u64 rp_cnp_ignored;
+ u64 read_rsp_out_of_seq;
+ u64 implied_nak_seq_err;
+ /*by function*/
+ u64 out_of_sequence;
+ u64 packet_seq_err;
+ u64 out_of_buffer;
+ u64 rnr_nak_retry_err;
+ u64 local_ack_timeout_err;
+ u64 rx_read_requests;
+ u64 rx_write_requests;
+ u64 duplicate_requests;
+ u64 rdma_tx_pkts_func;
+ u64 rdma_tx_payload_bytes;
+ u64 rdma_rx_pkts_func;
+ u64 rdma_rx_payload_bytes;
+ /*global*/
+ u64 rdma_loopback_pkts;
+ u64 rdma_loopback_bytes;
+ /*for diamond*/
+ u64 out_of_sequence_sr;
+ u64 packet_seq_err_sr;
+ u64 rdma_ndp_rx_pkts;
+ u64 rdma_ndp_rx_trimmed_pkts;
+ u64 rdma_ndp_trimmed_pkts_sr;
+ u64 rx_icrc_encapsulated;
+};
+
+struct xsc_hw_stats_rdma_vf {
+ /*by function*/
+ u64 rdma_tx_pkts_func;
+ u64 rdma_tx_payload_bytes;
+ u64 rdma_rx_pkts_func;
+ u64 rdma_rx_payload_bytes;
+
+ u64 out_of_sequence;
+ u64 packet_seq_err;
+ u64 out_of_buffer;
+ u64 rnr_nak_retry_err;
+ u64 local_ack_timeout_err;
+ u64 rx_read_requests;
+ u64 rx_write_requests;
+ u64 duplicate_requests;
+};
+
+struct xsc_hw_stats_rdma {
+ u8 is_pf;
+ u8 rsv;
+ __be16 ver;
+ union {
+ struct xsc_hw_stats_rdma_pf pf_stats;
+ struct xsc_hw_stats_rdma_vf vf_stats;
+ } stats;
+};
+
+#define CMD_QUERY_HW_STATS_V1 1
+struct xsc_hw_stats_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ u8 mac_port;
+ u8 is_lag;
+ u8 lag_member_num;
+ u8 member_port[];
+};
+
+struct xsc_hw_stats_rdma_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ struct xsc_hw_stats_rdma hw_stats;
+};
+
+struct xsc_hw_global_stats_rdma {
+ /*by global*/
+ u64 rdma_loopback_pkts;
+ u64 rdma_loopback_bytes;
+ u64 rx_icrc_encapsulated;
+ u64 req_cqe_error;
+ u64 resp_cqe_error;
+ u64 cqe_msg_code_error;
+};
+
+struct xsc_hw_global_stats_mbox_in {
+ struct xsc_inbox_hdr hdr;
+ u8 rsv[4];
+};
+
+struct xsc_hw_global_stats_mbox_out {
+ struct xsc_outbox_hdr hdr;
+ struct xsc_hw_global_stats_rdma hw_stats;
+};
+
+#endif /* __XSC_CMD_H */
diff --git a/drivers/net/ethernet/yunsilicon/xsc/common/xsc_cmd_api.h b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_cmd_api.h
new file mode 100644
index 000000000..3ef6080ae
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_cmd_api.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021-2026, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#ifndef __XSC_DRIVER_H
+#define __XSC_DRIVER_H
+
+#include "common/xsc_core.h"
+#include "common/xsc_cmd.h"
+
+int xsc_cmd_init(struct xsc_core_device *xdev);
+void xsc_cmd_cleanup(struct xsc_core_device *xdev);
+void xsc_cmd_use_events(struct xsc_core_device *xdev);
+void xsc_cmd_use_polling(struct xsc_core_device *xdev);
+int xsc_cmd_err_handler(struct xsc_core_device *xdev);
+void xsc_cmd_resp_handler(struct xsc_core_device *xdev);
+int xsc_cmd_exec(struct xsc_core_device *xdev,
+ void *in, unsigned int in_size,
+ void *out, unsigned int out_size);
+int xsc_cmd_version_check(struct xsc_core_device *xdev);
+
+int xsc_cmd_status_to_err(struct xsc_outbox_hdr *hdr);
+
+#endif
diff --git a/drivers/net/ethernet/yunsilicon/xsc/common/xsc_cmdq.h b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_cmdq.h
new file mode 100644
index 000000000..004611146
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_cmdq.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021-2026, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#ifndef __XSC_CMDQ_H
+#define __XSC_CMDQ_H
+
+#include <linux/if_ether.h>
+
+#include "common/xsc_cmd.h"
+
+#define XSC_CMD_MAX_RETRY_CNT 3
+
+enum {
+ XSC_CMD_TIMEOUT_MSEC = 10 * 1000,
+ XSC_CMD_WQ_MAX_NAME = 32,
+};
+
+enum {
+ XSC_CMD_DATA, /* print command payload only */
+ XSC_CMD_TIME, /* print command execution time */
+};
+
+enum {
+ XSC_MAX_COMMANDS = 32,
+ XSC_CMD_DATA_BLOCK_SIZE = 512,
+ XSC_PCI_CMD_XPORT = 7,
+};
+
+struct xsc_cmd_prot_block {
+ u8 data[XSC_CMD_DATA_BLOCK_SIZE];
+ u8 rsvd0[48];
+ __be64 next;
+ __be32 block_num;
+ /* init to 0, dma user should change this val to 1 */
+ u8 owner_status;
+ u8 token;
+ u8 ctrl_sig;
+ u8 sig;
+};
+
+struct cache_ent {
+ /* protect block chain allocations */
+ spinlock_t lock;
+ struct list_head head;
+};
+
+struct cmd_msg_cache {
+ struct cache_ent large;
+ struct cache_ent med;
+
+};
+
+#define CMD_FIRST_SIZE 8
+struct xsc_cmd_first {
+ __be32 data[CMD_FIRST_SIZE];
+};
+
+struct xsc_cmd_mailbox {
+ void *buf;
+ dma_addr_t dma;
+ struct xsc_cmd_mailbox *next;
+};
+
+struct xsc_cmd_msg {
+ struct list_head list;
+ struct cache_ent *cache;
+ u32 len;
+ struct xsc_cmd_first first;
+ struct xsc_cmd_mailbox *next;
+};
+
+#define RSP_FIRST_SIZE 14
+struct xsc_rsp_first {
+ /* can be larger, xsc_rsp_layout */
+ __be32 data[RSP_FIRST_SIZE];
+};
+
+struct xsc_rsp_msg {
+ struct list_head list;
+ struct cache_ent *cache;
+ u32 len;
+ struct xsc_rsp_first first;
+ struct xsc_cmd_mailbox *next;
+};
+
+typedef void (*xsc_cmd_cbk_t)(int status, void *context);
+
+/* hw will use this for some records(e.g. vf_id) */
+struct cmdq_rsv {
+ u16 vf_id;
+ u8 rsv[2];
+};
+
+/* related with hw, won't change */
+
+struct xsc_cmd_layout {
+ struct cmdq_rsv rsv0;
+ __be32 inlen;
+ __be64 in_ptr;
+ __be32 in[CMD_FIRST_SIZE];
+ __be64 out_ptr;
+ __be32 outlen;
+ u8 token;
+ u8 sig;
+ u8 idx;
+ u8 type: 7;
+ /* rsv for hw, arm will check this bit to make sure mem written */
+ u8 owner_bit: 1;
+};
+
+struct xsc_rsp_layout {
+ struct cmdq_rsv rsv0;
+ __be32 out[RSP_FIRST_SIZE];
+ u8 token;
+ u8 sig;
+ u8 idx;
+ u8 type: 7;
+ /* rsv for hw, driver will check this bit to make sure mem written */
+ u8 owner_bit: 1;
+};
+
+struct xsc_cmd_work_ent {
+ struct xsc_cmd_msg *in;
+ struct xsc_rsp_msg *out;
+ int idx;
+ struct completion done;
+ struct xsc_cmd *cmd;
+ struct work_struct work;
+ struct xsc_cmd_layout *lay;
+ struct xsc_rsp_layout *rsp_lay;
+ int ret;
+ u8 status;
+ u8 token;
+};
+
+enum xsc_cmd_status {
+ XSC_CMD_STATUS_NORMAL,
+ XSC_CMD_STATUS_TIMEDOUT,
+};
+
+enum xsc_cmd_mode {
+ XSC_CMD_MODE_POLLING,
+ XSC_CMD_MODE_EVENTS,
+};
+
+struct xsc_cmd {
+ void *cmd_buf;
+ void *cq_buf;
+ dma_addr_t dma;
+ dma_addr_t cq_dma;
+ u16 cmd_pid;
+ u16 cq_cid;
+ u8 owner_bit;
+ u8 retry_cnt;
+ u8 cmdif_rev;
+ u8 log_sz;
+ u8 log_stride;
+ int max_reg_cmds;
+ int events;
+ u32 __iomem *vector;
+
+ /* protect command queue allocations */
+ spinlock_t alloc_lock;
+ /* protect token allocations */
+ spinlock_t token_lock;
+ /* protect cmdq req pid doorbell */
+ spinlock_t doorbell_lock;
+ u8 token;
+ unsigned long cmd_entry_mask;
+ char wq_name[XSC_CMD_WQ_MAX_NAME];
+ struct workqueue_struct *wq;
+ struct task_struct *cq_task;
+ /* The semaphore limits the number of working commands
+ * to max_reg_cmds. Each exec_cmd call does a down
+ * to acquire the semaphore before execution and an up
+ * after completion, ensuring no more than max_reg_cmds
+ * commands run at the same time.
+ */
+ struct semaphore sem;
+ enum xsc_cmd_mode mode;
+ struct xsc_cmd_work_ent *ent_arr[XSC_MAX_COMMANDS];
+ struct dma_pool *pool;
+ struct cmd_msg_cache cache;
+ int checksum_disabled;
+ unsigned int irqn;
+ u8 ownerbit_learned;
+ u8 cmd_status;
+};
+
+#endif
diff --git a/drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h
new file mode 100644
index 000000000..f491b9d8d
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h
@@ -0,0 +1,707 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021-2026, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#ifndef __XSC_CORE_H
+#define __XSC_CORE_H
+
+#include <linux/pci.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/if_vlan.h>
+#include <linux/reboot.h>
+
+#include "common/xsc_reg.h"
+#include "common/xsc_cmdq.h"
+
+#define XSC_PCI_VENDOR_ID 0x1f67
+
+#define XSC_MC_PF_DEV_ID 0x1011
+#define XSC_MC_VF_DEV_ID 0x1012
+
+#define XSC_MF_HOST_PF_DEV_ID 0x1051
+#define XSC_MF_HOST_VF_DEV_ID 0x1052
+#define XSC_MF_SOC_PF_DEV_ID 0x1053
+
+#define XSC_MS_PF_DEV_ID 0x1111
+#define XSC_MS_VF_DEV_ID 0x1112
+
+#define XSC_MV_HOST_PF_DEV_ID 0x1151
+#define XSC_MV_HOST_VF_DEV_ID 0x1152
+#define XSC_MV_SOC_PF_DEV_ID 0x1153
+
+#define PAGE_SHIFT_4K 12
+#define PAGE_SIZE_4K (_AC(1, UL) << PAGE_SHIFT_4K)
+
+#define XSC_ORIGIN_PF_BAR_SIZE (256 * 1024 * 1024)
+
+enum xsc_coredev_type {
+ XSC_COREDEV_PF,
+ XSC_COREDEV_VF,
+ XSC_COREDEV_SF
+};
+
+enum {
+ XSC_MAX_EQ_NAME = 20
+};
+
+enum {
+ XSC_MAX_IRQ_NAME = 32
+};
+
+enum {
+ XSC_MAX_FW_PORTS = 1,
+};
+
+enum {
+ XSC_BF_REGS_PER_PAGE = 4,
+ XSC_MAX_UAR_PAGES = 1 << 8,
+ XSC_MAX_UUARS = XSC_MAX_UAR_PAGES * XSC_BF_REGS_PER_PAGE,
+};
+
+/* alloc */
+struct xsc_buf_list {
+ void *buf;
+ dma_addr_t map;
+};
+
+struct xsc_buf {
+ struct xsc_buf_list direct;
+ struct xsc_buf_list *page_list;
+ unsigned long nbufs;
+ unsigned long npages;
+ unsigned long page_shift;
+ unsigned long size;
+};
+
+struct xsc_frag_buf {
+ struct xsc_buf_list *frags;
+ unsigned long npages;
+ unsigned long size;
+ u8 page_shift;
+};
+
+struct xsc_frag_buf_ctrl {
+ struct xsc_buf_list *frags;
+ u32 sz_m1;
+ u16 frag_sz_m1;
+ u16 strides_offset;
+ u8 log_sz;
+ u8 log_stride;
+ u8 log_frag_strides;
+};
+
+/* qp */
+struct xsc_send_wqe_ctrl_seg {
+ union {
+ __le32 data0;
+ struct {
+ __le32 msg_opcode:8;
+ __le32 with_immdt:1;
+ __le32 csum_en:2;
+ __le32 ds_data_num:5;
+ __le32 wqe_id:16;
+ };
+ };
+#define XSC_WQE_CTRL_SEG_MSG_OPCODE_MASK GENMASK(7, 0)
+#define XSC_WQE_CTRL_SEG_WITH_IMM BIT(8)
+#define XSC_WQE_CTRL_SEG_CSUM_EN_MASK GENMASK(10, 9)
+#define XSC_WQE_CTRL_SEG_DS_DATA_NUM_MASK GENMASK(15, 11)
+#define XSC_WQE_CTRL_SEG_WQE_ID_MASK GENMASK(31, 16)
+
+ __le32 msg_len;
+
+ union {
+ __le32 data2;
+ __le32 opcode_data;
+ struct {
+ u8 has_pph:1;
+ u8 so_type:1;
+ __le16 so_data_size:14;
+ u8:8;
+ u8 so_hdr_len:8;
+ };
+ };
+#define XSC_WQE_CTRL_SEG_HAS_PPH BIT(0)
+#define XSC_WQE_CTRL_SEG_SO_TYPE BIT(1)
+#define XSC_WQE_CTRL_SEG_SO_DATA_SIZE_MASK GENMASK(15, 2)
+#define XSC_WQE_CTRL_SEG_SO_HDR_LEN_MASK GENMASK(31, 24)
+
+ union {
+ __le32 data3;
+ struct {
+ __le32 se:1;
+ __le32 ce:1;
+ __le32:30;
+ };
+ };
+#define XSC_WQE_CTRL_SEG_SE BIT(0)
+#define XSC_WQE_CTRL_SEG_CE BIT(1)
+};
+
+struct xsc_wqe_data_seg {
+ union {
+ __le32 data0;
+ __le32 in_line:1;
+ struct {
+ __le32:1;
+ __le32 seg_len:31;
+ __le32 mkey;
+ __le64 va;
+ };
+ struct {
+ __le32:1;
+ __le32 len:7;
+ u8 in_line_data[15];
+ };
+ };
+#define XSC_WQE_DATA_SEG_SEG_LEN_MASK GENMASK(31, 1)
+};
+
+struct xsc_core_qp {
+ void (*event)(struct xsc_core_qp *qp, int type);
+ u32 qpn;
+ atomic_t refcount;
+ struct completion free;
+ int pid;
+ u16 qp_type;
+ u16 eth_queue_type;
+ u16 qp_type_internal;
+ u16 grp_id;
+ u8 mac_id;
+ u8 err_occurred;
+ u32 qp_protocol_mode;
+ u32 qp_access_flags;
+};
+
+struct xsc_qp_table {
+ spinlock_t lock; /* protect radix tree */
+ struct radix_tree_root tree;
+};
+
+/* cq */
+#define XSC_MAX_NAME_LEN 32
+#define XSC_MAX_IBDEV_NAME_LEN 64
+
+struct xsc_priv {
+ char name[XSC_MAX_NAME_LEN];
+ char ibdev_name[XSC_MAX_IBDEV_NAME_LEN];
+ int cm_pcp;
+ int cm_dscp;
+ int force_pcp;
+ int force_dscp;
+};
+
+enum xsc_dev_event {
+ XSC_DEV_EVENT_SYS_ERROR,
+ XSC_DEV_EVENT_PORT_UP,
+ XSC_DEV_EVENT_PORT_DOWN,
+ XSC_DEV_EVENT_PORT_INITIALIZED,
+ XSC_DEV_EVENT_LID_CHANGE,
+ XSC_DEV_EVENT_PKEY_CHANGE,
+ XSC_DEV_EVENT_GUID_CHANGE,
+ XSC_DEV_EVENT_CLIENT_REREG,
+};
+
+enum {
+ RDMA_PROTO_ROCEV2,
+ RDMA_PROTO_VEROCE,
+};
+
+#define VEROCE_UDP_DPORT 4794
+#define MAX_MR_CACHE_ENTRIES 5000
+
+enum xsc_event {
+ XSC_EVENT_TYPE_COMP = 0x0,
+ /* mad */
+ XSC_EVENT_TYPE_COMM_EST = 0x02,
+ XSC_EVENT_TYPE_CQ_ERROR = 0x04,
+ XSC_EVENT_TYPE_WQ_CATAS_ERROR = 0x05,
+ XSC_EVENT_TYPE_INTERNAL_ERROR = 0x08,
+ /* IBV_EVENT_QP_REQ_ERR */
+ XSC_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10,
+ /* IBV_EVENT_QP_ACCESS_ERR */
+ XSC_EVENT_TYPE_WQ_ACCESS_ERROR = 0x11,
+};
+
+struct xsc_cqe {
+ union {
+ __le32 data0;
+ struct {
+ u8 placeholder1;
+#define XSC_CQE_MSG_OPCD_MASK GENMASK(7, 0)
+#define XSC_CQE_ERR_CODE_MASK GENMASK(6, 0)
+#define XSC_CQE_IS_ERR BIT(7)
+#define XSC_CQE_QP_ID_MASK GENMASK(22, 8)
+#define XSC_CQE_SE BIT(24)
+#define XSC_CQE_HAS_PPH BIT(25)
+#define XSC_CQE_TYPE BIT(26)
+#define XSC_CQE_WITH_IMM BIT(27)
+#define XSC_CQE_CSUM_ERR_MASK GENMASK(31, 28)
+ __le32 qp_id:15;
+ u8 rsv1:1;
+ u8 se:1;
+ u8 has_pph:1;
+ u8 type:1;
+ u8 with_immdt:1;
+ u8 csum_err:4;
+ };
+ };
+
+ __le32 imm_data;
+ __le32 msg_len;
+ __le32 vni;
+
+ __le64 ts:48;
+
+ __le16 wqe_id;
+ u8 placeholder2;
+ u8 rsv3;
+ __le16 rsv[1];
+
+ union {
+ __le32 data1;
+ struct {
+ __le16 rsv0;
+ __le16 rsv2:15;
+#define XSC_CQE_OWNER BIT(31)
+ u8 owner:1;
+ };
+ };
+};
+
+struct xsc_cqe64 {
+ struct xsc_cqe cqe;
+ u8 padding[32];
+};
+
+struct xsc_core_cq {
+ u32 cqn;
+ u32 cqe_sz;
+ struct xsc_core_device *xdev;
+ struct xsc_core_device *dev;
+ atomic_t refcount;
+ struct completion free;
+ unsigned int vector;
+ unsigned int irqn;
+ void (*comp)(struct xsc_core_cq *cq);
+ void (*event)(struct xsc_core_cq *cq,
+ enum xsc_event);
+ u32 cons_index;
+ unsigned int arm_sn;
+ int pid;
+ u32 reg_next_cid;
+ u32 reg_done_pid;
+ struct xsc_eq *eq;
+};
+
+struct xsc_cq_table {
+ spinlock_t lock; /* protect radix tree */
+ struct radix_tree_root tree;
+};
+
+/* mr */
+struct xsc_core_mr {
+ u64 iova;
+ u64 size;
+ u32 key;
+ u32 pd;
+ u32 access;
+};
+
+/* eq */
+struct xsc_eq {
+ struct xsc_core_device *dev;
+ struct xsc_cq_table cq_table;
+ u32 cons_index;
+ struct xsc_buf buf;
+ unsigned int irqn;
+ u32 eqn;
+ u32 nent;
+ cpumask_var_t mask;
+ char name[XSC_MAX_EQ_NAME];
+ struct list_head list;
+ u16 index;
+};
+
+struct xsc_eq_table {
+ void __iomem *update_ci;
+ void __iomem *update_arm_ci;
+ struct list_head comp_eqs_list;
+ struct xsc_eq pages_eq;
+ struct xsc_eq async_eq;
+ struct xsc_eq cmd_eq;
+ int num_comp_vectors;
+ int eq_vec_comp_base;
+ /* protect EQs list */
+ spinlock_t lock;
+};
+
+/* irq */
+struct xsc_irq_info {
+ cpumask_var_t mask;
+ char name[XSC_MAX_IRQ_NAME];
+};
+
+/* adev */
+#define XSC_PCI_DRV_NAME "xsc_pci"
+#define XSC_ETH_ADEV_NAME "eth"
+#define XSC_IB_ADEV_NAME "ib"
+
+enum xsc_adev_idx {
+ XSC_ADEV_IDX_ETH,
+ XSC_ADEV_IDX_IB,
+ XSC_ADEV_IDX_MAX,
+};
+
+struct xsc_adev {
+ struct auxiliary_device adev;
+ struct xsc_core_device *xdev;
+
+ int idx;
+};
+
+struct xsc_board_info {
+ u32 board_id;
+ char board_sn[XSC_BOARD_SN_LEN];
+ __be64 guid;
+ u8 guid_valid;
+ u8 hw_config_activated;
+ struct xsc_msg_opcode *msg_opcode;
+};
+
+struct xsc_caps {
+ u8 log_max_eq;
+ u8 log_max_cq;
+ u8 log_max_qp;
+ u8 log_max_mkey;
+ u8 log_max_pd;
+ u8 log_max_srq;
+ u8 log_max_msix;
+ u32 max_cq;
+ u32 max_qp;
+ u32 max_pd;
+ u32 max_cqes;
+ u32 max_wqes;
+ u32 max_sq_desc_sz;
+ u32 max_rq_desc_sz;
+ u64 flags;
+ u16 stat_rate_support;
+ u32 log_max_msg;
+ u32 num_ports;
+ u32 max_ra_res_qp;
+ u32 max_ra_req_qp;
+ u32 max_srq_wqes;
+ u32 bf_reg_size;
+ u32 bf_regs_per_page;
+ u32 reserved_lkey;
+ u8 local_ca_ack_delay;
+ u8 log_max_mcg;
+ u16 max_qp_mcg;
+ u32 min_page_sz;
+ u32 send_ds_num;
+ u32 send_wqe_shift;
+ u32 recv_ds_num;
+ u32 recv_wqe_shift;
+ u32 rx_pkt_len_max;
+
+ u32 msix_enable:1;
+ u32 port_type:1;
+ u32 embedded_cpu:1;
+ u32 eswitch_manager:1;
+ u32 ecpf_vport_exists:1;
+ u32 vport_group_manager:1;
+ u32 sf:1;
+ u32 wqe_inline_mode:3;
+ u32 raweth_qp_id_base:15;
+ u32 rsvd0:7;
+
+ u16 max_vfs;
+ u8 log_max_qp_depth;
+ u8 log_max_current_uc_list;
+ u8 log_max_current_mc_list;
+ u16 log_max_vlan_list;
+ u8 fdb_multi_path_to_table;
+ u8 log_esw_max_sched_depth;
+
+ u8 max_num_sf_partitions;
+ u8 log_max_esw_sf;
+ u16 sf_base_id;
+
+ u32 max_tc:8;
+ u32 ets:1;
+ u32 dcbx:1;
+ u32 dscp:1;
+ u32 sbcam_reg:1;
+ u32 qos:1;
+ u32 port_buf:1;
+ u32 rsvd1:2;
+ u32 raw_tpe_qp_num:16;
+ u32 max_num_eqs:8;
+ u32 mac_port:8;
+ u32 raweth_rss_qp_id_base:16;
+ u16 msix_base;
+ u16 msix_num;
+ u8 log_max_mtt;
+ u8 log_max_tso;
+ u32 hca_core_clock;
+ u32 max_rwq_indirection_tables; /* rss_caps */
+ u32 max_rwq_indirection_table_size; /* rss_caps */
+ u16 raweth_qp_id_end;
+ u32 qp_rate_limit_min;
+ u32 qp_rate_limit_max;
+ u32 hw_feature_flag;
+ u16 pf0_vf_funcid_base;
+ u16 pf0_vf_funcid_top;
+ u16 pf1_vf_funcid_base;
+ u16 pf1_vf_funcid_top;
+ u16 pcie0_pf_funcid_base;
+ u16 pcie0_pf_funcid_top;
+ u16 pcie1_pf_funcid_base;
+ u16 pcie1_pf_funcid_top;
+ u8 nif_port_num;
+ u8 pcie_host;
+ u8 mac_bit;
+ u16 funcid_to_logic_port;
+ u8 lag_logic_port_ofst;
+
+ /* RDMA / MR resources (populated from hca_cap V1~V9) */
+ u64 max_mr_size;
+ u16 max_cmd_in_len;
+ u16 max_cmd_out_len;
+ u32 max_mtt;
+ u32 mpt_tbl_addr;
+ u32 mpt_tbl_depth;
+ u32 mpt_tbl_width;
+ u32 mtt_inst_base_addr;
+ u32 mtt_inst_stride;
+ u32 mtt_inst_num_log;
+ u32 mtt_inst_depth;
+ u32 mdb_num;
+ u64 mdb_base;
+};
+
+struct xsc_srq_cache_wr;
+
+/* xsc_core */
+struct xsc_dev_resource {
+ struct xsc_qp_table qp_table;
+ struct xsc_cq_table cq_table;
+ struct xsc_eq_table eq_table;
+ struct xsc_irq_info *irq_info;
+ /* protect buffer allocation according to numa node */
+ struct mutex alloc_mutex;
+ /* protect mkey key allocation */
+ spinlock_t mkey_lock;
+ u8 mkey_key;
+
+ /* srq number allocation, srqn is a software index only */
+ spinlock_t srq_lock;
+ unsigned long *srq_tbl;
+ struct xsc_srq_cache_wr *srq_cache_wr;
+ u32 max_srq_num;
+};
+
+struct xsc_core_device {
+ struct pci_dev *pdev;
+ struct device *device;
+ int adev_id;
+ struct xsc_adev **xsc_adev_list;
+ void *eth_priv;
+ struct xsc_dev_resource *dev_res;
+ int numa_node;
+
+ /* async event plumbing, owned by the PCI layer */
+ struct work_struct event_work;
+ struct workqueue_struct *event_wq;
+ void (*link_event_handler)(void *xdev);
+
+ void __iomem *bar;
+ int bar_num;
+ enum xsc_coredev_type coredev_type;
+ struct xsc_hw_reg *hal_regs;
+
+ u8 mac_port;
+ u8 pcie_no;
+ u8 pf_id;
+ u16 glb_func_id;
+ u16 gsi_qpn;
+ atomic_t num_qps;
+
+ u16 msix_vec_base;
+
+ void *netdev;
+
+ u32 rdma_proto_mode;
+ u16 cm_udp_dst_port;
+ u16 veroce_udp_dst_port;
+ u8 read_flush;
+ u8 bql_thresh;
+
+ struct xsc_priv priv;
+
+ struct xsc_cmd cmd;
+ u16 cmdq_ver;
+
+ struct xsc_caps caps;
+ struct xsc_board_info *board_info;
+
+ u32 chip_ver_h;
+ u32 chip_ver_m;
+ u32 chip_ver_l;
+ u32 hotfix_num;
+ u32 feature_flag;
+
+ u8 fw_version_major;
+ u8 fw_version_minor;
+ u16 fw_version_patch;
+ u32 fw_version_tweak;
+ u8 fw_version_extra_flag;
+ cpumask_var_t xps_cpumask;
+};
+
+int xsc_core_create_resource_common(struct xsc_core_device *xdev,
+ struct xsc_core_qp *qp);
+void xsc_core_destroy_resource_common(struct xsc_core_device *xdev,
+ struct xsc_core_qp *qp);
+int xsc_core_eth_create_qp(struct xsc_core_device *xdev,
+ struct xsc_create_qp_mbox_in *in,
+ int insize, u32 *p_qpn);
+int xsc_core_eth_modify_qp_status(struct xsc_core_device *xdev,
+ u32 qpn, u16 status);
+int xsc_core_eth_destroy_qp(struct xsc_core_device *xdev, u32 qpn);
+int xsc_core_eth_create_rss_qp_rqs(struct xsc_core_device *xdev,
+ struct xsc_create_multiqp_mbox_in *in,
+ int insize,
+ u32 *p_qpn_base);
+int xsc_core_eth_modify_raw_qp(struct xsc_core_device *xdev,
+ struct xsc_modify_raw_qp_mbox_in *in);
+int xsc_core_eth_create_cq(struct xsc_core_device *xdev,
+ struct xsc_core_cq *xcq,
+ struct xsc_create_cq_mbox_in *in,
+ int insize);
+int xsc_core_eth_destroy_cq(struct xsc_core_device *xdev,
+ struct xsc_core_cq *xcq);
+
+struct xsc_eq *xsc_core_eq_get(struct xsc_core_device *xdev, int i);
+int xsc_core_vector2eqn(struct xsc_core_device *xdev, int vector, u32 *eqn,
+ unsigned int *irqn);
+
+/*
+ * Link event callback registration. The events are dispatched from the PCI
+ * layer's own workqueue; unregister detaches the callback and waits for one
+ * already in flight, so it must precede freeing what the handler touches.
+ */
+void xsc_irq_event_register(struct xsc_core_device *xdev,
+ void (*handler)(void *xdev));
+void xsc_irq_event_unregister(struct xsc_core_device *xdev);
+void xsc_core_fill_page_frag_array(struct xsc_frag_buf *buf,
+ __be64 *pas, unsigned int npages);
+int xsc_core_frag_buf_alloc_node(struct xsc_core_device *xdev,
+ unsigned long size,
+ struct xsc_frag_buf *buf,
+ int node);
+void xsc_core_frag_buf_free(struct xsc_core_device *xdev,
+ struct xsc_frag_buf *buf);
+
+u8 xsc_core_query_vport_state(struct xsc_core_device *xdev, u16 vport);
+
+static inline void *xsc_buf_offset(struct xsc_buf *buf, unsigned long offset)
+{
+ if (likely(buf->nbufs == 1))
+ return buf->direct.buf + offset;
+ else
+ return buf->page_list[offset >> PAGE_SHIFT].buf +
+ (offset & (PAGE_SIZE - 1));
+}
+
+static inline bool xsc_fw_is_available(struct xsc_core_device *xdev)
+{
+ return xdev->cmd.cmd_status == XSC_CMD_STATUS_NORMAL;
+}
+
+static inline u8 get_cqe_opcode(struct xsc_cqe *cqe)
+{
+ return FIELD_GET(XSC_CQE_MSG_OPCD_MASK, le32_to_cpu(cqe->data0));
+}
+
+static inline bool xsc_core_is_pf(const struct xsc_core_device *dev)
+{
+ return dev->coredev_type == XSC_COREDEV_PF;
+}
+
+static inline bool is_support_hw_pf_stats(struct xsc_core_device *dev)
+{
+ return xsc_core_is_pf(dev);
+}
+
+static inline bool is_support_cqe64(struct xsc_core_device *dev)
+{
+ return dev->caps.hw_feature_flag & XSC_HW_CQE64_SUPPORT;
+}
+
+static inline bool is_support_rdma_cm(struct xsc_core_device *dev)
+{
+ return dev->caps.hw_feature_flag & XSC_HW_RDMA_CM_SUPPORT;
+}
+
+static inline bool is_support_rdma_atomic(struct xsc_core_device *dev)
+{
+ return dev->caps.hw_feature_flag & XSC_HW_RDMA_ATOMIC_SUPPORT;
+}
+
+static inline bool is_support_rdma(struct xsc_core_device *dev)
+{
+ return dev->caps.hw_feature_flag & XSC_HW_RDMA_SUPPORT;
+}
+
+static inline bool is_support_8k_mtu(struct xsc_core_device *dev)
+{
+ return dev->caps.hw_feature_flag & XSC_HW_MTU_8192_SUPPORT;
+}
+
+static inline bool is_pf_bar_compressed(struct xsc_core_device *dev)
+{
+ return pci_resource_len(dev->pdev, 0) != XSC_ORIGIN_PF_BAR_SIZE;
+}
+
+static inline bool is_support_multi_doorbell(struct xsc_core_device *dev)
+{
+ return dev->caps.hw_feature_flag & XSC_HW_MULTIDOORBELL_SUPPORT;
+}
+
+void xsc_remove_rdma_driver(void);
+int xsc_counters_init(struct ib_device *ib_dev, struct xsc_core_device *xdev);
+void xsc_counters_fini(struct ib_device *ib_dev, struct xsc_core_device *xdev);
+void xsc_ib_sysfs_init(struct ib_device *ib_dev, struct xsc_core_device *xdev);
+void xsc_ib_sysfs_fini(struct ib_device *ib_dev, struct xsc_core_device *xdev);
+
+void xsc_init_hal(struct xsc_core_device *xdev, u32 device_id);
+
+u8 xsc_get_mr_page_mode(struct xsc_core_device *xdev, u8 page_shift);
+u64 xsc_get_max_mr_size(struct xsc_core_device *xdev);
+void xsc_set_data_seg(struct xsc_core_device *xdev, void *data_seg, u64 addr,
+ u32 key, u32 length);
+u64 xsc_get_rdma_stat_mask(struct xsc_core_device *xdev, u16 ver);
+u32 xsc_get_max_qp_depth(struct xsc_core_device *xdev);
+bool xsc_check_max_qp_depth(struct xsc_core_device *xdev, u32 *wqe_cnt,
+ u32 max_qp_depth);
+void xsc_set_wqe_id(struct xsc_core_device *xdev, void *cseg, u32 wqe_id);
+int xsc_get_cqe_wqe_id(struct xsc_core_device *xdev, void *cqe);
+void xsc_get_multidb_info(struct xsc_core_device *xdev, u32 *num, u32 *base);
+u8 xsc_get_cqe_opcode(struct xsc_core_device *xdev, void *cqe);
+u32 xsc_get_recv_ds_num(struct xsc_core_device *xdev);
+int xsc_get_link_speed(struct xsc_core_device *xdev);
+void xsc_set_mtt_info(struct xsc_core_device *xdev);
+void xsc_set_pf_db_addr(struct xsc_core_device *xdev,
+ u64 tx_db, u64 rx_db, u64 cq_db, u64 cq_reg, u64 eq_db);
+void xsc_get_db_addr(struct xsc_core_device *xdev,
+ u64 *tx_db, u64 *rx_db, u64 *cq_db, u64 *cq_reg, u64 *eq_db);
+
+void xsc_update_tx_db(struct xsc_core_device *xdev, u32 sqn, u32 next_pid);
+void xsc_update_rx_db(struct xsc_core_device *xdev, u32 rqn, u32 next_pid);
+void xsc_arm_cq(struct xsc_core_device *xdev, u32 cqn, u32 next_cid, u8 solicited);
+void xsc_update_cq_ci(struct xsc_core_device *xdev, u32 cqn, u32 next_cid);
+
+#endif
diff --git a/drivers/net/ethernet/yunsilicon/xsc/common/xsc_device.h b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_device.h
new file mode 100644
index 000000000..302534839
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_device.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021-2026, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#ifndef __XSC_DEVICE_H
+#define __XSC_DEVICE_H
+
+#include <linux/types.h>
+
+/* QP type */
+enum {
+ 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_SNIFFER = 8,
+ XSC_QUEUE_TYPE_WORC = 9,
+ XSC_QUEUE_TYPE_INVALID = 0xFF,
+};
+
+enum {
+ XSC_PERM_LOCAL_READ = 1 << 0,
+ XSC_PERM_LOCAL_WRITE = 1 << 1,
+ XSC_PERM_REMOTE_READ = 1 << 2,
+ XSC_PERM_REMOTE_WRITE = 1 << 3,
+ XSC_PERM_ATOMIC = 1 << 4,
+ XSC_PERM_UMR_EN = 1 << 7,
+};
+
+enum {
+ XSC_DEV_CAP_FLAG_RC = 1LL << 0,
+ XSC_DEV_CAP_FLAG_UC = 1LL << 1,
+ XSC_DEV_CAP_FLAG_UD = 1LL << 2,
+ XSC_DEV_CAP_FLAG_XRC = 1LL << 3,
+ XSC_DEV_CAP_FLAG_SRQ = 1LL << 6,
+ XSC_DEV_CAP_FLAG_BAD_PKEY_CNTR = 1LL << 8,
+ XSC_DEV_CAP_FLAG_BAD_QKEY_CNTR = 1LL << 9,
+ XSC_DEV_CAP_FLAG_APM = 1LL << 17,
+ XSC_DEV_CAP_FLAG_ATOMIC = 1LL << 18,
+ XSC_DEV_CAP_FLAG_ON_DMND_PG = 1LL << 24,
+ XSC_DEV_CAP_FLAG_RESIZE_SRQ = 1LL << 32,
+ XSC_DEV_CAP_FLAG_REMOTE_FENCE = 1LL << 38,
+ XSC_DEV_CAP_FLAG_TLP_HINTS = 1LL << 39,
+ XSC_DEV_CAP_FLAG_SIG_HAND_OVER = 1LL << 40,
+ XSC_DEV_CAP_FLAG_DCT = 1LL << 41,
+ XSC_DEV_CAP_FLAG_CMDIF_CSUM = 1LL << 46,
+};
+
+enum xsc_traffic_types {
+ XSC_TT_IPV4,
+ XSC_TT_IPV4_TCP,
+ XSC_TT_IPV4_UDP,
+ XSC_TT_IPV6,
+ XSC_TT_IPV6_TCP,
+ XSC_TT_IPV6_UDP,
+ XSC_TT_IPV4_IPSEC_AH,
+ XSC_TT_IPV6_IPSEC_AH,
+ XSC_TT_IPV4_IPSEC_ESP,
+ XSC_TT_IPV6_IPSEC_ESP,
+ XSC_TT_ANY,
+ XSC_NUM_TT,
+};
+
+#define XSC_NUM_INDIR_TIRS XSC_NUM_TT
+
+enum {
+ XSC_L3_PROT_TYPE_IPV4 = BIT(0),
+ XSC_L3_PROT_TYPE_IPV6 = BIT(1),
+};
+
+enum {
+ XSC_L4_PROT_TYPE_TCP = BIT(0),
+ XSC_L4_PROT_TYPE_UDP = BIT(1),
+};
+
+struct xsc_tirc_config {
+ u8 l3_prot_type;
+ u8 l4_prot_type;
+ u32 rx_hash_fields;
+};
+
+enum {
+ XSC_HASH_FUNC_XOR = 0,
+ XSC_HASH_FUNC_TOP = 1,
+ XSC_HASH_FUNC_TOP_SYM = 2,
+ XSC_HASH_FUNC_RSV = 3,
+};
+
+#endif
diff --git a/drivers/net/ethernet/yunsilicon/xsc/common/xsc_hsi.h b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_hsi.h
new file mode 100644
index 000000000..aa2049f89
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_hsi.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021 - 2026, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#ifndef XSC_HSI_H
+#define XSC_HSI_H
+
+#include <asm/byteorder.h>
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+#define WR_LE_32(x, val) (x = __cpu_to_le32(val))
+#define WR_LE_64(x, val) (x = __cpu_to_le64(val))
+
+#define WR_BE_32(x, val) (x = __cpu_to_be32(val))
+
+#define RD_LE_32(x) __le32_to_cpu(x)
+#define RD_BE_32(x) __be32_to_cpu(x)
+
+struct xsc_msg_opcode {
+ u32 send;
+ u32 send_with_imm;
+ u32 rdma_write;
+ u32 rdma_write_with_imm;
+ u32 rdma_read;
+ u32 atomic_cmp_and_swp;
+ u32 atomic_fetch_and_add;
+ u32 masked_atomic_cmp_and_swp;
+ u32 masked_atomic_fetch_and_add;
+ u32 mad;
+};
+
+/* sw cqe opcode */
+enum {
+ XSC_OPCODE_RDMA_REQ_SEND = 0,
+ XSC_OPCODE_RDMA_REQ_SEND_IMMDT = 1,
+ XSC_OPCODE_RDMA_RSP_RECV = 2,
+ XSC_OPCODE_RDMA_RSP_RECV_IMMDT = 3,
+ XSC_OPCODE_RDMA_REQ_WRITE = 4,
+ XSC_OPCODE_RDMA_REQ_WRITE_IMMDT = 5,
+ XSC_OPCODE_RDMA_RSP_WRITE_IMMDT = 6,
+ XSC_OPCODE_RDMA_REQ_READ = 7,
+ XSC_OPCODE_RDMA_REQ_ERROR = 8,
+ XSC_OPCODE_RDMA_RSP_ERROR = 9,
+ XSC_OPCODE_RDMA_CQE_ERROR = 10,
+ XSC_OPCODE_RDMA_MAD_REQ_SEND = 11,
+ XSC_OPCODE_RDMA_MAD_RSP_RECV = 12,
+ XSC_OPCODE_RDMA_CQE_RAW_SNF = 13,
+};
+
+enum {
+ XSC_SEND_SEG_MAX = 32,
+ XSC_BASE_WQE_SHIFT = 4,
+ XSC_SEND_SEG_NUM = 4,
+ XSC_SEND_WQE_SHIFT = 6,
+ XSC_CTRL_SEG_NUM = 1,
+ XSC_RADDR_SEG_NUM = 1,
+};
+
+enum {
+ XSC_RECV_SEG_MAX = 4,
+ XSC_RECV_SEG_NUM = 1,
+ XSC_RECV_WQE_SHIFT = 4,
+};
+
+enum {
+ XSC_INLINE_SIZE_MAX = 15,
+};
+
+#define XSC_MPT_MAP_EN 0
+
+enum {
+ XSC_REQ = 0,
+ XSC_RSP = 1,
+};
+
+enum {
+ XSC_WITHOUT_IMMDT = 0,
+ XSC_WITH_IMMDT = 1,
+};
+
+/* CQE error codes */
+enum {
+ XSC_ERR_CODE_NAK_RETRY = 0x40,
+ XSC_ERR_CODE_NAK_OPCODE = 0x41,
+ XSC_ERR_CODE_NAK_MR = 0x42,
+ XSC_ERR_CODE_NAK_OPERATION = 0x43,
+ XSC_ERR_CODE_NAK_RNR = 0x44,
+ XSC_ERR_CODE_LOCAL_MR = 0x45,
+ XSC_ERR_CODE_LOCAL_LEN = 0x46,
+ XSC_ERR_CODE_LOCAL_OPCODE = 0x47,
+ XSC_ERR_CODE_CQ_OVER_FLOW = 0x48,
+ XSC_ERR_CODE_STRG_ACC_GEN_CQE = 0x4c,
+ XSC_ERR_CODE_CQE_ACC = 0x4d,
+ XSC_ERR_CODE_FLUSH = 0x4e,
+ XSC_ERR_CODE_MALF_WQE_HOST = 0x50,
+ XSC_ERR_CODE_MALF_WQE_INFO = 0x51,
+ XSC_ERR_CODE_MR_NON_NAK = 0x52,
+ XSC_ERR_CODE_OPCODE_GEN_CQE = 0x61,
+ XSC_ERR_CODE_MANY_READ = 0x62,
+ XSC_ERR_CODE_LEN_GEN_CQE = 0x63,
+ XSC_ERR_CODE_MR = 0x65,
+ XSC_ERR_CODE_MR_GEN_CQE = 0x66,
+ XSC_ERR_CODE_OPERATION = 0x67,
+ XSC_ERR_CODE_MALF_WQE_INFO_GEN_NAK = 0x68,
+};
+
+enum xsc_qp_state {
+ XSC_QP_STATE_RST = 0,
+ XSC_QP_STATE_INIT = 1,
+ XSC_QP_STATE_RTR = 2,
+ XSC_QP_STATE_RTS = 3,
+ XSC_QP_STATE_SQER = 4,
+ XSC_QP_STATE_SQD = 5,
+ XSC_QP_STATE_ERR = 6,
+ XSC_QP_STATE_SQ_DRAINING = 7,
+ XSC_QP_STATE_SUSPENDED = 9,
+ XSC_QP_NUM_STATE
+};
+
+#endif /* XSC_HSI_H */
diff --git a/drivers/net/ethernet/yunsilicon/xsc/common/xsc_reg.h b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_reg.h
new file mode 100644
index 000000000..babdb5802
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_reg.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021 - 2026, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#ifndef XSC_REG_H
+#define XSC_REG_H
+#define CMDQM_HOST_REQ_BUF_BASE_H_ADDR_MEM_ADDR 0x0
+#define CMDQM_HOST_REQ_BUF_BASE_L_ADDR_MEM_ADDR 0x4
+#define CMDQM_HOST_REQ_PID_MEM_ADDR 0x8
+#define CMDQM_HOST_REQ_CID_MEM_ADDR 0xc
+#define CMDQM_HOST_RSP_BUF_BASE_H_ADDR_MEM_ADDR 0x10
+#define CMDQM_HOST_RSP_BUF_BASE_L_ADDR_MEM_ADDR 0x14
+#define CMDQM_HOST_RSP_PID_MEM_ADDR 0x18
+#define CMDQM_HOST_RSP_CID_MEM_ADDR 0x1c
+#define CMDQM_HOST_VF_ERR_STS_MEM_ADDR 0x20
+#define CMDQM_VECTOR_ID_MEM_ADDR 0x24
+
+#define DB_CQ_FUNC_MEM_ADDR 0x8c4
+#define DB_EQ_FUNC_MEM_ADDR 0x8c8
+#define DB_CQ_CID_DIRECT_MEM_ADDR 0x8cc
+#define TX_DB_FUNC_MEM_ADDR 0x8d0
+#define RX_DB_FUNC_MEM_ADDR 0x8d4
+
+#define MDB_NUM 64
+#define QPM_TX_MDB_BASE_REG_ADDR 0xd00
+
+#endif
diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
new file mode 100644
index 000000000..1cc3f7b49
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021-2026, Shanghai Yunsilicon Technology Co., Ltd.
+# All rights reserved.
+# Yunsilicon PCI configuration
+#
+
+config YUNSILICON_XSC_PCI
+ tristate "Yunsilicon XSC PCI driver"
+ depends on PCI
+ help
+ This driver is common for Yunsilicon XSC
+ ethernet and RDMA drivers.
+
+ To compile this driver as a module, choose M here. The module
+ will be called xsc_pci.
diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/Makefile b/drivers/net/ethernet/yunsilicon/xsc/pci/Makefile
new file mode 100644
index 000000000..c163aa950
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021-2026, Shanghai Yunsilicon Technology Co., Ltd.
+# All rights reserved.
+
+ccflags-y += -I$(srctree)/drivers/net/ethernet/yunsilicon/xsc
+
+obj-$(CONFIG_YUNSILICON_XSC_PCI) += xsc_pci.o
+
+xsc_pci-y := main.o
diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/main.c b/drivers/net/ethernet/yunsilicon/xsc/pci/main.c
new file mode 100644
index 000000000..734d48825
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/main.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2021-2026, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#include "common/xsc_core.h"
+
+static const struct pci_device_id xsc_pci_id_table[] = {
+ { PCI_DEVICE(XSC_PCI_VENDOR_ID, XSC_MC_PF_DEV_ID) },
+ { PCI_DEVICE(XSC_PCI_VENDOR_ID, XSC_MF_HOST_PF_DEV_ID) },
+ { PCI_DEVICE(XSC_PCI_VENDOR_ID, XSC_MF_SOC_PF_DEV_ID) },
+ { PCI_DEVICE(XSC_PCI_VENDOR_ID, XSC_MS_PF_DEV_ID) },
+ { PCI_DEVICE(XSC_PCI_VENDOR_ID, XSC_MV_HOST_PF_DEV_ID) },
+ { PCI_DEVICE(XSC_PCI_VENDOR_ID, XSC_MV_SOC_PF_DEV_ID) },
+ { 0 }
+};
+
+static int xsc_set_dma_caps(struct pci_dev *pdev)
+{
+ int err;
+
+ err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+ if (!err)
+ dma_set_max_seg_size(&pdev->dev, SZ_2G);
+
+ return err;
+}
+
+static int xsc_pci_init(struct xsc_core_device *xdev,
+ const struct pci_device_id *id)
+{
+ struct pci_dev *pdev = xdev->pdev;
+ void __iomem *bar_base;
+ int bar_num = 0;
+ int err;
+
+ xdev->numa_node = dev_to_node(&pdev->dev);
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ pci_err(pdev, "failed to enable PCI device: err=%d\n", err);
+ goto err_out;
+ }
+
+ err = pci_request_region(pdev, bar_num, KBUILD_MODNAME);
+ if (err) {
+ pci_err(pdev, "failed to request %s pci_region=%d: err=%d\n",
+ KBUILD_MODNAME, bar_num, err);
+ goto err_disable;
+ }
+
+ pci_set_master(pdev);
+
+ err = xsc_set_dma_caps(pdev);
+ if (err) {
+ pci_err(pdev, "failed to set DMA capabilities mask: err=%d\n",
+ err);
+ goto err_clr_master;
+ }
+
+ bar_base = pci_ioremap_bar(pdev, bar_num);
+ if (!bar_base) {
+ pci_err(pdev, "failed to ioremap %s bar%d\n", KBUILD_MODNAME,
+ bar_num);
+ err = -ENOMEM;
+ goto err_clr_master;
+ }
+
+ err = pci_save_state(pdev);
+ if (err) {
+ pci_err(pdev, "pci_save_state failed: err=%d\n", err);
+ goto err_io_unmap;
+ }
+
+ xdev->bar_num = bar_num;
+ xdev->bar = bar_base;
+
+ return 0;
+
+err_io_unmap:
+ pci_iounmap(pdev, bar_base);
+err_clr_master:
+ pci_clear_master(pdev);
+ pci_release_region(pdev, bar_num);
+err_disable:
+ pci_disable_device(pdev);
+err_out:
+ return err;
+}
+
+static void xsc_pci_fini(struct xsc_core_device *xdev)
+{
+ struct pci_dev *pdev = xdev->pdev;
+
+ pci_iounmap(pdev, xdev->bar);
+ pci_clear_master(pdev);
+ pci_release_region(pdev, xdev->bar_num);
+ pci_disable_device(pdev);
+}
+
+static int xsc_dev_res_init(struct xsc_core_device *xdev)
+{
+ struct xsc_dev_resource *dev_res;
+
+ dev_res = kvzalloc_obj(*dev_res, GFP_KERNEL);
+ if (!dev_res)
+ return -ENOMEM;
+
+ xdev->dev_res = dev_res;
+ mutex_init(&dev_res->alloc_mutex);
+ spin_lock_init(&dev_res->mkey_lock);
+
+ return 0;
+}
+
+static void xsc_dev_res_cleanup(struct xsc_core_device *xdev)
+{
+ kfree(xdev->dev_res);
+}
+
+static int xsc_core_dev_init(struct xsc_core_device *xdev)
+{
+ int err;
+
+ err = xsc_dev_res_init(xdev);
+ if (err) {
+ pci_err(xdev->pdev, "xsc dev res init failed %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static void xsc_core_dev_cleanup(struct xsc_core_device *xdev)
+{
+ xsc_dev_res_cleanup(xdev);
+}
+
+static int xsc_hw_setup(struct xsc_core_device *xdev)
+{
+ return 0;
+}
+
+static void xsc_hw_cleanup(struct xsc_core_device *xdev)
+{
+}
+
+static int xsc_load(struct xsc_core_device *xdev)
+{
+ int err = 0;
+
+ err = xsc_hw_setup(xdev);
+ if (err) {
+ pci_err(xdev->pdev, "xsc_hw_setup failed %d\n", err);
+ goto err_out;
+ }
+
+ return 0;
+err_out:
+ return err;
+}
+
+static void xsc_unload(struct xsc_core_device *xdev)
+{
+ xsc_hw_cleanup(xdev);
+}
+
+static int xsc_pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *id)
+{
+ struct xsc_core_device *xdev;
+ int err;
+
+ xdev = kzalloc_obj(*xdev, GFP_KERNEL);
+ if (!xdev)
+ return -ENOMEM;
+
+ xdev->pdev = pci_dev;
+ xdev->device = &pci_dev->dev;
+ xdev->coredev_type = pci_dev->is_virtfn ? XSC_COREDEV_VF : XSC_COREDEV_PF;
+
+ pci_set_drvdata(pci_dev, xdev);
+ err = xsc_pci_init(xdev, id);
+ if (err) {
+ pci_err(pci_dev, "xsc_pci_init failed %d\n", err);
+ goto err_unset_pci_drvdata;
+ }
+
+ err = xsc_core_dev_init(xdev);
+ if (err) {
+ pci_err(pci_dev, "xsc_core_dev_init failed %d\n", err);
+ goto err_pci_fini;
+ }
+
+ err = xsc_load(xdev);
+ if (err) {
+ pci_err(xdev->pdev, "xsc_load failed %d\n", err);
+ goto err_core_dev_cleanup;
+ }
+
+ return 0;
+err_core_dev_cleanup:
+ xsc_core_dev_cleanup(xdev);
+err_pci_fini:
+ xsc_pci_fini(xdev);
+err_unset_pci_drvdata:
+ pci_set_drvdata(pci_dev, NULL);
+ kfree(xdev);
+
+ return err;
+}
+
+static void xsc_pci_remove(struct pci_dev *pci_dev)
+{
+ struct xsc_core_device *xdev = pci_get_drvdata(pci_dev);
+
+ xsc_unload(xdev);
+ xsc_core_dev_cleanup(xdev);
+ xsc_pci_fini(xdev);
+ pci_set_drvdata(pci_dev, NULL);
+ kfree(xdev);
+}
+
+static struct pci_driver xsc_pci_driver = {
+ .name = "xsc-pci",
+ .id_table = xsc_pci_id_table,
+ .probe = xsc_pci_probe,
+ .remove = xsc_pci_remove,
+};
+
+static int __init xsc_init(void)
+{
+ int err;
+
+ err = pci_register_driver(&xsc_pci_driver);
+ if (err) {
+ pr_err("failed to register pci driver\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static void __exit xsc_fini(void)
+{
+ pci_unregister_driver(&xsc_pci_driver);
+}
+
+module_init(xsc_init);
+module_exit(xsc_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Yunsilicon XSC PCI driver");