diff mbox series

[net-next,v5,07/10] net: libwx: allocate devlink for devlink port

Message ID 5CCBD90FF2823C29+20240804124841.71177-8-mengyuanlou@net-swift.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series [net-next,v5,01/10] net: libwx: Add malibox api for wangxun pf drivers | expand

Checks

Context Check Description
netdev/series_format warning Series does not have a cover letter
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: 29 this patch: 29
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 4 maintainers not CCed: jiawenwu@trustnetic.com edumazet@google.com pabeni@redhat.com kuba@kernel.org
netdev/build_clang success Errors and warnings before: 30 this patch: 30
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: 35 this patch: 35
netdev/checkpatch warning WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
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 fail net-next-2024-08-04--21-00 (tests: 701)

Commit Message

Mengyuan Lou Aug. 4, 2024, 12:48 p.m. UTC
Make devlink allocation function generic to use it for PF and for VF.

Add function for PF/VF devlink port creation. It will be used in
wangxun NICs.

Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>
---
 drivers/net/ethernet/wangxun/libwx/Makefile   |   2 +-
 .../net/ethernet/wangxun/libwx/wx_devlink.c   | 208 ++++++++++++++++++
 .../net/ethernet/wangxun/libwx/wx_devlink.h   |  13 ++
 drivers/net/ethernet/wangxun/libwx/wx_sriov.c |  13 +-
 drivers/net/ethernet/wangxun/libwx/wx_sriov.h |   1 +
 drivers/net/ethernet/wangxun/libwx/wx_type.h  |  14 ++
 6 files changed, 249 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_devlink.c
 create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_devlink.h

Comments

kernel test robot Aug. 5, 2024, 6:40 a.m. UTC | #1
Hi Mengyuan,

kernel test robot noticed the following build errors:

[auto build test ERROR on net-next/main]

