diff mbox series

[01/16] net-next/yunsilicon: Add yunsilicon xsc driver basic framework

Message ID 20241209071101.3392590-2-tianx@yunsilicon.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series [01/16] net-next/yunsilicon: Add yunsilicon xsc driver basic framework | expand

Checks

Context Check Description
netdev/series_format fail Series does not have a cover letter; Series longer than 15 patches (and no cover letter)
netdev/tree_selection success Guessed tree name to be 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 7 maintainers not CCed: Parthiban.Veerasooran@microchip.com andrew+netdev@lunn.ch kuba@kernel.org pabeni@redhat.com edumazet@google.com jacky@yunsilicon.com masahiroy@kernel.org
netdev/build_clang fail Errors and warnings before: 1 this patch: 2
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api fail Found: 'module_param' was: 0 now: 1
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 5 this patch: 6
netdev/checkpatch warning WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? WARNING: line length of 84 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns WARNING: line length of 91 exceeds 80 columns WARNING: line length of 93 exceeds 80 columns
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

Commit Message

tianx Dec. 9, 2024, 7:10 a.m. UTC
From: Xin Tian <tianx@yunsilicon.com>

Add yunsilicon xsc driver basic framework, including xsc_pci driver
and xsc_eth driver

Signed-off-by: Xin Tian <tianx@yunsilicon.com>
Signed-off-by: Honggang Wei <weihg@yunsilicon.com>
Signed-off-by: Lei Yan <jacky@yunsilicon.com>
---
 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 | 134 +++++++++
 .../net/ethernet/yunsilicon/xsc/net/Kconfig   |  16 +
 .../net/ethernet/yunsilicon/xsc/net/Makefile  |   9 +
 .../net/ethernet/yunsilicon/xsc/pci/Kconfig   |  17 ++
 .../net/ethernet/yunsilicon/xsc/pci/Makefile  |   9 +
 .../net/ethernet/yunsilicon/xsc/pci/main.c    | 278 ++++++++++++++++++
 10 files changed, 499 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

Przemek Kitszel Dec. 9, 2024, 11:52 a.m. UTC | #1
On 12/9/24 8:10 AM, Tian Xin wrote:
> From: Xin Tian <tianx@yunsilicon.com>
> 
> Add yunsilicon xsc driver basic framework, including xsc_pci driver
> and xsc_eth driver
> 
> Signed-off-by: Xin Tian <tianx@yunsilicon.com>

Submitter/sender Sign-off should be always the last tag.
What the two others mentioned did for this patch/series?
If they have provided a substantial (in relation to the given patch)
contribution, then Co-developed-by should be added for them.

> Signed-off-by: Honggang Wei <weihg@yunsilicon.com>
> Signed-off-by: Lei Yan <jacky@yunsilicon.com>
> ---

please ensure that your next revision will have all patches (and cover
letter) linked. Right now it looks like if you have submitted sixteen
separate email thread (but don't resubmit right now, please wait for the
first round of the feedback).

>   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 | 134 +++++++++
>   .../net/ethernet/yunsilicon/xsc/net/Kconfig   |  16 +
>   .../net/ethernet/yunsilicon/xsc/net/Makefile  |   9 +
>   .../net/ethernet/yunsilicon/xsc/pci/Kconfig   |  17 ++
>   .../net/ethernet/yunsilicon/xsc/pci/Makefile  |   9 +
>   .../net/ethernet/yunsilicon/xsc/pci/main.c    | 278 ++++++++++++++++++
>   10 files changed, 499 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/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..a387a8dde
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/Kconfig
> @@ -0,0 +1,26 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021 - 2023, Shanghai Yunsilicon Technology Co., Ltd.

you should put 2024 here, or, to minimize effort, put 2025 given it is
likely that for new driver the review phase takes over a month ;)

> +# All rights reserved.
> +# Yunsilicon driver configuration
> +#
> +
> +config NET_VENDOR_YUNSILICON
> +	bool "Yunsilicon devices"
> +	default y
> +	depends on PCI || NET

