diff mbox series

[net-next,v7,01/14] xsc: Add xsc driver basic framework

Message ID 20250228154122.216053-2-tianx@yunsilicon.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series xsc: ADD Yunsilicon XSC Ethernet Driver | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next, async
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 1 maintainers not CCed: geert+renesas@glider.be
netdev/build_clang success Errors and warnings before: 1 this patch: 1
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 8 this patch: 8
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 420 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2025-03-01--03-00 (tests: 893)

Commit Message

Xin Tian Feb. 28, 2025, 3:41 p.m. UTC
1. Add yunsilicon xsc driver basic compile framework, including
xsc_pci driver and xsc_eth driver
2. Implemented PCI device initialization.

Co-developed-by: Honggang Wei <weihg@yunsilicon.com>
Signed-off-by: Honggang Wei <weihg@yunsilicon.com>
Co-developed-by: Lei Yan <jacky@yunsilicon.com>
Signed-off-by: Lei Yan <jacky@yunsilicon.com>
Signed-off-by: Xin Tian <tianx@yunsilicon.com>
---
 MAINTAINERS                                   |   7 +
 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_core.h |  53 ++++
 .../net/ethernet/yunsilicon/xsc/net/Kconfig   |  17 ++
 .../net/ethernet/yunsilicon/xsc/net/Makefile  |   9 +
 .../net/ethernet/yunsilicon/xsc/pci/Kconfig   |  16 ++
 .../net/ethernet/yunsilicon/xsc/pci/Makefile  |   9 +
 .../net/ethernet/yunsilicon/xsc/pci/main.c    | 255 ++++++++++++++++++
 11 files changed, 402 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_core.h
 create mode 100644 drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
 create mode 100644 drivers/net/ethernet/yunsilicon/xsc/net/Makefile
 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

Comments

Jakub Kicinski March 5, 2025, 2:48 a.m. UTC | #1
On Fri, 28 Feb 2025 23:41:24 +0800 Xin Tian wrote:
> +config NET_VENDOR_YUNSILICON
> +	depends on ARM64 || X86_64

|| COMPILE_TEST please ?

> diff --git a/drivers/net/ethernet/yunsilicon/Makefile b/drivers/net/ethernet/yunsilicon/Makefile
> new file mode 100644
> index 000000000..6fc8259a7
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
> +# All rights reserved.
> +# Makefile for the Yunsilicon device drivers.
> +#
> +
> +# obj-$(CONFIG_YUNSILICON_XSC_ETH) += xsc/net/

Why are you adding commented out lines? Add them where needed

> +obj-$(CONFIG_YUNSILICON_XSC_PCI) += xsc/pci/
> \ No newline at end of file

new line missing

> new file mode 100644
> index 000000000..de743487e
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
> @@ -0,0 +1,17 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
> +# All rights reserved.
> +# Yunsilicon driver configuration
> +#
> +
> +config YUNSILICON_XSC_ETH
> +	tristate "Yunsilicon XSC ethernet driver"
> +	default n

n is the default, you don't have to specify it

> +xsc_eth-y := main.o
> \ No newline at end of file

new line

> diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
> new file mode 100644
> index 000000000..2b6d79905
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
> @@ -0,0 +1,16 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
> +# All rights reserved.
> +# Yunsilicon PCI configuration
> +#
> +
> +config YUNSILICON_XSC_PCI
> +	tristate "Yunsilicon XSC PCI driver"
> +	default n

no need

> +	select PAGE_POOL

Why is this in the PCI driver, not the ETH driver?
Please add this line in a patch which actually makes use of page pool

> +static int set_dma_caps(struct pci_dev *pdev)
> +{
> +	int err;
> +
> +	err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
> +	if (err)
> +		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
> +	else
> +		err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));

Please grep git history for dma_set_mask_and_coherent
The fallback is unnecessary, just:

	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));