url:    https://github.com/intel-lab-lkp/linux/commits/Mengyuan-Lou/net-libwx-Add-sriov-api-for-wangxun-nics/20240804-214836
base:   net-next/main
patch link:    https://lore.kernel.org/r/5CCBD90FF2823C29%2B20240804124841.71177-8-mengyuanlou%40net-swift.com
patch subject: [PATCH net-next v5 07/10] net: libwx: allocate devlink for devlink port
config: loongarch-defconfig (https://download.01.org/0day-ci/archive/20240805/202408051455.A9boD1Oe-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 14.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240805/202408051455.A9boD1Oe-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202408051455.A9boD1Oe-lkp@intel.com/

All errors (new ones prefixed by >>):

   loongarch64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_devlink.o: in function `wx_devlink_free':
>> wx_devlink.c:(.text+0x58): undefined reference to `devlink_unregister'
>> loongarch64-linux-ld: wx_devlink.c:(.text+0x6c): undefined reference to `devlink_free'
   loongarch64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_devlink.o: in function `wx_devlink_create_pf_port':
>> wx_devlink.c:(.text+0xa0): undefined reference to `priv_to_devlink'
>> loongarch64-linux-ld: wx_devlink.c:(.text+0xfc): undefined reference to `devlink_port_attrs_set'
>> loongarch64-linux-ld: wx_devlink.c:(.text+0x110): undefined reference to `devlink_port_register_with_ops'
   loongarch64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_devlink.o: in function `wx_devlink_destroy_pf_port':
>> wx_devlink.c:(.text+0x174): undefined reference to `devl_port_unregister'
   loongarch64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_devlink.o: in function `wx_create_devlink':
>> wx_devlink.c:(.text+0x2a0): undefined reference to `devlink_alloc_ns'
>> loongarch64-linux-ld: wx_devlink.c:(.text+0x2d4): undefined reference to `devlink_unregister'
   loongarch64-linux-ld: wx_devlink.c:(.text+0x2dc): undefined reference to `devlink_free'
>> loongarch64-linux-ld: wx_devlink.c:(.text+0x304): undefined reference to `devlink_register'
>> loongarch64-linux-ld: wx_devlink.c:(.text+0x31c): undefined reference to `devlink_priv'
   loongarch64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_devlink.o: in function `wx_devlink_create_vf_port':
   wx_devlink.c:(.text+0x354): undefined reference to `priv_to_devlink'
   loongarch64-linux-ld: wx_devlink.c:(.text+0x3d0): undefined reference to `devlink_port_attrs_set'
>> loongarch64-linux-ld: wx_devlink.c:(.text+0x3e8): undefined reference to `devl_port_register_with_ops'
   loongarch64-linux-ld: drivers/net/ethernet/wangxun/libwx/wx_devlink.o: in function `wx_devlink_destroy_vf_port':
   wx_devlink.c:(.text+0x47c): undefined reference to `devl_port_unregister'
Simon Horman Aug. 5, 2024, 4:41 p.m. UTC | #2
On Sun, Aug 04, 2024 at 08:48:38PM +0800, Mengyuan Lou wrote:
> Make devlink allocation function generic to use it for PF and for VF.
> 
> Add function for PF/VF devlink port creation. It will be used in
> wangxun NICs.
> 
> Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>

...

> diff --git a/drivers/net/ethernet/wangxun/libwx/wx_devlink.c b/drivers/net/ethernet/wangxun/libwx/wx_devlink.c
> new file mode 100644
> index 000000000000..b39da37c0842
> --- /dev/null
> +++ b/drivers/net/ethernet/wangxun/libwx/wx_devlink.c
> @@ -0,0 +1,208 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */
> +
> +#include <linux/vmalloc.h>
> +#include <linux/pci.h>
> +
> +#include "wx_type.h"
> +#include "wx_sriov.h"
> +#include "wx_devlink.h"
> +
> +static const struct devlink_ops wx_pf_devlink_ops = {
> +};
> +
> +static void wx_devlink_free(void *devlink_ptr)
> +{
> +	devlink_unregister((struct devlink *)devlink_ptr);
> +	devlink_free((struct devlink *)devlink_ptr);
> +}
> +
> +struct wx_dl_priv *wx_create_devlink(struct device *dev)
> +{
> +	struct devlink *devlink;
> +
> +	devlink = devlink_alloc(&wx_pf_devlink_ops, sizeof(devlink), dev);

Perhaps this should be sizeof(wx_dl_priv *) ?

Flagged by Coccinelle.

> +	if (!devlink)
> +		return NULL;
> +
> +	/* Add an action to teardown the devlink when unwinding the driver */
> +	if (devm_add_action_or_reset(dev, wx_devlink_free, devlink))
> +		return NULL;
> +
> +	devlink_register(devlink);
> +
> +	return devlink_priv(devlink);
> +}
> +EXPORT_SYMBOL(wx_create_devlink);

...
Jiri Pirko Aug. 6, 2024, 11:37 a.m. UTC | #3
Sun, Aug 04, 2024 at 02:48:38PM CEST, mengyuanlou@net-swift.com wrote:
>Make devlink allocation function generic to use it for PF and for VF.
>
>Add function for PF/VF devlink port creation. It will be used in
>wangxun NICs.
>
>Signed-off-by: Mengyuan Lou <mengyuanlou@net-swift.com>

Interesting how you decide to split the patches. Seems a bit odd to me
to have all you have here in one patch and for example eswitch mode set
in a separate patch. Anyway...

>---
> drivers/net/ethernet/wangxun/libwx/Makefile   |   2 +-
> .../net/ethernet/wangxun/libwx/wx_devlink.c   | 208 ++++++++++++++++++
> .../net/ethernet/wangxun/libwx/wx_devlink.h   |  13 ++
> drivers/net/ethernet/wangxun/libwx/wx_sriov.c |  13 +-
> drivers/net/ethernet/wangxun/libwx/wx_sriov.h |   1 +
> drivers/net/ethernet/wangxun/libwx/wx_type.h  |  14 ++
> 6 files changed, 249 insertions(+), 2 deletions(-)
> create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_devlink.c
> create mode 100644 drivers/net/ethernet/wangxun/libwx/wx_devlink.h
>
>diff --git a/drivers/net/ethernet/wangxun/libwx/Makefile b/drivers/net/ethernet/wangxun/libwx/Makefile
>index 5b996d973d29..643a5e947ba9 100644
>--- a/drivers/net/ethernet/wangxun/libwx/Makefile
>+++ b/drivers/net/ethernet/wangxun/libwx/Makefile
>@@ -4,4 +4,4 @@
> 
> obj-$(CONFIG_LIBWX) += libwx.o
> 
>-libwx-objs := wx_hw.o wx_lib.o wx_ethtool.o wx_mbx.o wx_sriov.o
>+libwx-objs := wx_hw.o wx_lib.o wx_ethtool.o wx_mbx.o wx_sriov.o wx_devlink.o
>diff --git a/drivers/net/ethernet/wangxun/libwx/wx_devlink.c b/drivers/net/ethernet/wangxun/libwx/wx_devlink.c
>new file mode 100644
>index 000000000000..b39da37c0842
>--- /dev/null
>+++ b/drivers/net/ethernet/wangxun/libwx/wx_devlink.c
>@@ -0,0 +1,208 @@
>+// SPDX-License-Identifier: GPL-2.0
>+/* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */
>+
>+#include <linux/vmalloc.h>
>+#include <linux/pci.h>
>+
>+#include "wx_type.h"
>+#include "wx_sriov.h"
>+#include "wx_devlink.h"
>+
>+static const struct devlink_ops wx_pf_devlink_ops = {
>+};
>+
>+static void wx_devlink_free(void *devlink_ptr)

"void *data" perhaps to follow the naming this usually has?

        struct devlink *devlink = data;

	devlink_unregister(devlink_ptr);
	devlink_free(devlink);

?

Certainly, you don't need to cast from (void*).


>+{
>+	devlink_unregister((struct devlink *)devlink_ptr);
>+	devlink_free((struct devlink *)devlink_ptr);
>+}
>+
>+struct wx_dl_priv *wx_create_devlink(struct device *dev)
>+{
>+	struct devlink *devlink;
>+
>+	devlink = devlink_alloc(&wx_pf_devlink_ops, sizeof(devlink), dev);

sizeof(struct wx) perhaps? Sizeof(devlink) is certainly wrong.

>+	if (!devlink)
>+		return NULL;
>+
>+	/* Add an action to teardown the devlink when unwinding the driver */
>+	if (devm_add_action_or_reset(dev, wx_devlink_free, devlink))
>+		return NULL;
>+
>+	devlink_register(devlink);
>+
>+	return devlink_priv(devlink);
>+}
>+EXPORT_SYMBOL(wx_create_devlink);
>+
>+/**
>+ * wx_devlink_set_switch_id - Set unique switch id based on pci dsn
>+ * @wx: the PF to create a devlink port for
>+ * @ppid: struct with switch id information
>+ */
>+static void wx_devlink_set_switch_id(struct wx *wx,
>+				     struct netdev_phys_item_id *ppid)
>+{
>+	struct pci_dev *pdev = wx->pdev;
>+	u64 id;
>+
>+	id = pci_get_dsn(pdev);
>+
>+	ppid->id_len = sizeof(id);
>+	put_unaligned_be64(id, &ppid->id);
>+}
>+
>+/**
>+ * wx_devlink_create_pf_port - Create a devlink port for this PF
>+ * @wx: the PF to create a devlink port for
>+ *
>+ * Create and register a devlink_port for this PF.
>+ * This function has to be called under devl_lock.
>+ *
>+ * Return: zero on success or an error code on failure.
>+ */
>+int wx_devlink_create_pf_port(struct wx *wx)
>+{
>+	struct devlink *devlink = priv_to_devlink(wx->dl_priv);
>+	struct devlink_port_attrs attrs = {};
>+	int err;
>+
>+	attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
>+	attrs.phys.port_number = wx->bus.func;

Interesting. bus.func is 0, 1? You have a port label "0" on you nic.
Quite odd.

Also, if you pass this through to VM, func can be anything, can't it?
You have to get port_number some place else. Perhaps your FW can tell
you?


>+	wx_devlink_set_switch_id(wx, &attrs.switch_id);
>+	devlink_port_attrs_set(&wx->devlink_port, &attrs);
>+	err = devlink_port_register(devlink, &wx->devlink_port, 0);
>+	if (err) {
>+		wx_err(wx, "Failed to create devlink port for PF%d, error %d\n",
>+		       wx->bus.func, err);
>+		return err;
>+	}
>+
>+	return 0;
>+}
>+EXPORT_SYMBOL(wx_devlink_create_pf_port);
>+
>+/**
>+ * wx_devlink_destroy_pf_port - Destroy the devlink_port for this PF
>+ * @wx: the PF to cleanup
>+ *
>+ * Unregisters the devlink_port structure associated with this PF.
>+ * This function has to be called under devl_lock.
>+ */
>+void wx_devlink_destroy_pf_port(struct wx *wx)
>+{
>+	devl_port_unregister(&wx->devlink_port);
>+}
>+EXPORT_SYMBOL(wx_devlink_destroy_pf_port);
>+
>+/**
>+ * wx_devlink_port_get_vf_fn_mac - .port_fn_hw_addr_get devlink handler
>+ * @port: devlink port structure
>+ * @hw_addr: MAC address of the port
>+ * @hw_addr_len: length of MAC address
>+ * @extack: extended netdev ack structure
>+ *
>+ * Callback for the devlink .port_fn_hw_addr_get operation
>+ * Return: zero on success or an error code on failure.
>+ */
>+static int wx_devlink_port_get_vf_fn_mac(struct devlink_port *port,
>+					 u8 *hw_addr, int *hw_addr_len,
>+					 struct netlink_ext_ack *extack)
>+{
>+	struct vf_data_storage *vfinfo = container_of(port,
>+						      struct vf_data_storage,
>+						      devlink_port);
>+	struct devlink_port_attrs *attrs = &port->attrs;
>+	struct devlink_port_pci_vf_attrs *pci_vf;
>+	struct wx *wx = vfinfo->vf_priv_wx;
>+	u16 vf_id;
>+
>+	pci_vf = &attrs->pci_vf;
>+	vf_id = pci_vf->vf;
>+
>+	ether_addr_copy(hw_addr, wx->vfinfo[vf_id].vf_mac_addr);
>+	*hw_addr_len = ETH_ALEN;
>+
>+	return 0;
>+}
>+
>+/**
>+ * wx_devlink_port_set_vf_fn_mac - .port_fn_hw_addr_set devlink handler
>+ * @port: devlink port structure
>+ * @hw_addr: MAC address of the port
>+ * @hw_addr_len: length of MAC address
>+ * @extack: extended netdev ack structure
>+ *
>+ * Callback for the devlink .port_fn_hw_addr_set operation
>+ * Return: zero on success or an error code on failure.
>+ */
>+static int wx_devlink_port_set_vf_fn_mac(struct devlink_port *port,
>+					 const u8 *hw_addr,
>+					 int hw_addr_len,
>+					 struct netlink_ext_ack *extack)
>+
>+{
>+	struct vf_data_storage *vfinfo = container_of(port,

You name the structure vf_data_storage yet you name the variable with
"info". Why not to somehow keep this consistent?


>+						      struct vf_data_storage,
>+						      devlink_port);
>+	struct devlink_port_attrs *attrs = &port->attrs;
>+	struct devlink_port_pci_vf_attrs *pci_vf;
>+	struct wx *wx = vfinfo->vf_priv_wx;
>+	int ret = 0;

Pointless init.


>+	u16 vf_id;
>+
>+	pci_vf = &attrs->pci_vf;
>+	vf_id = pci_vf->vf;
>+
>+	if (!is_valid_ether_addr(hw_addr) || vf_id >= wx->num_vfs)

Fillup extack message with appropriate error.

How exacly (vf_id >= wx->num_vfs) could ever evaluate to "true"?


>+		return -EINVAL;
>+
>+	ret = wx_set_vf_mac(wx, vf_id, hw_addr);
>+	if (ret >= 0) {
>+		wx->vfinfo[vf_id].pf_set_mac = true;
>+		if (!netif_running(wx->netdev))
>+			wx_err(wx, "Bring the PF device up before use vfs\n");
>+	} else {
>+		wx_err(wx, "The VF MAC address was NOT set due to invalid\n");

Invalid what? Finish the sentence.


Instead of this, use extack message.



>+	}
>+
>+	return 0;


return ret;


>+}
>+
>+static const struct devlink_port_ops wx_devlink_vf_port_ops = {
>+	.port_fn_hw_addr_get = wx_devlink_port_get_vf_fn_mac,
>+	.port_fn_hw_addr_set = wx_devlink_port_set_vf_fn_mac,
>+};
>+
>+int wx_devlink_create_vf_port(struct wx *wx, int vf_id)
>+{
>+	struct devlink *devlink = priv_to_devlink(wx->dl_priv);
>+	struct devlink_port_attrs attrs = {};
>+	struct devlink_port *devlink_port;
>+	int err;
>+
>+	devlink_port = &wx->vfinfo[vf_id].devlink_port;
>+	attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF;
>+	attrs.pci_vf.pf = wx->bus.func;

Again, this looks wrong. You have to get the pf index (0, 1, ...) from
some place else.


>+	attrs.pci_vf.vf = vf_id;
>+
>+	wx_devlink_set_switch_id(wx, &attrs.switch_id);
>+	devlink_port_attrs_set(devlink_port, &attrs);
>+	err = devl_port_register_with_ops(devlink, devlink_port, vf_id + 1,

This +1 may be a bit confusing for user to see VF0 with index 1. Perhaps
start at some base offset instead?


>+					  &wx_devlink_vf_port_ops);
>+	if (err) {
>+		wx_err(wx, "Failed to create devlink port for VF %d, error %d\n",
>+		       vf_id, err);
>+		return err;
>+	}
>+
>+	return 0;
>+}
>+
>+void wx_devlink_destroy_vf_port(struct wx *wx)
>+{
>+	int i;
>+
>+	for (i = 0; i < wx->num_vfs; i++)
>+		devl_port_unregister(&wx->vfinfo[i].devlink_port);
>+}
>diff --git a/drivers/net/ethernet/wangxun/libwx/wx_devlink.h b/drivers/net/ethernet/wangxun/libwx/wx_devlink.h
>new file mode 100644
>index 000000000000..0754579ed304
>--- /dev/null
>+++ b/drivers/net/ethernet/wangxun/libwx/wx_devlink.h
>@@ -0,0 +1,13 @@
>+/* SPDX-License-Identifier: GPL-2.0 */
>+/* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */
>+
>+#ifndef _WX_DEVLINK_H_
>+#define _WX_DEVLINK_H_
>+
>+struct wx_dl_priv *wx_create_devlink(struct device *dev);
>+int wx_devlink_create_pf_port(struct wx *wx);
>+void wx_devlink_destroy_pf_port(struct wx *wx);
>+int wx_devlink_create_vf_port(struct wx *wx, int vf_id);
>+void wx_devlink_destroy_vf_port(struct wx *wx);
>+
>+#endif /* _WX_DEVLINK_H_ */
>diff --git a/drivers/net/ethernet/wangxun/libwx/wx_sriov.c b/drivers/net/ethernet/wangxun/libwx/wx_sriov.c
>index 08738738d02e..88ef82f1a1a3 100644
>--- a/drivers/net/ethernet/wangxun/libwx/wx_sriov.c
>+++ b/drivers/net/ethernet/wangxun/libwx/wx_sriov.c
>@@ -7,6 +7,7 @@
> #include "wx_type.h"
> #include "wx_hw.h"
> #include "wx_mbx.h"
>+#include "wx_devlink.h"
> #include "wx_sriov.h"
> 
> static void wx_vf_configuration(struct pci_dev *pdev, int event_mask)
>@@ -92,6 +93,7 @@ static int __wx_enable_sriov(struct wx *wx, u8 num_vfs)
> 	wr32m(wx, WX_PSR_CTL, WX_PSR_CTL_SW_EN, WX_PSR_CTL_SW_EN);
> 
> 	for (i = 0; i < num_vfs; i++) {
>+		wx->vfinfo[i].vf_priv_wx = wx;
> 		/* enable spoof checking for all VFs */
> 		wx->vfinfo[i].spoofchk_enabled = true;
> 		wx->vfinfo[i].link_enable = true;
>@@ -130,6 +132,7 @@ void wx_disable_sriov(struct wx *wx)
> 	else
> 		wx_err(wx, "Unloading driver while VFs are assigned.\n");
> 
>+	wx_devlink_destroy_vf_port(wx);
> 	/* clear flags and free allloced data */
> 	wx_sriov_clear_data(wx);
> }
>@@ -158,7 +161,15 @@ static int wx_pci_sriov_enable(struct pci_dev *dev,
> 		goto err_out;
> 	}
> 
>+	for (i = 0; i < wx->num_vfs; i++) {
>+		err = wx_devlink_create_vf_port(wx, i);
>+		if (err)
>+			goto err_dis_sriov;
>+	}
>+
> 	return num_vfs;
>+err_dis_sriov:
>+	pci_disable_sriov(dev);
> err_out:
> 	wx_sriov_clear_data(wx);
> 	return err;
>@@ -210,7 +221,7 @@ int wx_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
> }
> EXPORT_SYMBOL(wx_pci_sriov_configure);
> 
>-static int wx_set_vf_mac(struct wx *wx, u16 vf, const u8 *mac_addr)
>+int wx_set_vf_mac(struct wx *wx, u16 vf, const u8 *mac_addr)
> {
> 	u8 hw_addr[ETH_ALEN];
> 	int ret = 0;
>diff --git a/drivers/net/ethernet/wangxun/libwx/wx_sriov.h b/drivers/net/ethernet/wangxun/libwx/wx_sriov.h
>index 2aa68947c0d3..e876cb03c2c9 100644
>--- a/drivers/net/ethernet/wangxun/libwx/wx_sriov.h
>+++ b/drivers/net/ethernet/wangxun/libwx/wx_sriov.h
>@@ -6,6 +6,7 @@
> 
> void wx_disable_sriov(struct wx *wx);
> int wx_pci_sriov_configure(struct pci_dev *pdev, int num_vfs);
>+int wx_set_vf_mac(struct wx *wx, u16 vf, const u8 *mac_addr);
> void wx_msg_task(struct wx *wx);
> void wx_disable_vf_rx_tx(struct wx *wx);
> void wx_ping_all_vfs_with_link_status(struct wx *wx, bool link_up);
>diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
>index e50a75e7c58b..a8722f69cebb 100644
>--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
>+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
>@@ -8,6 +8,7 @@
> #include <linux/netdevice.h>
> #include <linux/if_vlan.h>
> #include <linux/phylink.h>
>+#include <net/devlink.h>
> #include <net/ip.h>
> 
> #define WX_NCSI_SUP                             0x8000
>@@ -1084,6 +1085,10 @@ enum wx_state {
> 
> struct vf_data_storage {
> 	struct pci_dev *vfdev;
>+	struct wx *vf_priv_wx;
>+	/* vf devlink port data */
>+	struct devlink_port devlink_port;
>+
> 	unsigned char vf_mac_addr[ETH_ALEN];
> 	bool spoofchk_enabled;
> 	bool link_enable;
>@@ -1119,6 +1124,10 @@ enum wx_pf_flags {
> 	WX_PF_FLAGS_NBITS               /* must be last */
> };
> 
>+struct wx_dl_priv {
>+	struct wx *priv_wx;
>+};

This is nonsence structure. Just let devlink_alloc() to allocate struct
wx or you.


> struct wx {
> 	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
> 	DECLARE_BITMAP(state, WX_STATE_NBITS);
>@@ -1128,6 +1137,11 @@ struct wx {
> 	u8 __iomem *hw_addr;
> 	struct pci_dev *pdev;
> 	struct net_device *netdev;
>+
>+	/* devlink port data */
>+	struct devlink_port devlink_port;
>+	struct wx_dl_priv *dl_priv;
>+
> 	struct wx_bus_info bus;
> 	struct wx_mbx_info mbx;
> 	struct wx_mac_info mac;
>-- 
>2.45.2
>
>
diff mbox series

Patch

diff --git a/drivers/net/ethernet/wangxun/libwx/Makefile b/drivers/net/ethernet/wangxun/libwx/Makefile
index 5b996d973d29..643a5e947ba9 100644
--- a/drivers/net/ethernet/wangxun/libwx/Makefile
+++ b/drivers/net/ethernet/wangxun/libwx/Makefile
@@ -4,4 +4,4 @@ 
 
 obj-$(CONFIG_LIBWX) += libwx.o
 
-libwx-objs := wx_hw.o wx_lib.o wx_ethtool.o wx_mbx.o wx_sriov.o
+libwx-objs := wx_hw.o wx_lib.o wx_ethtool.o wx_mbx.o wx_sriov.o wx_devlink.o
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_devlink.c b/drivers/net/ethernet/wangxun/libwx/wx_devlink.c
new file mode 100644
index 000000000000..b39da37c0842
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_devlink.c
@@ -0,0 +1,208 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */
+
+#include <linux/vmalloc.h>
+#include <linux/pci.h>
+
+#include "wx_type.h"
+#include "wx_sriov.h"
+#include "wx_devlink.h"
+
+static const struct devlink_ops wx_pf_devlink_ops = {
+};
+
+static void wx_devlink_free(void *devlink_ptr)
+{
+	devlink_unregister((struct devlink *)devlink_ptr);
+	devlink_free((struct devlink *)devlink_ptr);
+}
+
+struct wx_dl_priv *wx_create_devlink(struct device *dev)
+{
+	struct devlink *devlink;
+
+	devlink = devlink_alloc(&wx_pf_devlink_ops, sizeof(devlink), dev);
+	if (!devlink)
+		return NULL;
+
+	/* Add an action to teardown the devlink when unwinding the driver */
+	if (devm_add_action_or_reset(dev, wx_devlink_free, devlink))
+		return NULL;
+
+	devlink_register(devlink);
+
+	return devlink_priv(devlink);
+}
+EXPORT_SYMBOL(wx_create_devlink);
+
+/**
+ * wx_devlink_set_switch_id - Set unique switch id based on pci dsn
+ * @wx: the PF to create a devlink port for
+ * @ppid: struct with switch id information
+ */
+static void wx_devlink_set_switch_id(struct wx *wx,
+				     struct netdev_phys_item_id *ppid)
+{
+	struct pci_dev *pdev = wx->pdev;
+	u64 id;
+
+	id = pci_get_dsn(pdev);
+
+	ppid->id_len = sizeof(id);
+	put_unaligned_be64(id, &ppid->id);
+}
+
+/**
+ * wx_devlink_create_pf_port - Create a devlink port for this PF
+ * @wx: the PF to create a devlink port for
+ *
+ * Create and register a devlink_port for this PF.
+ * This function has to be called under devl_lock.
+ *
+ * Return: zero on success or an error code on failure.
+ */
+int wx_devlink_create_pf_port(struct wx *wx)
+{
+	struct devlink *devlink = priv_to_devlink(wx->dl_priv);
+	struct devlink_port_attrs attrs = {};
+	int err;
+
+	attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
+	attrs.phys.port_number = wx->bus.func;
+	wx_devlink_set_switch_id(wx, &attrs.switch_id);
+	devlink_port_attrs_set(&wx->devlink_port, &attrs);
+	err = devlink_port_register(devlink, &wx->devlink_port, 0);
+	if (err) {
+		wx_err(wx, "Failed to create devlink port for PF%d, error %d\n",
+		       wx->bus.func, err);
+		return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(wx_devlink_create_pf_port);
+
+/**
+ * wx_devlink_destroy_pf_port - Destroy the devlink_port for this PF
+ * @wx: the PF to cleanup
+ *
+ * Unregisters the devlink_port structure associated with this PF.
+ * This function has to be called under devl_lock.
+ */
+void wx_devlink_destroy_pf_port(struct wx *wx)
+{
+	devl_port_unregister(&wx->devlink_port);
+}
+EXPORT_SYMBOL(wx_devlink_destroy_pf_port);
+
+/**
+ * wx_devlink_port_get_vf_fn_mac - .port_fn_hw_addr_get devlink handler
+ * @port: devlink port structure
+ * @hw_addr: MAC address of the port
+ * @hw_addr_len: length of MAC address
+ * @extack: extended netdev ack structure
+ *
+ * Callback for the devlink .port_fn_hw_addr_get operation
+ * Return: zero on success or an error code on failure.
+ */
+static int wx_devlink_port_get_vf_fn_mac(struct devlink_port *port,
+					 u8 *hw_addr, int *hw_addr_len,
+					 struct netlink_ext_ack *extack)
+{
+	struct vf_data_storage *vfinfo = container_of(port,
+						      struct vf_data_storage,
+						      devlink_port);
+	struct devlink_port_attrs *attrs = &port->attrs;
+	struct devlink_port_pci_vf_attrs *pci_vf;
+	struct wx *wx = vfinfo->vf_priv_wx;
+	u16 vf_id;
+
+	pci_vf = &attrs->pci_vf;
+	vf_id = pci_vf->vf;
+
+	ether_addr_copy(hw_addr, wx->vfinfo[vf_id].vf_mac_addr);
+	*hw_addr_len = ETH_ALEN;
+
+	return 0;
+}
+
+/**
+ * wx_devlink_port_set_vf_fn_mac - .port_fn_hw_addr_set devlink handler
+ * @port: devlink port structure
+ * @hw_addr: MAC address of the port
+ * @hw_addr_len: length of MAC address
+ * @extack: extended netdev ack structure
+ *
+ * Callback for the devlink .port_fn_hw_addr_set operation
+ * Return: zero on success or an error code on failure.
+ */
+static int wx_devlink_port_set_vf_fn_mac(struct devlink_port *port,
+					 const u8 *hw_addr,
+					 int hw_addr_len,
+					 struct netlink_ext_ack *extack)
+
+{
+	struct vf_data_storage *vfinfo = container_of(port,
+						      struct vf_data_storage,
+						      devlink_port);
+	struct devlink_port_attrs *attrs = &port->attrs;
+	struct devlink_port_pci_vf_attrs *pci_vf;
+	struct wx *wx = vfinfo->vf_priv_wx;
+	int ret = 0;
+	u16 vf_id;
+
+	pci_vf = &attrs->pci_vf;
+	vf_id = pci_vf->vf;
+
+	if (!is_valid_ether_addr(hw_addr) || vf_id >= wx->num_vfs)
+		return -EINVAL;
+
+	ret = wx_set_vf_mac(wx, vf_id, hw_addr);
+	if (ret >= 0) {
+		wx->vfinfo[vf_id].pf_set_mac = true;
+		if (!netif_running(wx->netdev))
+			wx_err(wx, "Bring the PF device up before use vfs\n");
+	} else {
+		wx_err(wx, "The VF MAC address was NOT set due to invalid\n");
+	}
+
+	return 0;
+}
+
+static const struct devlink_port_ops wx_devlink_vf_port_ops = {
+	.port_fn_hw_addr_get = wx_devlink_port_get_vf_fn_mac,
+	.port_fn_hw_addr_set = wx_devlink_port_set_vf_fn_mac,
+};
+
+int wx_devlink_create_vf_port(struct wx *wx, int vf_id)
+{
+	struct devlink *devlink = priv_to_devlink(wx->dl_priv);
+	struct devlink_port_attrs attrs = {};
+	struct devlink_port *devlink_port;
+	int err;
+
+	devlink_port = &wx->vfinfo[vf_id].devlink_port;
+	attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF;
+	attrs.pci_vf.pf = wx->bus.func;
+	attrs.pci_vf.vf = vf_id;
+
+	wx_devlink_set_switch_id(wx, &attrs.switch_id);
+	devlink_port_attrs_set(devlink_port, &attrs);
+	err = devl_port_register_with_ops(devlink, devlink_port, vf_id + 1,
+					  &wx_devlink_vf_port_ops);
+	if (err) {
+		wx_err(wx, "Failed to create devlink port for VF %d, error %d\n",
+		       vf_id, err);
+		return err;
+	}
+
+	return 0;
+}
+
+void wx_devlink_destroy_vf_port(struct wx *wx)
+{
+	int i;
+
+	for (i = 0; i < wx->num_vfs; i++)
+		devl_port_unregister(&wx->vfinfo[i].devlink_port);
+}
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_devlink.h b/drivers/net/ethernet/wangxun/libwx/wx_devlink.h
new file mode 100644
index 000000000000..0754579ed304
--- /dev/null
+++ b/drivers/net/ethernet/wangxun/libwx/wx_devlink.h
@@ -0,0 +1,13 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */
+
+#ifndef _WX_DEVLINK_H_
+#define _WX_DEVLINK_H_
+
+struct wx_dl_priv *wx_create_devlink(struct device *dev);
+int wx_devlink_create_pf_port(struct wx *wx);
+void wx_devlink_destroy_pf_port(struct wx *wx);
+int wx_devlink_create_vf_port(struct wx *wx, int vf_id);
+void wx_devlink_destroy_vf_port(struct wx *wx);
+
+#endif /* _WX_DEVLINK_H_ */
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_sriov.c b/drivers/net/ethernet/wangxun/libwx/wx_sriov.c
index 08738738d02e..88ef82f1a1a3 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_sriov.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_sriov.c
@@ -7,6 +7,7 @@ 
 #include "wx_type.h"
 #include "wx_hw.h"
 #include "wx_mbx.h"
+#include "wx_devlink.h"
 #include "wx_sriov.h"
 
 static void wx_vf_configuration(struct pci_dev *pdev, int event_mask)
@@ -92,6 +93,7 @@  static int __wx_enable_sriov(struct wx *wx, u8 num_vfs)
 	wr32m(wx, WX_PSR_CTL, WX_PSR_CTL_SW_EN, WX_PSR_CTL_SW_EN);
 
 	for (i = 0; i < num_vfs; i++) {
+		wx->vfinfo[i].vf_priv_wx = wx;
 		/* enable spoof checking for all VFs */
 		wx->vfinfo[i].spoofchk_enabled = true;
 		wx->vfinfo[i].link_enable = true;
@@ -130,6 +132,7 @@  void wx_disable_sriov(struct wx *wx)
 	else
 		wx_err(wx, "Unloading driver while VFs are assigned.\n");
 
+	wx_devlink_destroy_vf_port(wx);
 	/* clear flags and free allloced data */
 	wx_sriov_clear_data(wx);
 }
@@ -158,7 +161,15 @@  static int wx_pci_sriov_enable(struct pci_dev *dev,
 		goto err_out;
 	}
 
+	for (i = 0; i < wx->num_vfs; i++) {
+		err = wx_devlink_create_vf_port(wx, i);
+		if (err)
+			goto err_dis_sriov;
+	}
+
 	return num_vfs;
+err_dis_sriov:
+	pci_disable_sriov(dev);
 err_out:
 	wx_sriov_clear_data(wx);
 	return err;
@@ -210,7 +221,7 @@  int wx_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
 }
 EXPORT_SYMBOL(wx_pci_sriov_configure);
 
-static int wx_set_vf_mac(struct wx *wx, u16 vf, const u8 *mac_addr)
+int wx_set_vf_mac(struct wx *wx, u16 vf, const u8 *mac_addr)
 {
 	u8 hw_addr[ETH_ALEN];
 	int ret = 0;
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_sriov.h b/drivers/net/ethernet/wangxun/libwx/wx_sriov.h
index 2aa68947c0d3..e876cb03c2c9 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_sriov.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_sriov.h
@@ -6,6 +6,7 @@ 
 
 void wx_disable_sriov(struct wx *wx);
 int wx_pci_sriov_configure(struct pci_dev *pdev, int num_vfs);
+int wx_set_vf_mac(struct wx *wx, u16 vf, const u8 *mac_addr);
 void wx_msg_task(struct wx *wx);
 void wx_disable_vf_rx_tx(struct wx *wx);
 void wx_ping_all_vfs_with_link_status(struct wx *wx, bool link_up);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index e50a75e7c58b..a8722f69cebb 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -8,6 +8,7 @@ 
 #include <linux/netdevice.h>
 #include <linux/if_vlan.h>
 #include <linux/phylink.h>
+#include <net/devlink.h>
 #include <net/ip.h>
 
 #define WX_NCSI_SUP                             0x8000
@@ -1084,6 +1085,10 @@  enum wx_state {
 
 struct vf_data_storage {
 	struct pci_dev *vfdev;
+	struct wx *vf_priv_wx;
+	/* vf devlink port data */
+	struct devlink_port devlink_port;
+
 	unsigned char vf_mac_addr[ETH_ALEN];
 	bool spoofchk_enabled;
 	bool link_enable;
@@ -1119,6 +1124,10 @@  enum wx_pf_flags {
 	WX_PF_FLAGS_NBITS               /* must be last */
 };
 
+struct wx_dl_priv {
+	struct wx *priv_wx;
+};
+
 struct wx {
 	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
 	DECLARE_BITMAP(state, WX_STATE_NBITS);
@@ -1128,6 +1137,11 @@  struct wx {
 	u8 __iomem *hw_addr;
 	struct pci_dev *pdev;
 	struct net_device *netdev;
+
+	/* devlink port data */
+	struct devlink_port devlink_port;
+	struct wx_dl_priv *dl_priv;
+
 	struct wx_bus_info bus;
 	struct wx_mbx_info mbx;
 	struct wx_mac_info mac;