your PCI driver does SELECT NET_DEVLINK and your ETH driver depends on
your PCI one, is it really possible to have only one of PCI / NET on and
have something useful in terms of Yunsilicon eth/rdma?

> +	depends on ARM64 || X86_64
> +	help
> +	  If you have a network (Ethernet or RDMA) 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 devices. If you say Y, you will be
> +	  asked for your specific card in the following questions.

the Note section is rather a obvious expanding of the prev paragraph,
not needed. (If you insinst, fix the typo).

> +
> +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..950fd2663
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021 - 2023, 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..6049c2c65
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h
> @@ -0,0 +1,134 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2021 - 2023, Shanghai Yunsilicon Technology Co., Ltd.
> + * All rights reserved.
> + */
> +
> +#ifndef XSC_CORE_H
> +#define XSC_CORE_H
> +
> +#include <linux/kernel.h>
> +#include <linux/pci.h>
> +
> +extern unsigned int xsc_log_level;
> +
> +#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
> +
> +enum {
> +	XSC_LOG_LEVEL_DBG	= 0,
> +	XSC_LOG_LEVEL_INFO	= 1,
> +	XSC_LOG_LEVEL_WARN	= 2,
> +	XSC_LOG_LEVEL_ERR	= 3,
> +};
> +
> +#define xsc_dev_log(condition, level, dev, fmt, ...)			\
> +do {									\
> +	if (condition)							\
> +		dev_printk(level, dev, dev_fmt(fmt), ##__VA_ARGS__);	\
> +} while (0)
> +
> +#define xsc_core_dbg(__dev, format, ...)				\
> +	xsc_dev_log(xsc_log_level <= XSC_LOG_LEVEL_DBG, KERN_DEBUG,	\
> +		&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,		\
> +		__func__, __LINE__, current->pid, ##__VA_ARGS__)
> +
> +#define xsc_core_dbg_once(__dev, format, ...)				\
> +	dev_dbg_once(&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,	\
> +		     __func__, __LINE__, current->pid,			\
> +		     ##__VA_ARGS__)
> +
> +#define xsc_core_dbg_mask(__dev, mask, format, ...)			\
> +do {									\
> +	if ((mask) & xsc_debug_mask)					\
> +		xsc_core_dbg(__dev, format, ##__VA_ARGS__);		\
> +} while (0)
> +
> +#define xsc_core_err(__dev, format, ...)				\
> +	xsc_dev_log(xsc_log_level <= XSC_LOG_LEVEL_ERR, KERN_ERR,	\
> +		&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,		\
> +		__func__, __LINE__, current->pid, ##__VA_ARGS__)
> +
> +#define xsc_core_err_rl(__dev, format, ...)				\
> +	dev_err_ratelimited(&(__dev)->pdev->dev,			\
> +			   "%s:%d:(pid %d): " format,			\
> +			   __func__, __LINE__, current->pid,		\
> +			   ##__VA_ARGS__)
> +
> +#define xsc_core_warn(__dev, format, ...)				\
> +	xsc_dev_log(xsc_log_level <= XSC_LOG_LEVEL_WARN, KERN_WARNING,	\
> +		&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,		\
> +		__func__, __LINE__, current->pid, ##__VA_ARGS__)
> +
> +#define xsc_core_info(__dev, format, ...)				\
> +	xsc_dev_log(xsc_log_level <= XSC_LOG_LEVEL_INFO, KERN_INFO,	\
> +		&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,		\
> +		__func__, __LINE__, current->pid, ##__VA_ARGS__)
> +
> +#define xsc_pr_debug(format, ...)					\
> +do {									\
> +	if (xsc_log_level <= XSC_LOG_LEVEL_DBG)				\
> +		pr_debug(format, ##__VA_ARGS__);		\
> +} while (0)
> +
> +#define assert(__dev, expr)						\
> +do {									\
> +	if (!(expr)) {							\
> +		dev_err(&(__dev)->pdev->dev,				\
> +		"Assertion failed! %s, %s, %s, line %d\n",		\
> +		#expr, __FILE__, __func__, __LINE__);			\
> +	}								\
> +} while (0)
> +


oh wow, please stop reinventing the kernel functionality
log levels, log macros, asserting functionality, etc
I see that you want to have possibility to enable more verbose logging
per module though, but this is not something that should be done
within the module (try to do it in a way that other drivers could
benefit, and double check if there is already something like that)

> +enum {
> +	XSC_MAX_NAME_LEN = 32,
> +};

I find it weird that there is no easy to use #define for 32
that will make sense here (you are free to add one)


> +
> +struct xsc_dev_resource {
> +	struct mutex alloc_mutex;	/* protect buffer alocation according to numa node */
> +	int numa_node;
> +};
> +
> +enum xsc_pci_status {
> +	XSC_PCI_STATUS_DISABLED,
> +	XSC_PCI_STATUS_ENABLED,
> +};
> +
> +struct xsc_priv {
> +	char			name[XSC_MAX_NAME_LEN];
> +	struct list_head	dev_list;
> +	struct list_head	ctx_list;
> +	spinlock_t		ctx_lock;	/* protect ctx_list */
> +	int			numa_node;
> +};
> +
> +/* our core device */

please no obvious comments

> +struct xsc_core_device {
> +	struct pci_dev		*pdev;
> +	struct device		*device;
> +	struct xsc_priv		priv;
> +	struct xsc_dev_resource	*dev_res;
> +
> +	void __iomem		*bar;
> +	int			bar_num;
> +
> +	struct mutex		pci_status_mutex;	/* protect pci_status */
> +	enum xsc_pci_status	pci_status;
> +	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..30889caa9
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
> @@ -0,0 +1,16 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021 - 2023, 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
> +	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..6ac74b27a
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/net/Makefile
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021 - 2023, 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..fafa69b8a
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
> @@ -0,0 +1,17 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021 - 2023, Shanghai Yunsilicon Technology Co., Ltd.
> +# All rights reserved.
> +# Yunsilicon PCI configuration
> +#
> +
> +config YUNSILICON_XSC_PCI
> +	tristate "Yunsilicon XSC PCI driver"
> +	default n
> +	select NET_DEVLINK
> +	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..b2ae73fb9
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Makefile
> @@ -0,0 +1,9 @@
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2021 - 2023, 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..1d26ffa8d
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/main.c
> @@ -0,0 +1,278 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (C) 2021 - 2023, Shanghai Yunsilicon Technology Co., Ltd.
> + * All rights reserved.
> + */
> +
> +#include "common/xsc_core.h"
> +
> +unsigned int xsc_log_level = XSC_LOG_LEVEL_WARN;
> +module_param_named(log_level, xsc_log_level, uint, 0644);

module parameters are not liked in general

> +MODULE_PARM_DESC(log_level,
> +		 "lowest log level to print: 0=debug, 1=info, 2=warning, 3=error. Default=1");
> +EXPORT_SYMBOL(xsc_log_level);
> +
> +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 = 0;

don't (zero-)init variables that are going to be initialized by other
means without reading this value

> +
> +	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, 2u * 1024 * 1024 * 1024);

see SZ_2G and other stuff from linux/sizes.h

> +
> +	return err;
> +}
> +
> +static int xsc_pci_enable_device(struct xsc_core_device *dev)
> +{
> +	struct pci_dev *pdev = dev->pdev;
> +	int err = 0;

ditto zero-init
(general rule: if there is some complain, fix whole series)

> +
> +	mutex_lock(&dev->pci_status_mutex);
> +	if (dev->pci_status == XSC_PCI_STATUS_DISABLED) {
> +		err = pci_enable_device(pdev);
> +		if (!err)
> +			dev->pci_status = XSC_PCI_STATUS_ENABLED;
> +	}
> +	mutex_unlock(&dev->pci_status_mutex);
> +
> +	return err;
> +}
> +
> +static void xsc_pci_disable_device(struct xsc_core_device *dev)

as there is rather much interaction with struct device, I would
avoid using the name dev for other things, especially that your
driver has a nice three-letter name, you could name your
param xsc, or xsc_core (depending what else you name xsc "later")

> +{
> +	struct pci_dev *pdev = dev->pdev;
> +
> +	mutex_lock(&dev->pci_status_mutex);
> +	if (dev->pci_status == XSC_PCI_STATUS_ENABLED) {

instead of status, this field should be rather name state,
as you encode a state machine, and in general, hand written
state machine code scattered through the driver is hard to maintain
(my drivers have that exact problem)

anyway, this whole function is just a wrapper, that you need
to don't call pci_disable_device() on already disabled one

> +		pci_disable_device(pdev);
> +		dev->pci_status = XSC_PCI_STATUS_DISABLED;
> +	}
> +	mutex_unlock(&dev->pci_status_mutex);
> +}
> +
> +static int xsc_pci_init(struct xsc_core_device *dev, const struct pci_device_id *id)
> +{
> +	struct pci_dev *pdev = dev->pdev;
> +	int err = 0;
> +	int bar_num = 0;
> +	void __iomem *bar_base = NULL;

there is RCT rule (reverse x-mass three formatting rule) for networking,
it mandates to sort variable declarations lines from the longest to the
shortest

> +
> +	mutex_init(&dev->pci_status_mutex);
> +	dev->priv.numa_node = dev_to_node(&pdev->dev);
> +	if (dev->priv.numa_node == -1)
> +		dev->priv.numa_node = 0;

that way you are going to pin to node 0 when there was no prior choice,
wouldn't it be better to use random spread instead?

> +
> +	/* enable the device */

ditto obvious comments

> +	err = xsc_pci_enable_device(dev);
> +	if (err) {
> +		xsc_core_err(dev, "failed to enable PCI device: err=%d\n", err);
> +		goto err_ret;
> +	}
> +
> +	err = pci_request_region(pdev, bar_num, KBUILD_MODNAME);
> +	if (err) {
> +		xsc_core_err(dev, "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) {
> +		xsc_core_err(dev, "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) {
> +		xsc_core_err(dev, "failed to ioremap %s bar%d\n", KBUILD_MODNAME, bar_num);

massing your module name to your logging macro seems silly

> +		goto err_clr_master;
> +	}
> +
> +	err = pci_save_state(pdev);
> +	if (err) {
> +		xsc_core_err(dev, "pci_save_state failed: err=%d\n", err);
> +		goto err_io_unmap;
> +	}
> +
> +	dev->bar_num = bar_num;
> +	dev->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(dev);
> +err_ret:
> +	return err;

very good goto-label naming, a way to go!

> +}
> +
> +static void xsc_pci_fini(struct xsc_core_device *dev)
> +{
> +	struct pci_dev *pdev = dev->pdev;
> +
> +	if (dev->bar)
> +		pci_iounmap(pdev, dev->bar);
> +	pci_clear_master(pdev);
> +	pci_release_region(pdev, dev->bar_num);
> +	xsc_pci_disable_device(dev);
> +}
> +
> +static int xsc_priv_init(struct xsc_core_device *dev)
> +{
> +	struct xsc_priv *priv = &dev->priv;
> +
> +	strscpy(priv->name, dev_name(&dev->pdev->dev), XSC_MAX_NAME_LEN);
> +	priv->name[XSC_MAX_NAME_LEN - 1] = 0;

strscpy doc:
The destination @dst buffer is always NUL terminated,
unless it's zero-sized.


> +
> +	INIT_LIST_HEAD(&priv->ctx_list);
> +	spin_lock_init(&priv->ctx_lock);
> +	mutex_init(&dev->intf_state_mutex);
> +
> +	return 0;
> +}
> +
> +static int xsc_dev_res_init(struct xsc_core_device *dev)
> +{
> +	struct xsc_dev_resource *dev_res = NULL;

same no unneded zero-init rule for =NULL

> +
> +	dev_res = kvzalloc(sizeof(*dev_res), GFP_KERNEL);
> +	if (!dev_res)
> +		return -ENOMEM;
> +
> +	dev->dev_res = dev_res;
> +	mutex_init(&dev_res->alloc_mutex);
> +
> +	return 0;
> +}
> +
> +static void xsc_dev_res_cleanup(struct xsc_core_device *dev)
> +{
> +	kfree(dev->dev_res);
> +	dev->dev_res = NULL;

most pointers should not be overwritten by NULL after freeing,
do you support reinit of some sort?

> +}
> +
> +static int xsc_core_dev_init(struct xsc_core_device *dev)
> +{
> +	int err = 0;
> +
> +	xsc_priv_init(dev);
> +
> +	err = xsc_dev_res_init(dev);
> +	if (err) {
> +		xsc_core_err(dev, "xsc dev res init failed %d\n", err);
> +		goto err_res_init;
> +	}
> +
> +	return 0;
> +err_res_init:

and here is badly named label, don't name after "came from", name after
"what to do", here it will be simpy exit/fail/out

in this particular case, as you do nothing here, this whole function
should be just:
	xsc_priv_init(dev);
	return xsc_dev_res_init(dev);

+error message printing if you really must (and if there is no same
error in the xsc_dev_res_init())

> +	return err;
> +}
> +
> +static void xsc_core_dev_cleanup(struct xsc_core_device *dev)
> +{
> +	xsc_dev_res_cleanup(dev);
> +}
> +
> +static int xsc_pci_probe(struct pci_dev *pci_dev,
> +			 const struct pci_device_id *id)
> +{
> +	struct xsc_core_device *xdev;

xdev sounds nice

> +	int err;
> +
> +	/* allocate core structure and fill it out */

really?

> +	xdev = kzalloc(sizeof(*xdev), GFP_KERNEL);
> +	if (!xdev)
> +		return -ENOMEM;
> +
> +	xdev->pdev = pci_dev;
> +	xdev->device = &pci_dev->dev;
> +
> +	/* init pcie device */
> +	pci_set_drvdata(pci_dev, xdev);
> +	err = xsc_pci_init(xdev, id);
> +	if (err) {
> +		xsc_core_err(xdev, "xsc_pci_init failed %d\n", err);
> +		goto err_pci_init;
> +	}
> +
> +	err = xsc_core_dev_init(xdev);
> +	if (err) {
> +		xsc_core_err(xdev, "xsc_core_dev_init failed %d\n", err);
> +		goto err_dev_init;
> +	}
> +
> +	return 0;
> +err_dev_init:
> +	xsc_pci_fini(xdev);
> +err_pci_init:
> +	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 err_register;
> +	}
> +
> +	return 0;
> +
> +err_register:
> +	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");
> +
Jeff Johnson Dec. 10, 2024, 12:11 a.m. UTC | #2
On 12/8/24 23:10, Tian Xin wrote:
...

> 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..1d26ffa8d
> --- /dev/null
> +++ b/drivers/net/ethernet/yunsilicon/xsc/pci/main.c
> @@ -0,0 +1,278 @@
...
> +module_init(xsc_init);
> +module_exit(xsc_fini);
> +
> +MODULE_LICENSE("GPL");
> +

Since commit 1fffe7a34c89 ("script: modpost: emit a warning when the
description is missing"), a module without a MODULE_DESCRIPTION() will
result in a warning with make W=1. Please add a MODULE_DESCRIPTION()
to avoid this warning.

/jeff
diff mbox series

Patch

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..a387a8dde
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/Kconfig
@@ -0,0 +1,26 @@ 
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021 - 2023, Shanghai Yunsilicon Technology Co., Ltd.
+# All rights reserved.
+# Yunsilicon driver configuration
+#
+
+config NET_VENDOR_YUNSILICON
+	bool "Yunsilicon devices"
+	default y
+	depends on PCI || NET
+	depends on ARM64 || X86_64
+	help
+	  If you have a network (Ethernet or RDMA) 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 devices. 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..950fd2663
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/Makefile
@@ -0,0 +1,8 @@ 
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021 - 2023, 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..6049c2c65
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h
@@ -0,0 +1,134 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021 - 2023, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#ifndef XSC_CORE_H
+#define XSC_CORE_H
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+extern unsigned int xsc_log_level;
+
+#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
+
+enum {
+	XSC_LOG_LEVEL_DBG	= 0,
+	XSC_LOG_LEVEL_INFO	= 1,
+	XSC_LOG_LEVEL_WARN	= 2,
+	XSC_LOG_LEVEL_ERR	= 3,
+};
+
+#define xsc_dev_log(condition, level, dev, fmt, ...)			\
+do {									\
+	if (condition)							\
+		dev_printk(level, dev, dev_fmt(fmt), ##__VA_ARGS__);	\
+} while (0)
+
+#define xsc_core_dbg(__dev, format, ...)				\
+	xsc_dev_log(xsc_log_level <= XSC_LOG_LEVEL_DBG, KERN_DEBUG,	\
+		&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,		\
+		__func__, __LINE__, current->pid, ##__VA_ARGS__)
+
+#define xsc_core_dbg_once(__dev, format, ...)				\
+	dev_dbg_once(&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,	\
+		     __func__, __LINE__, current->pid,			\
+		     ##__VA_ARGS__)
+
+#define xsc_core_dbg_mask(__dev, mask, format, ...)			\
+do {									\
+	if ((mask) & xsc_debug_mask)					\
+		xsc_core_dbg(__dev, format, ##__VA_ARGS__);		\
+} while (0)
+
+#define xsc_core_err(__dev, format, ...)				\
+	xsc_dev_log(xsc_log_level <= XSC_LOG_LEVEL_ERR, KERN_ERR,	\
+		&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,		\
+		__func__, __LINE__, current->pid, ##__VA_ARGS__)
+
+#define xsc_core_err_rl(__dev, format, ...)				\
+	dev_err_ratelimited(&(__dev)->pdev->dev,			\
+			   "%s:%d:(pid %d): " format,			\
+			   __func__, __LINE__, current->pid,		\
+			   ##__VA_ARGS__)
+
+#define xsc_core_warn(__dev, format, ...)				\
+	xsc_dev_log(xsc_log_level <= XSC_LOG_LEVEL_WARN, KERN_WARNING,	\
+		&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,		\
+		__func__, __LINE__, current->pid, ##__VA_ARGS__)
+
+#define xsc_core_info(__dev, format, ...)				\
+	xsc_dev_log(xsc_log_level <= XSC_LOG_LEVEL_INFO, KERN_INFO,	\
+		&(__dev)->pdev->dev, "%s:%d:(pid %d): " format,		\
+		__func__, __LINE__, current->pid, ##__VA_ARGS__)
+
+#define xsc_pr_debug(format, ...)					\
+do {									\
+	if (xsc_log_level <= XSC_LOG_LEVEL_DBG)				\
+		pr_debug(format, ##__VA_ARGS__);		\
+} while (0)
+
+#define assert(__dev, expr)						\
+do {									\
+	if (!(expr)) {							\
+		dev_err(&(__dev)->pdev->dev,				\
+		"Assertion failed! %s, %s, %s, line %d\n",		\
+		#expr, __FILE__, __func__, __LINE__);			\
+	}								\
+} while (0)
+
+enum {
+	XSC_MAX_NAME_LEN = 32,
+};
+
+struct xsc_dev_resource {
+	struct mutex alloc_mutex;	/* protect buffer alocation according to numa node */
+	int numa_node;
+};
+
+enum xsc_pci_status {
+	XSC_PCI_STATUS_DISABLED,
+	XSC_PCI_STATUS_ENABLED,
+};
+
+struct xsc_priv {
+	char			name[XSC_MAX_NAME_LEN];
+	struct list_head	dev_list;
+	struct list_head	ctx_list;
+	spinlock_t		ctx_lock;	/* protect ctx_list */
+	int			numa_node;
+};
+
+/* our core device */
+struct xsc_core_device {
+	struct pci_dev		*pdev;
+	struct device		*device;
+	struct xsc_priv		priv;
+	struct xsc_dev_resource	*dev_res;
+
+	void __iomem		*bar;
+	int			bar_num;
+
+	struct mutex		pci_status_mutex;	/* protect pci_status */
+	enum xsc_pci_status	pci_status;
+	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..30889caa9
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/net/Kconfig
@@ -0,0 +1,16 @@ 
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021 - 2023, 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
+	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..6ac74b27a
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/net/Makefile
@@ -0,0 +1,9 @@ 
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021 - 2023, 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..fafa69b8a
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Kconfig
@@ -0,0 +1,17 @@ 
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021 - 2023, Shanghai Yunsilicon Technology Co., Ltd.
+# All rights reserved.
+# Yunsilicon PCI configuration
+#
+
+config YUNSILICON_XSC_PCI
+	tristate "Yunsilicon XSC PCI driver"
+	default n
+	select NET_DEVLINK
+	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..b2ae73fb9
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Makefile
@@ -0,0 +1,9 @@ 
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2021 - 2023, 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..1d26ffa8d
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/main.c
@@ -0,0 +1,278 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2021 - 2023, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#include "common/xsc_core.h"
+
+unsigned int xsc_log_level = XSC_LOG_LEVEL_WARN;
+module_param_named(log_level, xsc_log_level, uint, 0644);
+MODULE_PARM_DESC(log_level,
+		 "lowest log level to print: 0=debug, 1=info, 2=warning, 3=error. Default=1");
+EXPORT_SYMBOL(xsc_log_level);
+
+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 = 0;
+
+	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, 2u * 1024 * 1024 * 1024);
+
+	return err;
+}
+
+static int xsc_pci_enable_device(struct xsc_core_device *dev)
+{
+	struct pci_dev *pdev = dev->pdev;
+	int err = 0;
+
+	mutex_lock(&dev->pci_status_mutex);
+	if (dev->pci_status == XSC_PCI_STATUS_DISABLED) {
+		err = pci_enable_device(pdev);
+		if (!err)
+			dev->pci_status = XSC_PCI_STATUS_ENABLED;
+	}
+	mutex_unlock(&dev->pci_status_mutex);
+
+	return err;
+}
+
+static void xsc_pci_disable_device(struct xsc_core_device *dev)
+{
+	struct pci_dev *pdev = dev->pdev;
+
+	mutex_lock(&dev->pci_status_mutex);
+	if (dev->pci_status == XSC_PCI_STATUS_ENABLED) {
+		pci_disable_device(pdev);
+		dev->pci_status = XSC_PCI_STATUS_DISABLED;
+	}
+	mutex_unlock(&dev->pci_status_mutex);
+}
+
+static int xsc_pci_init(struct xsc_core_device *dev, const struct pci_device_id *id)
+{
+	struct pci_dev *pdev = dev->pdev;
+	int err = 0;
+	int bar_num = 0;
+	void __iomem *bar_base = NULL;
+
+	mutex_init(&dev->pci_status_mutex);
+	dev->priv.numa_node = dev_to_node(&pdev->dev);
+	if (dev->priv.numa_node == -1)
+		dev->priv.numa_node = 0;
+
+	/* enable the device */
+	err = xsc_pci_enable_device(dev);
+	if (err) {
+		xsc_core_err(dev, "failed to enable PCI device: err=%d\n", err);
+		goto err_ret;
+	}
+
+	err = pci_request_region(pdev, bar_num, KBUILD_MODNAME);
+	if (err) {
+		xsc_core_err(dev, "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) {
+		xsc_core_err(dev, "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) {
+		xsc_core_err(dev, "failed to ioremap %s bar%d\n", KBUILD_MODNAME, bar_num);
+		goto err_clr_master;
+	}
+
+	err = pci_save_state(pdev);
+	if (err) {
+		xsc_core_err(dev, "pci_save_state failed: err=%d\n", err);
+		goto err_io_unmap;
+	}
+
+	dev->bar_num = bar_num;
+	dev->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(dev);
+err_ret:
+	return err;
+}
+
+static void xsc_pci_fini(struct xsc_core_device *dev)
+{
+	struct pci_dev *pdev = dev->pdev;
+
+	if (dev->bar)
+		pci_iounmap(pdev, dev->bar);
+	pci_clear_master(pdev);
+	pci_release_region(pdev, dev->bar_num);
+	xsc_pci_disable_device(dev);
+}
+
+static int xsc_priv_init(struct xsc_core_device *dev)
+{
+	struct xsc_priv *priv = &dev->priv;
+
+	strscpy(priv->name, dev_name(&dev->pdev->dev), XSC_MAX_NAME_LEN);
+	priv->name[XSC_MAX_NAME_LEN - 1] = 0;
+
+	INIT_LIST_HEAD(&priv->ctx_list);
+	spin_lock_init(&priv->ctx_lock);
+	mutex_init(&dev->intf_state_mutex);
+
+	return 0;
+}
+
+static int xsc_dev_res_init(struct xsc_core_device *dev)
+{
+	struct xsc_dev_resource *dev_res = NULL;
+
+	dev_res = kvzalloc(sizeof(*dev_res), GFP_KERNEL);
+	if (!dev_res)
+		return -ENOMEM;
+
+	dev->dev_res = dev_res;
+	mutex_init(&dev_res->alloc_mutex);
+
+	return 0;
+}
+
+static void xsc_dev_res_cleanup(struct xsc_core_device *dev)
+{
+	kfree(dev->dev_res);
+	dev->dev_res = NULL;
+}
+
+static int xsc_core_dev_init(struct xsc_core_device *dev)
+{
+	int err = 0;
+
+	xsc_priv_init(dev);
+
+	err = xsc_dev_res_init(dev);
+	if (err) {
+		xsc_core_err(dev, "xsc dev res init failed %d\n", err);
+		goto err_res_init;
+	}
+
+	return 0;
+err_res_init:
+	return err;
+}
+
+static void xsc_core_dev_cleanup(struct xsc_core_device *dev)
+{
+	xsc_dev_res_cleanup(dev);
+}
+
+static int xsc_pci_probe(struct pci_dev *pci_dev,
+			 const struct pci_device_id *id)
+{
+	struct xsc_core_device *xdev;
+	int err;
+
+	/* allocate core structure and fill it out */
+	xdev = kzalloc(sizeof(*xdev), GFP_KERNEL);
+	if (!xdev)
+		return -ENOMEM;
+
+	xdev->pdev = pci_dev;
+	xdev->device = &pci_dev->dev;
+
+	/* init pcie device */
+	pci_set_drvdata(pci_dev, xdev);
+	err = xsc_pci_init(xdev, id);
+	if (err) {
+		xsc_core_err(xdev, "xsc_pci_init failed %d\n", err);
+		goto err_pci_init;
+	}
+
+	err = xsc_core_dev_init(xdev);
+	if (err) {
+		xsc_core_err(xdev, "xsc_core_dev_init failed %d\n", err);
+		goto err_dev_init;
+	}
+
+	return 0;
+err_dev_init:
+	xsc_pci_fini(xdev);
+err_pci_init:
+	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 err_register;
+	}
+
+	return 0;
+
+err_register:
+	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");
+