lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 27 Apr 2023 09:45:45 -0700
From:   Shannon Nelson <shannon.nelson@....com>
To:     <shannon.nelson@....com>, <brett.creeley@....com>,
        <netdev@...r.kernel.org>
CC:     <drivers@...sando.io>
Subject: [PATCH RFC net-next 1/2] pds_core: netdev representors for each VF

When using pds_core VFs, we want to do some amount of control
and configuration - specifically, we need the ability to
configure port vlans.  Here we add switchdev and create
representor netdevs for the VFs.

The pds_core switchdev can be enabled before or after the
VFs have been enabled.  This means that they can be brought
up specifically for configuring the VF vlan, then can be
immediately turned back off.  Disabling the switchdev will
not affect VF vlan configuration.

Due to the design of this particular device, there is no packet
switching to the PF: the only datapaths available are through
the VFs.  Therefore, neither the PF nor the VF representors
have packet processing queues.  For now, these representors
are just enough to send a few tc configuration commands to
the FW for setting port vlans on each VF.

Signed-off-by: Shannon Nelson <shannon.nelson@....com>
---
 drivers/net/ethernet/amd/pds_core/Makefile |   1 +
 drivers/net/ethernet/amd/pds_core/core.h   |  10 ++
 drivers/net/ethernet/amd/pds_core/main.c   |  28 ++++-
 drivers/net/ethernet/amd/pds_core/rep.c    | 140 +++++++++++++++++++++
 4 files changed, 177 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ethernet/amd/pds_core/rep.c

diff --git a/drivers/net/ethernet/amd/pds_core/Makefile b/drivers/net/ethernet/amd/pds_core/Makefile
index 0abc33ce826c..3bfcfa4eda42 100644
--- a/drivers/net/ethernet/amd/pds_core/Makefile
+++ b/drivers/net/ethernet/amd/pds_core/Makefile
@@ -9,6 +9,7 @@ pds_core-y := main.o \
 	      dev.o \
 	      adminq.o \
 	      core.o \
+	      rep.o \
 	      fw.o
 
 pds_core-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h
index e545fafc4819..2f38143dd5c2 100644
--- a/drivers/net/ethernet/amd/pds_core/core.h
+++ b/drivers/net/ethernet/amd/pds_core/core.h
@@ -171,6 +171,7 @@ struct pdsc {
 	unsigned int wdtimer_period;
 	struct work_struct health_work;
 	struct devlink_health_reporter *fw_reporter;
+	struct devlink_port dl_port;
 	u32 fw_recoveries;
 
 	struct pdsc_devinfo dev_info;
@@ -196,6 +197,9 @@ struct pdsc {
 	struct pdsc_qcq notifyqcq;
 	u64 last_eid;
 	struct pdsc_viftype *viftype_status;
+
+	struct net_device *netdev;
+	enum devlink_eswitch_mode eswitch_mode;
 };
 
 /** enum pds_core_dbell_bits - bitwise composition of dbell values.
@@ -309,4 +313,10 @@ irqreturn_t pdsc_adminq_isr(int irq, void *data);
 
 int pdsc_firmware_update(struct pdsc *pdsc, const struct firmware *fw,
 			 struct netlink_ext_ack *extack);
+
+int pdsc_add_rep(struct pdsc *vf, struct pdsc *pf);
+void pdsc_del_rep(struct pdsc *vf);
+int pdsc_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode);
+int pdsc_dl_eswitch_mode_set(struct devlink *devlink, u16 mode,
+			     struct netlink_ext_ack *extack);
 #endif /* _PDSC_H_ */
diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c
index e2d14b1ca471..272a8979e53d 100644
--- a/drivers/net/ethernet/amd/pds_core/main.c
+++ b/drivers/net/ethernet/amd/pds_core/main.c
@@ -185,12 +185,27 @@ static int pdsc_init_vf(struct pdsc *vf)
 
 	pf->vfs[vf->vf_id].vf = vf;
 	err = pdsc_auxbus_dev_add(vf, pf);
-	if (err) {
+	if (err)
+		goto err_dl_unreg;
+
+	if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
 		devl_lock(dl);
-		devl_unregister(dl);
+		err = pdsc_add_rep(vf, pf);
 		devl_unlock(dl);
+		if (err)
+			goto err_del_aux;
 	}
 
+	return 0;
+
+err_del_aux:
+	pdsc_auxbus_dev_del(vf, pf);
+	pf->vfs[vf->vf_id].vf = NULL;
+err_dl_unreg:
+	devl_lock(dl);
+	devl_unregister(dl);
+	devl_unlock(dl);
+
 	return err;
 }
 
@@ -262,6 +277,8 @@ static int pdsc_init_pf(struct pdsc *pdsc)
 		goto err_out_unlock_dl;
 	}
 
