[RFC PATCH net-next v5 07/10] net: libwx: allocate devlink for devlink port
From: Mengyuan Lou <mengyuanlou@net-swift.com>
Date: 2024-07-26 10:03:40
Subsystem:
networking drivers, the rest, wangxun ethernet driver · Maintainers:
Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds, Jiawen Wu, Mengyuan Lou
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
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;
--
2.43.2