> +	if (!err)
> +		dma_set_max_seg_size(&pdev->dev, SZ_2G);
> +
> +	return err;
> +}
Xin Tian March 5, 2025, 4:17 a.m. UTC | #2
On 2025/3/5 10:48, Jakub Kicinski wrote:
> On Fri, 28 Feb 2025 23:41:24 +0800 Xin Tian wrote:
>> +config NET_VENDOR_YUNSILICON
>> +	depends on ARM64 || X86_64
> || COMPILE_TEST please ?
OK
>
>> diff --git a/drivers/net/ethernet/yunsilicon/Makefile b/drivers/net/ethernet/yunsilicon/Makefile
>> new file mode 100644
>> index 000000000..6fc8259a7
>> --- /dev/null
>> +++ b/drivers/net/ethernet/yunsilicon/Makefile
>> @@ -0,0 +1,8 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
>> +# All rights reserved.
>> +# Makefile for the Yunsilicon device drivers.
>> +#
>> +
>> +# obj-$(CONFIG_YUNSILICON_XSC_ETH) += xsc/net/
> Why are you adding commented out lines? Add them where needed
ack
>
>> +obj-$(CONFIG_YUNSILICON_XSC_PCI) += xsc/pci/
>> \ No newline at end of file
> new line missing
ack
>
>> new file mode 100644
>> index 000000000..de743487e
>> --- /dev/null
>> +++ b/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
>> @@ -0,0 +1,17 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
>> +# All rights reserved.
>> +# Yunsilicon driver configuration
>> +#
>> +
>> +config YUNSILICON_XSC_ETH
>> +	tristate "Yunsilicon XSC ethernet driver"
>> +	default n
> n is the default, you don't have to specify it
ack
>
>> +xsc_eth-y := main.o
>> \ No newline at end of file
> new line
ack
>> diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
>> new file mode 100644
>> index 000000000..2b6d79905
>> --- /dev/null
>> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
>> @@ -0,0 +1,16 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
>> +# All rights reserved.
>> +# Yunsilicon PCI configuration
>> +#
>> +
>> +config YUNSILICON_XSC_PCI
>> +	tristate "Yunsilicon XSC PCI driver"
>> +	default n
> no need
ack
>
>> +	select PAGE_POOL
> Why is this in the PCI driver, not the ETH driver?
> Please add this line in a patch which actually makes use of page pool
OK, should be in the ETH driver, thanks for pointing that out
>> +static int set_dma_caps(struct pci_dev *pdev)
>> +{
>> +	int err;
>> +
>> +	err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
>> +	if (err)
>> +		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
>> +	else
>> +		err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
> Please grep git history for dma_set_mask_and_coherent
> The fallback is unnecessary, just:
>
> 	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));

OK

Thanks