+	pdsc->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
+
 	hr = devl_health_reporter_create(dl, &pdsc_fw_reporter_ops, 0, pdsc);
 	if (IS_ERR(hr)) {
 		dev_warn(pdsc->dev, "Failed to create fw reporter: %pe\n", hr);
@@ -304,6 +321,8 @@ static int pdsc_init_pf(struct pdsc *pdsc)
 static const struct devlink_ops pdsc_dl_ops = {
 	.info_get	= pdsc_dl_info_get,
 	.flash_update	= pdsc_dl_flash_update,
+	.eswitch_mode_set = pdsc_dl_eswitch_mode_set,
+	.eswitch_mode_get = pdsc_dl_eswitch_mode_get,
 };
 
 static const struct devlink_ops pdsc_dl_vf_ops = {
@@ -406,6 +425,11 @@ static void pdsc_remove(struct pci_dev *pdev)
 
 		pf = pdsc_get_pf_struct(pdsc->pdev);
 		if (!IS_ERR(pf)) {
+			if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
+				devl_lock(dl);
+				pdsc_del_rep(pdsc);
+				devl_unlock(dl);
+			}
 			pdsc_auxbus_dev_del(pdsc, pf);
 			pf->vfs[pdsc->vf_id].vf = NULL;
 		}
diff --git a/drivers/net/ethernet/amd/pds_core/rep.c b/drivers/net/ethernet/amd/pds_core/rep.c
new file mode 100644
index 000000000000..297d9e2bac31
--- /dev/null
+++ b/drivers/net/ethernet/amd/pds_core/rep.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2023 Advanced Micro Devices, Inc */
+
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+
+#include "core.h"
+
+struct pds_rep {
+	struct pdsc *vf;
+	struct pdsc *pf;
+};
+
+static const struct net_device_ops pdsc_rep_netdev_ops = {
+};
+
+static void pdsc_get_rep_drvinfo(struct net_device *netdev,
+				 struct ethtool_drvinfo *drvinfo)
+{
+	struct pds_rep *rep = netdev_priv(netdev);
+
+	strscpy(drvinfo->driver, PDS_CORE_DRV_NAME,
+		sizeof(drvinfo->driver));
+	strscpy(drvinfo->bus_info, pci_name(rep->vf->pdev),
+		sizeof(drvinfo->bus_info));
+	strscpy(drvinfo->fw_version, rep->pf->dev_info.fw_version,
+		sizeof(drvinfo->fw_version));
+}
+
+static const struct ethtool_ops pdsc_rep_ethtool_ops = {
+	.get_drvinfo = pdsc_get_rep_drvinfo,
+};
+
+int pdsc_add_rep(struct pdsc *vf, struct pdsc *pf)
+{
+	struct pds_rep *rep;
+	int err = 0;
+
+	memset(&vf->dl_port, 0, sizeof(vf->dl_port));
+	devlink_port_attrs_pci_vf_set(&vf->dl_port, 0, PCI_FUNC(pf->pdev->devfn),
+				      vf->vf_id, false);
+	err = devl_port_register(priv_to_devlink(vf), &vf->dl_port, vf->vf_id);
+	if (err) {
+		dev_err(vf->dev, "devlink_port_register failed: %pe\n",
+			ERR_PTR(err));
+		return err;
+	}
+
+	vf->netdev = alloc_etherdev(sizeof(struct pds_rep));
+	if (!vf->netdev) {
+		err = -ENOMEM;
+		goto err_unreg_port;
+	}
+	SET_NETDEV_DEV(vf->netdev, vf->dev);
+
+	rep = netdev_priv(vf->netdev);
+	rep->pf = pf;
+	rep->vf = vf;
+
+	vf->netdev->netdev_ops = &pdsc_rep_netdev_ops;
+	vf->netdev->ethtool_ops = &pdsc_rep_ethtool_ops;
+	netif_carrier_off(vf->netdev);
+
+	SET_NETDEV_DEVLINK_PORT(vf->netdev,  &vf->dl_port);
+	err = register_netdev(vf->netdev);
+	if (err) {
+		dev_err(vf->dev, "register_netdev failed: %pe\n",
+			ERR_PTR(err));
+		goto err_free_netdev;
+	}
+
+	return 0;
+
+err_free_netdev:
+	free_netdev(vf->netdev);
+	vf->netdev = NULL;
+err_unreg_port:
+	devl_port_unregister(&vf->dl_port);
+	return err;
+}
+
+void pdsc_del_rep(struct pdsc *vf)
+{
+	unregister_netdev(vf->netdev);
+	free_netdev(vf->netdev);
+	vf->netdev = NULL;
+	devl_port_unregister(&vf->dl_port);
+}
+
+int pdsc_dl_eswitch_mode_get(struct devlink *dl, u16 *mode)
+{
+	struct pdsc *pf = devlink_priv(dl);
+
+	*mode = pf->eswitch_mode;
+	return 0;
+}
+
+int pdsc_dl_eswitch_mode_set(struct devlink *dl, u16 mode,
+			     struct netlink_ext_ack *extack)
+{
+	struct pdsc *pf = devlink_priv(dl);
+	char *msg;
+	int ret = 0;
+	int i;
+
+	if (pf->eswitch_mode == mode)
+		return 0;
+
+	switch (mode) {
+	case DEVLINK_ESWITCH_MODE_LEGACY:
+		for (i = pf->num_vfs - 1; i >= 0; i--)
+			pdsc_del_rep(pf->vfs[i].vf);
+		msg = "Changed eswitch mode to legacy";
+		dev_info(pf->dev, msg);
+		NL_SET_ERR_MSG_FMT_MOD(extack, "%s", msg);
+		break;
+
+	case DEVLINK_ESWITCH_MODE_SWITCHDEV:
+		for (i = 0; i < pf->num_vfs && !ret; i++)
+			ret = pdsc_add_rep(pf->vfs[i].vf, pf);
+		if (ret) {
+			for (i-- ; i >= 0; i--)
+				pdsc_del_rep(pf->vfs[i].vf);
+			return ret;
+		}
+
+		msg = "Changed eswitch mode to switchdev";
+		dev_info(pf->dev, msg);
+		NL_SET_ERR_MSG_FMT_MOD(extack, "%s", msg);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	pf->eswitch_mode = mode;
+
+	return 0;
+}
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