>
>> +	if (!err)
>> +		dma_set_max_seg_size(&pdev->dev, SZ_2G);
>> +
>> +	return err;
>> +}
Kalesh AP March 5, 2025, 8:55 a.m. UTC | #3
On Fri, Feb 28, 2025 at 9:12 PM Xin Tian <tianx@yunsilicon.com> wrote:
>
> 1. Add yunsilicon xsc driver basic compile framework, including
> xsc_pci driver and xsc_eth driver
> 2. Implemented PCI device initialization.
>
> Co-developed-by: Honggang Wei <weihg@yunsilicon.com>
> Signed-off-by: Honggang Wei <weihg@yunsilicon.com>
> Co-developed-by: Lei Yan <jacky@yunsilicon.com>
> Signed-off-by: Lei Yan <jacky@yunsilicon.com>
> Signed-off-by: Xin Tian <tianx@yunsilicon.com>
> ---
>  MAINTAINERS                                   |   7 +
>  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_core.h |  53 ++++
>  .../net/ethernet/yunsilicon/xsc/net/Kconfig   |  17 ++
>  .../net/ethernet/yunsilicon/xsc/net/Makefile  |   9 +
>  .../net/ethernet/yunsilicon/xsc/pci/Kconfig   |  16 ++
>  .../net/ethernet/yunsilicon/xsc/pci/Makefile  |   9 +
>  .../net/ethernet/yunsilicon/xsc/pci/main.c    | 255 ++++++++++++++++++
>  11 files changed, 402 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_core.h
>  create mode 100644 drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
>  create mode 100644 drivers/net/ethernet/yunsilicon/xsc/net/Makefile
>  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/MAINTAINERS b/MAINTAINERS
> index cc40a9d9b..4892dd63e 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -25285,6 +25285,13 @@ S:     Maintained
>  F:     Documentation/input/devices/yealink.rst
>  F:     drivers/input/misc/yealink.*
>
> +YUNSILICON XSC DRIVERS
> +M:     Honggang Wei <weihg@yunsilicon.com>
> +M:     Xin Tian <tianx@yunsilicon.com>
> +L:     netdev@vger.kernel.org
> +S:     Maintained
> +F:     drivers/net/ethernet/yunsilicon/xsc
> +
>  Z3FOLD COMPRESSED PAGE ALLOCATOR
>  M:     Vitaly Wool <vitaly.wool@konsulko.com>
>  R:     Miaohe Lin <linmiaohe@huawei.com>
> diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
> index 0baac25db..aa6016597 100644
> --- a/drivers/net/ethernet/Kconfig
> +++ b/drivers/net/ethernet/Kconfig
> @@ -82,6 +82,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 c03203439..c16c34d4b 100644
> --- a/drivers/net/ethernet/Makefile
> +++ b/drivers/net/ethernet/Makefile
> @@ -51,6 +51,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..ff57fedf8
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/Kconfig
> @@ -0,0 +1,26 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021-2025, 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 ARM64 || X86_64
> +       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/net/Kconfig"
> +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..6fc8259a7
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
> +# All rights reserved.
> +# Makefile for the Yunsilicon device drivers.
> +#
> +
> +# obj-$(CONFIG_YUNSILICON_XSC_ETH) += xsc/net/
> +obj-$(CONFIG_YUNSILICON_XSC_PCI) += xsc/pci/
> \ No newline at end of file
> 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..6627a176a
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h
> @@ -0,0 +1,53 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
> + * All rights reserved.
> + */
> +
> +#ifndef __XSC_CORE_H
> +#define __XSC_CORE_H
> +
> +#include <linux/pci.h>
> +
> +#define XSC_PCI_VENDOR_ID              0x1f67
> +
> +#define XSC_MC_PF_DEV_ID               0x1011
> +#define XSC_MC_VF_DEV_ID               0x1012
> +#define XSC_MC_PF_DEV_ID_DIAMOND       0x1021
> +
> +#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
> +
> +struct xsc_dev_resource {
> +       /* protect buffer allocation according to numa node */
> +       struct mutex            alloc_mutex;
> +};
> +
> +enum xsc_pci_state {
> +       XSC_PCI_STATE_DISABLED,
> +       XSC_PCI_STATE_ENABLED,
> +};
> +
> +struct xsc_core_device {
> +       struct pci_dev          *pdev;
> +       struct device           *device;
> +       struct xsc_dev_resource *dev_res;
> +       int                     numa_node;
> +
> +       void __iomem            *bar;
> +       int                     bar_num;
> +
> +       struct mutex            pci_state_mutex;        /* protect pci_state */
> +       enum xsc_pci_state      pci_state;
> +       struct mutex            intf_state_mutex;       /* protect intf_state */
> +       unsigned long           intf_state;
> +};
> +
> +#endif
> diff --git a/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig b/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
> new file mode 100644
> index 000000000..de743487e
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
> @@ -0,0 +1,17 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
> +# All rights reserved.
> +# Yunsilicon driver configuration
> +#
> +
> +config YUNSILICON_XSC_ETH
> +       tristate "Yunsilicon XSC ethernet driver"
> +       default n
> +       depends on YUNSILICON_XSC_PCI
> +       depends on NET
> +       help
> +         This driver provides ethernet support for
> +         Yunsilicon XSC devices.
> +
> +         To compile this driver as a module, choose M here. The module
> +         will be called xsc_eth.
> diff --git a/drivers/net/ethernet/yunsilicon/xsc/net/Makefile b/drivers/net/ethernet/yunsilicon/xsc/net/Makefile
> new file mode 100644
> index 000000000..2811433af
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/net/Makefile
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
> +# All rights reserved.
> +
> +ccflags-y += -I$(srctree)/drivers/net/ethernet/yunsilicon/xsc
> +
> +obj-$(CONFIG_YUNSILICON_XSC_ETH) += xsc_eth.o
> +
> +xsc_eth-y := main.o
> \ No newline at end of file
> diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
> new file mode 100644
> index 000000000..2b6d79905
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
> @@ -0,0 +1,16 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
> +# All rights reserved.
> +# Yunsilicon PCI configuration
> +#
> +
> +config YUNSILICON_XSC_PCI
> +       tristate "Yunsilicon XSC PCI driver"
> +       default n
> +       select PAGE_POOL
> +       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..709270df8
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Makefile
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021-2025, 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..ec3181a8e
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/main.c
> @@ -0,0 +1,255 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (C) 2021-2025, 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_MC_PF_DEV_ID_DIAMOND) },
> +       { 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 set_dma_caps(struct pci_dev *pdev)
> +{
> +       int err;
> +
> +       err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
> +       if (err)
> +               err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
> +       else
> +               err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
You can simplify this as:

        err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
        if (err)
                err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
> +
> +       if (!err)
> +               dma_set_max_seg_size(&pdev->dev, SZ_2G);
> +
> +       return err;
> +}
> +
> +static int xsc_pci_enable_device(struct xsc_core_device *xdev)
> +{
> +       struct pci_dev *pdev = xdev->pdev;
> +       int err = 0;
> +
> +       mutex_lock(&xdev->pci_state_mutex);
> +       if (xdev->pci_state == XSC_PCI_STATE_DISABLED) {
Why is this pci_state checking needed. any reason to not use
pci_is_enabled(dev)?
> +               err = pci_enable_device(pdev);
> +               if (!err)
> +                       xdev->pci_state = XSC_PCI_STATE_ENABLED;
> +       }
> +       mutex_unlock(&xdev->pci_state_mutex);
> +
> +       return err;
> +}
> +
> +static void xsc_pci_disable_device(struct xsc_core_device *xdev)
> +{
> +       struct pci_dev *pdev = xdev->pdev;
> +
> +       mutex_lock(&xdev->pci_state_mutex);
> +       if (xdev->pci_state == XSC_PCI_STATE_ENABLED) {
> +               pci_disable_device(pdev);
> +               xdev->pci_state = XSC_PCI_STATE_DISABLED;
> +       }
> +       mutex_unlock(&xdev->pci_state_mutex);
> +}
> +
> +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 = xsc_pci_enable_device(xdev);
> +       if (err) {
> +               pci_err(pdev, "failed to enable PCI device: err=%d\n", err);
> +               goto err_ret;
You can return directly from here
> +       }
> +
> +       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 = 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:
> +       xsc_pci_disable_device(xdev);
> +err_ret:
> +       return err;
> +}
> +
> +static void xsc_pci_fini(struct xsc_core_device *xdev)
> +{
> +       struct pci_dev *pdev = xdev->pdev;
> +
> +       if (xdev->bar)
Is this check really needed?
> +               pci_iounmap(pdev, xdev->bar);
> +       pci_clear_master(pdev);
> +       pci_release_region(pdev, xdev->bar_num);
> +       xsc_pci_disable_device(xdev);
> +}
> +
> +static int xsc_dev_res_init(struct xsc_core_device *xdev)
> +{
> +       struct xsc_dev_resource *dev_res;
> +
> +       dev_res = kvzalloc(sizeof(*dev_res), GFP_KERNEL);
> +       if (!dev_res)
> +               return -ENOMEM;
> +
> +       xdev->dev_res = dev_res;
> +       mutex_init(&dev_res->alloc_mutex);
> +
> +       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;
> +
> +       mutex_init(&xdev->pci_state_mutex);
> +       mutex_init(&xdev->intf_state_mutex);
> +
> +       err = xsc_dev_res_init(xdev);
> +       if (err) {
> +               pci_err(xdev->pdev, "xsc dev res init failed %d\n", err);
> +               goto out;
You can avoid this label by doing "return err" instead of "return 0"
the line below
> +       }
> +
> +       return 0;
> +out:
> +       return err;
> +}
> +
> +static void xsc_core_dev_cleanup(struct xsc_core_device *xdev)
> +{
> +       xsc_dev_res_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(sizeof(*xdev), GFP_KERNEL);
> +       if (!xdev)
> +               return -ENOMEM;
> +
> +       xdev->pdev = pci_dev;
> +       xdev->device = &pci_dev->dev;
> +
> +       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;
> +       }
> +
> +       return 0;
> +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_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");
> +               goto out;
There is no need of this label
> +       }
> +       return 0;
"return err" here
> +
> +out:
> +       return err;
> +}
> +
> +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");
> --
> 2.18.4
>
Xin Tian March 6, 2025, 2:48 a.m. UTC | #4
On 2025/3/5 16:55, Kalesh Anakkur Purayil wrote:
> On Fri, Feb 28, 2025 at 9:12 PM Xin Tian <tianx@yunsilicon.com> wrote:
>> 1. Add yunsilicon xsc driver basic compile framework, including
>> xsc_pci driver and xsc_eth driver
>> 2. Implemented PCI device initialization.
>>
>> Co-developed-by: Honggang Wei <weihg@yunsilicon.com>
>> Signed-off-by: Honggang Wei <weihg@yunsilicon.com>
>> Co-developed-by: Lei Yan <jacky@yunsilicon.com>
>> Signed-off-by: Lei Yan <jacky@yunsilicon.com>
>> Signed-off-by: Xin Tian <tianx@yunsilicon.com>
>> ---
>>   MAINTAINERS                                   |   7 +
>>   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_core.h |  53 ++++
>>   .../net/ethernet/yunsilicon/xsc/net/Kconfig   |  17 ++
>>   .../net/ethernet/yunsilicon/xsc/net/Makefile  |   9 +
>>   .../net/ethernet/yunsilicon/xsc/pci/Kconfig   |  16 ++
>>   .../net/ethernet/yunsilicon/xsc/pci/Makefile  |   9 +
>>   .../net/ethernet/yunsilicon/xsc/pci/main.c    | 255 ++++++++++++++++++
>>   11 files changed, 402 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_core.h
>>   create mode 100644 drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
>>   create mode 100644 drivers/net/ethernet/yunsilicon/xsc/net/Makefile
>>   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/MAINTAINERS b/MAINTAINERS
>> index cc40a9d9b..4892dd63e 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -25285,6 +25285,13 @@ S:     Maintained
>>   F:     Documentation/input/devices/yealink.rst
>>   F:     drivers/input/misc/yealink.*
>>
>> +YUNSILICON XSC DRIVERS
>> +M:     Honggang Wei <weihg@yunsilicon.com>
>> +M:     Xin Tian <tianx@yunsilicon.com>
>> +L:     netdev@vger.kernel.org
>> +S:     Maintained
>> +F:     drivers/net/ethernet/yunsilicon/xsc
>> +
>>   Z3FOLD COMPRESSED PAGE ALLOCATOR
>>   M:     Vitaly Wool <vitaly.wool@konsulko.com>
>>   R:     Miaohe Lin <linmiaohe@huawei.com>
>> diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
>> index 0baac25db..aa6016597 100644
>> --- a/drivers/net/ethernet/Kconfig
>> +++ b/drivers/net/ethernet/Kconfig
>> @@ -82,6 +82,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 c03203439..c16c34d4b 100644
>> --- a/drivers/net/ethernet/Makefile
>> +++ b/drivers/net/ethernet/Makefile
>> @@ -51,6 +51,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..ff57fedf8
>> --- /dev/null
>> +++ b/drivers/net/ethernet/yunsilicon/Kconfig
>> @@ -0,0 +1,26 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2021-2025, 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 ARM64 || X86_64
>> +       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/net/Kconfig"
>> +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..6fc8259a7
>> --- /dev/null
>> +++ b/drivers/net/ethernet/yunsilicon/Makefile
>> @@ -0,0 +1,8 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
>> +# All rights reserved.
>> +# Makefile for the Yunsilicon device drivers.
>> +#
>> +
>> +# obj-$(CONFIG_YUNSILICON_XSC_ETH) += xsc/net/
>> +obj-$(CONFIG_YUNSILICON_XSC_PCI) += xsc/pci/
>> \ No newline at end of file
>> 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..6627a176a
>> --- /dev/null
>> +++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h
>> @@ -0,0 +1,53 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/* Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
>> + * All rights reserved.
>> + */
>> +
>> +#ifndef __XSC_CORE_H
>> +#define __XSC_CORE_H
>> +
>> +#include <linux/pci.h>
>> +
>> +#define XSC_PCI_VENDOR_ID              0x1f67
>> +
>> +#define XSC_MC_PF_DEV_ID               0x1011
>> +#define XSC_MC_VF_DEV_ID               0x1012
>> +#define XSC_MC_PF_DEV_ID_DIAMOND       0x1021
>> +
>> +#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
>> +
>> +struct xsc_dev_resource {
>> +       /* protect buffer allocation according to numa node */
>> +       struct mutex            alloc_mutex;
>> +};
>> +
>> +enum xsc_pci_state {
>> +       XSC_PCI_STATE_DISABLED,
>> +       XSC_PCI_STATE_ENABLED,
>> +};
>> +
>> +struct xsc_core_device {
>> +       struct pci_dev          *pdev;
>> +       struct device           *device;
>> +       struct xsc_dev_resource *dev_res;
>> +       int                     numa_node;
>> +
>> +       void __iomem            *bar;
>> +       int                     bar_num;
>> +
>> +       struct mutex            pci_state_mutex;        /* protect pci_state */
>> +       enum xsc_pci_state      pci_state;
>> +       struct mutex            intf_state_mutex;       /* protect intf_state */
>> +       unsigned long           intf_state;
>> +};
>> +
>> +#endif
>> diff --git a/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig b/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
>> new file mode 100644
>> index 000000000..de743487e
>> --- /dev/null
>> +++ b/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
>> @@ -0,0 +1,17 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
>> +# All rights reserved.
>> +# Yunsilicon driver configuration
>> +#
>> +
>> +config YUNSILICON_XSC_ETH
>> +       tristate "Yunsilicon XSC ethernet driver"
>> +       default n
>> +       depends on YUNSILICON_XSC_PCI
>> +       depends on NET
>> +       help
>> +         This driver provides ethernet support for
>> +         Yunsilicon XSC devices.
>> +
>> +         To compile this driver as a module, choose M here. The module
>> +         will be called xsc_eth.
>> diff --git a/drivers/net/ethernet/yunsilicon/xsc/net/Makefile b/drivers/net/ethernet/yunsilicon/xsc/net/Makefile
>> new file mode 100644
>> index 000000000..2811433af
>> --- /dev/null
>> +++ b/drivers/net/ethernet/yunsilicon/xsc/net/Makefile
>> @@ -0,0 +1,9 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
>> +# All rights reserved.
>> +
>> +ccflags-y += -I$(srctree)/drivers/net/ethernet/yunsilicon/xsc
>> +
>> +obj-$(CONFIG_YUNSILICON_XSC_ETH) += xsc_eth.o
>> +
>> +xsc_eth-y := main.o
>> \ No newline at end of file
>> diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
>> new file mode 100644
>> index 000000000..2b6d79905
>> --- /dev/null
>> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
>> @@ -0,0 +1,16 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
>> +# All rights reserved.
>> +# Yunsilicon PCI configuration
>> +#
>> +
>> +config YUNSILICON_XSC_PCI
>> +       tristate "Yunsilicon XSC PCI driver"
>> +       default n
>> +       select PAGE_POOL
>> +       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..709270df8
>> --- /dev/null
>> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Makefile
>> @@ -0,0 +1,9 @@
>> +# SPDX-License-Identifier: GPL-2.0
>> +# Copyright (C) 2021-2025, 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..ec3181a8e
>> --- /dev/null
>> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/main.c
>> @@ -0,0 +1,255 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/* Copyright (C) 2021-2025, 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_MC_PF_DEV_ID_DIAMOND) },
>> +       { 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 set_dma_caps(struct pci_dev *pdev)
>> +{
>> +       int err;
>> +
>> +       err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
>> +       if (err)
>> +               err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
>> +       else
>> +               err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
> You can simplify this as:
>
>          err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
>          if (err)
>                  err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));

Thanks, Kalesh

Jakub also raised a comment here suggesting that it can be simplified to

|err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); |

There's no need to fall back to a 32-bit mask now. You can see the 
reason here:

https://lkml.org/lkml/2021/6/7/227

>> +
>> +       if (!err)
>> +               dma_set_max_seg_size(&pdev->dev, SZ_2G);
>> +
>> +       return err;
>> +}
>> +
>> +static int xsc_pci_enable_device(struct xsc_core_device *xdev)
>> +{
>> +       struct pci_dev *pdev = xdev->pdev;
>> +       int err = 0;
>> +
>> +       mutex_lock(&xdev->pci_state_mutex);
>> +       if (xdev->pci_state == XSC_PCI_STATE_DISABLED) {
> Why is this pci_state checking needed. any reason to not use
> pci_is_enabled(dev)?

This is just a personal habit.

I agree that it's somewhat redundant here, and using pci_is_enabled

is enough and clearer.

I'll change the code accordingly.

>> +               err = pci_enable_device(pdev);
>> +               if (!err)
>> +                       xdev->pci_state = XSC_PCI_STATE_ENABLED;
>> +       }
>> +       mutex_unlock(&xdev->pci_state_mutex);
>> +
>> +       return err;
>> +}
>> +
>> +static void xsc_pci_disable_device(struct xsc_core_device *xdev)
>> +{
>> +       struct pci_dev *pdev = xdev->pdev;
>> +
>> +       mutex_lock(&xdev->pci_state_mutex);
>> +       if (xdev->pci_state == XSC_PCI_STATE_ENABLED) {
>> +               pci_disable_device(pdev);
>> +               xdev->pci_state = XSC_PCI_STATE_DISABLED;
>> +       }
>> +       mutex_unlock(&xdev->pci_state_mutex);
>> +}
>> +
>> +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 = xsc_pci_enable_device(xdev);
>> +       if (err) {
>> +               pci_err(pdev, "failed to enable PCI device: err=%d\n", err);
>> +               goto err_ret;
> You can return directly from here
Yes, will change
>> +       }
>> +
>> +       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 = 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:
>> +       xsc_pci_disable_device(xdev);
>> +err_ret:
>> +       return err;
>> +}
>> +
>> +static void xsc_pci_fini(struct xsc_core_device *xdev)
>> +{
>> +       struct pci_dev *pdev = xdev->pdev;
>> +
>> +       if (xdev->bar)
> Is this check really needed?
no need, will drop it.
>> +               pci_iounmap(pdev, xdev->bar);
>> +       pci_clear_master(pdev);
>> +       pci_release_region(pdev, xdev->bar_num);
>> +       xsc_pci_disable_device(xdev);
>> +}
>> +
>> +static int xsc_dev_res_init(struct xsc_core_device *xdev)
>> +{
>> +       struct xsc_dev_resource *dev_res;
>> +
>> +       dev_res = kvzalloc(sizeof(*dev_res), GFP_KERNEL);
>> +       if (!dev_res)
>> +               return -ENOMEM;
>> +
>> +       xdev->dev_res = dev_res;
>> +       mutex_init(&dev_res->alloc_mutex);
>> +
>> +       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;
>> +
>> +       mutex_init(&xdev->pci_state_mutex);
>> +       mutex_init(&xdev->intf_state_mutex);
>> +
>> +       err = xsc_dev_res_init(xdev);
>> +       if (err) {
>> +               pci_err(xdev->pdev, "xsc dev res init failed %d\n", err);
>> +               goto out;
> You can avoid this label by doing "return err" instead of "return 0"
> the line below

The code is added to maintain structure with additions of next patch. ( 
same for the latter two)

Since you feel it not suitable, I'll remove  and add it where needed.

Thanks

>> +       }
>> +
>> +       return 0;
>> +out:
>> +       return err;
>> +}
>> +
>> +static void xsc_core_dev_cleanup(struct xsc_core_device *xdev)
>> +{
>> +       xsc_dev_res_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(sizeof(*xdev), GFP_KERNEL);
>> +       if (!xdev)
>> +               return -ENOMEM;
>> +
>> +       xdev->pdev = pci_dev;
>> +       xdev->device = &pci_dev->dev;
>> +
>> +       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;
>> +       }
>> +
>> +       return 0;
>> +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_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");
>> +               goto out;
> There is no need of this label
>> +       }
>> +       return 0;
> "return err" here
>> +
>> +out:
>> +       return err;
>> +}
>> +
>> +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");
>> --
>> 2.18.4
>>
>
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index cc40a9d9b..4892dd63e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25285,6 +25285,13 @@  S:	Maintained
 F:	Documentation/input/devices/yealink.rst
 F:	drivers/input/misc/yealink.*
 
+YUNSILICON XSC DRIVERS
+M:	Honggang Wei <weihg@yunsilicon.com>
+M:	Xin Tian <tianx@yunsilicon.com>
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	drivers/net/ethernet/yunsilicon/xsc
+
 Z3FOLD COMPRESSED PAGE ALLOCATOR
 M:	Vitaly Wool <vitaly.wool@konsulko.com>
 R:	Miaohe Lin <linmiaohe@huawei.com>
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 0baac25db..aa6016597 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -82,6 +82,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 c03203439..c16c34d4b 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -51,6 +51,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..ff57fedf8
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/Kconfig
@@ -0,0 +1,26 @@ 
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021-2025, 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 ARM64 || X86_64
+	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/net/Kconfig"
+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..6fc8259a7
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/Makefile
@@ -0,0 +1,8 @@ 
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
+# All rights reserved.
+# Makefile for the Yunsilicon device drivers.
+#
+
+# obj-$(CONFIG_YUNSILICON_XSC_ETH) += xsc/net/
+obj-$(CONFIG_YUNSILICON_XSC_PCI) += xsc/pci/
\ No newline at end of file
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..6627a176a
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h
@@ -0,0 +1,53 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#ifndef __XSC_CORE_H
+#define __XSC_CORE_H
+
+#include <linux/pci.h>
+
+#define XSC_PCI_VENDOR_ID		0x1f67
+
+#define XSC_MC_PF_DEV_ID		0x1011
+#define XSC_MC_VF_DEV_ID		0x1012
+#define XSC_MC_PF_DEV_ID_DIAMOND	0x1021
+
+#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
+
+struct xsc_dev_resource {
+	/* protect buffer allocation according to numa node */
+	struct mutex		alloc_mutex;
+};
+
+enum xsc_pci_state {
+	XSC_PCI_STATE_DISABLED,
+	XSC_PCI_STATE_ENABLED,
+};
+
+struct xsc_core_device {
+	struct pci_dev		*pdev;
+	struct device		*device;
+	struct xsc_dev_resource	*dev_res;
+	int			numa_node;
+
+	void __iomem		*bar;
+	int			bar_num;
+
+	struct mutex		pci_state_mutex;	/* protect pci_state */
+	enum xsc_pci_state	pci_state;
+	struct mutex		intf_state_mutex;	/* protect intf_state */
+	unsigned long		intf_state;
+};
+
+#endif
diff --git a/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig b/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
new file mode 100644
index 000000000..de743487e
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
@@ -0,0 +1,17 @@ 
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
+# All rights reserved.
+# Yunsilicon driver configuration
+#
+
+config YUNSILICON_XSC_ETH
+	tristate "Yunsilicon XSC ethernet driver"
+	default n
+	depends on YUNSILICON_XSC_PCI
+	depends on NET
+	help
+	  This driver provides ethernet support for
+	  Yunsilicon XSC devices.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called xsc_eth.
diff --git a/drivers/net/ethernet/yunsilicon/xsc/net/Makefile b/drivers/net/ethernet/yunsilicon/xsc/net/Makefile
new file mode 100644
index 000000000..2811433af
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/net/Makefile
@@ -0,0 +1,9 @@ 
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
+# All rights reserved.
+
+ccflags-y += -I$(srctree)/drivers/net/ethernet/yunsilicon/xsc
+
+obj-$(CONFIG_YUNSILICON_XSC_ETH) += xsc_eth.o
+
+xsc_eth-y := main.o
\ No newline at end of file
diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
new file mode 100644
index 000000000..2b6d79905
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
@@ -0,0 +1,16 @@ 
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
+# All rights reserved.
+# Yunsilicon PCI configuration
+#
+
+config YUNSILICON_XSC_PCI
+	tristate "Yunsilicon XSC PCI driver"
+	default n
+	select PAGE_POOL
+	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..709270df8
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Makefile
@@ -0,0 +1,9 @@ 
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021-2025, 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..ec3181a8e
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/main.c
@@ -0,0 +1,255 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2021-2025, 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_MC_PF_DEV_ID_DIAMOND) },
+	{ 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 set_dma_caps(struct pci_dev *pdev)
+{
+	int err;
+
+	err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+	if (err)
+		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+	else
+		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_enable_device(struct xsc_core_device *xdev)
+{
+	struct pci_dev *pdev = xdev->pdev;
+	int err = 0;
+
+	mutex_lock(&xdev->pci_state_mutex);
+	if (xdev->pci_state == XSC_PCI_STATE_DISABLED) {
+		err = pci_enable_device(pdev);
+		if (!err)
+			xdev->pci_state = XSC_PCI_STATE_ENABLED;
+	}
+	mutex_unlock(&xdev->pci_state_mutex);
+
+	return err;
+}
+
+static void xsc_pci_disable_device(struct xsc_core_device *xdev)
+{
+	struct pci_dev *pdev = xdev->pdev;
+
+	mutex_lock(&xdev->pci_state_mutex);
+	if (xdev->pci_state == XSC_PCI_STATE_ENABLED) {
+		pci_disable_device(pdev);
+		xdev->pci_state = XSC_PCI_STATE_DISABLED;
+	}
+	mutex_unlock(&xdev->pci_state_mutex);
+}
+
+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 = xsc_pci_enable_device(xdev);
+	if (err) {
+		pci_err(pdev, "failed to enable PCI device: err=%d\n", err);
+		goto err_ret;
+	}
+
+	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 = 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:
+	xsc_pci_disable_device(xdev);
+err_ret:
+	return err;
+}
+
+static void xsc_pci_fini(struct xsc_core_device *xdev)
+{
+	struct pci_dev *pdev = xdev->pdev;
+
+	if (xdev->bar)
+		pci_iounmap(pdev, xdev->bar);
+	pci_clear_master(pdev);
+	pci_release_region(pdev, xdev->bar_num);
+	xsc_pci_disable_device(xdev);
+}
+
+static int xsc_dev_res_init(struct xsc_core_device *xdev)
+{
+	struct xsc_dev_resource *dev_res;
+
+	dev_res = kvzalloc(sizeof(*dev_res), GFP_KERNEL);
+	if (!dev_res)
+		return -ENOMEM;
+
+	xdev->dev_res = dev_res;
+	mutex_init(&dev_res->alloc_mutex);
+
+	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;
+
+	mutex_init(&xdev->pci_state_mutex);
+	mutex_init(&xdev->intf_state_mutex);
+
+	err = xsc_dev_res_init(xdev);
+	if (err) {
+		pci_err(xdev->pdev, "xsc dev res init failed %d\n", err);
+		goto out;
+	}
+
+	return 0;
+out:
+	return err;
+}
+
+static void xsc_core_dev_cleanup(struct xsc_core_device *xdev)
+{
+	xsc_dev_res_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(sizeof(*xdev), GFP_KERNEL);
+	if (!xdev)
+		return -ENOMEM;
+
+	xdev->pdev = pci_dev;
+	xdev->device = &pci_dev->dev;
+
+	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;
+	}
+
+	return 0;
+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_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");
+		goto out;
+	}
+	return 0;
+
+out:
+	return err;
+}
+
+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");