All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 0/7] sfc: devlink support for ef100
@ 2023-01-19 11:31 alejandro.lucero-palau
  2023-01-19 11:31 ` [PATCH net-next 1/7] sfc: add " alejandro.lucero-palau
                   ` (7 more replies)
  0 siblings, 8 replies; 52+ messages in thread
From: alejandro.lucero-palau @ 2023-01-19 11:31 UTC (permalink / raw)
  To: netdev, linux-net-drivers
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx, Alejandro Lucero

From: Alejandro Lucero <alejandro.lucero-palau@amd.com>

This patchset adds devlink port support for ef100 allowing setting VFs
mac addresses through the VF representors netdevs.

Basic devlink support is first introduced for info command. Then changes
for enumerating MAE ports which will be used for devlik port creation
when netdevs are register.

Adding support for devlink port_function_hw_addr_get requires changes in
the ef100 driver for getting the mac address based on a client handle.
This allows to obtain VFs mac address during netdev initialization as
well what is included in patch 5.

Such client handle is used in patches 6 and 7 for getting and setting
devlink ports addresses.

Alejandro Lucero (7):
  sfc: add devlink support for ef100
  sfc: enumerate mports in ef100
  sfc: add mport lookup based on driver's mport data
  sfc: add devlink port support for ef100
  sfc: obtain device mac address based on firmware handle for ef100
  sfc: add support for port_function_hw_addr_get devlink in ef100
  sfc: add support for devlink port_function_hw_addr_set in ef100

 drivers/net/ethernet/sfc/Kconfig        |   1 +
 drivers/net/ethernet/sfc/Makefile       |   3 +-
 drivers/net/ethernet/sfc/ef100_netdev.c |  20 +-
 drivers/net/ethernet/sfc/ef100_nic.c    |  96 +++-
 drivers/net/ethernet/sfc/ef100_nic.h    |   7 +
 drivers/net/ethernet/sfc/ef100_rep.c    |  58 ++-
 drivers/net/ethernet/sfc/ef100_rep.h    |   9 +
 drivers/net/ethernet/sfc/efx_devlink.c  | 629 ++++++++++++++++++++++++
 drivers/net/ethernet/sfc/efx_devlink.h  |  27 +
 drivers/net/ethernet/sfc/mae.c          | 212 +++++++-
 drivers/net/ethernet/sfc/mae.h          |  39 ++
 drivers/net/ethernet/sfc/mcdi.c         |  72 +++
 drivers/net/ethernet/sfc/mcdi.h         |  10 +
 drivers/net/ethernet/sfc/net_driver.h   |   7 +
 14 files changed, 1162 insertions(+), 28 deletions(-)
 create mode 100644 drivers/net/ethernet/sfc/efx_devlink.c
 create mode 100644 drivers/net/ethernet/sfc/efx_devlink.h

-- 
2.17.1


^ permalink raw reply	[flat|nested] 52+ messages in thread

* [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 11:31 [PATCH net-next 0/7] sfc: devlink support for ef100 alejandro.lucero-palau
@ 2023-01-19 11:31 ` alejandro.lucero-palau
  2023-01-19 12:14   ` Jiri Pirko
                     ` (4 more replies)
  2023-01-19 11:31 ` [PATCH net-next 2/7] sfc: enumerate mports in ef100 alejandro.lucero-palau
                   ` (6 subsequent siblings)
  7 siblings, 5 replies; 52+ messages in thread
From: alejandro.lucero-palau @ 2023-01-19 11:31 UTC (permalink / raw)
  To: netdev, linux-net-drivers
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx, Alejandro Lucero

From: Alejandro Lucero <alejandro.lucero-palau@amd.com>

Basic support for devlink info command.

Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
---
 drivers/net/ethernet/sfc/Kconfig       |   1 +
 drivers/net/ethernet/sfc/Makefile      |   3 +-
 drivers/net/ethernet/sfc/ef100_nic.c   |   6 +
 drivers/net/ethernet/sfc/efx_devlink.c | 427 +++++++++++++++++++++++++
 drivers/net/ethernet/sfc/efx_devlink.h |  20 ++
 drivers/net/ethernet/sfc/mcdi.c        |  72 +++++
 drivers/net/ethernet/sfc/mcdi.h        |   3 +
 drivers/net/ethernet/sfc/net_driver.h  |   2 +
 8 files changed, 533 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/sfc/efx_devlink.c
 create mode 100644 drivers/net/ethernet/sfc/efx_devlink.h

diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
index 0950e6b0508f..4af36ba8906b 100644
--- a/drivers/net/ethernet/sfc/Kconfig
+++ b/drivers/net/ethernet/sfc/Kconfig
@@ -22,6 +22,7 @@ config SFC
 	depends on PTP_1588_CLOCK_OPTIONAL
 	select MDIO
 	select CRC32
+	select NET_DEVLINK
 	help
 	  This driver supports 10/40-gigabit Ethernet cards based on
 	  the Solarflare SFC9100-family controllers.
diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
index 712a48d00069..55b9c73cd8ef 100644
--- a/drivers/net/ethernet/sfc/Makefile
+++ b/drivers/net/ethernet/sfc/Makefile
@@ -6,7 +6,8 @@ sfc-y			+= efx.o efx_common.o efx_channels.o nic.o \
 			   mcdi.o mcdi_port.o mcdi_port_common.o \
 			   mcdi_functions.o mcdi_filters.o mcdi_mon.o \
 			   ef100.o ef100_nic.o ef100_netdev.o \
-			   ef100_ethtool.o ef100_rx.o ef100_tx.o
+			   ef100_ethtool.o ef100_rx.o ef100_tx.o \
+			   efx_devlink.o
 sfc-$(CONFIG_SFC_MTD)	+= mtd.o
 sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
                            mae.o tc.o tc_bindings.o tc_counters.o
diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index ad686c671ab8..14af8f314b83 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -27,6 +27,7 @@
 #include "tc.h"
 #include "mae.h"
 #include "rx_common.h"
+#include "efx_devlink.h"
 
 #define EF100_MAX_VIS 4096
 #define EF100_NUM_MCDI_BUFFERS	1
@@ -1124,6 +1125,10 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
 		netif_warn(efx, probe, net_dev,
 			   "Failed to probe base mport rc %d; representors will not function\n",
 			   rc);
+	} else {
+		if (efx_probe_devlink(efx))
+			netif_warn(efx, probe, net_dev,
+				   "Failed to register devlink\n");
 	}
 
 	rc = efx_init_tc(efx);
@@ -1157,6 +1162,7 @@ void ef100_remove(struct efx_nic *efx)
 {
 	struct ef100_nic_data *nic_data = efx->nic_data;
 
+	efx_fini_devlink(efx);
 	efx_mcdi_detach(efx);
 	efx_mcdi_fini(efx);
 	if (nic_data)
diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
new file mode 100644
index 000000000000..c506f8f35d25
--- /dev/null
+++ b/drivers/net/ethernet/sfc/efx_devlink.c
@@ -0,0 +1,427 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/****************************************************************************
+ * Driver for AMD network controllers and boards
+ * Copyright (C) 2023, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/rtc.h>
+#include "net_driver.h"
+#include "ef100_nic.h"
+#include "efx_devlink.h"
+#include "nic.h"
+#include "mcdi.h"
+#include "mcdi_functions.h"
+#include "mcdi_pcol.h"
+
+/* Custom devlink-info version object names for details that do not map to the
+ * generic standardized names.
+ */
+#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC	"fw.mgmt.suc"
+#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC	"fw.mgmt.cmc"
+#define EFX_DEVLINK_INFO_VERSION_FPGA_REV	"fpga.rev"
+#define EFX_DEVLINK_INFO_VERSION_DATAPATH_HW	"fpga.app"
+#define EFX_DEVLINK_INFO_VERSION_DATAPATH_FW	DEVLINK_INFO_VERSION_GENERIC_FW_APP
+#define EFX_DEVLINK_INFO_VERSION_SOC_BOOT	"coproc.boot"
+#define EFX_DEVLINK_INFO_VERSION_SOC_UBOOT	"coproc.uboot"
+#define EFX_DEVLINK_INFO_VERSION_SOC_MAIN	"coproc.main"
+#define EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY	"coproc.recovery"
+#define EFX_DEVLINK_INFO_VERSION_FW_EXPROM	"fw.exprom"
+#define EFX_DEVLINK_INFO_VERSION_FW_UEFI	"fw.uefi"
+
+#define EFX_MAX_VERSION_INFO_LEN	64
+
+static int efx_devlink_info_nvram_partition(struct efx_nic *efx,
+					    struct devlink_info_req *req,
+					    unsigned int partition_type,
+					    const char *version_name)
+{
+	char buf[EFX_MAX_VERSION_INFO_LEN];
+	u16 version[4];
+	int rc;
+
+	rc = efx_mcdi_nvram_metadata(efx, partition_type, NULL, version, NULL,
+				     0);
+	if (rc)
+		return rc;
+
+	snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u", version[0],
+		 version[1], version[2], version[3]);
+	devlink_info_version_stored_put(req, version_name, buf);
+
+	return 0;
+}
+
+static void efx_devlink_info_stored_versions(struct efx_nic *efx,
+					     struct devlink_info_req *req)
+{
+	efx_devlink_info_nvram_partition(efx, req, NVRAM_PARTITION_TYPE_BUNDLE,
+					 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID);
+	efx_devlink_info_nvram_partition(efx, req,
+					 NVRAM_PARTITION_TYPE_MC_FIRMWARE,
+					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT);
+	efx_devlink_info_nvram_partition(efx, req,
+					 NVRAM_PARTITION_TYPE_SUC_FIRMWARE,
+					 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC);
+	efx_devlink_info_nvram_partition(efx, req,
+					 NVRAM_PARTITION_TYPE_EXPANSION_ROM,
+					 EFX_DEVLINK_INFO_VERSION_FW_EXPROM);
+	efx_devlink_info_nvram_partition(efx, req,
+					 NVRAM_PARTITION_TYPE_EXPANSION_UEFI,
+					 EFX_DEVLINK_INFO_VERSION_FW_UEFI);
+}
+
+#define EFX_MAX_SERIALNUM_LEN	(ETH_ALEN * 2 + 1)
+
+static void efx_devlink_info_board_cfg(struct efx_nic *efx,
+				       struct devlink_info_req *req)
+{
+	char sn[EFX_MAX_SERIALNUM_LEN];
+	u8 mac_address[ETH_ALEN];
+	int rc;
+
+	rc = efx_mcdi_get_board_cfg(efx, (u8 *)mac_address, NULL, NULL);
+	if (!rc) {
+		snprintf(sn, EFX_MAX_SERIALNUM_LEN, "%pm", mac_address);
+		devlink_info_serial_number_put(req, sn);
+	}
+}
+
+#define EFX_VER_FLAG(_f)	\
+	(MC_CMD_GET_VERSION_V5_OUT_ ## _f ## _PRESENT_LBN)
+
+static void efx_devlink_info_running_versions(struct efx_nic *efx,
+					      struct devlink_info_req *req)
+{
+	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_V5_OUT_LEN);
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_VERSION_EXT_IN_LEN);
+	char buf[EFX_MAX_VERSION_INFO_LEN];
+	unsigned int flags, build_id;
+	union {
+		const __le32 *dwords;
+		const __le16 *words;
+		const char *str;
+	} ver;
+	struct rtc_time build_date;
+	size_t outlength, offset;
+	u64 tstamp;
+	int rc;
+
+	rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, inbuf, sizeof(inbuf),
+			  outbuf, sizeof(outbuf), &outlength);
+	if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN)
+		return;
+
+	/* Handle previous output */
+	if (outlength < MC_CMD_GET_VERSION_V2_OUT_LEN) {
+		ver.words = (__le16 *)MCDI_PTR(outbuf,
+					       GET_VERSION_EXT_OUT_VERSION);
+		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
+				  le16_to_cpu(ver.words[0]),
+				  le16_to_cpu(ver.words[1]),
+				  le16_to_cpu(ver.words[2]),
+				  le16_to_cpu(ver.words[3]));
+
+		devlink_info_version_running_put(req,
+						 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
+						 buf);
+		return;
+	}
+
+	/* Handle V2 additions */
+	flags = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_FLAGS);
+	if (flags & BIT(EFX_VER_FLAG(BOARD_EXT_INFO))) {
+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%s",
+			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_NAME));
+		devlink_info_version_fixed_put(req,
+					       DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
+					       buf);
+
+		/* Favour full board version if present (in V5 or later) */
+		if (~flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
+			snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u",
+				 MCDI_DWORD(outbuf,
+					    GET_VERSION_V2_OUT_BOARD_REVISION));
+			devlink_info_version_fixed_put(req,
+						       DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
+						       buf);
+		}
+
+		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_SERIAL);
+		if (ver.str[0])
+			devlink_info_board_serial_number_put(req, ver.str);
+	}
+
+	if (flags & BIT(EFX_VER_FLAG(FPGA_EXT_INFO))) {
+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
+						GET_VERSION_V2_OUT_FPGA_VERSION);
+		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u_%c%u",
+				  le32_to_cpu(ver.dwords[0]),
+				  'A' + le32_to_cpu(ver.dwords[1]),
+				  le32_to_cpu(ver.dwords[2]));
+
+		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_FPGA_EXTRA);
+		if (ver.str[0])
+			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
+				 " (%s)", ver.str);
+
+		devlink_info_version_running_put(req,
+						 EFX_DEVLINK_INFO_VERSION_FPGA_REV,
+						 buf);
+	}
+
+	if (flags & BIT(EFX_VER_FLAG(CMC_EXT_INFO))) {
+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
+						GET_VERSION_V2_OUT_CMCFW_VERSION);
+		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
+				  le32_to_cpu(ver.dwords[0]),
+				  le32_to_cpu(ver.dwords[1]),
+				  le32_to_cpu(ver.dwords[2]),
+				  le32_to_cpu(ver.dwords[3]));
+
+		tstamp = MCDI_QWORD(outbuf,
+				    GET_VERSION_V2_OUT_CMCFW_BUILD_DATE);
+		if (tstamp) {
+			rtc_time64_to_tm(tstamp, &build_date);
+			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
+				 " (%ptRd)", &build_date);
+		}
+
+		devlink_info_version_running_put(req,
+						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC,
+						 buf);
+	}
+
+	ver.words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_V2_OUT_VERSION);
+	offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
+			  le16_to_cpu(ver.words[0]), le16_to_cpu(ver.words[1]),
+			  le16_to_cpu(ver.words[2]), le16_to_cpu(ver.words[3]));
+	if (flags & BIT(EFX_VER_FLAG(MCFW_EXT_INFO))) {
+		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_ID);
+		snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
+			 " (%x) %s", build_id,
+			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_NAME));
+	}
+	devlink_info_version_running_put(req,
+					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
+					 buf);
+
+	if (flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
+						GET_VERSION_V2_OUT_SUCFW_VERSION);
+		tstamp = MCDI_QWORD(outbuf,
+				    GET_VERSION_V2_OUT_SUCFW_BUILD_DATE);
+		rtc_time64_to_tm(tstamp, &build_date);
+		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_SUCFW_CHIP_ID);
+
+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN,
+			 "%u.%u.%u.%u type %x (%ptRd)",
+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
+			 le32_to_cpu(ver.dwords[2]), le32_to_cpu(ver.dwords[3]),
+			 build_id, &build_date);
+
+		devlink_info_version_running_put(req,
+						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
+						 buf);
+	}
+
+	if (outlength < MC_CMD_GET_VERSION_V3_OUT_LEN)
+		return;
+
+	/* Handle V3 additions */
+	if (flags & BIT(EFX_VER_FLAG(DATAPATH_HW_VERSION))) {
+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
+						GET_VERSION_V3_OUT_DATAPATH_HW_VERSION);
+
+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
+			 le32_to_cpu(ver.dwords[2]));
+
+		devlink_info_version_running_put(req,
+						 EFX_DEVLINK_INFO_VERSION_DATAPATH_HW,
+						 buf);
+	}
+
+	if (flags & BIT(EFX_VER_FLAG(DATAPATH_FW_VERSION))) {
+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
+						GET_VERSION_V3_OUT_DATAPATH_FW_VERSION);
+
+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
+			 le32_to_cpu(ver.dwords[2]));
+
+		devlink_info_version_running_put(req,
+						 EFX_DEVLINK_INFO_VERSION_DATAPATH_FW,
+						 buf);
+	}
+
+	if (outlength < MC_CMD_GET_VERSION_V4_OUT_LEN)
+		return;
+
+	/* Handle V4 additions */
+	if (flags & BIT(EFX_VER_FLAG(SOC_BOOT_VERSION))) {
+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
+						GET_VERSION_V4_OUT_SOC_BOOT_VERSION);
+
+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
+			 le32_to_cpu(ver.dwords[2]),
+			 le32_to_cpu(ver.dwords[3]));
+
+		devlink_info_version_running_put(req,
+						 EFX_DEVLINK_INFO_VERSION_SOC_BOOT,
+						 buf);
+	}
+
+	if (flags & BIT(EFX_VER_FLAG(SOC_UBOOT_VERSION))) {
+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
+						GET_VERSION_V4_OUT_SOC_UBOOT_VERSION);
+
+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
+			 le32_to_cpu(ver.dwords[2]),
+			 le32_to_cpu(ver.dwords[3]));
+
+		devlink_info_version_running_put(req,
+						 EFX_DEVLINK_INFO_VERSION_SOC_UBOOT,
+						 buf);
+	}
+
+	if (flags & BIT(EFX_VER_FLAG(SOC_MAIN_ROOTFS_VERSION))) {
+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
+						GET_VERSION_V4_OUT_SOC_MAIN_ROOTFS_VERSION);
+
+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
+			 le32_to_cpu(ver.dwords[2]),
+			 le32_to_cpu(ver.dwords[3]));
+
+		devlink_info_version_running_put(req,
+						 EFX_DEVLINK_INFO_VERSION_SOC_MAIN,
+						 buf);
+	}
+
+	if (flags & BIT(EFX_VER_FLAG(SOC_RECOVERY_BUILDROOT_VERSION))) {
+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
+						GET_VERSION_V4_OUT_SOC_RECOVERY_BUILDROOT_VERSION);
+
+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
+			 le32_to_cpu(ver.dwords[2]),
+			 le32_to_cpu(ver.dwords[3]));
+
+		devlink_info_version_running_put(req,
+						 EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY,
+						 buf);
+	}
+
+	if (flags & BIT(EFX_VER_FLAG(SUCFW_VERSION)) &&
+	    ~flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
+						GET_VERSION_V4_OUT_SUCFW_VERSION);
+
+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
+			 le32_to_cpu(ver.dwords[2]),
+			 le32_to_cpu(ver.dwords[3]));
+
+		devlink_info_version_running_put(req,
+						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
+						 buf);
+	}
+
+	if (outlength < MC_CMD_GET_VERSION_V5_OUT_LEN)
+		return;
+
+	/* Handle V5 additions */
+
+	if (flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
+						GET_VERSION_V5_OUT_BOARD_VERSION);
+
+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
+			 le32_to_cpu(ver.dwords[2]),
+			 le32_to_cpu(ver.dwords[3]));
+
+		devlink_info_version_running_put(req,
+						 DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
+						 buf);
+	}
+
+	if (flags & BIT(EFX_VER_FLAG(BUNDLE_VERSION))) {
+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
+						GET_VERSION_V5_OUT_BUNDLE_VERSION);
+
+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
+			 le32_to_cpu(ver.dwords[2]),
+			 le32_to_cpu(ver.dwords[3]));
+
+		devlink_info_version_running_put(req,
+						 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
+						 buf);
+	}
+}
+
+#undef EFX_VER_FLAG
+
+static void efx_devlink_info_query_all(struct efx_nic *efx,
+				       struct devlink_info_req *req)
+{
+	efx_devlink_info_board_cfg(efx, req);
+	efx_devlink_info_stored_versions(efx, req);
+	efx_devlink_info_running_versions(efx, req);
+}
+
+struct efx_devlink {
+	struct efx_nic *efx;
+};
+
+static int efx_devlink_info_get(struct devlink *devlink,
+				struct devlink_info_req *req,
+				struct netlink_ext_ack *extack)
+{
+	struct efx_devlink *devlink_private = devlink_priv(devlink);
+	struct efx_nic *efx = devlink_private->efx;
+
+	efx_devlink_info_query_all(efx, req);
+	return 0;
+}
+
+static const struct devlink_ops sfc_devlink_ops = {
+	.info_get			= efx_devlink_info_get,
+};
+
+void efx_fini_devlink(struct efx_nic *efx)
+{
+	if (efx->devlink) {
+		struct efx_devlink *devlink_private;
+
+		devlink_private = devlink_priv(efx->devlink);
+
+		devlink_unregister(efx->devlink);
+		devlink_free(efx->devlink);
+		efx->devlink = NULL;
+	}
+}
+
+int efx_probe_devlink(struct efx_nic *efx)
+{
+	struct efx_devlink *devlink_private;
+
+	efx->devlink = devlink_alloc(&sfc_devlink_ops,
+				     sizeof(struct efx_devlink),
+				     &efx->pci_dev->dev);
+	if (!efx->devlink)
+		return -ENOMEM;
+	devlink_private = devlink_priv(efx->devlink);
+	devlink_private->efx = efx;
+
+	devlink_register(efx->devlink);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/sfc/efx_devlink.h b/drivers/net/ethernet/sfc/efx_devlink.h
new file mode 100644
index 000000000000..997f878aea93
--- /dev/null
+++ b/drivers/net/ethernet/sfc/efx_devlink.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/****************************************************************************
+ * Driver for AMD network controllers and boards
+ * Copyright (C) 2023, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef _EFX_DEVLINK_H
+#define _EFX_DEVLINK_H
+
+#include "net_driver.h"
+#include <net/devlink.h>
+
+int efx_probe_devlink(struct efx_nic *efx);
+void efx_fini_devlink(struct efx_nic *efx);
+
+#endif	/* _EFX_DEVLINK_H */
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index af338208eae9..328cae82a7d8 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -2308,6 +2308,78 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
 	return rc;
 }
 
+int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
+			    u32 *subtype, u16 version[4], char *desc,
+			    size_t descsize)
+{
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN);
+	efx_dword_t *outbuf;
+	size_t outlen;
+	u32 flags;
+	int rc;
+
+	outbuf = kzalloc(MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2, GFP_KERNEL);
+	if (!outbuf)
+		return -ENOMEM;
+
+	MCDI_SET_DWORD(inbuf, NVRAM_METADATA_IN_TYPE, type);
+
+	rc = efx_mcdi_rpc_quiet(efx, MC_CMD_NVRAM_METADATA, inbuf,
+				sizeof(inbuf), outbuf,
+				MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2,
+				&outlen);
+	if (rc)
+		goto out_free;
+	if (outlen < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
+		rc = -EIO;
+		goto out_free;
+	}
+
+	flags = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_FLAGS);
+
+	if (desc && descsize > 0) {
+		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_VALID_LBN)) {
+			if (descsize <=
+			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)) {
+				rc = -E2BIG;
+				goto out_free;
+			}
+
+			strncpy(desc,
+				MCDI_PTR(outbuf, NVRAM_METADATA_OUT_DESCRIPTION),
+				MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen));
+			desc[MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)] = '\0';
+		} else {
+			desc[0] = '\0';
+		}
+	}
+
+	if (subtype) {
+		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_SUBTYPE_VALID_LBN))
+			*subtype = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_SUBTYPE);
+		else
+			*subtype = 0;
+	}
+
+	if (version) {
+		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_VERSION_VALID_LBN)) {
+			version[0] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_W);
+			version[1] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_X);
+			version[2] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Y);
+			version[3] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Z);
+		} else {
+			version[0] = 0;
+			version[1] = 0;
+			version[2] = 0;
+			version[3] = 0;
+		}
+	}
+
+out_free:
+	kfree(outbuf);
+	return rc;
+}
+
 int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
 		      size_t len, size_t *retlen, u8 *buffer)
 {
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index 7e35fec9da35..63b090587f7a 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -379,6 +379,9 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
 			bool *protected_out);
 int efx_new_mcdi_nvram_test_all(struct efx_nic *efx);
 int efx_mcdi_nvram_test_all(struct efx_nic *efx);
+int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
+			    u32 *subtype, u16 version[4], char *desc,
+			    size_t descsize);
 int efx_mcdi_handle_assertion(struct efx_nic *efx);
 int efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
 int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac,
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 3b49e216768b..d036641dc043 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -994,6 +994,7 @@ enum efx_xdp_tx_queues_mode {
  *      xdp_rxq_info structures?
  * @netdev_notifier: Netdevice notifier.
  * @tc: state for TC offload (EF100).
+ * @devlink: reference to devlink structure owned by this device
  * @mem_bar: The BAR that is mapped into membase.
  * @reg_base: Offset from the start of the bar to the function control window.
  * @monitor_work: Hardware monitor workitem
@@ -1179,6 +1180,7 @@ struct efx_nic {
 	struct notifier_block netdev_notifier;
 	struct efx_tc_state *tc;
 
+	struct devlink *devlink;
 	unsigned int mem_bar;
 	u32 reg_base;
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH net-next 2/7] sfc: enumerate mports in ef100
  2023-01-19 11:31 [PATCH net-next 0/7] sfc: devlink support for ef100 alejandro.lucero-palau
  2023-01-19 11:31 ` [PATCH net-next 1/7] sfc: add " alejandro.lucero-palau
@ 2023-01-19 11:31 ` alejandro.lucero-palau
  2023-01-19 23:48   ` Jacob Keller
  2023-01-20 12:47   ` kernel test robot
  2023-01-19 11:31 ` [PATCH net-next 3/7] sfc: add mport lookup based on driver's mport data alejandro.lucero-palau
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 52+ messages in thread
From: alejandro.lucero-palau @ 2023-01-19 11:31 UTC (permalink / raw)
  To: netdev, linux-net-drivers
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx, Alejandro Lucero

From: Alejandro Lucero <alejandro.lucero-palau@amd.com>

MAE ports (mports) are the ports on the EF100 embedded switch such
as networking PCIe functions, the physical port, and potentially
others.

This patch enumerates the mports obtained from the firmware and
registers them in driver structures. This data will be used when
creating representors and will be exposed through devlink port
interface in future patches.

Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
---
 drivers/net/ethernet/sfc/ef100_nic.c  |  23 ++++
 drivers/net/ethernet/sfc/ef100_nic.h  |   4 +
 drivers/net/ethernet/sfc/ef100_rep.c  |  22 +++
 drivers/net/ethernet/sfc/ef100_rep.h  |   2 +
 drivers/net/ethernet/sfc/mae.c        | 185 ++++++++++++++++++++++++++
 drivers/net/ethernet/sfc/mae.h        |  37 ++++++
 drivers/net/ethernet/sfc/mcdi.h       |   7 +
 drivers/net/ethernet/sfc/net_driver.h |   4 +
 8 files changed, 284 insertions(+)

diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index 14af8f314b83..ee260b508377 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -748,6 +748,18 @@ static int efx_ef100_get_base_mport(struct efx_nic *efx)
 			   id);
 	nic_data->base_mport = id;
 	nic_data->have_mport = true;
+
+	/* Construct mport selector for "calling PF" */
+	efx_mae_mport_uplink(efx, &selector);
+	/* Look up actual mport ID */
+	rc = efx_mae_lookup_mport(efx, selector, &id);
+	if (rc)
+		return rc;
+	if (id >> 16)
+		netif_warn(efx, probe, efx->net_dev, "Bad own m-port id %#x\n",
+			   id);
+	nic_data->own_mport = id;
+	nic_data->have_own_mport = true;
 	return 0;
 }
 #endif
@@ -1129,6 +1141,13 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
 		if (efx_probe_devlink(efx))
 			netif_warn(efx, probe, net_dev,
 				   "Failed to register devlink\n");
+		rc = efx_init_mae(efx);
+		if (rc)
+			pci_warn(efx->pci_dev,
+				 "Failed to init MAE rc %d; representors will not function\n",
+				 rc);
+		else
+			efx_ef100_init_reps(efx);
 	}
 
 	rc = efx_init_tc(efx);
@@ -1162,6 +1181,10 @@ void ef100_remove(struct efx_nic *efx)
 {
 	struct ef100_nic_data *nic_data = efx->nic_data;
 
+	if (efx->mae) {
+		efx_ef100_fini_reps(efx);
+		efx_fini_mae(efx);
+	}
 	efx_fini_devlink(efx);
 	efx_mcdi_detach(efx);
 	efx_mcdi_fini(efx);
diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
index 0295933145fa..496aea43c60f 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.h
+++ b/drivers/net/ethernet/sfc/ef100_nic.h
@@ -74,6 +74,10 @@ struct ef100_nic_data {
 	u64 stats[EF100_STAT_COUNT];
 	u32 base_mport;
 	bool have_mport; /* base_mport was populated successfully */
+	u32 own_mport;
+	u32 local_mae_intf; /* interface_idx that corresponds to us, in mport enumerate */
+	bool have_own_mport; /* own_mport was populated successfully */
+	bool have_local_intf; /* local_mae_intf was populated successfully */
 	bool grp_mae; /* MAE Privilege */
 	u16 tso_max_hdr_len;
 	u16 tso_max_payload_num_segs;
diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index 81ab22c74635..ebe7b1275713 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -9,6 +9,7 @@
  * by the Free Software Foundation, incorporated herein by reference.
  */
 
+#include <linux/rhashtable.h>
 #include "ef100_rep.h"
 #include "ef100_netdev.h"
 #include "ef100_nic.h"
@@ -341,6 +342,27 @@ void efx_ef100_fini_vfreps(struct efx_nic *efx)
 		efx_ef100_vfrep_destroy(efx, efv);
 }
 
+void efx_ef100_init_reps(struct efx_nic *efx)
+{
+	struct ef100_nic_data *nic_data = efx->nic_data;
+	int rc;
+
+	nic_data->have_local_intf = false;
+	rc = efx_mae_enumerate_mports(efx);
+	if (rc)
+		pci_warn(efx->pci_dev,
+			 "Could not enumerate mports (rc=%d), are we admin?",
+			 rc);
+}
+
+void efx_ef100_fini_reps(struct efx_nic *efx)
+{
+	struct efx_mae *mae = efx->mae;
+
+	rhashtable_free_and_destroy(&mae->mports_ht, efx_mae_remove_mport,
+				    NULL);
+}
+
 static int efx_ef100_rep_poll(struct napi_struct *napi, int weight)
 {
 	struct efx_rep *efv = container_of(napi, struct efx_rep, napi);
diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
index c21bc716f847..328ac0cbb532 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.h
+++ b/drivers/net/ethernet/sfc/ef100_rep.h
@@ -67,4 +67,6 @@ void efx_ef100_rep_rx_packet(struct efx_rep *efv, struct efx_rx_buffer *rx_buf);
  */
 struct efx_rep *efx_ef100_find_rep_by_mport(struct efx_nic *efx, u16 mport);
 extern const struct net_device_ops efx_ef100_rep_netdev_ops;
+void efx_ef100_init_reps(struct efx_nic *efx);
+void efx_ef100_fini_reps(struct efx_nic *efx);
 #endif /* EF100_REP_H */
diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c
index 583baf69981c..bf039862ee14 100644
--- a/drivers/net/ethernet/sfc/mae.c
+++ b/drivers/net/ethernet/sfc/mae.c
@@ -9,8 +9,11 @@
  * by the Free Software Foundation, incorporated herein by reference.
  */
 
+#include <linux/rhashtable.h>
+#include "ef100_nic.h"
 #include "mae.h"
 #include "mcdi.h"
+#include "mcdi_pcol.h"
 #include "mcdi_pcol_mae.h"
 
 int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label)
@@ -490,6 +493,162 @@ static bool efx_mae_asl_id(u32 id)
 	return !!(id & BIT(31));
 }
 
+/* mport handling */
+static const struct rhashtable_params efx_mae_mports_ht_params = {
+	.key_len	= sizeof(u32),
+	.key_offset	= offsetof(struct mae_mport_desc, mport_id),
+	.head_offset	= offsetof(struct mae_mport_desc, linkage),
+};
+
+struct mae_mport_desc *efx_mae_get_mport(struct efx_nic *efx, u32 mport_id)
+{
+	return rhashtable_lookup_fast(&efx->mae->mports_ht, &mport_id,
+				      efx_mae_mports_ht_params);
+}
+
+static int efx_mae_add_mport(struct efx_nic *efx, struct mae_mport_desc *desc)
+{
+	struct efx_mae *mae = efx->mae;
+	int rc;
+
+	rc = rhashtable_insert_fast(&mae->mports_ht, &desc->linkage,
+				    efx_mae_mports_ht_params);
+
+	if (rc) {
+		pci_err(efx->pci_dev, "Failed to insert MPORT %08x, rc %d\n",
+			desc->mport_id, rc);
+		kfree(desc);
+		return rc;
+	}
+
+	return rc;
+}
+
+void efx_mae_remove_mport(void *desc, void *arg)
+{
+	struct mae_mport_desc *mport = desc;
+
+	synchronize_rcu();
+	kfree(mport);
+}
+
+static int efx_mae_process_mport(struct efx_nic *efx,
+				 struct mae_mport_desc *desc)
+{
+	struct ef100_nic_data *nic_data = efx->nic_data;
+	struct mae_mport_desc *mport;
+
+	mport = efx_mae_get_mport(efx, desc->mport_id);
+	if (!IS_ERR_OR_NULL(mport)) {
+		netif_err(efx, drv, efx->net_dev,
+			  "mport with id %u does exist!!!\n", desc->mport_id);
+		return -EEXIST;
+	}
+
+	if (nic_data->have_own_mport &&
+	    desc->mport_id == nic_data->own_mport) {
+		WARN_ON(desc->mport_type != MAE_MPORT_DESC_MPORT_TYPE_VNIC);
+		WARN_ON(desc->vnic_client_type !=
+			MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION);
+		nic_data->local_mae_intf = desc->interface_idx;
+		nic_data->have_local_intf = true;
+		pci_dbg(efx->pci_dev, "MAE interface_idx is %u\n",
+			nic_data->local_mae_intf);
+	}
+
+	return efx_mae_add_mport(efx, desc);
+}
+
+int efx_mae_enumerate_mports(struct efx_nic *efx)
+{
+#define MCDI_MPORT_JOURNAL_LEN \
+	sizeof(efx_dword_t[DIV_ROUND_UP(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4)])
+	efx_dword_t *outbuf = kzalloc(MCDI_MPORT_JOURNAL_LEN, GFP_KERNEL);
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN);
+	MCDI_DECLARE_STRUCT_PTR(desc);
+	size_t outlen, stride, count;
+	int rc = 0, i;
+
+	if (!outbuf)
+		return -ENOMEM;
+	do {
+		rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_READ_JOURNAL, inbuf,
+				  sizeof(inbuf), outbuf,
+				  MCDI_MPORT_JOURNAL_LEN, &outlen);
+		if (rc)
+			goto fail;
+		if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST) {
+			rc = -EIO;
+			goto fail;
+		}
+		count = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT);
+		if (!count)
+			continue; /* not break; we want to look at MORE flag */
+		stride = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC);
+		if (stride < MAE_MPORT_DESC_LEN) {
+			rc = -EIO;
+			goto fail;
+		}
+		if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LEN(count * stride)) {
+			rc = -EIO;
+			goto fail;
+		}
+
+		for (i = 0; i < count; i++) {
+			struct mae_mport_desc *d;
+
+			d = kzalloc(sizeof(*d), GFP_KERNEL);
+			if (!d) {
+				rc = -ENOMEM;
+				goto fail;
+			}
+
+			desc = (efx_dword_t *)
+				_MCDI_PTR(outbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST +
+					  i * stride);
+			d->mport_id = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_MPORT_ID);
+			d->flags = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_FLAGS);
+			d->caller_flags = MCDI_STRUCT_DWORD(desc,
+							    MAE_MPORT_DESC_CALLER_FLAGS);
+			d->mport_type = MCDI_STRUCT_DWORD(desc,
+							  MAE_MPORT_DESC_MPORT_TYPE);
+			switch (d->mport_type) {
+			case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
+				d->port_idx = MCDI_STRUCT_DWORD(desc,
+								MAE_MPORT_DESC_NET_PORT_IDX);
+				break;
+			case MAE_MPORT_DESC_MPORT_TYPE_ALIAS:
+				d->alias_mport_id = MCDI_STRUCT_DWORD(desc,
+								      MAE_MPORT_DESC_ALIAS_DELIVER_MPORT_ID);
+				break;
+			case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
+				d->vnic_client_type = MCDI_STRUCT_DWORD(desc,
+									MAE_MPORT_DESC_VNIC_CLIENT_TYPE);
+				d->interface_idx = MCDI_STRUCT_DWORD(desc,
+								     MAE_MPORT_DESC_VNIC_FUNCTION_INTERFACE);
+				d->pf_idx = MCDI_STRUCT_WORD(desc,
+							     MAE_MPORT_DESC_VNIC_FUNCTION_PF_IDX);
+				d->vf_idx = MCDI_STRUCT_WORD(desc,
+							     MAE_MPORT_DESC_VNIC_FUNCTION_VF_IDX);
+				break;
+			default:
+				/* Unknown mport_type, just accept it */
+				break;
+			}
+			rc = efx_mae_process_mport(efx, d);
+			/* Any failure will be due to memory allocation faiure,
+			 * so there is no point to try subsequent entries.
+			 */
+			if (rc)
+				goto fail;
+		}
+	} while (MCDI_FIELD(outbuf, MAE_MPORT_READ_JOURNAL_OUT, MORE) &&
+		 !WARN_ON(!count));
+fail:
+	kfree(outbuf);
+	return rc;
+}
+
 int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
 {
 	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
@@ -805,3 +964,29 @@ int efx_mae_delete_rule(struct efx_nic *efx, u32 id)
 		return -EIO;
 	return 0;
 }
+
+int efx_init_mae(struct efx_nic *efx)
+{
+	struct efx_mae *mae = kmalloc(sizeof(*mae), GFP_KERNEL);
+	int rc;
+
+	if (!mae)
+		return -ENOMEM;
+
+	rc = rhashtable_init(&mae->mports_ht, &efx_mae_mports_ht_params);
+	if (rc < 0) {
+		kfree(mae);
+		return rc;
+	}
+	efx->mae = mae;
+	mae->efx = efx;
+	return 0;
+}
+
+void efx_fini_mae(struct efx_nic *efx)
+{
+	struct efx_mae *mae = efx->mae;
+
+	kfree(mae);
+	efx->mae = NULL;
+}
diff --git a/drivers/net/ethernet/sfc/mae.h b/drivers/net/ethernet/sfc/mae.h
index 72343e90e222..e1f057f01f08 100644
--- a/drivers/net/ethernet/sfc/mae.h
+++ b/drivers/net/ethernet/sfc/mae.h
@@ -27,6 +27,40 @@ void efx_mae_mport_mport(struct efx_nic *efx, u32 mport_id, u32 *out);
 
 int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id);
 
+struct mae_mport_desc {
+	u32 mport_id;
+	u32 flags;
+	u32 caller_flags; /* enum mae_mport_desc_caller_flags */
+	u32 mport_type; /* MAE_MPORT_DESC_MPORT_TYPE_* */
+	union {
+		u32 port_idx; /* for mport_type == NET_PORT */
+		u32 alias_mport_id; /* for mport_type == ALIAS */
+		struct { /* for mport_type == VNIC */
+			u32 vnic_client_type; /* MAE_MPORT_DESC_VNIC_CLIENT_TYPE_* */
+			u32 interface_idx;
+			u16 pf_idx;
+			u16 vf_idx;
+		};
+	};
+	struct rhash_head linkage;
+	struct efx_rep *efv;
+};
+
+int efx_mae_enumerate_mports(struct efx_nic *efx);
+struct mae_mport_desc *efx_mae_get_mport(struct efx_nic *efx, u32 mport_id);
+void efx_mae_put_mport(struct efx_nic *efx, struct mae_mport_desc *desc);
+
+/**
+ * struct efx_mae - MAE information
+ *
+ * @efx: The associated NIC
+ * @mports_ht: m-port descriptions from MC_CMD_MAE_MPORT_READ_JOURNAL
+ */
+struct efx_mae {
+	struct efx_nic *efx;
+	struct rhashtable mports_ht;
+};
+
 int efx_mae_start_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue);
 int efx_mae_stop_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue);
 void efx_mae_counters_grant_credits(struct work_struct *work);
@@ -60,4 +94,7 @@ int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match,
 			u32 prio, u32 acts_id, u32 *id);
 int efx_mae_delete_rule(struct efx_nic *efx, u32 id);
 
+int efx_init_mae(struct efx_nic *efx);
+void efx_fini_mae(struct efx_nic *efx);
+void efx_mae_remove_mport(void *desc, void *arg);
 #endif /* EF100_MAE_H */
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index 63b090587f7a..5fd2215da951 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -199,6 +199,8 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
 	MCDI_DECLARE_BUF(_name, 8)
 #define _MCDI_PTR(_buf, _offset)					\
 	((u8 *)(_buf) + (_offset))
+#define MCDI_STRUCT_PTR(_buf, _field)                                   \
+	_MCDI_PTR(_buf, _field ## _OFST)
 #define MCDI_PTR(_buf, _field)						\
 	_MCDI_PTR(_buf, MC_CMD_ ## _field ## _OFST)
 /* Use MCDI_STRUCT_ functions to access members of MCDI structuredefs.
@@ -229,6 +231,9 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
 #define MCDI_WORD(_buf, _field)						\
 	((u16)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2) +	\
 	 le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field)))
+#define MCDI_STRUCT_WORD(_buf, _field)                                  \
+	((void)BUILD_BUG_ON_ZERO(_field ## _LEN != 2),  \
+	le16_to_cpu(*(__force const __le16 *)MCDI_STRUCT_PTR(_buf, _field)))
 /* Write a 16-bit field defined in the protocol as being big-endian. */
 #define MCDI_STRUCT_SET_WORD_BE(_buf, _field, _value) do {		\
 	BUILD_BUG_ON(_field ## _LEN != 2);				\
@@ -241,6 +246,8 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
 	EFX_POPULATE_DWORD_1(*_MCDI_STRUCT_DWORD(_buf, _field), EFX_DWORD_0, _value)
 #define MCDI_DWORD(_buf, _field)					\
 	EFX_DWORD_FIELD(*_MCDI_DWORD(_buf, _field), EFX_DWORD_0)
+#define MCDI_STRUCT_DWORD(_buf, _field)                                 \
+	EFX_DWORD_FIELD(*_MCDI_STRUCT_DWORD(_buf, _field), EFX_DWORD_0)
 /* Write a 32-bit field defined in the protocol as being big-endian. */
 #define MCDI_STRUCT_SET_DWORD_BE(_buf, _field, _value) do {		\
 	BUILD_BUG_ON(_field ## _LEN != 4);				\
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index d036641dc043..bc9efbfb3d6b 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -845,6 +845,8 @@ enum efx_xdp_tx_queues_mode {
 	EFX_XDP_TX_QUEUES_BORROWED	/* queues borrowed from net stack */
 };
 
+struct efx_mae;
+
 /**
  * struct efx_nic - an Efx NIC
  * @name: Device name (net device name or bus id before net device registered)
@@ -881,6 +883,7 @@ enum efx_xdp_tx_queues_mode {
  * @msi_context: Context for each MSI
  * @extra_channel_types: Types of extra (non-traffic) channels that
  *	should be allocated for this NIC
+ * @mae: Details of the Match Action Engine
  * @xdp_tx_queue_count: Number of entries in %xdp_tx_queues.
  * @xdp_tx_queues: Array of pointers to tx queues used for XDP transmit.
  * @xdp_txq_queues_mode: XDP TX queues sharing strategy.
@@ -1044,6 +1047,7 @@ struct efx_nic {
 	struct efx_msi_context msi_context[EFX_MAX_CHANNELS];
 	const struct efx_channel_type *
 	extra_channel_type[EFX_MAX_EXTRA_CHANNELS];
+	struct efx_mae *mae;
 
 	unsigned int xdp_tx_queue_count;
 	struct efx_tx_queue **xdp_tx_queues;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH net-next 3/7] sfc: add mport lookup based on driver's mport data
  2023-01-19 11:31 [PATCH net-next 0/7] sfc: devlink support for ef100 alejandro.lucero-palau
  2023-01-19 11:31 ` [PATCH net-next 1/7] sfc: add " alejandro.lucero-palau
  2023-01-19 11:31 ` [PATCH net-next 2/7] sfc: enumerate mports in ef100 alejandro.lucero-palau
@ 2023-01-19 11:31 ` alejandro.lucero-palau
  2023-01-19 23:57   ` Jacob Keller
  2023-01-19 11:31 ` [PATCH net-next 4/7] sfc: add devlink port support for ef100 alejandro.lucero-palau
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 52+ messages in thread
From: alejandro.lucero-palau @ 2023-01-19 11:31 UTC (permalink / raw)
  To: netdev, linux-net-drivers
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx, Alejandro Lucero

From: Alejandro Lucero <alejandro.lucero-palau@amd.com>

Obtaining mport id is based on asking the firmware about it. This is
still needed for mport initialization itself, but once the mport data is
now kept by the driver, further mport id request can be satisfied
internally without firmware interaction.

Previous function is just modified in name making clear the firmware
interaction. The new function uses the old name and looks for the data
in the mport data structure.

Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
---
 drivers/net/ethernet/sfc/ef100_nic.c |  4 ++--
 drivers/net/ethernet/sfc/ef100_rep.c |  5 +----
 drivers/net/ethernet/sfc/mae.c       | 27 ++++++++++++++++++++++++++-
 drivers/net/ethernet/sfc/mae.h       |  2 ++
 4 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index ee260b508377..38c809eb7828 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -737,7 +737,7 @@ static int efx_ef100_get_base_mport(struct efx_nic *efx)
 	/* Construct mport selector for "physical network port" */
 	efx_mae_mport_wire(efx, &selector);
 	/* Look up actual mport ID */
-	rc = efx_mae_lookup_mport(efx, selector, &id);
+	rc = efx_mae_fw_lookup_mport(efx, selector, &id);
 	if (rc)
 		return rc;
 	/* The ID should always fit in 16 bits, because that's how wide the
@@ -752,7 +752,7 @@ static int efx_ef100_get_base_mport(struct efx_nic *efx)
 	/* Construct mport selector for "calling PF" */
 	efx_mae_mport_uplink(efx, &selector);
 	/* Look up actual mport ID */
-	rc = efx_mae_lookup_mport(efx, selector, &id);
+	rc = efx_mae_fw_lookup_mport(efx, selector, &id);
 	if (rc)
 		return rc;
 	if (id >> 16)
diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index ebe7b1275713..9cd1a3ac67e0 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -243,14 +243,11 @@ static struct efx_rep *efx_ef100_rep_create_netdev(struct efx_nic *efx,
 static int efx_ef100_configure_rep(struct efx_rep *efv)
 {
 	struct efx_nic *efx = efv->parent;
-	u32 selector;
 	int rc;
 
 	efv->rx_pring_size = EFX_REP_DEFAULT_PSEUDO_RING_SIZE;
-	/* Construct mport selector for corresponding VF */
-	efx_mae_mport_vf(efx, efv->idx, &selector);
 	/* Look up actual mport ID */
-	rc = efx_mae_lookup_mport(efx, selector, &efv->mport);
+	rc = efx_mae_lookup_mport(efx, efv->idx, &efv->mport);
 	if (rc)
 		return rc;
 	pci_dbg(efx->pci_dev, "VF %u has mport ID %#x\n", efv->idx, efv->mport);
diff --git a/drivers/net/ethernet/sfc/mae.c b/drivers/net/ethernet/sfc/mae.c
index bf039862ee14..6a5ab3a037db 100644
--- a/drivers/net/ethernet/sfc/mae.c
+++ b/drivers/net/ethernet/sfc/mae.c
@@ -97,7 +97,7 @@ void efx_mae_mport_mport(struct efx_nic *efx __always_unused, u32 mport_id, u32
 }
 
 /* id is really only 24 bits wide */
-int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
+int efx_mae_fw_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
 {
 	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN);
 	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_LOOKUP_IN_LEN);
@@ -488,6 +488,31 @@ int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt)
 	return 0;
 }
 
+int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id)
+{
+	struct ef100_nic_data *nic_data = efx->nic_data;
+	struct efx_mae *mae = efx->mae;
+	struct rhashtable_iter walk;
+	struct mae_mport_desc *m;
+	int rc = -ENOENT;
+
+	rhashtable_walk_enter(&mae->mports_ht, &walk);
+	rhashtable_walk_start(&walk);
+	while ((m = rhashtable_walk_next(&walk)) != NULL) {
+		if (m->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC &&
+		    m->interface_idx == nic_data->local_mae_intf &&
+		    m->pf_idx == 0 &&
+		    m->vf_idx == vf_idx) {
+			*id = m->mport_id;
+			rc = 0;
+			break;
+		}
+	}
+	rhashtable_walk_stop(&walk);
+	rhashtable_walk_exit(&walk);
+	return rc;
+}
+
 static bool efx_mae_asl_id(u32 id)
 {
 	return !!(id & BIT(31));
diff --git a/drivers/net/ethernet/sfc/mae.h b/drivers/net/ethernet/sfc/mae.h
index e1f057f01f08..d9adeafc0654 100644
--- a/drivers/net/ethernet/sfc/mae.h
+++ b/drivers/net/ethernet/sfc/mae.h
@@ -97,4 +97,6 @@ int efx_mae_delete_rule(struct efx_nic *efx, u32 id);
 int efx_init_mae(struct efx_nic *efx);
 void efx_fini_mae(struct efx_nic *efx);
 void efx_mae_remove_mport(void *desc, void *arg);
+int efx_mae_fw_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id);
+int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf, u32 *id);
 #endif /* EF100_MAE_H */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH net-next 4/7] sfc: add devlink port support for ef100
  2023-01-19 11:31 [PATCH net-next 0/7] sfc: devlink support for ef100 alejandro.lucero-palau
                   ` (2 preceding siblings ...)
  2023-01-19 11:31 ` [PATCH net-next 3/7] sfc: add mport lookup based on driver's mport data alejandro.lucero-palau
@ 2023-01-19 11:31 ` alejandro.lucero-palau
  2023-01-19 12:33   ` Jiri Pirko
                     ` (2 more replies)
  2023-01-19 11:31 ` [PATCH net-next 5/7] sfc: obtain device mac address based on firmware handle " alejandro.lucero-palau
                   ` (3 subsequent siblings)
  7 siblings, 3 replies; 52+ messages in thread
From: alejandro.lucero-palau @ 2023-01-19 11:31 UTC (permalink / raw)
  To: netdev, linux-net-drivers
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx, Alejandro Lucero

From: Alejandro Lucero <alejandro.lucero-palau@amd.com>

Using the data when enumerating mports, create devlink ports just before
netdevs are registered and removing those devlink ports after netdev has
been unregister.

Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
---
 drivers/net/ethernet/sfc/ef100_netdev.c |  14 ++-
 drivers/net/ethernet/sfc/ef100_rep.c    |  23 +++++
 drivers/net/ethernet/sfc/ef100_rep.h    |   6 ++
 drivers/net/ethernet/sfc/efx_devlink.c  | 114 ++++++++++++++++++++++++
 drivers/net/ethernet/sfc/efx_devlink.h  |   7 ++
 drivers/net/ethernet/sfc/net_driver.h   |   1 +
 6 files changed, 161 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c
index ddcc325ed570..4a5d028f757e 100644
--- a/drivers/net/ethernet/sfc/ef100_netdev.c
+++ b/drivers/net/ethernet/sfc/ef100_netdev.c
@@ -24,6 +24,7 @@
 #include "rx_common.h"
 #include "ef100_sriov.h"
 #include "tc_bindings.h"
+#include "efx_devlink.h"
 
 static void ef100_update_name(struct efx_nic *efx)
 {
@@ -280,6 +281,9 @@ static int ef100_register_netdev(struct efx_nic *efx)
 	net_dev->max_mtu = EFX_MAX_MTU;
 	net_dev->ethtool_ops = &ef100_ethtool_ops;
 
+	if (!efx->type->is_vf)
+		ef100_pf_set_devlink_port(efx);
+
 	rtnl_lock();
 
 	rc = dev_alloc_name(net_dev, net_dev->name);
@@ -302,6 +306,7 @@ static int ef100_register_netdev(struct efx_nic *efx)
 
 fail_locked:
 	rtnl_unlock();
+	ef100_pf_unset_devlink_port(efx);
 	netif_err(efx, drv, efx->net_dev, "could not register net dev\n");
 	return rc;
 }
@@ -312,6 +317,7 @@ static void ef100_unregister_netdev(struct efx_nic *efx)
 		efx_fini_mcdi_logging(efx);
 		efx->state = STATE_PROBED;
 		unregister_netdev(efx->net_dev);
+		ef100_pf_unset_devlink_port(efx);
 	}
 }
 
@@ -405,16 +411,16 @@ int ef100_probe_netdev(struct efx_probe_data *probe_data)
 	/* Don't fail init if RSS setup doesn't work. */
 	efx_mcdi_push_default_indir_table(efx, efx->n_rx_channels);
 
-	rc = ef100_register_netdev(efx);
-	if (rc)
-		goto fail;
-
 	if (!efx->type->is_vf) {
 		rc = ef100_probe_netdev_pf(efx);
 		if (rc)
 			goto fail;
 	}
 
+	rc = ef100_register_netdev(efx);
+	if (rc)
+		goto fail;
+
 	efx->netdev_notifier.notifier_call = ef100_netdev_event;
 	rc = register_netdevice_notifier(&efx->netdev_notifier);
 	if (rc) {
diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index 9cd1a3ac67e0..ff0c8da61919 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -16,6 +16,7 @@
 #include "mae.h"
 #include "rx_common.h"
 #include "tc_bindings.h"
+#include "efx_devlink.h"
 
 #define EFX_EF100_REP_DRIVER	"efx_ef100_rep"
 
@@ -297,6 +298,7 @@ int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i)
 			i, rc);
 		goto fail1;
 	}
+	ef100_rep_set_devlink_port(efv);
 	rc = register_netdev(efv->net_dev);
 	if (rc) {
 		pci_err(efx->pci_dev,
@@ -304,10 +306,12 @@ int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i)
 			i, rc);
 		goto fail2;
 	}
+
 	pci_dbg(efx->pci_dev, "Representor for VF %d is %s\n", i,
 		efv->net_dev->name);
 	return 0;
 fail2:
+	ef100_rep_unset_devlink_port(efv);
 	efx_ef100_deconfigure_rep(efv);
 fail1:
 	efx_ef100_rep_destroy_netdev(efv);
@@ -323,6 +327,7 @@ void efx_ef100_vfrep_destroy(struct efx_nic *efx, struct efx_rep *efv)
 		return;
 	netif_dbg(efx, drv, rep_dev, "Removing VF representor\n");
 	unregister_netdev(rep_dev);
+	ef100_rep_unset_devlink_port(efv);
 	efx_ef100_deconfigure_rep(efv);
 	efx_ef100_rep_destroy_netdev(efv);
 }
@@ -339,6 +344,24 @@ void efx_ef100_fini_vfreps(struct efx_nic *efx)
 		efx_ef100_vfrep_destroy(efx, efv);
 }
 
+bool ef100_mport_is_pcie_vnic(struct mae_mport_desc *mport_desc)
+{
+	return mport_desc->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC &&
+	       mport_desc->vnic_client_type == MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION;
+}
+
+bool ef100_mport_on_local_intf(struct efx_nic *efx,
+			       struct mae_mport_desc *mport_desc)
+{
+	bool pcie_func;
+	struct ef100_nic_data *nic_data = efx->nic_data;
+
+	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
+
+	return nic_data->have_local_intf && pcie_func &&
+		     mport_desc->interface_idx == nic_data->local_mae_intf;
+}
+
 void efx_ef100_init_reps(struct efx_nic *efx)
 {
 	struct ef100_nic_data *nic_data = efx->nic_data;
diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
index 328ac0cbb532..9cca41614982 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.h
+++ b/drivers/net/ethernet/sfc/ef100_rep.h
@@ -22,6 +22,8 @@ struct efx_rep_sw_stats {
 	atomic64_t rx_dropped, tx_errors;
 };
 
+struct devlink_port;
+
 /**
  * struct efx_rep - Private data for an Efx representor
  *
@@ -54,6 +56,7 @@ struct efx_rep {
 	spinlock_t rx_lock;
 	struct napi_struct napi;
 	struct efx_rep_sw_stats stats;
+	struct devlink_port *dl_port;
 };
 
 int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i);
@@ -69,4 +72,7 @@ struct efx_rep *efx_ef100_find_rep_by_mport(struct efx_nic *efx, u16 mport);
 extern const struct net_device_ops efx_ef100_rep_netdev_ops;
 void efx_ef100_init_reps(struct efx_nic *efx);
 void efx_ef100_fini_reps(struct efx_nic *efx);
+struct mae_mport_desc;
+bool ef100_mport_on_local_intf(struct efx_nic *efx,
+			       struct mae_mport_desc *mport_desc);
 #endif /* EF100_REP_H */
diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
index c506f8f35d25..bb19d3ad7ffd 100644
--- a/drivers/net/ethernet/sfc/efx_devlink.c
+++ b/drivers/net/ethernet/sfc/efx_devlink.c
@@ -16,6 +16,8 @@
 #include "mcdi.h"
 #include "mcdi_functions.h"
 #include "mcdi_pcol.h"
+#include "mae.h"
+#include "ef100_rep.h"
 
 /* Custom devlink-info version object names for details that do not map to the
  * generic standardized names.
@@ -381,6 +383,52 @@ struct efx_devlink {
 	struct efx_nic *efx;
 };
 
+static void efx_devlink_del_port(struct devlink_port *dl_port)
+{
+	if (!dl_port)
+		return;
+	devlink_port_unregister(dl_port);
+	kfree(dl_port);
+}
+
+static int efx_devlink_add_port(struct efx_nic *efx,
+				struct mae_mport_desc *mport,
+				struct devlink_port *dl_port)
+{
+	struct devlink_port_attrs attrs = {};
+	bool external = false;
+	int err;
+
+	if (!ef100_mport_on_local_intf(efx, mport))
+		external = true;
+
+	switch (mport->mport_type) {
+	case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
+		attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
+		attrs.phys.port_number = mport->port_idx;
+		devlink_port_attrs_set(dl_port, &attrs);
+		break;
+	case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
+		if (mport->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL) {
+			devlink_port_attrs_pci_vf_set(dl_port, 0, mport->pf_idx,
+						      mport->vf_idx,
+						      external);
+		} else {
+			devlink_port_attrs_pci_pf_set(dl_port, 0, mport->pf_idx,
+						      external);
+		}
+		break;
+	default:
+		/* MAE_MPORT_DESC_MPORT_ALIAS and UNDEFINED */
+		return 0;
+	}
+
+	dl_port->index = mport->mport_id;
+	err = devlink_port_register(efx->devlink, dl_port, mport->mport_id);
+
+	return err;
+}
+
 static int efx_devlink_info_get(struct devlink *devlink,
 				struct devlink_info_req *req,
 				struct netlink_ext_ack *extack)
@@ -396,6 +444,72 @@ static const struct devlink_ops sfc_devlink_ops = {
 	.info_get			= efx_devlink_info_get,
 };
 
+static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
+{
+	struct mae_mport_desc *mport;
+	struct devlink_port *dl_port;
+	u32 id;
+
+	if (efx_mae_lookup_mport(efx, idx, &id)) {
+		/* This should not happen. */
+		if (idx == MAE_MPORT_DESC_VF_IDX_NULL)
+			pci_warn(efx->pci_dev, "No mport ID found for PF.\n");
+		else
+			pci_warn(efx->pci_dev, "No mport ID found for VF %u.\n",
+				 idx);
+		return NULL;
+	}
+
+	mport = efx_mae_get_mport(efx, id);
+	if (!mport) {
+		/* This should not happen. */
+		if (idx == MAE_MPORT_DESC_VF_IDX_NULL)
+			pci_warn(efx->pci_dev, "No mport found for PF.\n");
+		else
+			pci_warn(efx->pci_dev, "No mport found for VF %u.\n",
+				 idx);
+		return NULL;
+	}
+
+	dl_port = kzalloc(sizeof(*dl_port), GFP_KERNEL);
+	if (!dl_port)
+		return NULL;
+
+	if (efx_devlink_add_port(efx, mport, dl_port)) {
+		if (idx == MAE_MPORT_DESC_VF_IDX_NULL)
+			pci_warn(efx->pci_dev,
+				 "devlink port creation for PF failed.\n");
+		else
+			pci_warn(efx->pci_dev,
+				 "devlink_port creationg for VF %u failed.\n",
+				 idx);
+		kfree(dl_port);
+		return NULL;
+	}
+
+	return dl_port;
+}
+
+void ef100_rep_set_devlink_port(struct efx_rep *efv)
+{
+	efv->dl_port = ef100_set_devlink_port(efv->parent, efv->idx);
+}
+
+void ef100_pf_set_devlink_port(struct efx_nic *efx)
+{
+	efx->dl_port = ef100_set_devlink_port(efx, MAE_MPORT_DESC_VF_IDX_NULL);
+}
+
+void ef100_rep_unset_devlink_port(struct efx_rep *efv)
+{
+	efx_devlink_del_port(efv->dl_port);
+}
+
+void ef100_pf_unset_devlink_port(struct efx_nic *efx)
+{
+	efx_devlink_del_port(efx->dl_port);
+}
+
 void efx_fini_devlink(struct efx_nic *efx)
 {
 	if (efx->devlink) {
diff --git a/drivers/net/ethernet/sfc/efx_devlink.h b/drivers/net/ethernet/sfc/efx_devlink.h
index 997f878aea93..a834c393a9ad 100644
--- a/drivers/net/ethernet/sfc/efx_devlink.h
+++ b/drivers/net/ethernet/sfc/efx_devlink.h
@@ -17,4 +17,11 @@
 int efx_probe_devlink(struct efx_nic *efx);
 void efx_fini_devlink(struct efx_nic *efx);
 
+struct mae_mport_desc;
+struct efx_rep;
+
+void ef100_pf_set_devlink_port(struct efx_nic *efx);
+void ef100_rep_set_devlink_port(struct efx_rep *efv);
+void ef100_pf_unset_devlink_port(struct efx_nic *efx);
+void ef100_rep_unset_devlink_port(struct efx_rep *efv);
 #endif	/* _EFX_DEVLINK_H */
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index bc9efbfb3d6b..20f43695d082 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -1185,6 +1185,7 @@ struct efx_nic {
 	struct efx_tc_state *tc;
 
 	struct devlink *devlink;
+	struct devlink_port *dl_port;
 	unsigned int mem_bar;
 	u32 reg_base;
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH net-next 5/7] sfc: obtain device mac address based on firmware handle for ef100
  2023-01-19 11:31 [PATCH net-next 0/7] sfc: devlink support for ef100 alejandro.lucero-palau
                   ` (3 preceding siblings ...)
  2023-01-19 11:31 ` [PATCH net-next 4/7] sfc: add devlink port support for ef100 alejandro.lucero-palau
@ 2023-01-19 11:31 ` alejandro.lucero-palau
  2023-01-19 19:47   ` kernel test robot
  2023-01-20  0:03   ` Jacob Keller
  2023-01-19 11:31 ` [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100 alejandro.lucero-palau
                   ` (2 subsequent siblings)
  7 siblings, 2 replies; 52+ messages in thread
From: alejandro.lucero-palau @ 2023-01-19 11:31 UTC (permalink / raw)
  To: netdev, linux-net-drivers
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx, Alejandro Lucero

From: Alejandro Lucero <alejandro.lucero-palau@amd.com>

Getting device mac address is currently based on a specific MCDI command
only available for the PF. This patch changes the MCDI command to a
generic one for PFs and VFs based on a client handle. This allows both
PFs and VFs to ask for their mac address during initialization using the
CLIENT_HANDLE_SELF.

Moreover, the patch allows other client handles which will be used by
the PF to ask for mac addresses linked to VFs. This is necessary for
suporting the port_function_hw_addr_get devlink function in further
patches.

Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
---
 drivers/net/ethernet/sfc/ef100_netdev.c | 10 +++++++
 drivers/net/ethernet/sfc/ef100_nic.c    | 38 ++++++++++++-------------
 drivers/net/ethernet/sfc/ef100_nic.h    |  2 ++
 3 files changed, 31 insertions(+), 19 deletions(-)

diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c
index 4a5d028f757e..1a1842bd6e12 100644
--- a/drivers/net/ethernet/sfc/ef100_netdev.c
+++ b/drivers/net/ethernet/sfc/ef100_netdev.c
@@ -360,6 +360,7 @@ int ef100_probe_netdev(struct efx_probe_data *probe_data)
 {
 	struct efx_nic *efx = &probe_data->efx;
 	struct efx_probe_data **probe_ptr;
+	struct ef100_nic_data *nic_data;
 	struct net_device *net_dev;
 	int rc;
 
@@ -411,6 +412,15 @@ int ef100_probe_netdev(struct efx_probe_data *probe_data)
 	/* Don't fail init if RSS setup doesn't work. */
 	efx_mcdi_push_default_indir_table(efx, efx->n_rx_channels);
 
+	nic_data = efx->nic_data;
+	rc = ef100_get_mac_address(efx, net_dev->perm_addr, CLIENT_HANDLE_SELF,
+				   efx->type->is_vf);
+	if (rc)
+		return rc;
+	/* Assign MAC address */
+	eth_hw_addr_set(net_dev, net_dev->perm_addr);
+	ether_addr_copy(nic_data->port_id, net_dev->perm_addr);
+
 	if (!efx->type->is_vf) {
 		rc = ef100_probe_netdev_pf(efx);
 		if (rc)
diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index 38c809eb7828..f4e913593f2b 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -131,23 +131,33 @@ static void ef100_mcdi_reboot_detected(struct efx_nic *efx)
 
 /*	MCDI calls
  */
-static int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address)
+int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
+			  int client_handle, bool empty_ok)
 {
-	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_MAC_ADDRESSES_OUT_LEN);
+	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_MAC_ADDRESSES_OUT_LEN(1));
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_MAC_ADDRESSES_IN_LEN);
 	size_t outlen;
 	int rc;
 
 	BUILD_BUG_ON(MC_CMD_GET_MAC_ADDRESSES_IN_LEN != 0);
+	MCDI_SET_DWORD(inbuf, GET_CLIENT_MAC_ADDRESSES_IN_CLIENT_HANDLE,
+		       client_handle);
 
-	rc = efx_mcdi_rpc(efx, MC_CMD_GET_MAC_ADDRESSES, NULL, 0,
-			  outbuf, sizeof(outbuf), &outlen);
+	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_MAC_ADDRESSES, inbuf,
+			  sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
 	if (rc)
 		return rc;
-	if (outlen < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)
-		return -EIO;
-
-	ether_addr_copy(mac_address,
-			MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE));
+	if (outlen >= MC_CMD_GET_CLIENT_MAC_ADDRESSES_OUT_LEN(1)) {
+		ether_addr_copy(mac_address,
+				MCDI_PTR(outbuf, GET_CLIENT_MAC_ADDRESSES_OUT_MAC_ADDRS));
+	} else if (empty_ok) {
+		pci_warn(efx->pci_dev,
+			 "No MAC address provisioned for client ID %#x.\n",
+			 client_handle);
+		eth_zero_addr(mac_address);
+	} else {
+		return -ENOENT;
+	}
 	return 0;
 }
 
@@ -1117,13 +1127,6 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
 	struct net_device *net_dev = efx->net_dev;
 	int rc;
 
-	rc = ef100_get_mac_address(efx, net_dev->perm_addr);
-	if (rc)
-		goto fail;
-	/* Assign MAC address */
-	eth_hw_addr_set(net_dev, net_dev->perm_addr);
-	memcpy(nic_data->port_id, net_dev->perm_addr, ETH_ALEN);
-
 	if (!nic_data->grp_mae)
 		return 0;
 
@@ -1166,9 +1169,6 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
 		efx->fixed_features |= NETIF_F_HW_TC;
 	}
 #endif
-	return 0;
-
-fail:
 	return rc;
 }
 
diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
index 496aea43c60f..e59044072333 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.h
+++ b/drivers/net/ethernet/sfc/ef100_nic.h
@@ -92,4 +92,6 @@ int efx_ef100_init_datapath_caps(struct efx_nic *efx);
 int ef100_phy_probe(struct efx_nic *efx);
 int ef100_filter_table_probe(struct efx_nic *efx);
 
+int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
+			  int client_handle, bool empty_ok);
 #endif	/* EFX_EF100_NIC_H */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-19 11:31 [PATCH net-next 0/7] sfc: devlink support for ef100 alejandro.lucero-palau
                   ` (4 preceding siblings ...)
  2023-01-19 11:31 ` [PATCH net-next 5/7] sfc: obtain device mac address based on firmware handle " alejandro.lucero-palau
@ 2023-01-19 11:31 ` alejandro.lucero-palau
  2023-01-19 12:25   ` Jiri Pirko
  2023-01-19 12:37   ` Jiri Pirko
  2023-01-19 11:31 ` [PATCH net-next 7/7] sfc: add support for devlink port_function_hw_addr_set " alejandro.lucero-palau
  2023-01-20  8:55 ` [PATCH net-next 0/7] sfc: devlink support for ef100 Martin Habets
  7 siblings, 2 replies; 52+ messages in thread
From: alejandro.lucero-palau @ 2023-01-19 11:31 UTC (permalink / raw)
  To: netdev, linux-net-drivers
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx, Alejandro Lucero

From: Alejandro Lucero <alejandro.lucero-palau@amd.com>

Using the builtin client handle id infrastructure, this patch adds
support for obtaining the mac address linked to mports in ef100. This
implies to execute an MCDI command for getting the data from the
firmware for each devlink port.

Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
---
 drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
 drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
 drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
 drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
 drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
 5 files changed, 81 insertions(+)

diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
index f4e913593f2b..4400ce622228 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.c
+++ b/drivers/net/ethernet/sfc/ef100_nic.c
@@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
 	return rc;
 }
 
+/* MCDI commands are related to the same device issuing them. This function
+ * allows to do an MCDI command on behalf of another device, mainly PFs setting
+ * things for VFs.
+ */
+int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
+{
+	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
+	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
+	size_t outlen;
+	int rc;
+
+	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
+		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
+	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
+		       pciefn_flat);
+
+	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
+			  outbuf, sizeof(outbuf), &outlen);
+	if (rc)
+		return rc;
+	if (outlen < sizeof(outbuf))
+		return -EIO;
+	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
+	return 0;
+}
+
 int ef100_probe_netdev_pf(struct efx_nic *efx)
 {
 	struct ef100_nic_data *nic_data = efx->nic_data;
diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
index e59044072333..f1ed481c1260 100644
--- a/drivers/net/ethernet/sfc/ef100_nic.h
+++ b/drivers/net/ethernet/sfc/ef100_nic.h
@@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
 
 int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
 			  int client_handle, bool empty_ok);
+int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
 #endif	/* EFX_EF100_NIC_H */
diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
index ff0c8da61919..974c9ff901a0 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.c
+++ b/drivers/net/ethernet/sfc/ef100_rep.c
@@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
 		     mport_desc->interface_idx == nic_data->local_mae_intf;
 }
 
+bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
+{
+	bool pcie_func;
+
+	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
+	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
+}
+
 void efx_ef100_init_reps(struct efx_nic *efx)
 {
 	struct ef100_nic_data *nic_data = efx->nic_data;
diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
index 9cca41614982..74853ccbc937 100644
--- a/drivers/net/ethernet/sfc/ef100_rep.h
+++ b/drivers/net/ethernet/sfc/ef100_rep.h
@@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
 struct mae_mport_desc;
 bool ef100_mport_on_local_intf(struct efx_nic *efx,
 			       struct mae_mport_desc *mport_desc);
+bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
 #endif /* EF100_REP_H */
diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
index bb19d3ad7ffd..2a57c4f6d2b2 100644
--- a/drivers/net/ethernet/sfc/efx_devlink.c
+++ b/drivers/net/ethernet/sfc/efx_devlink.c
@@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
 	return err;
 }
 
+static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
+				     int *hw_addr_len,
+				     struct netlink_ext_ack *extack)
+{
+	struct efx_devlink *devlink = devlink_priv(port->devlink);
+	struct mae_mport_desc *mport_desc;
+	efx_qword_t pciefn;
+	u32 client_id;
+	int rc = 0;
+
+	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
+	if (!mport_desc)
+		return -EINVAL;
+
+	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
+		goto out;
+
+	if (ef100_mport_is_vf(mport_desc))
+		EFX_POPULATE_QWORD_3(pciefn,
+				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
+				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
+				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
+	else
+		EFX_POPULATE_QWORD_3(pciefn,
+				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
+				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
+				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
+
+	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
+	if (rc) {
+		netif_err(devlink->efx, drv, devlink->efx->net_dev,
+			  "Failed to get client ID for port index %u, rc %d\n",
+			  port->index, rc);
+		return rc;
+	}
+
+	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
+out:
+	*hw_addr_len = ETH_ALEN;
+
+	return rc;
+}
+
 static int efx_devlink_info_get(struct devlink *devlink,
 				struct devlink_info_req *req,
 				struct netlink_ext_ack *extack)
@@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
 
 static const struct devlink_ops sfc_devlink_ops = {
 	.info_get			= efx_devlink_info_get,
+	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
 };
 
 static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* [PATCH net-next 7/7] sfc: add support for devlink port_function_hw_addr_set in ef100
  2023-01-19 11:31 [PATCH net-next 0/7] sfc: devlink support for ef100 alejandro.lucero-palau
                   ` (5 preceding siblings ...)
  2023-01-19 11:31 ` [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100 alejandro.lucero-palau
@ 2023-01-19 11:31 ` alejandro.lucero-palau
  2023-01-19 12:27   ` Jiri Pirko
  2023-01-20  8:55 ` [PATCH net-next 0/7] sfc: devlink support for ef100 Martin Habets
  7 siblings, 1 reply; 52+ messages in thread
From: alejandro.lucero-palau @ 2023-01-19 11:31 UTC (permalink / raw)
  To: netdev, linux-net-drivers
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx, Alejandro Lucero

From: Alejandro Lucero <alejandro.lucero-palau@amd.com>

Using the builtin client handle id infrastructure, this patch adds
support for setting the mac address linked to mports in ef100. This
implies to execute an MCDI command for giving the address to the
firmware for the specific devlink port.

Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
---
 drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
index 2a57c4f6d2b2..a85b2d4e54ab 100644
--- a/drivers/net/ethernet/sfc/efx_devlink.c
+++ b/drivers/net/ethernet/sfc/efx_devlink.c
@@ -472,6 +472,49 @@ static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
 	return rc;
 }
 
+static int efx_devlink_port_addr_set(struct devlink_port *port,
+				     const u8 *hw_addr, int hw_addr_len,
+				     struct netlink_ext_ack *extack)
+{
+	MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_CLIENT_MAC_ADDRESSES_IN_LEN(1));
+	struct efx_devlink *devlink = devlink_priv(port->devlink);
+	struct mae_mport_desc *mport_desc;
+	efx_qword_t pciefn;
+	u32 client_id;
+	int rc;
+
+	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
+	if (!mport_desc)
+		return -EINVAL;
+
+	if (!ef100_mport_is_vf(mport_desc))
+		return -EPERM;
+
+	EFX_POPULATE_QWORD_3(pciefn,
+			     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
+			     PCIE_FUNCTION_VF, mport_desc->vf_idx,
+			     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
+
+	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
+	if (rc) {
+		netif_err(devlink->efx, drv, devlink->efx->net_dev,
+			  "Failed to get client ID for port index %u, rc %d\n",
+			  port->index, rc);
+		return rc;
+	}
+
+	MCDI_SET_DWORD(inbuf, SET_CLIENT_MAC_ADDRESSES_IN_CLIENT_HANDLE,
+		       client_id);
+
+	ether_addr_copy(MCDI_PTR(inbuf, SET_CLIENT_MAC_ADDRESSES_IN_MAC_ADDRS),
+			hw_addr);
+
+	rc = efx_mcdi_rpc(devlink->efx, MC_CMD_SET_CLIENT_MAC_ADDRESSES, inbuf,
+			  sizeof(inbuf), NULL, 0, NULL);
+
+	return rc;
+}
+
 static int efx_devlink_info_get(struct devlink *devlink,
 				struct devlink_info_req *req,
 				struct netlink_ext_ack *extack)
@@ -486,6 +529,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
 static const struct devlink_ops sfc_devlink_ops = {
 	.info_get			= efx_devlink_info_get,
 	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
+	.port_function_hw_addr_set	= efx_devlink_port_addr_set,
 };
 
 static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 11:31 ` [PATCH net-next 1/7] sfc: add " alejandro.lucero-palau
@ 2023-01-19 12:14   ` Jiri Pirko
  2023-01-19 14:51     ` Lucero Palau, Alejandro
  2023-01-19 15:50   ` kernel test robot
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 52+ messages in thread
From: Jiri Pirko @ 2023-01-19 12:14 UTC (permalink / raw)
  To: alejandro.lucero-palau
  Cc: netdev, linux-net-drivers, davem, kuba, pabeni, edumazet,
	habetsm, ecree.xilinx

Thu, Jan 19, 2023 at 12:31:34PM CET, alejandro.lucero-palau@amd.com wrote:
>From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>
>Basic support for devlink info command.
>
>Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>---
> drivers/net/ethernet/sfc/Kconfig       |   1 +
> drivers/net/ethernet/sfc/Makefile      |   3 +-
> drivers/net/ethernet/sfc/ef100_nic.c   |   6 +
> drivers/net/ethernet/sfc/efx_devlink.c | 427 +++++++++++++++++++++++++
> drivers/net/ethernet/sfc/efx_devlink.h |  20 ++
> drivers/net/ethernet/sfc/mcdi.c        |  72 +++++
> drivers/net/ethernet/sfc/mcdi.h        |   3 +
> drivers/net/ethernet/sfc/net_driver.h  |   2 +
> 8 files changed, 533 insertions(+), 1 deletion(-)
> create mode 100644 drivers/net/ethernet/sfc/efx_devlink.c
> create mode 100644 drivers/net/ethernet/sfc/efx_devlink.h

Could you please split?

At least the devlink introduction part and info implementation.


>
>diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
>index 0950e6b0508f..4af36ba8906b 100644
>--- a/drivers/net/ethernet/sfc/Kconfig
>+++ b/drivers/net/ethernet/sfc/Kconfig
>@@ -22,6 +22,7 @@ config SFC
> 	depends on PTP_1588_CLOCK_OPTIONAL
> 	select MDIO
> 	select CRC32
>+	select NET_DEVLINK
> 	help
> 	  This driver supports 10/40-gigabit Ethernet cards based on
> 	  the Solarflare SFC9100-family controllers.
>diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
>index 712a48d00069..55b9c73cd8ef 100644
>--- a/drivers/net/ethernet/sfc/Makefile
>+++ b/drivers/net/ethernet/sfc/Makefile
>@@ -6,7 +6,8 @@ sfc-y			+= efx.o efx_common.o efx_channels.o nic.o \
> 			   mcdi.o mcdi_port.o mcdi_port_common.o \
> 			   mcdi_functions.o mcdi_filters.o mcdi_mon.o \
> 			   ef100.o ef100_nic.o ef100_netdev.o \
>-			   ef100_ethtool.o ef100_rx.o ef100_tx.o
>+			   ef100_ethtool.o ef100_rx.o ef100_tx.o \
>+			   efx_devlink.o
> sfc-$(CONFIG_SFC_MTD)	+= mtd.o
> sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
>                            mae.o tc.o tc_bindings.o tc_counters.o
>diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>index ad686c671ab8..14af8f314b83 100644
>--- a/drivers/net/ethernet/sfc/ef100_nic.c
>+++ b/drivers/net/ethernet/sfc/ef100_nic.c
>@@ -27,6 +27,7 @@
> #include "tc.h"
> #include "mae.h"
> #include "rx_common.h"
>+#include "efx_devlink.h"
> 
> #define EF100_MAX_VIS 4096
> #define EF100_NUM_MCDI_BUFFERS	1
>@@ -1124,6 +1125,10 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
> 		netif_warn(efx, probe, net_dev,
> 			   "Failed to probe base mport rc %d; representors will not function\n",
> 			   rc);
>+	} else {
>+		if (efx_probe_devlink(efx))

I don't understand why the devlink register call is here.
1) You can registers it for PF and VF. I don't follow why you do it only
   for PF.
2) It should be done as the first thing in the probe flow. Then devlink
   port register, only after that netdev. It makes sense from the
   perspective of object hierarchy.

   It is also usual to have the devlink priv as the "main" driver
   structure storage, see how that is done in mlx5 of mlxsw for example.



>+			netif_warn(efx, probe, net_dev,
>+				   "Failed to register devlink\n");
> 	}
> 
> 	rc = efx_init_tc(efx);
>@@ -1157,6 +1162,7 @@ void ef100_remove(struct efx_nic *efx)
> {
> 	struct ef100_nic_data *nic_data = efx->nic_data;
> 
>+	efx_fini_devlink(efx);
> 	efx_mcdi_detach(efx);
> 	efx_mcdi_fini(efx);
> 	if (nic_data)
>diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>new file mode 100644
>index 000000000000..c506f8f35d25
>--- /dev/null
>+++ b/drivers/net/ethernet/sfc/efx_devlink.c
>@@ -0,0 +1,427 @@
>+// SPDX-License-Identifier: GPL-2.0-only
>+/****************************************************************************
>+ * Driver for AMD network controllers and boards
>+ * Copyright (C) 2023, Advanced Micro Devices, Inc.
>+ *
>+ * This program is free software; you can redistribute it and/or modify it
>+ * under the terms of the GNU General Public License version 2 as published
>+ * by the Free Software Foundation, incorporated herein by reference.
>+ */
>+
>+#include <linux/rtc.h>
>+#include "net_driver.h"
>+#include "ef100_nic.h"
>+#include "efx_devlink.h"
>+#include "nic.h"
>+#include "mcdi.h"
>+#include "mcdi_functions.h"
>+#include "mcdi_pcol.h"
>+
>+/* Custom devlink-info version object names for details that do not map to the
>+ * generic standardized names.
>+ */
>+#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC	"fw.mgmt.suc"
>+#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC	"fw.mgmt.cmc"
>+#define EFX_DEVLINK_INFO_VERSION_FPGA_REV	"fpga.rev"
>+#define EFX_DEVLINK_INFO_VERSION_DATAPATH_HW	"fpga.app"
>+#define EFX_DEVLINK_INFO_VERSION_DATAPATH_FW	DEVLINK_INFO_VERSION_GENERIC_FW_APP
>+#define EFX_DEVLINK_INFO_VERSION_SOC_BOOT	"coproc.boot"
>+#define EFX_DEVLINK_INFO_VERSION_SOC_UBOOT	"coproc.uboot"
>+#define EFX_DEVLINK_INFO_VERSION_SOC_MAIN	"coproc.main"
>+#define EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY	"coproc.recovery"
>+#define EFX_DEVLINK_INFO_VERSION_FW_EXPROM	"fw.exprom"
>+#define EFX_DEVLINK_INFO_VERSION_FW_UEFI	"fw.uefi"
>+
>+#define EFX_MAX_VERSION_INFO_LEN	64
>+
>+static int efx_devlink_info_nvram_partition(struct efx_nic *efx,
>+					    struct devlink_info_req *req,
>+					    unsigned int partition_type,
>+					    const char *version_name)
>+{
>+	char buf[EFX_MAX_VERSION_INFO_LEN];
>+	u16 version[4];
>+	int rc;
>+
>+	rc = efx_mcdi_nvram_metadata(efx, partition_type, NULL, version, NULL,
>+				     0);
>+	if (rc)
>+		return rc;
>+
>+	snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u", version[0],
>+		 version[1], version[2], version[3]);
>+	devlink_info_version_stored_put(req, version_name, buf);
>+
>+	return 0;
>+}
>+
>+static void efx_devlink_info_stored_versions(struct efx_nic *efx,
>+					     struct devlink_info_req *req)
>+{
>+	efx_devlink_info_nvram_partition(efx, req, NVRAM_PARTITION_TYPE_BUNDLE,
>+					 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID);
>+	efx_devlink_info_nvram_partition(efx, req,
>+					 NVRAM_PARTITION_TYPE_MC_FIRMWARE,
>+					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT);
>+	efx_devlink_info_nvram_partition(efx, req,
>+					 NVRAM_PARTITION_TYPE_SUC_FIRMWARE,
>+					 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC);
>+	efx_devlink_info_nvram_partition(efx, req,
>+					 NVRAM_PARTITION_TYPE_EXPANSION_ROM,
>+					 EFX_DEVLINK_INFO_VERSION_FW_EXPROM);
>+	efx_devlink_info_nvram_partition(efx, req,
>+					 NVRAM_PARTITION_TYPE_EXPANSION_UEFI,
>+					 EFX_DEVLINK_INFO_VERSION_FW_UEFI);
>+}
>+
>+#define EFX_MAX_SERIALNUM_LEN	(ETH_ALEN * 2 + 1)
>+
>+static void efx_devlink_info_board_cfg(struct efx_nic *efx,
>+				       struct devlink_info_req *req)
>+{
>+	char sn[EFX_MAX_SERIALNUM_LEN];
>+	u8 mac_address[ETH_ALEN];
>+	int rc;
>+
>+	rc = efx_mcdi_get_board_cfg(efx, (u8 *)mac_address, NULL, NULL);
>+	if (!rc) {
>+		snprintf(sn, EFX_MAX_SERIALNUM_LEN, "%pm", mac_address);
>+		devlink_info_serial_number_put(req, sn);
>+	}
>+}
>+
>+#define EFX_VER_FLAG(_f)	\
>+	(MC_CMD_GET_VERSION_V5_OUT_ ## _f ## _PRESENT_LBN)
>+
>+static void efx_devlink_info_running_versions(struct efx_nic *efx,
>+					      struct devlink_info_req *req)
>+{
>+	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_V5_OUT_LEN);
>+	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_VERSION_EXT_IN_LEN);
>+	char buf[EFX_MAX_VERSION_INFO_LEN];
>+	unsigned int flags, build_id;
>+	union {
>+		const __le32 *dwords;
>+		const __le16 *words;
>+		const char *str;
>+	} ver;
>+	struct rtc_time build_date;
>+	size_t outlength, offset;
>+	u64 tstamp;
>+	int rc;
>+
>+	rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, inbuf, sizeof(inbuf),
>+			  outbuf, sizeof(outbuf), &outlength);
>+	if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN)
>+		return;
>+
>+	/* Handle previous output */
>+	if (outlength < MC_CMD_GET_VERSION_V2_OUT_LEN) {
>+		ver.words = (__le16 *)MCDI_PTR(outbuf,
>+					       GET_VERSION_EXT_OUT_VERSION);
>+		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>+				  le16_to_cpu(ver.words[0]),
>+				  le16_to_cpu(ver.words[1]),
>+				  le16_to_cpu(ver.words[2]),
>+				  le16_to_cpu(ver.words[3]));
>+
>+		devlink_info_version_running_put(req,
>+						 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>+						 buf);
>+		return;
>+	}
>+
>+	/* Handle V2 additions */
>+	flags = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_FLAGS);
>+	if (flags & BIT(EFX_VER_FLAG(BOARD_EXT_INFO))) {
>+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%s",
>+			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_NAME));
>+		devlink_info_version_fixed_put(req,
>+					       DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
>+					       buf);
>+
>+		/* Favour full board version if present (in V5 or later) */
>+		if (~flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>+			snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u",
>+				 MCDI_DWORD(outbuf,
>+					    GET_VERSION_V2_OUT_BOARD_REVISION));
>+			devlink_info_version_fixed_put(req,
>+						       DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>+						       buf);
>+		}
>+
>+		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_SERIAL);
>+		if (ver.str[0])
>+			devlink_info_board_serial_number_put(req, ver.str);
>+	}
>+
>+	if (flags & BIT(EFX_VER_FLAG(FPGA_EXT_INFO))) {
>+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>+						GET_VERSION_V2_OUT_FPGA_VERSION);
>+		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u_%c%u",
>+				  le32_to_cpu(ver.dwords[0]),
>+				  'A' + le32_to_cpu(ver.dwords[1]),
>+				  le32_to_cpu(ver.dwords[2]));
>+
>+		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_FPGA_EXTRA);
>+		if (ver.str[0])
>+			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>+				 " (%s)", ver.str);
>+
>+		devlink_info_version_running_put(req,
>+						 EFX_DEVLINK_INFO_VERSION_FPGA_REV,
>+						 buf);
>+	}
>+
>+	if (flags & BIT(EFX_VER_FLAG(CMC_EXT_INFO))) {
>+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>+						GET_VERSION_V2_OUT_CMCFW_VERSION);
>+		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>+				  le32_to_cpu(ver.dwords[0]),
>+				  le32_to_cpu(ver.dwords[1]),
>+				  le32_to_cpu(ver.dwords[2]),
>+				  le32_to_cpu(ver.dwords[3]));
>+
>+		tstamp = MCDI_QWORD(outbuf,
>+				    GET_VERSION_V2_OUT_CMCFW_BUILD_DATE);
>+		if (tstamp) {
>+			rtc_time64_to_tm(tstamp, &build_date);
>+			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>+				 " (%ptRd)", &build_date);
>+		}
>+
>+		devlink_info_version_running_put(req,
>+						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC,
>+						 buf);
>+	}
>+
>+	ver.words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_V2_OUT_VERSION);
>+	offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>+			  le16_to_cpu(ver.words[0]), le16_to_cpu(ver.words[1]),
>+			  le16_to_cpu(ver.words[2]), le16_to_cpu(ver.words[3]));
>+	if (flags & BIT(EFX_VER_FLAG(MCFW_EXT_INFO))) {
>+		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_ID);
>+		snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>+			 " (%x) %s", build_id,
>+			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_NAME));
>+	}
>+	devlink_info_version_running_put(req,
>+					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>+					 buf);
>+
>+	if (flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>+						GET_VERSION_V2_OUT_SUCFW_VERSION);
>+		tstamp = MCDI_QWORD(outbuf,
>+				    GET_VERSION_V2_OUT_SUCFW_BUILD_DATE);
>+		rtc_time64_to_tm(tstamp, &build_date);
>+		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_SUCFW_CHIP_ID);
>+
>+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN,
>+			 "%u.%u.%u.%u type %x (%ptRd)",
>+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>+			 le32_to_cpu(ver.dwords[2]), le32_to_cpu(ver.dwords[3]),
>+			 build_id, &build_date);
>+
>+		devlink_info_version_running_put(req,
>+						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>+						 buf);
>+	}
>+
>+	if (outlength < MC_CMD_GET_VERSION_V3_OUT_LEN)
>+		return;
>+
>+	/* Handle V3 additions */
>+	if (flags & BIT(EFX_VER_FLAG(DATAPATH_HW_VERSION))) {
>+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>+						GET_VERSION_V3_OUT_DATAPATH_HW_VERSION);
>+
>+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>+			 le32_to_cpu(ver.dwords[2]));
>+
>+		devlink_info_version_running_put(req,
>+						 EFX_DEVLINK_INFO_VERSION_DATAPATH_HW,
>+						 buf);
>+	}
>+
>+	if (flags & BIT(EFX_VER_FLAG(DATAPATH_FW_VERSION))) {
>+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>+						GET_VERSION_V3_OUT_DATAPATH_FW_VERSION);
>+
>+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>+			 le32_to_cpu(ver.dwords[2]));
>+
>+		devlink_info_version_running_put(req,
>+						 EFX_DEVLINK_INFO_VERSION_DATAPATH_FW,
>+						 buf);
>+	}
>+
>+	if (outlength < MC_CMD_GET_VERSION_V4_OUT_LEN)
>+		return;
>+
>+	/* Handle V4 additions */
>+	if (flags & BIT(EFX_VER_FLAG(SOC_BOOT_VERSION))) {
>+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>+						GET_VERSION_V4_OUT_SOC_BOOT_VERSION);
>+
>+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>+			 le32_to_cpu(ver.dwords[2]),
>+			 le32_to_cpu(ver.dwords[3]));
>+
>+		devlink_info_version_running_put(req,
>+						 EFX_DEVLINK_INFO_VERSION_SOC_BOOT,
>+						 buf);
>+	}
>+
>+	if (flags & BIT(EFX_VER_FLAG(SOC_UBOOT_VERSION))) {
>+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>+						GET_VERSION_V4_OUT_SOC_UBOOT_VERSION);
>+
>+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>+			 le32_to_cpu(ver.dwords[2]),
>+			 le32_to_cpu(ver.dwords[3]));
>+
>+		devlink_info_version_running_put(req,
>+						 EFX_DEVLINK_INFO_VERSION_SOC_UBOOT,
>+						 buf);
>+	}
>+
>+	if (flags & BIT(EFX_VER_FLAG(SOC_MAIN_ROOTFS_VERSION))) {
>+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>+						GET_VERSION_V4_OUT_SOC_MAIN_ROOTFS_VERSION);
>+
>+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>+			 le32_to_cpu(ver.dwords[2]),
>+			 le32_to_cpu(ver.dwords[3]));
>+
>+		devlink_info_version_running_put(req,
>+						 EFX_DEVLINK_INFO_VERSION_SOC_MAIN,
>+						 buf);
>+	}
>+
>+	if (flags & BIT(EFX_VER_FLAG(SOC_RECOVERY_BUILDROOT_VERSION))) {
>+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>+						GET_VERSION_V4_OUT_SOC_RECOVERY_BUILDROOT_VERSION);
>+
>+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>+			 le32_to_cpu(ver.dwords[2]),
>+			 le32_to_cpu(ver.dwords[3]));
>+
>+		devlink_info_version_running_put(req,
>+						 EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY,
>+						 buf);
>+	}
>+
>+	if (flags & BIT(EFX_VER_FLAG(SUCFW_VERSION)) &&
>+	    ~flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>+						GET_VERSION_V4_OUT_SUCFW_VERSION);
>+
>+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>+			 le32_to_cpu(ver.dwords[2]),
>+			 le32_to_cpu(ver.dwords[3]));
>+
>+		devlink_info_version_running_put(req,
>+						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>+						 buf);
>+	}
>+
>+	if (outlength < MC_CMD_GET_VERSION_V5_OUT_LEN)
>+		return;
>+
>+	/* Handle V5 additions */
>+
>+	if (flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>+						GET_VERSION_V5_OUT_BOARD_VERSION);
>+
>+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>+			 le32_to_cpu(ver.dwords[2]),
>+			 le32_to_cpu(ver.dwords[3]));
>+
>+		devlink_info_version_running_put(req,
>+						 DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>+						 buf);
>+	}
>+
>+	if (flags & BIT(EFX_VER_FLAG(BUNDLE_VERSION))) {
>+		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>+						GET_VERSION_V5_OUT_BUNDLE_VERSION);
>+
>+		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>+			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>+			 le32_to_cpu(ver.dwords[2]),
>+			 le32_to_cpu(ver.dwords[3]));
>+
>+		devlink_info_version_running_put(req,
>+						 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
>+						 buf);
>+	}
>+}
>+
>+#undef EFX_VER_FLAG
>+
>+static void efx_devlink_info_query_all(struct efx_nic *efx,
>+				       struct devlink_info_req *req)
>+{
>+	efx_devlink_info_board_cfg(efx, req);
>+	efx_devlink_info_stored_versions(efx, req);
>+	efx_devlink_info_running_versions(efx, req);
>+}
>+
>+struct efx_devlink {
>+	struct efx_nic *efx;
>+};
>+
>+static int efx_devlink_info_get(struct devlink *devlink,
>+				struct devlink_info_req *req,
>+				struct netlink_ext_ack *extack)
>+{
>+	struct efx_devlink *devlink_private = devlink_priv(devlink);
>+	struct efx_nic *efx = devlink_private->efx;
>+
>+	efx_devlink_info_query_all(efx, req);

I don't understand the reason for having efx_devlink_info_query_all() as
a separate function in compare to inline its code here.


>+	return 0;
>+}
>+
>+static const struct devlink_ops sfc_devlink_ops = {
>+	.info_get			= efx_devlink_info_get,
>+};
>+
>+void efx_fini_devlink(struct efx_nic *efx)
>+{
>+	if (efx->devlink) {
>+		struct efx_devlink *devlink_private;
>+
>+		devlink_private = devlink_priv(efx->devlink);
>+
>+		devlink_unregister(efx->devlink);
>+		devlink_free(efx->devlink);
>+		efx->devlink = NULL;
>+	}
>+}
>+
>+int efx_probe_devlink(struct efx_nic *efx)
>+{
>+	struct efx_devlink *devlink_private;
>+
>+	efx->devlink = devlink_alloc(&sfc_devlink_ops,
>+				     sizeof(struct efx_devlink),
>+				     &efx->pci_dev->dev);
>+	if (!efx->devlink)
>+		return -ENOMEM;
>+	devlink_private = devlink_priv(efx->devlink);
>+	devlink_private->efx = efx;
>+
>+	devlink_register(efx->devlink);
>+
>+	return 0;
>+}
>diff --git a/drivers/net/ethernet/sfc/efx_devlink.h b/drivers/net/ethernet/sfc/efx_devlink.h
>new file mode 100644
>index 000000000000..997f878aea93
>--- /dev/null
>+++ b/drivers/net/ethernet/sfc/efx_devlink.h
>@@ -0,0 +1,20 @@
>+/* SPDX-License-Identifier: GPL-2.0-only */
>+/****************************************************************************
>+ * Driver for AMD network controllers and boards
>+ * Copyright (C) 2023, Advanced Micro Devices, Inc.
>+ *
>+ * This program is free software; you can redistribute it and/or modify it
>+ * under the terms of the GNU General Public License version 2 as published
>+ * by the Free Software Foundation, incorporated herein by reference.
>+ */
>+
>+#ifndef _EFX_DEVLINK_H
>+#define _EFX_DEVLINK_H
>+
>+#include "net_driver.h"
>+#include <net/devlink.h>
>+
>+int efx_probe_devlink(struct efx_nic *efx);
>+void efx_fini_devlink(struct efx_nic *efx);
>+
>+#endif	/* _EFX_DEVLINK_H */
>diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
>index af338208eae9..328cae82a7d8 100644
>--- a/drivers/net/ethernet/sfc/mcdi.c
>+++ b/drivers/net/ethernet/sfc/mcdi.c
>@@ -2308,6 +2308,78 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
> 	return rc;
> }
> 
>+int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>+			    u32 *subtype, u16 version[4], char *desc,
>+			    size_t descsize)
>+{
>+	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN);
>+	efx_dword_t *outbuf;
>+	size_t outlen;
>+	u32 flags;
>+	int rc;
>+
>+	outbuf = kzalloc(MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2, GFP_KERNEL);
>+	if (!outbuf)
>+		return -ENOMEM;
>+
>+	MCDI_SET_DWORD(inbuf, NVRAM_METADATA_IN_TYPE, type);
>+
>+	rc = efx_mcdi_rpc_quiet(efx, MC_CMD_NVRAM_METADATA, inbuf,
>+				sizeof(inbuf), outbuf,
>+				MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2,
>+				&outlen);
>+	if (rc)
>+		goto out_free;
>+	if (outlen < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
>+		rc = -EIO;
>+		goto out_free;
>+	}
>+
>+	flags = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_FLAGS);
>+
>+	if (desc && descsize > 0) {
>+		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_VALID_LBN)) {
>+			if (descsize <=
>+			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)) {
>+				rc = -E2BIG;
>+				goto out_free;
>+			}
>+
>+			strncpy(desc,
>+				MCDI_PTR(outbuf, NVRAM_METADATA_OUT_DESCRIPTION),
>+				MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen));
>+			desc[MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)] = '\0';
>+		} else {
>+			desc[0] = '\0';
>+		}
>+	}
>+
>+	if (subtype) {
>+		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_SUBTYPE_VALID_LBN))
>+			*subtype = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_SUBTYPE);
>+		else
>+			*subtype = 0;
>+	}
>+
>+	if (version) {
>+		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_VERSION_VALID_LBN)) {
>+			version[0] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_W);
>+			version[1] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_X);
>+			version[2] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Y);
>+			version[3] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Z);
>+		} else {
>+			version[0] = 0;
>+			version[1] = 0;
>+			version[2] = 0;
>+			version[3] = 0;
>+		}
>+	}
>+
>+out_free:
>+	kfree(outbuf);
>+	return rc;
>+}
>+
> int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
> 		      size_t len, size_t *retlen, u8 *buffer)
> {
>diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
>index 7e35fec9da35..63b090587f7a 100644
>--- a/drivers/net/ethernet/sfc/mcdi.h
>+++ b/drivers/net/ethernet/sfc/mcdi.h
>@@ -379,6 +379,9 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
> 			bool *protected_out);
> int efx_new_mcdi_nvram_test_all(struct efx_nic *efx);
> int efx_mcdi_nvram_test_all(struct efx_nic *efx);
>+int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>+			    u32 *subtype, u16 version[4], char *desc,
>+			    size_t descsize);
> int efx_mcdi_handle_assertion(struct efx_nic *efx);
> int efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
> int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac,
>diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
>index 3b49e216768b..d036641dc043 100644
>--- a/drivers/net/ethernet/sfc/net_driver.h
>+++ b/drivers/net/ethernet/sfc/net_driver.h
>@@ -994,6 +994,7 @@ enum efx_xdp_tx_queues_mode {
>  *      xdp_rxq_info structures?
>  * @netdev_notifier: Netdevice notifier.
>  * @tc: state for TC offload (EF100).
>+ * @devlink: reference to devlink structure owned by this device
>  * @mem_bar: The BAR that is mapped into membase.
>  * @reg_base: Offset from the start of the bar to the function control window.
>  * @monitor_work: Hardware monitor workitem
>@@ -1179,6 +1180,7 @@ struct efx_nic {
> 	struct notifier_block netdev_notifier;
> 	struct efx_tc_state *tc;
> 
>+	struct devlink *devlink;
> 	unsigned int mem_bar;
> 	u32 reg_base;
> 
>-- 
>2.17.1
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-19 11:31 ` [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100 alejandro.lucero-palau
@ 2023-01-19 12:25   ` Jiri Pirko
  2023-01-19 14:59     ` Lucero Palau, Alejandro
  2023-01-19 12:37   ` Jiri Pirko
  1 sibling, 1 reply; 52+ messages in thread
From: Jiri Pirko @ 2023-01-19 12:25 UTC (permalink / raw)
  To: alejandro.lucero-palau
  Cc: netdev, linux-net-drivers, davem, kuba, pabeni, edumazet,
	habetsm, ecree.xilinx

Thu, Jan 19, 2023 at 12:31:39PM CET, alejandro.lucero-palau@amd.com wrote:
>From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>
>Using the builtin client handle id infrastructure, this patch adds
>support for obtaining the mac address linked to mports in ef100. This
>implies to execute an MCDI command for getting the data from the
>firmware for each devlink port.
>
>Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>---
> drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
> drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
> drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
> drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
> 5 files changed, 81 insertions(+)
>
>diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>index f4e913593f2b..4400ce622228 100644
>--- a/drivers/net/ethernet/sfc/ef100_nic.c
>+++ b/drivers/net/ethernet/sfc/ef100_nic.c
>@@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
> 	return rc;
> }
> 
>+/* MCDI commands are related to the same device issuing them. This function
>+ * allows to do an MCDI command on behalf of another device, mainly PFs setting
>+ * things for VFs.
>+ */
>+int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
>+{
>+	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
>+	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
>+	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
>+	size_t outlen;
>+	int rc;
>+
>+	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
>+		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
>+	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
>+		       pciefn_flat);
>+
>+	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
>+			  outbuf, sizeof(outbuf), &outlen);
>+	if (rc)
>+		return rc;
>+	if (outlen < sizeof(outbuf))
>+		return -EIO;
>+	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
>+	return 0;
>+}
>+
> int ef100_probe_netdev_pf(struct efx_nic *efx)
> {
> 	struct ef100_nic_data *nic_data = efx->nic_data;
>diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>index e59044072333..f1ed481c1260 100644
>--- a/drivers/net/ethernet/sfc/ef100_nic.h
>+++ b/drivers/net/ethernet/sfc/ef100_nic.h
>@@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
> 
> int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
> 			  int client_handle, bool empty_ok);
>+int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
> #endif	/* EFX_EF100_NIC_H */
>diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>index ff0c8da61919..974c9ff901a0 100644
>--- a/drivers/net/ethernet/sfc/ef100_rep.c
>+++ b/drivers/net/ethernet/sfc/ef100_rep.c
>@@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
> 		     mport_desc->interface_idx == nic_data->local_mae_intf;
> }
> 
>+bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
>+{
>+	bool pcie_func;
>+
>+	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>+	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
>+}
>+
> void efx_ef100_init_reps(struct efx_nic *efx)
> {
> 	struct ef100_nic_data *nic_data = efx->nic_data;
>diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>index 9cca41614982..74853ccbc937 100644
>--- a/drivers/net/ethernet/sfc/ef100_rep.h
>+++ b/drivers/net/ethernet/sfc/ef100_rep.h
>@@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
> struct mae_mport_desc;
> bool ef100_mport_on_local_intf(struct efx_nic *efx,
> 			       struct mae_mport_desc *mport_desc);
>+bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
> #endif /* EF100_REP_H */
>diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>index bb19d3ad7ffd..2a57c4f6d2b2 100644
>--- a/drivers/net/ethernet/sfc/efx_devlink.c
>+++ b/drivers/net/ethernet/sfc/efx_devlink.c
>@@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
> 	return err;
> }
> 
>+static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>+				     int *hw_addr_len,
>+				     struct netlink_ext_ack *extack)
>+{
>+	struct efx_devlink *devlink = devlink_priv(port->devlink);
>+	struct mae_mport_desc *mport_desc;
>+	efx_qword_t pciefn;
>+	u32 client_id;
>+	int rc = 0;
>+
>+	mport_desc = efx_mae_get_mport(devlink->efx, port->index);

Dont use port->index, never. It's devlink internal. You have port
pointer passed here. Usually, what drivers do is to embed
the struct devlink_port in the driver port struct. Then you do just
simple container of to get it here. Mlxsw example:

static void *__dl_port(struct devlink_port *devlink_port)
{
        return container_of(devlink_port, struct mlxsw_core_port, devlink_port);
}

static int mlxsw_devlink_port_split(struct devlink *devlink,
                                    struct devlink_port *port,
                                    unsigned int count,
                                    struct netlink_ext_ack *extack)
{
        struct mlxsw_core_port *mlxsw_core_port = __dl_port(port);
...



>+	if (!mport_desc)

Tell the user what's wrong, extack is here for that.



>+		return -EINVAL;
>+
>+	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
>+		goto out;
>+
>+	if (ef100_mport_is_vf(mport_desc))
>+		EFX_POPULATE_QWORD_3(pciefn,
>+				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>+				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>+				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>+	else
>+		EFX_POPULATE_QWORD_3(pciefn,
>+				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
>+				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
>+				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>+
>+	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>+	if (rc) {
>+		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>+			  "Failed to get client ID for port index %u, rc %d\n",
>+			  port->index, rc);

Don't write to dmesg, use extack msg instead.


>+		return rc;
>+	}
>+
>+	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);

Again, extack would be nice here if (rc)


>+out:
>+	*hw_addr_len = ETH_ALEN;
>+
>+	return rc;
>+}
>+
> static int efx_devlink_info_get(struct devlink *devlink,
> 				struct devlink_info_req *req,
> 				struct netlink_ext_ack *extack)
>@@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
> 
> static const struct devlink_ops sfc_devlink_ops = {
> 	.info_get			= efx_devlink_info_get,
>+	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
> };
> 
> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>-- 
>2.17.1
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 7/7] sfc: add support for devlink port_function_hw_addr_set in ef100
  2023-01-19 11:31 ` [PATCH net-next 7/7] sfc: add support for devlink port_function_hw_addr_set " alejandro.lucero-palau
@ 2023-01-19 12:27   ` Jiri Pirko
  2023-01-19 15:10     ` Lucero Palau, Alejandro
  0 siblings, 1 reply; 52+ messages in thread
From: Jiri Pirko @ 2023-01-19 12:27 UTC (permalink / raw)
  To: alejandro.lucero-palau
  Cc: netdev, linux-net-drivers, davem, kuba, pabeni, edumazet,
	habetsm, ecree.xilinx

Thu, Jan 19, 2023 at 12:31:40PM CET, alejandro.lucero-palau@amd.com wrote:
>From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>
>Using the builtin client handle id infrastructure, this patch adds
>support for setting the mac address linked to mports in ef100. This
>implies to execute an MCDI command for giving the address to the
>firmware for the specific devlink port.
>
>Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>---
> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
> 1 file changed, 44 insertions(+)
>
>diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>index 2a57c4f6d2b2..a85b2d4e54ab 100644
>--- a/drivers/net/ethernet/sfc/efx_devlink.c
>+++ b/drivers/net/ethernet/sfc/efx_devlink.c
>@@ -472,6 +472,49 @@ static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
> 	return rc;
> }
> 
>+static int efx_devlink_port_addr_set(struct devlink_port *port,

Similar comments here as for the _get callback: embed devlink_port
struct, use extack.


>+				     const u8 *hw_addr, int hw_addr_len,
>+				     struct netlink_ext_ack *extack)
>+{
>+	MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_CLIENT_MAC_ADDRESSES_IN_LEN(1));
>+	struct efx_devlink *devlink = devlink_priv(port->devlink);
>+	struct mae_mport_desc *mport_desc;
>+	efx_qword_t pciefn;
>+	u32 client_id;
>+	int rc;
>+
>+	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
>+	if (!mport_desc)
>+		return -EINVAL;
>+
>+	if (!ef100_mport_is_vf(mport_desc))
>+		return -EPERM;
>+
>+	EFX_POPULATE_QWORD_3(pciefn,
>+			     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>+			     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>+			     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>+
>+	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>+	if (rc) {
>+		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>+			  "Failed to get client ID for port index %u, rc %d\n",
>+			  port->index, rc);
>+		return rc;
>+	}
>+
>+	MCDI_SET_DWORD(inbuf, SET_CLIENT_MAC_ADDRESSES_IN_CLIENT_HANDLE,
>+		       client_id);
>+
>+	ether_addr_copy(MCDI_PTR(inbuf, SET_CLIENT_MAC_ADDRESSES_IN_MAC_ADDRS),
>+			hw_addr);
>+
>+	rc = efx_mcdi_rpc(devlink->efx, MC_CMD_SET_CLIENT_MAC_ADDRESSES, inbuf,
>+			  sizeof(inbuf), NULL, 0, NULL);
>+
>+	return rc;
>+}
>+
> static int efx_devlink_info_get(struct devlink *devlink,
> 				struct devlink_info_req *req,
> 				struct netlink_ext_ack *extack)
>@@ -486,6 +529,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
> static const struct devlink_ops sfc_devlink_ops = {
> 	.info_get			= efx_devlink_info_get,
> 	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
>+	.port_function_hw_addr_set	= efx_devlink_port_addr_set,
> };
> 
> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>-- 
>2.17.1
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 4/7] sfc: add devlink port support for ef100
  2023-01-19 11:31 ` [PATCH net-next 4/7] sfc: add devlink port support for ef100 alejandro.lucero-palau
@ 2023-01-19 12:33   ` Jiri Pirko
  2023-01-19 15:03     ` Lucero Palau, Alejandro
  2023-01-19 13:37   ` kernel test robot
  2023-01-20 21:21   ` kernel test robot
  2 siblings, 1 reply; 52+ messages in thread
From: Jiri Pirko @ 2023-01-19 12:33 UTC (permalink / raw)
  To: alejandro.lucero-palau
  Cc: netdev, linux-net-drivers, davem, kuba, pabeni, edumazet,
	habetsm, ecree.xilinx

Thu, Jan 19, 2023 at 12:31:37PM CET, alejandro.lucero-palau@amd.com wrote:
>From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>
>Using the data when enumerating mports, create devlink ports just before
>netdevs are registered and removing those devlink ports after netdev has
>been unregister.
>
>Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>---
> drivers/net/ethernet/sfc/ef100_netdev.c |  14 ++-
> drivers/net/ethernet/sfc/ef100_rep.c    |  23 +++++
> drivers/net/ethernet/sfc/ef100_rep.h    |   6 ++
> drivers/net/ethernet/sfc/efx_devlink.c  | 114 ++++++++++++++++++++++++
> drivers/net/ethernet/sfc/efx_devlink.h  |   7 ++
> drivers/net/ethernet/sfc/net_driver.h   |   1 +
> 6 files changed, 161 insertions(+), 4 deletions(-)
>
>diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c
>index ddcc325ed570..4a5d028f757e 100644
>--- a/drivers/net/ethernet/sfc/ef100_netdev.c
>+++ b/drivers/net/ethernet/sfc/ef100_netdev.c
>@@ -24,6 +24,7 @@
> #include "rx_common.h"
> #include "ef100_sriov.h"
> #include "tc_bindings.h"
>+#include "efx_devlink.h"
> 
> static void ef100_update_name(struct efx_nic *efx)
> {
>@@ -280,6 +281,9 @@ static int ef100_register_netdev(struct efx_nic *efx)
> 	net_dev->max_mtu = EFX_MAX_MTU;
> 	net_dev->ethtool_ops = &ef100_ethtool_ops;
> 
>+	if (!efx->type->is_vf)
>+		ef100_pf_set_devlink_port(efx);

Again, why no port for VF while you are at it?


>+
> 	rtnl_lock();
> 
> 	rc = dev_alloc_name(net_dev, net_dev->name);
>@@ -302,6 +306,7 @@ static int ef100_register_netdev(struct efx_nic *efx)
> 
> fail_locked:
> 	rtnl_unlock();
>+	ef100_pf_unset_devlink_port(efx);
> 	netif_err(efx, drv, efx->net_dev, "could not register net dev\n");
> 	return rc;
> }
>@@ -312,6 +317,7 @@ static void ef100_unregister_netdev(struct efx_nic *efx)
> 		efx_fini_mcdi_logging(efx);
> 		efx->state = STATE_PROBED;
> 		unregister_netdev(efx->net_dev);
>+		ef100_pf_unset_devlink_port(efx);
> 	}
> }
> 
>@@ -405,16 +411,16 @@ int ef100_probe_netdev(struct efx_probe_data *probe_data)
> 	/* Don't fail init if RSS setup doesn't work. */
> 	efx_mcdi_push_default_indir_table(efx, efx->n_rx_channels);
> 
>-	rc = ef100_register_netdev(efx);
>-	if (rc)
>-		goto fail;
>-
> 	if (!efx->type->is_vf) {
> 		rc = ef100_probe_netdev_pf(efx);
> 		if (rc)
> 			goto fail;
> 	}
> 
>+	rc = ef100_register_netdev(efx);
>+	if (rc)
>+		goto fail;
>+
> 	efx->netdev_notifier.notifier_call = ef100_netdev_event;
> 	rc = register_netdevice_notifier(&efx->netdev_notifier);
> 	if (rc) {
>diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>index 9cd1a3ac67e0..ff0c8da61919 100644
>--- a/drivers/net/ethernet/sfc/ef100_rep.c
>+++ b/drivers/net/ethernet/sfc/ef100_rep.c
>@@ -16,6 +16,7 @@
> #include "mae.h"
> #include "rx_common.h"
> #include "tc_bindings.h"
>+#include "efx_devlink.h"
> 
> #define EFX_EF100_REP_DRIVER	"efx_ef100_rep"
> 
>@@ -297,6 +298,7 @@ int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i)
> 			i, rc);
> 		goto fail1;
> 	}
>+	ef100_rep_set_devlink_port(efv);
> 	rc = register_netdev(efv->net_dev);
> 	if (rc) {
> 		pci_err(efx->pci_dev,
>@@ -304,10 +306,12 @@ int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i)
> 			i, rc);
> 		goto fail2;
> 	}
>+
> 	pci_dbg(efx->pci_dev, "Representor for VF %d is %s\n", i,
> 		efv->net_dev->name);
> 	return 0;
> fail2:
>+	ef100_rep_unset_devlink_port(efv);
> 	efx_ef100_deconfigure_rep(efv);
> fail1:
> 	efx_ef100_rep_destroy_netdev(efv);
>@@ -323,6 +327,7 @@ void efx_ef100_vfrep_destroy(struct efx_nic *efx, struct efx_rep *efv)
> 		return;
> 	netif_dbg(efx, drv, rep_dev, "Removing VF representor\n");
> 	unregister_netdev(rep_dev);
>+	ef100_rep_unset_devlink_port(efv);
> 	efx_ef100_deconfigure_rep(efv);
> 	efx_ef100_rep_destroy_netdev(efv);
> }
>@@ -339,6 +344,24 @@ void efx_ef100_fini_vfreps(struct efx_nic *efx)
> 		efx_ef100_vfrep_destroy(efx, efv);
> }
> 
>+bool ef100_mport_is_pcie_vnic(struct mae_mport_desc *mport_desc)
>+{
>+	return mport_desc->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC &&
>+	       mport_desc->vnic_client_type == MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION;
>+}
>+
>+bool ef100_mport_on_local_intf(struct efx_nic *efx,
>+			       struct mae_mport_desc *mport_desc)
>+{
>+	bool pcie_func;
>+	struct ef100_nic_data *nic_data = efx->nic_data;

Reverse christmas tree ordering please:
***************
*********
****




>+
>+	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>+
>+	return nic_data->have_local_intf && pcie_func &&
>+		     mport_desc->interface_idx == nic_data->local_mae_intf;
>+}
>+
> void efx_ef100_init_reps(struct efx_nic *efx)
> {
> 	struct ef100_nic_data *nic_data = efx->nic_data;
>diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>index 328ac0cbb532..9cca41614982 100644
>--- a/drivers/net/ethernet/sfc/ef100_rep.h
>+++ b/drivers/net/ethernet/sfc/ef100_rep.h
>@@ -22,6 +22,8 @@ struct efx_rep_sw_stats {
> 	atomic64_t rx_dropped, tx_errors;
> };
> 
>+struct devlink_port;
>+
> /**
>  * struct efx_rep - Private data for an Efx representor
>  *
>@@ -54,6 +56,7 @@ struct efx_rep {
> 	spinlock_t rx_lock;
> 	struct napi_struct napi;
> 	struct efx_rep_sw_stats stats;
>+	struct devlink_port *dl_port;
> };
> 
> int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i);
>@@ -69,4 +72,7 @@ struct efx_rep *efx_ef100_find_rep_by_mport(struct efx_nic *efx, u16 mport);
> extern const struct net_device_ops efx_ef100_rep_netdev_ops;
> void efx_ef100_init_reps(struct efx_nic *efx);
> void efx_ef100_fini_reps(struct efx_nic *efx);
>+struct mae_mport_desc;
>+bool ef100_mport_on_local_intf(struct efx_nic *efx,
>+			       struct mae_mport_desc *mport_desc);
> #endif /* EF100_REP_H */
>diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>index c506f8f35d25..bb19d3ad7ffd 100644
>--- a/drivers/net/ethernet/sfc/efx_devlink.c
>+++ b/drivers/net/ethernet/sfc/efx_devlink.c
>@@ -16,6 +16,8 @@
> #include "mcdi.h"
> #include "mcdi_functions.h"
> #include "mcdi_pcol.h"
>+#include "mae.h"
>+#include "ef100_rep.h"
> 
> /* Custom devlink-info version object names for details that do not map to the
>  * generic standardized names.
>@@ -381,6 +383,52 @@ struct efx_devlink {
> 	struct efx_nic *efx;
> };
> 
>+static void efx_devlink_del_port(struct devlink_port *dl_port)
>+{
>+	if (!dl_port)
>+		return;
>+	devlink_port_unregister(dl_port);
>+	kfree(dl_port);
>+}
>+
>+static int efx_devlink_add_port(struct efx_nic *efx,
>+				struct mae_mport_desc *mport,
>+				struct devlink_port *dl_port)
>+{
>+	struct devlink_port_attrs attrs = {};
>+	bool external = false;
>+	int err;
>+
>+	if (!ef100_mport_on_local_intf(efx, mport))
>+		external = true;
>+
>+	switch (mport->mport_type) {
>+	case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
>+		attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
>+		attrs.phys.port_number = mport->port_idx;
>+		devlink_port_attrs_set(dl_port, &attrs);
>+		break;
>+	case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
>+		if (mport->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL) {

No need for {}'s in this if-else


>+			devlink_port_attrs_pci_vf_set(dl_port, 0, mport->pf_idx,
>+						      mport->vf_idx,
>+						      external);
>+		} else {
>+			devlink_port_attrs_pci_pf_set(dl_port, 0, mport->pf_idx,
>+						      external);
>+		}
>+		break;
>+	default:
>+		/* MAE_MPORT_DESC_MPORT_ALIAS and UNDEFINED */
>+		return 0;
>+	}
>+
>+	dl_port->index = mport->mport_id;
>+	err = devlink_port_register(efx->devlink, dl_port, mport->mport_id);

Just return.


>+
>+	return err;
>+}
>+
> static int efx_devlink_info_get(struct devlink *devlink,
> 				struct devlink_info_req *req,
> 				struct netlink_ext_ack *extack)
>@@ -396,6 +444,72 @@ static const struct devlink_ops sfc_devlink_ops = {
> 	.info_get			= efx_devlink_info_get,
> };
> 
>+static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>+{
>+	struct mae_mport_desc *mport;
>+	struct devlink_port *dl_port;
>+	u32 id;
>+
>+	if (efx_mae_lookup_mport(efx, idx, &id)) {
>+		/* This should not happen. */
>+		if (idx == MAE_MPORT_DESC_VF_IDX_NULL)
>+			pci_warn(efx->pci_dev, "No mport ID found for PF.\n");
>+		else
>+			pci_warn(efx->pci_dev, "No mport ID found for VF %u.\n",
>+				 idx);
>+		return NULL;
>+	}
>+
>+	mport = efx_mae_get_mport(efx, id);
>+	if (!mport) {
>+		/* This should not happen. */
>+		if (idx == MAE_MPORT_DESC_VF_IDX_NULL)
>+			pci_warn(efx->pci_dev, "No mport found for PF.\n");
>+		else
>+			pci_warn(efx->pci_dev, "No mport found for VF %u.\n",
>+				 idx);
>+		return NULL;
>+	}
>+
>+	dl_port = kzalloc(sizeof(*dl_port), GFP_KERNEL);
>+	if (!dl_port)
>+		return NULL;
>+
>+	if (efx_devlink_add_port(efx, mport, dl_port)) {
>+		if (idx == MAE_MPORT_DESC_VF_IDX_NULL)
>+			pci_warn(efx->pci_dev,
>+				 "devlink port creation for PF failed.\n");
>+		else
>+			pci_warn(efx->pci_dev,
>+				 "devlink_port creationg for VF %u failed.\n",
>+				 idx);
>+		kfree(dl_port);
>+		return NULL;
>+	}
>+
>+	return dl_port;
>+}
>+
>+void ef100_rep_set_devlink_port(struct efx_rep *efv)
>+{
>+	efv->dl_port = ef100_set_devlink_port(efv->parent, efv->idx);
>+}
>+
>+void ef100_pf_set_devlink_port(struct efx_nic *efx)
>+{
>+	efx->dl_port = ef100_set_devlink_port(efx, MAE_MPORT_DESC_VF_IDX_NULL);
>+}
>+
>+void ef100_rep_unset_devlink_port(struct efx_rep *efv)
>+{
>+	efx_devlink_del_port(efv->dl_port);
>+}
>+
>+void ef100_pf_unset_devlink_port(struct efx_nic *efx)
>+{
>+	efx_devlink_del_port(efx->dl_port);
>+}
>+
> void efx_fini_devlink(struct efx_nic *efx)
> {
> 	if (efx->devlink) {
>diff --git a/drivers/net/ethernet/sfc/efx_devlink.h b/drivers/net/ethernet/sfc/efx_devlink.h
>index 997f878aea93..a834c393a9ad 100644
>--- a/drivers/net/ethernet/sfc/efx_devlink.h
>+++ b/drivers/net/ethernet/sfc/efx_devlink.h
>@@ -17,4 +17,11 @@
> int efx_probe_devlink(struct efx_nic *efx);
> void efx_fini_devlink(struct efx_nic *efx);
> 
>+struct mae_mport_desc;
>+struct efx_rep;
>+
>+void ef100_pf_set_devlink_port(struct efx_nic *efx);
>+void ef100_rep_set_devlink_port(struct efx_rep *efv);
>+void ef100_pf_unset_devlink_port(struct efx_nic *efx);
>+void ef100_rep_unset_devlink_port(struct efx_rep *efv);
> #endif	/* _EFX_DEVLINK_H */
>diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
>index bc9efbfb3d6b..20f43695d082 100644
>--- a/drivers/net/ethernet/sfc/net_driver.h
>+++ b/drivers/net/ethernet/sfc/net_driver.h
>@@ -1185,6 +1185,7 @@ struct efx_nic {
> 	struct efx_tc_state *tc;
> 
> 	struct devlink *devlink;
>+	struct devlink_port *dl_port;
> 	unsigned int mem_bar;
> 	u32 reg_base;
> 
>-- 
>2.17.1
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-19 11:31 ` [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100 alejandro.lucero-palau
  2023-01-19 12:25   ` Jiri Pirko
@ 2023-01-19 12:37   ` Jiri Pirko
  2023-01-19 15:09     ` Lucero Palau, Alejandro
  1 sibling, 1 reply; 52+ messages in thread
From: Jiri Pirko @ 2023-01-19 12:37 UTC (permalink / raw)
  To: alejandro.lucero-palau
  Cc: netdev, linux-net-drivers, davem, kuba, pabeni, edumazet,
	habetsm, ecree.xilinx

Thu, Jan 19, 2023 at 12:31:39PM CET, alejandro.lucero-palau@amd.com wrote:
>From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>
>Using the builtin client handle id infrastructure, this patch adds
>support for obtaining the mac address linked to mports in ef100. This
>implies to execute an MCDI command for getting the data from the
>firmware for each devlink port.
>
>Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>---
> drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
> drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
> drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
> drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
> 5 files changed, 81 insertions(+)
>
>diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>index f4e913593f2b..4400ce622228 100644
>--- a/drivers/net/ethernet/sfc/ef100_nic.c
>+++ b/drivers/net/ethernet/sfc/ef100_nic.c
>@@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
> 	return rc;
> }
> 
>+/* MCDI commands are related to the same device issuing them. This function
>+ * allows to do an MCDI command on behalf of another device, mainly PFs setting
>+ * things for VFs.
>+ */
>+int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
>+{
>+	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
>+	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
>+	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
>+	size_t outlen;
>+	int rc;
>+
>+	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
>+		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
>+	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
>+		       pciefn_flat);
>+
>+	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
>+			  outbuf, sizeof(outbuf), &outlen);
>+	if (rc)
>+		return rc;
>+	if (outlen < sizeof(outbuf))
>+		return -EIO;
>+	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
>+	return 0;
>+}
>+
> int ef100_probe_netdev_pf(struct efx_nic *efx)
> {
> 	struct ef100_nic_data *nic_data = efx->nic_data;
>diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>index e59044072333..f1ed481c1260 100644
>--- a/drivers/net/ethernet/sfc/ef100_nic.h
>+++ b/drivers/net/ethernet/sfc/ef100_nic.h
>@@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
> 
> int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
> 			  int client_handle, bool empty_ok);
>+int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
> #endif	/* EFX_EF100_NIC_H */
>diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>index ff0c8da61919..974c9ff901a0 100644
>--- a/drivers/net/ethernet/sfc/ef100_rep.c
>+++ b/drivers/net/ethernet/sfc/ef100_rep.c
>@@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
> 		     mport_desc->interface_idx == nic_data->local_mae_intf;
> }
> 
>+bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
>+{
>+	bool pcie_func;
>+
>+	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>+	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
>+}
>+
> void efx_ef100_init_reps(struct efx_nic *efx)
> {
> 	struct ef100_nic_data *nic_data = efx->nic_data;
>diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>index 9cca41614982..74853ccbc937 100644
>--- a/drivers/net/ethernet/sfc/ef100_rep.h
>+++ b/drivers/net/ethernet/sfc/ef100_rep.h
>@@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
> struct mae_mport_desc;
> bool ef100_mport_on_local_intf(struct efx_nic *efx,
> 			       struct mae_mport_desc *mport_desc);
>+bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
> #endif /* EF100_REP_H */
>diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>index bb19d3ad7ffd..2a57c4f6d2b2 100644
>--- a/drivers/net/ethernet/sfc/efx_devlink.c
>+++ b/drivers/net/ethernet/sfc/efx_devlink.c
>@@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
> 	return err;
> }
> 
>+static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>+				     int *hw_addr_len,
>+				     struct netlink_ext_ack *extack)
>+{
>+	struct efx_devlink *devlink = devlink_priv(port->devlink);
>+	struct mae_mport_desc *mport_desc;
>+	efx_qword_t pciefn;
>+	u32 client_id;
>+	int rc = 0;
>+
>+	mport_desc = efx_mae_get_mport(devlink->efx, port->index);

I may be missing something, where do you fail with -EOPNOTSUPP
in case this is called for PHYSICAL port ?



>+	if (!mport_desc)
>+		return -EINVAL;
>+
>+	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
>+		goto out;
>+
>+	if (ef100_mport_is_vf(mport_desc))
>+		EFX_POPULATE_QWORD_3(pciefn,
>+				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>+				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>+				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>+	else
>+		EFX_POPULATE_QWORD_3(pciefn,
>+				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
>+				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
>+				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>+
>+	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>+	if (rc) {
>+		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>+			  "Failed to get client ID for port index %u, rc %d\n",
>+			  port->index, rc);
>+		return rc;
>+	}
>+
>+	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
>+out:
>+	*hw_addr_len = ETH_ALEN;
>+
>+	return rc;
>+}
>+
> static int efx_devlink_info_get(struct devlink *devlink,
> 				struct devlink_info_req *req,
> 				struct netlink_ext_ack *extack)
>@@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
> 
> static const struct devlink_ops sfc_devlink_ops = {
> 	.info_get			= efx_devlink_info_get,
>+	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
> };
> 
> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>-- 
>2.17.1
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 4/7] sfc: add devlink port support for ef100
  2023-01-19 11:31 ` [PATCH net-next 4/7] sfc: add devlink port support for ef100 alejandro.lucero-palau
  2023-01-19 12:33   ` Jiri Pirko
@ 2023-01-19 13:37   ` kernel test robot
  2023-01-20 21:21   ` kernel test robot
  2 siblings, 0 replies; 52+ messages in thread
From: kernel test robot @ 2023-01-19 13:37 UTC (permalink / raw)
  To: alejandro.lucero-palau, netdev, linux-net-drivers
  Cc: oe-kbuild-all, davem, kuba, pabeni, edumazet, habetsm,
	ecree.xilinx, Alejandro Lucero

Hi,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/alejandro-lucero-palau-amd-com/sfc-add-devlink-support-for-ef100/20230119-193440
patch link:    https://lore.kernel.org/r/20230119113140.20208-5-alejandro.lucero-palau%40amd.com
patch subject: [PATCH net-next 4/7] sfc: add devlink port support for ef100
config: ia64-allyesconfig (https://download.01.org/0day-ci/archive/20230119/202301192118.a5QmN0m8-lkp@intel.com/config)
compiler: ia64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/5b06b1ae6605af55ed8127878054f8d69046b83c
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review alejandro-lucero-palau-amd-com/sfc-add-devlink-support-for-ef100/20230119-193440
        git checkout 5b06b1ae6605af55ed8127878054f8d69046b83c
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=ia64 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=ia64 SHELL=/bin/bash drivers/net/ethernet/sfc/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/net/ethernet/sfc/ef100_rep.c:347:6: warning: no previous prototype for 'ef100_mport_is_pcie_vnic' [-Wmissing-prototypes]
     347 | bool ef100_mport_is_pcie_vnic(struct mae_mport_desc *mport_desc)
         |      ^~~~~~~~~~~~~~~~~~~~~~~~


vim +/ef100_mport_is_pcie_vnic +347 drivers/net/ethernet/sfc/ef100_rep.c

   346	
 > 347	bool ef100_mport_is_pcie_vnic(struct mae_mport_desc *mport_desc)
   348	{
   349		return mport_desc->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC &&
   350		       mport_desc->vnic_client_type == MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION;
   351	}
   352	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 12:14   ` Jiri Pirko
@ 2023-01-19 14:51     ` Lucero Palau, Alejandro
  2023-01-19 16:29       ` Lucero Palau, Alejandro
  2023-01-20 11:00       ` Jiri Pirko
  0 siblings, 2 replies; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-19 14:51 UTC (permalink / raw)
  To: Jiri Pirko, Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx


On 1/19/23 12:14, Jiri Pirko wrote:
> Thu, Jan 19, 2023 at 12:31:34PM CET, alejandro.lucero-palau@amd.com wrote:
>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>
>> Basic support for devlink info command.
>>
>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>> ---
>> drivers/net/ethernet/sfc/Kconfig       |   1 +
>> drivers/net/ethernet/sfc/Makefile      |   3 +-
>> drivers/net/ethernet/sfc/ef100_nic.c   |   6 +
>> drivers/net/ethernet/sfc/efx_devlink.c | 427 +++++++++++++++++++++++++
>> drivers/net/ethernet/sfc/efx_devlink.h |  20 ++
>> drivers/net/ethernet/sfc/mcdi.c        |  72 +++++
>> drivers/net/ethernet/sfc/mcdi.h        |   3 +
>> drivers/net/ethernet/sfc/net_driver.h  |   2 +
>> 8 files changed, 533 insertions(+), 1 deletion(-)
>> create mode 100644 drivers/net/ethernet/sfc/efx_devlink.c
>> create mode 100644 drivers/net/ethernet/sfc/efx_devlink.h
> Could you please split?
>
> At least the devlink introduction part and info implementation.
> 

Sure.

>> diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
>> index 0950e6b0508f..4af36ba8906b 100644
>> --- a/drivers/net/ethernet/sfc/Kconfig
>> +++ b/drivers/net/ethernet/sfc/Kconfig
>> @@ -22,6 +22,7 @@ config SFC
>> 	depends on PTP_1588_CLOCK_OPTIONAL
>> 	select MDIO
>> 	select CRC32
>> +	select NET_DEVLINK
>> 	help
>> 	  This driver supports 10/40-gigabit Ethernet cards based on
>> 	  the Solarflare SFC9100-family controllers.
>> diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
>> index 712a48d00069..55b9c73cd8ef 100644
>> --- a/drivers/net/ethernet/sfc/Makefile
>> +++ b/drivers/net/ethernet/sfc/Makefile
>> @@ -6,7 +6,8 @@ sfc-y			+= efx.o efx_common.o efx_channels.o nic.o \
>> 			   mcdi.o mcdi_port.o mcdi_port_common.o \
>> 			   mcdi_functions.o mcdi_filters.o mcdi_mon.o \
>> 			   ef100.o ef100_nic.o ef100_netdev.o \
>> -			   ef100_ethtool.o ef100_rx.o ef100_tx.o
>> +			   ef100_ethtool.o ef100_rx.o ef100_tx.o \
>> +			   efx_devlink.o
>> sfc-$(CONFIG_SFC_MTD)	+= mtd.o
>> sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
>>                             mae.o tc.o tc_bindings.o tc_counters.o
>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>> index ad686c671ab8..14af8f314b83 100644
>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>> @@ -27,6 +27,7 @@
>> #include "tc.h"
>> #include "mae.h"
>> #include "rx_common.h"
>> +#include "efx_devlink.h"
>>
>> #define EF100_MAX_VIS 4096
>> #define EF100_NUM_MCDI_BUFFERS	1
>> @@ -1124,6 +1125,10 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
>> 		netif_warn(efx, probe, net_dev,
>> 			   "Failed to probe base mport rc %d; representors will not function\n",
>> 			   rc);
>> +	} else {
>> +		if (efx_probe_devlink(efx))
> I don't understand why the devlink register call is here.
> 1) You can registers it for PF and VF. I don't follow why you do it only
>     for PF.

We discuss the possibility of creating the devlink interface for VFs, 
but we decided not to. Arguably, this should not be available for VFs 
owned by VMs/containers, or at least in our case, since the interface is 
being used for getting information about the whole device or for 
getting/setting the MAC address. We plan to support more devlink 
functionalities in the near future, so maybe we add such support then if 
we consider it is needed.

> 2) It should be done as the first thing in the probe flow. Then devlink
>     port register, only after that netdev. It makes sense from the
>     perspective of object hierarchy.

I can not see a problem here. It is not the first thing done in the 
probe function, but I can not see any dependency for being so. And it is 
done before the devlink port registration and before the netdev 
registration what seems to be what other drivers do. What am I missing 
here?

>
>     It is also usual to have the devlink priv as the "main" driver
>     structure storage, see how that is done in mlx5 of mlxsw for example.

I will check the way others drivers use the devlink priv.

>
>
>> +			netif_warn(efx, probe, net_dev,
>> +				   "Failed to register devlink\n");
>> 	}
>>
>> 	rc = efx_init_tc(efx);
>> @@ -1157,6 +1162,7 @@ void ef100_remove(struct efx_nic *efx)
>> {
>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>
>> +	efx_fini_devlink(efx);
>> 	efx_mcdi_detach(efx);
>> 	efx_mcdi_fini(efx);
>> 	if (nic_data)
>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>> new file mode 100644
>> index 000000000000..c506f8f35d25
>> --- /dev/null
>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>> @@ -0,0 +1,427 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/****************************************************************************
>> + * Driver for AMD network controllers and boards
>> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published
>> + * by the Free Software Foundation, incorporated herein by reference.
>> + */
>> +
>> +#include <linux/rtc.h>
>> +#include "net_driver.h"
>> +#include "ef100_nic.h"
>> +#include "efx_devlink.h"
>> +#include "nic.h"
>> +#include "mcdi.h"
>> +#include "mcdi_functions.h"
>> +#include "mcdi_pcol.h"
>> +
>> +/* Custom devlink-info version object names for details that do not map to the
>> + * generic standardized names.
>> + */
>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC	"fw.mgmt.suc"
>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC	"fw.mgmt.cmc"
>> +#define EFX_DEVLINK_INFO_VERSION_FPGA_REV	"fpga.rev"
>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_HW	"fpga.app"
>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_FW	DEVLINK_INFO_VERSION_GENERIC_FW_APP
>> +#define EFX_DEVLINK_INFO_VERSION_SOC_BOOT	"coproc.boot"
>> +#define EFX_DEVLINK_INFO_VERSION_SOC_UBOOT	"coproc.uboot"
>> +#define EFX_DEVLINK_INFO_VERSION_SOC_MAIN	"coproc.main"
>> +#define EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY	"coproc.recovery"
>> +#define EFX_DEVLINK_INFO_VERSION_FW_EXPROM	"fw.exprom"
>> +#define EFX_DEVLINK_INFO_VERSION_FW_UEFI	"fw.uefi"
>> +
>> +#define EFX_MAX_VERSION_INFO_LEN	64
>> +
>> +static int efx_devlink_info_nvram_partition(struct efx_nic *efx,
>> +					    struct devlink_info_req *req,
>> +					    unsigned int partition_type,
>> +					    const char *version_name)
>> +{
>> +	char buf[EFX_MAX_VERSION_INFO_LEN];
>> +	u16 version[4];
>> +	int rc;
>> +
>> +	rc = efx_mcdi_nvram_metadata(efx, partition_type, NULL, version, NULL,
>> +				     0);
>> +	if (rc)
>> +		return rc;
>> +
>> +	snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u", version[0],
>> +		 version[1], version[2], version[3]);
>> +	devlink_info_version_stored_put(req, version_name, buf);
>> +
>> +	return 0;
>> +}
>> +
>> +static void efx_devlink_info_stored_versions(struct efx_nic *efx,
>> +					     struct devlink_info_req *req)
>> +{
>> +	efx_devlink_info_nvram_partition(efx, req, NVRAM_PARTITION_TYPE_BUNDLE,
>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID);
>> +	efx_devlink_info_nvram_partition(efx, req,
>> +					 NVRAM_PARTITION_TYPE_MC_FIRMWARE,
>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT);
>> +	efx_devlink_info_nvram_partition(efx, req,
>> +					 NVRAM_PARTITION_TYPE_SUC_FIRMWARE,
>> +					 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC);
>> +	efx_devlink_info_nvram_partition(efx, req,
>> +					 NVRAM_PARTITION_TYPE_EXPANSION_ROM,
>> +					 EFX_DEVLINK_INFO_VERSION_FW_EXPROM);
>> +	efx_devlink_info_nvram_partition(efx, req,
>> +					 NVRAM_PARTITION_TYPE_EXPANSION_UEFI,
>> +					 EFX_DEVLINK_INFO_VERSION_FW_UEFI);
>> +}
>> +
>> +#define EFX_MAX_SERIALNUM_LEN	(ETH_ALEN * 2 + 1)
>> +
>> +static void efx_devlink_info_board_cfg(struct efx_nic *efx,
>> +				       struct devlink_info_req *req)
>> +{
>> +	char sn[EFX_MAX_SERIALNUM_LEN];
>> +	u8 mac_address[ETH_ALEN];
>> +	int rc;
>> +
>> +	rc = efx_mcdi_get_board_cfg(efx, (u8 *)mac_address, NULL, NULL);
>> +	if (!rc) {
>> +		snprintf(sn, EFX_MAX_SERIALNUM_LEN, "%pm", mac_address);
>> +		devlink_info_serial_number_put(req, sn);
>> +	}
>> +}
>> +
>> +#define EFX_VER_FLAG(_f)	\
>> +	(MC_CMD_GET_VERSION_V5_OUT_ ## _f ## _PRESENT_LBN)
>> +
>> +static void efx_devlink_info_running_versions(struct efx_nic *efx,
>> +					      struct devlink_info_req *req)
>> +{
>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_V5_OUT_LEN);
>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_VERSION_EXT_IN_LEN);
>> +	char buf[EFX_MAX_VERSION_INFO_LEN];
>> +	unsigned int flags, build_id;
>> +	union {
>> +		const __le32 *dwords;
>> +		const __le16 *words;
>> +		const char *str;
>> +	} ver;
>> +	struct rtc_time build_date;
>> +	size_t outlength, offset;
>> +	u64 tstamp;
>> +	int rc;
>> +
>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, inbuf, sizeof(inbuf),
>> +			  outbuf, sizeof(outbuf), &outlength);
>> +	if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN)
>> +		return;
>> +
>> +	/* Handle previous output */
>> +	if (outlength < MC_CMD_GET_VERSION_V2_OUT_LEN) {
>> +		ver.words = (__le16 *)MCDI_PTR(outbuf,
>> +					       GET_VERSION_EXT_OUT_VERSION);
>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +				  le16_to_cpu(ver.words[0]),
>> +				  le16_to_cpu(ver.words[1]),
>> +				  le16_to_cpu(ver.words[2]),
>> +				  le16_to_cpu(ver.words[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>> +						 buf);
>> +		return;
>> +	}
>> +
>> +	/* Handle V2 additions */
>> +	flags = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_FLAGS);
>> +	if (flags & BIT(EFX_VER_FLAG(BOARD_EXT_INFO))) {
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%s",
>> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_NAME));
>> +		devlink_info_version_fixed_put(req,
>> +					       DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
>> +					       buf);
>> +
>> +		/* Favour full board version if present (in V5 or later) */
>> +		if (~flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>> +			snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u",
>> +				 MCDI_DWORD(outbuf,
>> +					    GET_VERSION_V2_OUT_BOARD_REVISION));
>> +			devlink_info_version_fixed_put(req,
>> +						       DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>> +						       buf);
>> +		}
>> +
>> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_SERIAL);
>> +		if (ver.str[0])
>> +			devlink_info_board_serial_number_put(req, ver.str);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(FPGA_EXT_INFO))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V2_OUT_FPGA_VERSION);
>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u_%c%u",
>> +				  le32_to_cpu(ver.dwords[0]),
>> +				  'A' + le32_to_cpu(ver.dwords[1]),
>> +				  le32_to_cpu(ver.dwords[2]));
>> +
>> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_FPGA_EXTRA);
>> +		if (ver.str[0])
>> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>> +				 " (%s)", ver.str);
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_FPGA_REV,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(CMC_EXT_INFO))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V2_OUT_CMCFW_VERSION);
>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +				  le32_to_cpu(ver.dwords[0]),
>> +				  le32_to_cpu(ver.dwords[1]),
>> +				  le32_to_cpu(ver.dwords[2]),
>> +				  le32_to_cpu(ver.dwords[3]));
>> +
>> +		tstamp = MCDI_QWORD(outbuf,
>> +				    GET_VERSION_V2_OUT_CMCFW_BUILD_DATE);
>> +		if (tstamp) {
>> +			rtc_time64_to_tm(tstamp, &build_date);
>> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>> +				 " (%ptRd)", &build_date);
>> +		}
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC,
>> +						 buf);
>> +	}
>> +
>> +	ver.words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_V2_OUT_VERSION);
>> +	offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			  le16_to_cpu(ver.words[0]), le16_to_cpu(ver.words[1]),
>> +			  le16_to_cpu(ver.words[2]), le16_to_cpu(ver.words[3]));
>> +	if (flags & BIT(EFX_VER_FLAG(MCFW_EXT_INFO))) {
>> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_ID);
>> +		snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>> +			 " (%x) %s", build_id,
>> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_NAME));
>> +	}
>> +	devlink_info_version_running_put(req,
>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>> +					 buf);
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V2_OUT_SUCFW_VERSION);
>> +		tstamp = MCDI_QWORD(outbuf,
>> +				    GET_VERSION_V2_OUT_SUCFW_BUILD_DATE);
>> +		rtc_time64_to_tm(tstamp, &build_date);
>> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_SUCFW_CHIP_ID);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN,
>> +			 "%u.%u.%u.%u type %x (%ptRd)",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]), le32_to_cpu(ver.dwords[3]),
>> +			 build_id, &build_date);
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>> +						 buf);
>> +	}
>> +
>> +	if (outlength < MC_CMD_GET_VERSION_V3_OUT_LEN)
>> +		return;
>> +
>> +	/* Handle V3 additions */
>> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_HW_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V3_OUT_DATAPATH_HW_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_HW,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_FW_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V3_OUT_DATAPATH_FW_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_FW,
>> +						 buf);
>> +	}
>> +
>> +	if (outlength < MC_CMD_GET_VERSION_V4_OUT_LEN)
>> +		return;
>> +
>> +	/* Handle V4 additions */
>> +	if (flags & BIT(EFX_VER_FLAG(SOC_BOOT_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SOC_BOOT_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_SOC_BOOT,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SOC_UBOOT_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SOC_UBOOT_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_SOC_UBOOT,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SOC_MAIN_ROOTFS_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SOC_MAIN_ROOTFS_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_SOC_MAIN,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SOC_RECOVERY_BUILDROOT_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SOC_RECOVERY_BUILDROOT_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_VERSION)) &&
>> +	    ~flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SUCFW_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>> +						 buf);
>> +	}
>> +
>> +	if (outlength < MC_CMD_GET_VERSION_V5_OUT_LEN)
>> +		return;
>> +
>> +	/* Handle V5 additions */
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V5_OUT_BOARD_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(BUNDLE_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V5_OUT_BUNDLE_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
>> +						 buf);
>> +	}
>> +}
>> +
>> +#undef EFX_VER_FLAG
>> +
>> +static void efx_devlink_info_query_all(struct efx_nic *efx,
>> +				       struct devlink_info_req *req)
>> +{
>> +	efx_devlink_info_board_cfg(efx, req);
>> +	efx_devlink_info_stored_versions(efx, req);
>> +	efx_devlink_info_running_versions(efx, req);
>> +}
>> +
>> +struct efx_devlink {
>> +	struct efx_nic *efx;
>> +};
>> +
>> +static int efx_devlink_info_get(struct devlink *devlink,
>> +				struct devlink_info_req *req,
>> +				struct netlink_ext_ack *extack)
>> +{
>> +	struct efx_devlink *devlink_private = devlink_priv(devlink);
>> +	struct efx_nic *efx = devlink_private->efx;
>> +
>> +	efx_devlink_info_query_all(efx, req);
> I don't understand the reason for having efx_devlink_info_query_all() as
> a separate function in compare to inline its code here.
>

Yes, it could be do as you say. I'll do.

Thanks

>> +	return 0;
>> +}
>> +
>> +static const struct devlink_ops sfc_devlink_ops = {
>> +	.info_get			= efx_devlink_info_get,
>> +};
>> +
>> +void efx_fini_devlink(struct efx_nic *efx)
>> +{
>> +	if (efx->devlink) {
>> +		struct efx_devlink *devlink_private;
>> +
>> +		devlink_private = devlink_priv(efx->devlink);
>> +
>> +		devlink_unregister(efx->devlink);
>> +		devlink_free(efx->devlink);
>> +		efx->devlink = NULL;
>> +	}
>> +}
>> +
>> +int efx_probe_devlink(struct efx_nic *efx)
>> +{
>> +	struct efx_devlink *devlink_private;
>> +
>> +	efx->devlink = devlink_alloc(&sfc_devlink_ops,
>> +				     sizeof(struct efx_devlink),
>> +				     &efx->pci_dev->dev);
>> +	if (!efx->devlink)
>> +		return -ENOMEM;
>> +	devlink_private = devlink_priv(efx->devlink);
>> +	devlink_private->efx = efx;
>> +
>> +	devlink_register(efx->devlink);
>> +
>> +	return 0;
>> +}
>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.h b/drivers/net/ethernet/sfc/efx_devlink.h
>> new file mode 100644
>> index 000000000000..997f878aea93
>> --- /dev/null
>> +++ b/drivers/net/ethernet/sfc/efx_devlink.h
>> @@ -0,0 +1,20 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/****************************************************************************
>> + * Driver for AMD network controllers and boards
>> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published
>> + * by the Free Software Foundation, incorporated herein by reference.
>> + */
>> +
>> +#ifndef _EFX_DEVLINK_H
>> +#define _EFX_DEVLINK_H
>> +
>> +#include "net_driver.h"
>> +#include <net/devlink.h>
>> +
>> +int efx_probe_devlink(struct efx_nic *efx);
>> +void efx_fini_devlink(struct efx_nic *efx);
>> +
>> +#endif	/* _EFX_DEVLINK_H */
>> diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
>> index af338208eae9..328cae82a7d8 100644
>> --- a/drivers/net/ethernet/sfc/mcdi.c
>> +++ b/drivers/net/ethernet/sfc/mcdi.c
>> @@ -2308,6 +2308,78 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
>> 	return rc;
>> }
>>
>> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>> +			    u32 *subtype, u16 version[4], char *desc,
>> +			    size_t descsize)
>> +{
>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN);
>> +	efx_dword_t *outbuf;
>> +	size_t outlen;
>> +	u32 flags;
>> +	int rc;
>> +
>> +	outbuf = kzalloc(MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2, GFP_KERNEL);
>> +	if (!outbuf)
>> +		return -ENOMEM;
>> +
>> +	MCDI_SET_DWORD(inbuf, NVRAM_METADATA_IN_TYPE, type);
>> +
>> +	rc = efx_mcdi_rpc_quiet(efx, MC_CMD_NVRAM_METADATA, inbuf,
>> +				sizeof(inbuf), outbuf,
>> +				MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2,
>> +				&outlen);
>> +	if (rc)
>> +		goto out_free;
>> +	if (outlen < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
>> +		rc = -EIO;
>> +		goto out_free;
>> +	}
>> +
>> +	flags = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_FLAGS);
>> +
>> +	if (desc && descsize > 0) {
>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_VALID_LBN)) {
>> +			if (descsize <=
>> +			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)) {
>> +				rc = -E2BIG;
>> +				goto out_free;
>> +			}
>> +
>> +			strncpy(desc,
>> +				MCDI_PTR(outbuf, NVRAM_METADATA_OUT_DESCRIPTION),
>> +				MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen));
>> +			desc[MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)] = '\0';
>> +		} else {
>> +			desc[0] = '\0';
>> +		}
>> +	}
>> +
>> +	if (subtype) {
>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_SUBTYPE_VALID_LBN))
>> +			*subtype = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_SUBTYPE);
>> +		else
>> +			*subtype = 0;
>> +	}
>> +
>> +	if (version) {
>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_VERSION_VALID_LBN)) {
>> +			version[0] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_W);
>> +			version[1] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_X);
>> +			version[2] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Y);
>> +			version[3] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Z);
>> +		} else {
>> +			version[0] = 0;
>> +			version[1] = 0;
>> +			version[2] = 0;
>> +			version[3] = 0;
>> +		}
>> +	}
>> +
>> +out_free:
>> +	kfree(outbuf);
>> +	return rc;
>> +}
>> +
>> int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
>> 		      size_t len, size_t *retlen, u8 *buffer)
>> {
>> diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
>> index 7e35fec9da35..63b090587f7a 100644
>> --- a/drivers/net/ethernet/sfc/mcdi.h
>> +++ b/drivers/net/ethernet/sfc/mcdi.h
>> @@ -379,6 +379,9 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
>> 			bool *protected_out);
>> int efx_new_mcdi_nvram_test_all(struct efx_nic *efx);
>> int efx_mcdi_nvram_test_all(struct efx_nic *efx);
>> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>> +			    u32 *subtype, u16 version[4], char *desc,
>> +			    size_t descsize);
>> int efx_mcdi_handle_assertion(struct efx_nic *efx);
>> int efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
>> int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac,
>> diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
>> index 3b49e216768b..d036641dc043 100644
>> --- a/drivers/net/ethernet/sfc/net_driver.h
>> +++ b/drivers/net/ethernet/sfc/net_driver.h
>> @@ -994,6 +994,7 @@ enum efx_xdp_tx_queues_mode {
>>   *      xdp_rxq_info structures?
>>   * @netdev_notifier: Netdevice notifier.
>>   * @tc: state for TC offload (EF100).
>> + * @devlink: reference to devlink structure owned by this device
>>   * @mem_bar: The BAR that is mapped into membase.
>>   * @reg_base: Offset from the start of the bar to the function control window.
>>   * @monitor_work: Hardware monitor workitem
>> @@ -1179,6 +1180,7 @@ struct efx_nic {
>> 	struct notifier_block netdev_notifier;
>> 	struct efx_tc_state *tc;
>>
>> +	struct devlink *devlink;
>> 	unsigned int mem_bar;
>> 	u32 reg_base;
>>
>> -- 
>> 2.17.1
>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-19 12:25   ` Jiri Pirko
@ 2023-01-19 14:59     ` Lucero Palau, Alejandro
  2023-01-20 11:05       ` Jiri Pirko
  0 siblings, 1 reply; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-19 14:59 UTC (permalink / raw)
  To: Jiri Pirko, Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx


On 1/19/23 12:25, Jiri Pirko wrote:
> Thu, Jan 19, 2023 at 12:31:39PM CET, alejandro.lucero-palau@amd.com wrote:
>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>
>> Using the builtin client handle id infrastructure, this patch adds
>> support for obtaining the mac address linked to mports in ef100. This
>> implies to execute an MCDI command for getting the data from the
>> firmware for each devlink port.
>>
>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>> ---
>> drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
>> drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
>> drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
>> drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
>> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
>> 5 files changed, 81 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>> index f4e913593f2b..4400ce622228 100644
>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>> @@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
>> 	return rc;
>> }
>>
>> +/* MCDI commands are related to the same device issuing them. This function
>> + * allows to do an MCDI command on behalf of another device, mainly PFs setting
>> + * things for VFs.
>> + */
>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
>> +{
>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
>> +	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
>> +	size_t outlen;
>> +	int rc;
>> +
>> +	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
>> +		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
>> +	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
>> +		       pciefn_flat);
>> +
>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
>> +			  outbuf, sizeof(outbuf), &outlen);
>> +	if (rc)
>> +		return rc;
>> +	if (outlen < sizeof(outbuf))
>> +		return -EIO;
>> +	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
>> +	return 0;
>> +}
>> +
>> int ef100_probe_netdev_pf(struct efx_nic *efx)
>> {
>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>> index e59044072333..f1ed481c1260 100644
>> --- a/drivers/net/ethernet/sfc/ef100_nic.h
>> +++ b/drivers/net/ethernet/sfc/ef100_nic.h
>> @@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
>>
>> int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
>> 			  int client_handle, bool empty_ok);
>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
>> #endif	/* EFX_EF100_NIC_H */
>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>> index ff0c8da61919..974c9ff901a0 100644
>> --- a/drivers/net/ethernet/sfc/ef100_rep.c
>> +++ b/drivers/net/ethernet/sfc/ef100_rep.c
>> @@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
>> 		     mport_desc->interface_idx == nic_data->local_mae_intf;
>> }
>>
>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
>> +{
>> +	bool pcie_func;
>> +
>> +	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>> +	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
>> +}
>> +
>> void efx_ef100_init_reps(struct efx_nic *efx)
>> {
>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>> index 9cca41614982..74853ccbc937 100644
>> --- a/drivers/net/ethernet/sfc/ef100_rep.h
>> +++ b/drivers/net/ethernet/sfc/ef100_rep.h
>> @@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
>> struct mae_mport_desc;
>> bool ef100_mport_on_local_intf(struct efx_nic *efx,
>> 			       struct mae_mport_desc *mport_desc);
>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
>> #endif /* EF100_REP_H */
>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>> index bb19d3ad7ffd..2a57c4f6d2b2 100644
>> --- a/drivers/net/ethernet/sfc/efx_devlink.c
>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>> @@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
>> 	return err;
>> }
>>
>> +static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>> +				     int *hw_addr_len,
>> +				     struct netlink_ext_ack *extack)
>> +{
>> +	struct efx_devlink *devlink = devlink_priv(port->devlink);
>> +	struct mae_mport_desc *mport_desc;
>> +	efx_qword_t pciefn;
>> +	u32 client_id;
>> +	int rc = 0;
>> +
>> +	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
> Dont use port->index, never. It's devlink internal. You have port
> pointer passed here. Usually, what drivers do is to embed
> the struct devlink_port in the driver port struct. Then you do just
> simple container of to get it here. Mlxsw example:

I do not understand this. Port index is set by the driver not by the 
devlink interface implementation.

Why can I not use it?

> static void *__dl_port(struct devlink_port *devlink_port)
> {
>          return container_of(devlink_port, struct mlxsw_core_port, devlink_port);
> }
>
> static int mlxsw_devlink_port_split(struct devlink *devlink,
>                                      struct devlink_port *port,
>                                      unsigned int count,
>                                      struct netlink_ext_ack *extack)
> {
>          struct mlxsw_core_port *mlxsw_core_port = __dl_port(port);
> ...
>
>
>
>> +	if (!mport_desc)
> Tell the user what's wrong, extack is here for that.
>
I'll do.
>
>> +		return -EINVAL;
>> +
>> +	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
>> +		goto out;
>> +
>> +	if (ef100_mport_is_vf(mport_desc))
>> +		EFX_POPULATE_QWORD_3(pciefn,
>> +				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>> +				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>> +	else
>> +		EFX_POPULATE_QWORD_3(pciefn,
>> +				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
>> +				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>> +
>> +	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>> +	if (rc) {
>> +		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>> +			  "Failed to get client ID for port index %u, rc %d\n",
>> +			  port->index, rc);
> Don't write to dmesg, use extack msg instead.


I'll do.

Thanks

>
>> +		return rc;
>> +	}
>> +
>> +	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
> Again, extack would be nice here if (rc)
>
Again, I'll do.
>> +out:
>> +	*hw_addr_len = ETH_ALEN;
>> +
>> +	return rc;
>> +}
>> +
>> static int efx_devlink_info_get(struct devlink *devlink,
>> 				struct devlink_info_req *req,
>> 				struct netlink_ext_ack *extack)
>> @@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
>>
>> static const struct devlink_ops sfc_devlink_ops = {
>> 	.info_get			= efx_devlink_info_get,
>> +	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
>> };
>>
>> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>> -- 
>> 2.17.1
>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 4/7] sfc: add devlink port support for ef100
  2023-01-19 12:33   ` Jiri Pirko
@ 2023-01-19 15:03     ` Lucero Palau, Alejandro
  0 siblings, 0 replies; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-19 15:03 UTC (permalink / raw)
  To: Jiri Pirko, Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, ecree.xilinx


On 1/19/23 12:33, Jiri Pirko wrote:
> Thu, Jan 19, 2023 at 12:31:37PM CET, alejandro.lucero-palau@amd.com wrote:
>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>
>> Using the data when enumerating mports, create devlink ports just before
>> netdevs are registered and removing those devlink ports after netdev has
>> been unregister.
>>
>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>> ---
>> drivers/net/ethernet/sfc/ef100_netdev.c |  14 ++-
>> drivers/net/ethernet/sfc/ef100_rep.c    |  23 +++++
>> drivers/net/ethernet/sfc/ef100_rep.h    |   6 ++
>> drivers/net/ethernet/sfc/efx_devlink.c  | 114 ++++++++++++++++++++++++
>> drivers/net/ethernet/sfc/efx_devlink.h  |   7 ++
>> drivers/net/ethernet/sfc/net_driver.h   |   1 +
>> 6 files changed, 161 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c
>> index ddcc325ed570..4a5d028f757e 100644
>> --- a/drivers/net/ethernet/sfc/ef100_netdev.c
>> +++ b/drivers/net/ethernet/sfc/ef100_netdev.c
>> @@ -24,6 +24,7 @@
>> #include "rx_common.h"
>> #include "ef100_sriov.h"
>> #include "tc_bindings.h"
>> +#include "efx_devlink.h"
>>
>> static void ef100_update_name(struct efx_nic *efx)
>> {
>> @@ -280,6 +281,9 @@ static int ef100_register_netdev(struct efx_nic *efx)
>> 	net_dev->max_mtu = EFX_MAX_MTU;
>> 	net_dev->ethtool_ops = &ef100_ethtool_ops;
>>
>> +	if (!efx->type->is_vf)
>> +		ef100_pf_set_devlink_port(efx);
> Again, why no port for VF while you are at it?


We create the devlink ports with the VF representors.


>
>> +
>> 	rtnl_lock();
>>
>> 	rc = dev_alloc_name(net_dev, net_dev->name);
>> @@ -302,6 +306,7 @@ static int ef100_register_netdev(struct efx_nic *efx)
>>
>> fail_locked:
>> 	rtnl_unlock();
>> +	ef100_pf_unset_devlink_port(efx);
>> 	netif_err(efx, drv, efx->net_dev, "could not register net dev\n");
>> 	return rc;
>> }
>> @@ -312,6 +317,7 @@ static void ef100_unregister_netdev(struct efx_nic *efx)
>> 		efx_fini_mcdi_logging(efx);
>> 		efx->state = STATE_PROBED;
>> 		unregister_netdev(efx->net_dev);
>> +		ef100_pf_unset_devlink_port(efx);
>> 	}
>> }
>>
>> @@ -405,16 +411,16 @@ int ef100_probe_netdev(struct efx_probe_data *probe_data)
>> 	/* Don't fail init if RSS setup doesn't work. */
>> 	efx_mcdi_push_default_indir_table(efx, efx->n_rx_channels);
>>
>> -	rc = ef100_register_netdev(efx);
>> -	if (rc)
>> -		goto fail;
>> -
>> 	if (!efx->type->is_vf) {
>> 		rc = ef100_probe_netdev_pf(efx);
>> 		if (rc)
>> 			goto fail;
>> 	}
>>
>> +	rc = ef100_register_netdev(efx);
>> +	if (rc)
>> +		goto fail;
>> +
>> 	efx->netdev_notifier.notifier_call = ef100_netdev_event;
>> 	rc = register_netdevice_notifier(&efx->netdev_notifier);
>> 	if (rc) {
>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>> index 9cd1a3ac67e0..ff0c8da61919 100644
>> --- a/drivers/net/ethernet/sfc/ef100_rep.c
>> +++ b/drivers/net/ethernet/sfc/ef100_rep.c
>> @@ -16,6 +16,7 @@
>> #include "mae.h"
>> #include "rx_common.h"
>> #include "tc_bindings.h"
>> +#include "efx_devlink.h"
>>
>> #define EFX_EF100_REP_DRIVER	"efx_ef100_rep"
>>
>> @@ -297,6 +298,7 @@ int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i)
>> 			i, rc);
>> 		goto fail1;
>> 	}
>> +	ef100_rep_set_devlink_port(efv);
>> 	rc = register_netdev(efv->net_dev);
>> 	if (rc) {
>> 		pci_err(efx->pci_dev,
>> @@ -304,10 +306,12 @@ int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i)
>> 			i, rc);
>> 		goto fail2;
>> 	}
>> +
>> 	pci_dbg(efx->pci_dev, "Representor for VF %d is %s\n", i,
>> 		efv->net_dev->name);
>> 	return 0;
>> fail2:
>> +	ef100_rep_unset_devlink_port(efv);
>> 	efx_ef100_deconfigure_rep(efv);
>> fail1:
>> 	efx_ef100_rep_destroy_netdev(efv);
>> @@ -323,6 +327,7 @@ void efx_ef100_vfrep_destroy(struct efx_nic *efx, struct efx_rep *efv)
>> 		return;
>> 	netif_dbg(efx, drv, rep_dev, "Removing VF representor\n");
>> 	unregister_netdev(rep_dev);
>> +	ef100_rep_unset_devlink_port(efv);
>> 	efx_ef100_deconfigure_rep(efv);
>> 	efx_ef100_rep_destroy_netdev(efv);
>> }
>> @@ -339,6 +344,24 @@ void efx_ef100_fini_vfreps(struct efx_nic *efx)
>> 		efx_ef100_vfrep_destroy(efx, efv);
>> }
>>
>> +bool ef100_mport_is_pcie_vnic(struct mae_mport_desc *mport_desc)
>> +{
>> +	return mport_desc->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC &&
>> +	       mport_desc->vnic_client_type == MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION;
>> +}
>> +
>> +bool ef100_mport_on_local_intf(struct efx_nic *efx,
>> +			       struct mae_mport_desc *mport_desc)
>> +{
>> +	bool pcie_func;
>> +	struct ef100_nic_data *nic_data = efx->nic_data;
> Reverse christmas tree ordering please:
> ***************
> *********
> ****
>
Damm it.

I'll fix it.

>
>
>> +
>> +	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>> +
>> +	return nic_data->have_local_intf && pcie_func &&
>> +		     mport_desc->interface_idx == nic_data->local_mae_intf;
>> +}
>> +
>> void efx_ef100_init_reps(struct efx_nic *efx)
>> {
>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>> index 328ac0cbb532..9cca41614982 100644
>> --- a/drivers/net/ethernet/sfc/ef100_rep.h
>> +++ b/drivers/net/ethernet/sfc/ef100_rep.h
>> @@ -22,6 +22,8 @@ struct efx_rep_sw_stats {
>> 	atomic64_t rx_dropped, tx_errors;
>> };
>>
>> +struct devlink_port;
>> +
>> /**
>>   * struct efx_rep - Private data for an Efx representor
>>   *
>> @@ -54,6 +56,7 @@ struct efx_rep {
>> 	spinlock_t rx_lock;
>> 	struct napi_struct napi;
>> 	struct efx_rep_sw_stats stats;
>> +	struct devlink_port *dl_port;
>> };
>>
>> int efx_ef100_vfrep_create(struct efx_nic *efx, unsigned int i);
>> @@ -69,4 +72,7 @@ struct efx_rep *efx_ef100_find_rep_by_mport(struct efx_nic *efx, u16 mport);
>> extern const struct net_device_ops efx_ef100_rep_netdev_ops;
>> void efx_ef100_init_reps(struct efx_nic *efx);
>> void efx_ef100_fini_reps(struct efx_nic *efx);
>> +struct mae_mport_desc;
>> +bool ef100_mport_on_local_intf(struct efx_nic *efx,
>> +			       struct mae_mport_desc *mport_desc);
>> #endif /* EF100_REP_H */
>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>> index c506f8f35d25..bb19d3ad7ffd 100644
>> --- a/drivers/net/ethernet/sfc/efx_devlink.c
>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>> @@ -16,6 +16,8 @@
>> #include "mcdi.h"
>> #include "mcdi_functions.h"
>> #include "mcdi_pcol.h"
>> +#include "mae.h"
>> +#include "ef100_rep.h"
>>
>> /* Custom devlink-info version object names for details that do not map to the
>>   * generic standardized names.
>> @@ -381,6 +383,52 @@ struct efx_devlink {
>> 	struct efx_nic *efx;
>> };
>>
>> +static void efx_devlink_del_port(struct devlink_port *dl_port)
>> +{
>> +	if (!dl_port)
>> +		return;
>> +	devlink_port_unregister(dl_port);
>> +	kfree(dl_port);
>> +}
>> +
>> +static int efx_devlink_add_port(struct efx_nic *efx,
>> +				struct mae_mport_desc *mport,
>> +				struct devlink_port *dl_port)
>> +{
>> +	struct devlink_port_attrs attrs = {};
>> +	bool external = false;
>> +	int err;
>> +
>> +	if (!ef100_mport_on_local_intf(efx, mport))
>> +		external = true;
>> +
>> +	switch (mport->mport_type) {
>> +	case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
>> +		attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
>> +		attrs.phys.port_number = mport->port_idx;
>> +		devlink_port_attrs_set(dl_port, &attrs);
>> +		break;
>> +	case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
>> +		if (mport->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL) {
> No need for {}'s in this if-else
>

OK


>> +			devlink_port_attrs_pci_vf_set(dl_port, 0, mport->pf_idx,
>> +						      mport->vf_idx,
>> +						      external);
>> +		} else {
>> +			devlink_port_attrs_pci_pf_set(dl_port, 0, mport->pf_idx,
>> +						      external);
>> +		}
>> +		break;
>> +	default:
>> +		/* MAE_MPORT_DESC_MPORT_ALIAS and UNDEFINED */
>> +		return 0;
>> +	}
>> +
>> +	dl_port->index = mport->mport_id;
>> +	err = devlink_port_register(efx->devlink, dl_port, mport->mport_id);
> Just return.
>

OK


>> +
>> +	return err;
>> +}
>> +
>> static int efx_devlink_info_get(struct devlink *devlink,
>> 				struct devlink_info_req *req,
>> 				struct netlink_ext_ack *extack)
>> @@ -396,6 +444,72 @@ static const struct devlink_ops sfc_devlink_ops = {
>> 	.info_get			= efx_devlink_info_get,
>> };
>>
>> +static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>> +{
>> +	struct mae_mport_desc *mport;
>> +	struct devlink_port *dl_port;
>> +	u32 id;
>> +
>> +	if (efx_mae_lookup_mport(efx, idx, &id)) {
>> +		/* This should not happen. */
>> +		if (idx == MAE_MPORT_DESC_VF_IDX_NULL)
>> +			pci_warn(efx->pci_dev, "No mport ID found for PF.\n");
>> +		else
>> +			pci_warn(efx->pci_dev, "No mport ID found for VF %u.\n",
>> +				 idx);
>> +		return NULL;
>> +	}
>> +
>> +	mport = efx_mae_get_mport(efx, id);
>> +	if (!mport) {
>> +		/* This should not happen. */
>> +		if (idx == MAE_MPORT_DESC_VF_IDX_NULL)
>> +			pci_warn(efx->pci_dev, "No mport found for PF.\n");
>> +		else
>> +			pci_warn(efx->pci_dev, "No mport found for VF %u.\n",
>> +				 idx);
>> +		return NULL;
>> +	}
>> +
>> +	dl_port = kzalloc(sizeof(*dl_port), GFP_KERNEL);
>> +	if (!dl_port)
>> +		return NULL;
>> +
>> +	if (efx_devlink_add_port(efx, mport, dl_port)) {
>> +		if (idx == MAE_MPORT_DESC_VF_IDX_NULL)
>> +			pci_warn(efx->pci_dev,
>> +				 "devlink port creation for PF failed.\n");
>> +		else
>> +			pci_warn(efx->pci_dev,
>> +				 "devlink_port creationg for VF %u failed.\n",
>> +				 idx);
>> +		kfree(dl_port);
>> +		return NULL;
>> +	}
>> +
>> +	return dl_port;
>> +}
>> +
>> +void ef100_rep_set_devlink_port(struct efx_rep *efv)
>> +{
>> +	efv->dl_port = ef100_set_devlink_port(efv->parent, efv->idx);
>> +}
>> +
>> +void ef100_pf_set_devlink_port(struct efx_nic *efx)
>> +{
>> +	efx->dl_port = ef100_set_devlink_port(efx, MAE_MPORT_DESC_VF_IDX_NULL);
>> +}
>> +
>> +void ef100_rep_unset_devlink_port(struct efx_rep *efv)
>> +{
>> +	efx_devlink_del_port(efv->dl_port);
>> +}
>> +
>> +void ef100_pf_unset_devlink_port(struct efx_nic *efx)
>> +{
>> +	efx_devlink_del_port(efx->dl_port);
>> +}
>> +
>> void efx_fini_devlink(struct efx_nic *efx)
>> {
>> 	if (efx->devlink) {
>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.h b/drivers/net/ethernet/sfc/efx_devlink.h
>> index 997f878aea93..a834c393a9ad 100644
>> --- a/drivers/net/ethernet/sfc/efx_devlink.h
>> +++ b/drivers/net/ethernet/sfc/efx_devlink.h
>> @@ -17,4 +17,11 @@
>> int efx_probe_devlink(struct efx_nic *efx);
>> void efx_fini_devlink(struct efx_nic *efx);
>>
>> +struct mae_mport_desc;
>> +struct efx_rep;
>> +
>> +void ef100_pf_set_devlink_port(struct efx_nic *efx);
>> +void ef100_rep_set_devlink_port(struct efx_rep *efv);
>> +void ef100_pf_unset_devlink_port(struct efx_nic *efx);
>> +void ef100_rep_unset_devlink_port(struct efx_rep *efv);
>> #endif	/* _EFX_DEVLINK_H */
>> diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
>> index bc9efbfb3d6b..20f43695d082 100644
>> --- a/drivers/net/ethernet/sfc/net_driver.h
>> +++ b/drivers/net/ethernet/sfc/net_driver.h
>> @@ -1185,6 +1185,7 @@ struct efx_nic {
>> 	struct efx_tc_state *tc;
>>
>> 	struct devlink *devlink;
>> +	struct devlink_port *dl_port;
>> 	unsigned int mem_bar;
>> 	u32 reg_base;
>>
>> -- 
>> 2.17.1
>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-19 12:37   ` Jiri Pirko
@ 2023-01-19 15:09     ` Lucero Palau, Alejandro
  2023-01-20 11:08       ` Jiri Pirko
  0 siblings, 1 reply; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-19 15:09 UTC (permalink / raw)
  To: Jiri Pirko, Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx


On 1/19/23 12:37, Jiri Pirko wrote:
> Thu, Jan 19, 2023 at 12:31:39PM CET, alejandro.lucero-palau@amd.com wrote:
>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>
>> Using the builtin client handle id infrastructure, this patch adds
>> support for obtaining the mac address linked to mports in ef100. This
>> implies to execute an MCDI command for getting the data from the
>> firmware for each devlink port.
>>
>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>> ---
>> drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
>> drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
>> drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
>> drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
>> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
>> 5 files changed, 81 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>> index f4e913593f2b..4400ce622228 100644
>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>> @@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
>> 	return rc;
>> }
>>
>> +/* MCDI commands are related to the same device issuing them. This function
>> + * allows to do an MCDI command on behalf of another device, mainly PFs setting
>> + * things for VFs.
>> + */
>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
>> +{
>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
>> +	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
>> +	size_t outlen;
>> +	int rc;
>> +
>> +	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
>> +		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
>> +	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
>> +		       pciefn_flat);
>> +
>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
>> +			  outbuf, sizeof(outbuf), &outlen);
>> +	if (rc)
>> +		return rc;
>> +	if (outlen < sizeof(outbuf))
>> +		return -EIO;
>> +	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
>> +	return 0;
>> +}
>> +
>> int ef100_probe_netdev_pf(struct efx_nic *efx)
>> {
>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>> index e59044072333..f1ed481c1260 100644
>> --- a/drivers/net/ethernet/sfc/ef100_nic.h
>> +++ b/drivers/net/ethernet/sfc/ef100_nic.h
>> @@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
>>
>> int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
>> 			  int client_handle, bool empty_ok);
>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
>> #endif	/* EFX_EF100_NIC_H */
>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>> index ff0c8da61919..974c9ff901a0 100644
>> --- a/drivers/net/ethernet/sfc/ef100_rep.c
>> +++ b/drivers/net/ethernet/sfc/ef100_rep.c
>> @@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
>> 		     mport_desc->interface_idx == nic_data->local_mae_intf;
>> }
>>
>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
>> +{
>> +	bool pcie_func;
>> +
>> +	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>> +	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
>> +}
>> +
>> void efx_ef100_init_reps(struct efx_nic *efx)
>> {
>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>> index 9cca41614982..74853ccbc937 100644
>> --- a/drivers/net/ethernet/sfc/ef100_rep.h
>> +++ b/drivers/net/ethernet/sfc/ef100_rep.h
>> @@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
>> struct mae_mport_desc;
>> bool ef100_mport_on_local_intf(struct efx_nic *efx,
>> 			       struct mae_mport_desc *mport_desc);
>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
>> #endif /* EF100_REP_H */
>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>> index bb19d3ad7ffd..2a57c4f6d2b2 100644
>> --- a/drivers/net/ethernet/sfc/efx_devlink.c
>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>> @@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
>> 	return err;
>> }
>>
>> +static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>> +				     int *hw_addr_len,
>> +				     struct netlink_ext_ack *extack)
>> +{
>> +	struct efx_devlink *devlink = devlink_priv(port->devlink);
>> +	struct mae_mport_desc *mport_desc;
>> +	efx_qword_t pciefn;
>> +	u32 client_id;
>> +	int rc = 0;
>> +
>> +	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
> I may be missing something, where do you fail with -EOPNOTSUPP
> in case this is called for PHYSICAL port ?
>

We do not create a devlink port for the physical port.

I'm aware this is not "fully compliant" with devlink design idea, just 
trying to use it for our current urgent necessities by now.

Do you think this could be a problem?


>
>> +	if (!mport_desc)
>> +		return -EINVAL;
>> +
>> +	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
>> +		goto out;
>> +
>> +	if (ef100_mport_is_vf(mport_desc))
>> +		EFX_POPULATE_QWORD_3(pciefn,
>> +				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>> +				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>> +	else
>> +		EFX_POPULATE_QWORD_3(pciefn,
>> +				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
>> +				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>> +
>> +	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>> +	if (rc) {
>> +		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>> +			  "Failed to get client ID for port index %u, rc %d\n",
>> +			  port->index, rc);
>> +		return rc;
>> +	}
>> +
>> +	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
>> +out:
>> +	*hw_addr_len = ETH_ALEN;
>> +
>> +	return rc;
>> +}
>> +
>> static int efx_devlink_info_get(struct devlink *devlink,
>> 				struct devlink_info_req *req,
>> 				struct netlink_ext_ack *extack)
>> @@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
>>
>> static const struct devlink_ops sfc_devlink_ops = {
>> 	.info_get			= efx_devlink_info_get,
>> +	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
>> };
>>
>> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>> -- 
>> 2.17.1
>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 7/7] sfc: add support for devlink port_function_hw_addr_set in ef100
  2023-01-19 12:27   ` Jiri Pirko
@ 2023-01-19 15:10     ` Lucero Palau, Alejandro
  0 siblings, 0 replies; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-19 15:10 UTC (permalink / raw)
  To: Jiri Pirko, Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx


On 1/19/23 12:27, Jiri Pirko wrote:
> Thu, Jan 19, 2023 at 12:31:40PM CET, alejandro.lucero-palau@amd.com wrote:
>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>
>> Using the builtin client handle id infrastructure, this patch adds
>> support for setting the mac address linked to mports in ef100. This
>> implies to execute an MCDI command for giving the address to the
>> firmware for the specific devlink port.
>>
>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>> ---
>> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
>> 1 file changed, 44 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>> index 2a57c4f6d2b2..a85b2d4e54ab 100644
>> --- a/drivers/net/ethernet/sfc/efx_devlink.c
>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>> @@ -472,6 +472,49 @@ static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>> 	return rc;
>> }
>>
>> +static int efx_devlink_port_addr_set(struct devlink_port *port,
> Similar comments here as for the _get callback: embed devlink_port
> struct, use extack.
>

I'll do.

Thanks


>> +				     const u8 *hw_addr, int hw_addr_len,
>> +				     struct netlink_ext_ack *extack)
>> +{
>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_CLIENT_MAC_ADDRESSES_IN_LEN(1));
>> +	struct efx_devlink *devlink = devlink_priv(port->devlink);
>> +	struct mae_mport_desc *mport_desc;
>> +	efx_qword_t pciefn;
>> +	u32 client_id;
>> +	int rc;
>> +
>> +	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
>> +	if (!mport_desc)
>> +		return -EINVAL;
>> +
>> +	if (!ef100_mport_is_vf(mport_desc))
>> +		return -EPERM;
>> +
>> +	EFX_POPULATE_QWORD_3(pciefn,
>> +			     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>> +			     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>> +			     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>> +
>> +	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>> +	if (rc) {
>> +		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>> +			  "Failed to get client ID for port index %u, rc %d\n",
>> +			  port->index, rc);
>> +		return rc;
>> +	}
>> +
>> +	MCDI_SET_DWORD(inbuf, SET_CLIENT_MAC_ADDRESSES_IN_CLIENT_HANDLE,
>> +		       client_id);
>> +
>> +	ether_addr_copy(MCDI_PTR(inbuf, SET_CLIENT_MAC_ADDRESSES_IN_MAC_ADDRS),
>> +			hw_addr);
>> +
>> +	rc = efx_mcdi_rpc(devlink->efx, MC_CMD_SET_CLIENT_MAC_ADDRESSES, inbuf,
>> +			  sizeof(inbuf), NULL, 0, NULL);
>> +
>> +	return rc;
>> +}
>> +
>> static int efx_devlink_info_get(struct devlink *devlink,
>> 				struct devlink_info_req *req,
>> 				struct netlink_ext_ack *extack)
>> @@ -486,6 +529,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
>> static const struct devlink_ops sfc_devlink_ops = {
>> 	.info_get			= efx_devlink_info_get,
>> 	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
>> +	.port_function_hw_addr_set	= efx_devlink_port_addr_set,
>> };
>>
>> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>> -- 
>> 2.17.1
>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 11:31 ` [PATCH net-next 1/7] sfc: add " alejandro.lucero-palau
  2023-01-19 12:14   ` Jiri Pirko
@ 2023-01-19 15:50   ` kernel test robot
  2023-01-19 17:16   ` Jakub Kicinski
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 52+ messages in thread
From: kernel test robot @ 2023-01-19 15:50 UTC (permalink / raw)
  To: alejandro.lucero-palau, netdev, linux-net-drivers
  Cc: oe-kbuild-all, davem, kuba, pabeni, edumazet, habetsm,
	ecree.xilinx, Alejandro Lucero

Hi,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/alejandro-lucero-palau-amd-com/sfc-add-devlink-support-for-ef100/20230119-193440
patch link:    https://lore.kernel.org/r/20230119113140.20208-2-alejandro.lucero-palau%40amd.com
patch subject: [PATCH net-next 1/7] sfc: add devlink support for ef100
config: sparc-allyesconfig (https://download.01.org/0day-ci/archive/20230119/202301192303.3zOqMgPP-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/f393f2642abb0e7536df6f9f08e0d69ecfd5b435
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review alejandro-lucero-palau-amd-com/sfc-add-devlink-support-for-ef100/20230119-193440
        git checkout f393f2642abb0e7536df6f9f08e0d69ecfd5b435
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sparc olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sparc SHELL=/bin/bash drivers/net/ethernet/sfc/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/net/ethernet/sfc/efx_devlink.c: In function 'efx_fini_devlink':
>> drivers/net/ethernet/sfc/efx_devlink.c:402:37: warning: variable 'devlink_private' set but not used [-Wunused-but-set-variable]
     402 |                 struct efx_devlink *devlink_private;
         |                                     ^~~~~~~~~~~~~~~


vim +/devlink_private +402 drivers/net/ethernet/sfc/efx_devlink.c

   398	
   399	void efx_fini_devlink(struct efx_nic *efx)
   400	{
   401		if (efx->devlink) {
 > 402			struct efx_devlink *devlink_private;
   403	
   404			devlink_private = devlink_priv(efx->devlink);
   405	
   406			devlink_unregister(efx->devlink);
   407			devlink_free(efx->devlink);
   408			efx->devlink = NULL;
   409		}
   410	}
   411	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 14:51     ` Lucero Palau, Alejandro
@ 2023-01-19 16:29       ` Lucero Palau, Alejandro
  2023-01-20 11:02         ` Jiri Pirko
  2023-01-20 11:00       ` Jiri Pirko
  1 sibling, 1 reply; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-19 16:29 UTC (permalink / raw)
  To: Lucero Palau, Alejandro, Jiri Pirko
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx


On 1/19/23 14:51, Lucero Palau, Alejandro wrote:
> On 1/19/23 12:14, Jiri Pirko wrote:
>> Thu, Jan 19, 2023 at 12:31:34PM CET, alejandro.lucero-palau@amd.com wrote:
>>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>
>>> Basic support for devlink info command.
>>>
>>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>> ---
>>> drivers/net/ethernet/sfc/Kconfig       |   1 +
>>> drivers/net/ethernet/sfc/Makefile      |   3 +-
>>> drivers/net/ethernet/sfc/ef100_nic.c   |   6 +
>>> drivers/net/ethernet/sfc/efx_devlink.c | 427 +++++++++++++++++++++++++
>>> drivers/net/ethernet/sfc/efx_devlink.h |  20 ++
>>> drivers/net/ethernet/sfc/mcdi.c        |  72 +++++
>>> drivers/net/ethernet/sfc/mcdi.h        |   3 +
>>> drivers/net/ethernet/sfc/net_driver.h  |   2 +
>>> 8 files changed, 533 insertions(+), 1 deletion(-)
>>> create mode 100644 drivers/net/ethernet/sfc/efx_devlink.c
>>> create mode 100644 drivers/net/ethernet/sfc/efx_devlink.h
>> Could you please split?
>>
>> At least the devlink introduction part and info implementation.
>>
> Sure.

Just for being sure, would it be fine to have a simple info 
implementation first along with the devlink infrastructure then a second 
patch adding the more complex devlink info support? I guess I need at 
least one operation supported initially.

>>> diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
>>> index 0950e6b0508f..4af36ba8906b 100644
>>> --- a/drivers/net/ethernet/sfc/Kconfig
>>> +++ b/drivers/net/ethernet/sfc/Kconfig
>>> @@ -22,6 +22,7 @@ config SFC
>>> 	depends on PTP_1588_CLOCK_OPTIONAL
>>> 	select MDIO
>>> 	select CRC32
>>> +	select NET_DEVLINK
>>> 	help
>>> 	  This driver supports 10/40-gigabit Ethernet cards based on
>>> 	  the Solarflare SFC9100-family controllers.
>>> diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
>>> index 712a48d00069..55b9c73cd8ef 100644
>>> --- a/drivers/net/ethernet/sfc/Makefile
>>> +++ b/drivers/net/ethernet/sfc/Makefile
>>> @@ -6,7 +6,8 @@ sfc-y			+= efx.o efx_common.o efx_channels.o nic.o \
>>> 			   mcdi.o mcdi_port.o mcdi_port_common.o \
>>> 			   mcdi_functions.o mcdi_filters.o mcdi_mon.o \
>>> 			   ef100.o ef100_nic.o ef100_netdev.o \
>>> -			   ef100_ethtool.o ef100_rx.o ef100_tx.o
>>> +			   ef100_ethtool.o ef100_rx.o ef100_tx.o \
>>> +			   efx_devlink.o
>>> sfc-$(CONFIG_SFC_MTD)	+= mtd.o
>>> sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
>>>                              mae.o tc.o tc_bindings.o tc_counters.o
>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>>> index ad686c671ab8..14af8f314b83 100644
>>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>>> @@ -27,6 +27,7 @@
>>> #include "tc.h"
>>> #include "mae.h"
>>> #include "rx_common.h"
>>> +#include "efx_devlink.h"
>>>
>>> #define EF100_MAX_VIS 4096
>>> #define EF100_NUM_MCDI_BUFFERS	1
>>> @@ -1124,6 +1125,10 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
>>> 		netif_warn(efx, probe, net_dev,
>>> 			   "Failed to probe base mport rc %d; representors will not function\n",
>>> 			   rc);
>>> +	} else {
>>> +		if (efx_probe_devlink(efx))
>> I don't understand why the devlink register call is here.
>> 1) You can registers it for PF and VF. I don't follow why you do it only
>>      for PF.
> We discuss the possibility of creating the devlink interface for VFs,
> but we decided not to. Arguably, this should not be available for VFs
> owned by VMs/containers, or at least in our case, since the interface is
> being used for getting information about the whole device or for
> getting/setting the MAC address. We plan to support more devlink
> functionalities in the near future, so maybe we add such support then if
> we consider it is needed.
>
>> 2) It should be done as the first thing in the probe flow. Then devlink
>>      port register, only after that netdev. It makes sense from the
>>      perspective of object hierarchy.
> I can not see a problem here. It is not the first thing done in the
> probe function, but I can not see any dependency for being so. And it is
> done before the devlink port registration and before the netdev
> registration what seems to be what other drivers do. What am I missing
> here?
>
>>      It is also usual to have the devlink priv as the "main" driver
>>      structure storage, see how that is done in mlx5 of mlxsw for example.
> I will check the way others drivers use the devlink priv.


Interestingly, there are 26 calls to devlink_alloc with half of them 
using the main driver structure and the other half using a specific 
devlink private struct. This is a huge responsibility now for me!

I'm afraid, for the shake of having this merged as soon as possible, 
I'll keep the current allocation. I did not suffer any problem with this 
approach while implementing the current support. If, for the further 
devlink support we plan to add, it turns out to be an issue, we will to 
the changes then. I would say it is a main change now or then, and 
current work does not justify it now.


>>
>>> +			netif_warn(efx, probe, net_dev,
>>> +				   "Failed to register devlink\n");
>>> 	}
>>>
>>> 	rc = efx_init_tc(efx);
>>> @@ -1157,6 +1162,7 @@ void ef100_remove(struct efx_nic *efx)
>>> {
>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>
>>> +	efx_fini_devlink(efx);
>>> 	efx_mcdi_detach(efx);
>>> 	efx_mcdi_fini(efx);
>>> 	if (nic_data)
>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>>> new file mode 100644
>>> index 000000000000..c506f8f35d25
>>> --- /dev/null
>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>>> @@ -0,0 +1,427 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only
>>> +/****************************************************************************
>>> + * Driver for AMD network controllers and boards
>>> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify it
>>> + * under the terms of the GNU General Public License version 2 as published
>>> + * by the Free Software Foundation, incorporated herein by reference.
>>> + */
>>> +
>>> +#include <linux/rtc.h>
>>> +#include "net_driver.h"
>>> +#include "ef100_nic.h"
>>> +#include "efx_devlink.h"
>>> +#include "nic.h"
>>> +#include "mcdi.h"
>>> +#include "mcdi_functions.h"
>>> +#include "mcdi_pcol.h"
>>> +
>>> +/* Custom devlink-info version object names for details that do not map to the
>>> + * generic standardized names.
>>> + */
>>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC	"fw.mgmt.suc"
>>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC	"fw.mgmt.cmc"
>>> +#define EFX_DEVLINK_INFO_VERSION_FPGA_REV	"fpga.rev"
>>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_HW	"fpga.app"
>>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_FW	DEVLINK_INFO_VERSION_GENERIC_FW_APP
>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_BOOT	"coproc.boot"
>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_UBOOT	"coproc.uboot"
>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_MAIN	"coproc.main"
>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY	"coproc.recovery"
>>> +#define EFX_DEVLINK_INFO_VERSION_FW_EXPROM	"fw.exprom"
>>> +#define EFX_DEVLINK_INFO_VERSION_FW_UEFI	"fw.uefi"
>>> +
>>> +#define EFX_MAX_VERSION_INFO_LEN	64
>>> +
>>> +static int efx_devlink_info_nvram_partition(struct efx_nic *efx,
>>> +					    struct devlink_info_req *req,
>>> +					    unsigned int partition_type,
>>> +					    const char *version_name)
>>> +{
>>> +	char buf[EFX_MAX_VERSION_INFO_LEN];
>>> +	u16 version[4];
>>> +	int rc;
>>> +
>>> +	rc = efx_mcdi_nvram_metadata(efx, partition_type, NULL, version, NULL,
>>> +				     0);
>>> +	if (rc)
>>> +		return rc;
>>> +
>>> +	snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u", version[0],
>>> +		 version[1], version[2], version[3]);
>>> +	devlink_info_version_stored_put(req, version_name, buf);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void efx_devlink_info_stored_versions(struct efx_nic *efx,
>>> +					     struct devlink_info_req *req)
>>> +{
>>> +	efx_devlink_info_nvram_partition(efx, req, NVRAM_PARTITION_TYPE_BUNDLE,
>>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID);
>>> +	efx_devlink_info_nvram_partition(efx, req,
>>> +					 NVRAM_PARTITION_TYPE_MC_FIRMWARE,
>>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT);
>>> +	efx_devlink_info_nvram_partition(efx, req,
>>> +					 NVRAM_PARTITION_TYPE_SUC_FIRMWARE,
>>> +					 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC);
>>> +	efx_devlink_info_nvram_partition(efx, req,
>>> +					 NVRAM_PARTITION_TYPE_EXPANSION_ROM,
>>> +					 EFX_DEVLINK_INFO_VERSION_FW_EXPROM);
>>> +	efx_devlink_info_nvram_partition(efx, req,
>>> +					 NVRAM_PARTITION_TYPE_EXPANSION_UEFI,
>>> +					 EFX_DEVLINK_INFO_VERSION_FW_UEFI);
>>> +}
>>> +
>>> +#define EFX_MAX_SERIALNUM_LEN	(ETH_ALEN * 2 + 1)
>>> +
>>> +static void efx_devlink_info_board_cfg(struct efx_nic *efx,
>>> +				       struct devlink_info_req *req)
>>> +{
>>> +	char sn[EFX_MAX_SERIALNUM_LEN];
>>> +	u8 mac_address[ETH_ALEN];
>>> +	int rc;
>>> +
>>> +	rc = efx_mcdi_get_board_cfg(efx, (u8 *)mac_address, NULL, NULL);
>>> +	if (!rc) {
>>> +		snprintf(sn, EFX_MAX_SERIALNUM_LEN, "%pm", mac_address);
>>> +		devlink_info_serial_number_put(req, sn);
>>> +	}
>>> +}
>>> +
>>> +#define EFX_VER_FLAG(_f)	\
>>> +	(MC_CMD_GET_VERSION_V5_OUT_ ## _f ## _PRESENT_LBN)
>>> +
>>> +static void efx_devlink_info_running_versions(struct efx_nic *efx,
>>> +					      struct devlink_info_req *req)
>>> +{
>>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_V5_OUT_LEN);
>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_VERSION_EXT_IN_LEN);
>>> +	char buf[EFX_MAX_VERSION_INFO_LEN];
>>> +	unsigned int flags, build_id;
>>> +	union {
>>> +		const __le32 *dwords;
>>> +		const __le16 *words;
>>> +		const char *str;
>>> +	} ver;
>>> +	struct rtc_time build_date;
>>> +	size_t outlength, offset;
>>> +	u64 tstamp;
>>> +	int rc;
>>> +
>>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, inbuf, sizeof(inbuf),
>>> +			  outbuf, sizeof(outbuf), &outlength);
>>> +	if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN)
>>> +		return;
>>> +
>>> +	/* Handle previous output */
>>> +	if (outlength < MC_CMD_GET_VERSION_V2_OUT_LEN) {
>>> +		ver.words = (__le16 *)MCDI_PTR(outbuf,
>>> +					       GET_VERSION_EXT_OUT_VERSION);
>>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +				  le16_to_cpu(ver.words[0]),
>>> +				  le16_to_cpu(ver.words[1]),
>>> +				  le16_to_cpu(ver.words[2]),
>>> +				  le16_to_cpu(ver.words[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>>> +						 buf);
>>> +		return;
>>> +	}
>>> +
>>> +	/* Handle V2 additions */
>>> +	flags = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_FLAGS);
>>> +	if (flags & BIT(EFX_VER_FLAG(BOARD_EXT_INFO))) {
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%s",
>>> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_NAME));
>>> +		devlink_info_version_fixed_put(req,
>>> +					       DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
>>> +					       buf);
>>> +
>>> +		/* Favour full board version if present (in V5 or later) */
>>> +		if (~flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>>> +			snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u",
>>> +				 MCDI_DWORD(outbuf,
>>> +					    GET_VERSION_V2_OUT_BOARD_REVISION));
>>> +			devlink_info_version_fixed_put(req,
>>> +						       DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>>> +						       buf);
>>> +		}
>>> +
>>> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_SERIAL);
>>> +		if (ver.str[0])
>>> +			devlink_info_board_serial_number_put(req, ver.str);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(FPGA_EXT_INFO))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V2_OUT_FPGA_VERSION);
>>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u_%c%u",
>>> +				  le32_to_cpu(ver.dwords[0]),
>>> +				  'A' + le32_to_cpu(ver.dwords[1]),
>>> +				  le32_to_cpu(ver.dwords[2]));
>>> +
>>> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_FPGA_EXTRA);
>>> +		if (ver.str[0])
>>> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>>> +				 " (%s)", ver.str);
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_FPGA_REV,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(CMC_EXT_INFO))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V2_OUT_CMCFW_VERSION);
>>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +				  le32_to_cpu(ver.dwords[0]),
>>> +				  le32_to_cpu(ver.dwords[1]),
>>> +				  le32_to_cpu(ver.dwords[2]),
>>> +				  le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		tstamp = MCDI_QWORD(outbuf,
>>> +				    GET_VERSION_V2_OUT_CMCFW_BUILD_DATE);
>>> +		if (tstamp) {
>>> +			rtc_time64_to_tm(tstamp, &build_date);
>>> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>>> +				 " (%ptRd)", &build_date);
>>> +		}
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC,
>>> +						 buf);
>>> +	}
>>> +
>>> +	ver.words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_V2_OUT_VERSION);
>>> +	offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			  le16_to_cpu(ver.words[0]), le16_to_cpu(ver.words[1]),
>>> +			  le16_to_cpu(ver.words[2]), le16_to_cpu(ver.words[3]));
>>> +	if (flags & BIT(EFX_VER_FLAG(MCFW_EXT_INFO))) {
>>> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_ID);
>>> +		snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>>> +			 " (%x) %s", build_id,
>>> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_NAME));
>>> +	}
>>> +	devlink_info_version_running_put(req,
>>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>>> +					 buf);
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V2_OUT_SUCFW_VERSION);
>>> +		tstamp = MCDI_QWORD(outbuf,
>>> +				    GET_VERSION_V2_OUT_SUCFW_BUILD_DATE);
>>> +		rtc_time64_to_tm(tstamp, &build_date);
>>> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_SUCFW_CHIP_ID);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN,
>>> +			 "%u.%u.%u.%u type %x (%ptRd)",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]), le32_to_cpu(ver.dwords[3]),
>>> +			 build_id, &build_date);
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (outlength < MC_CMD_GET_VERSION_V3_OUT_LEN)
>>> +		return;
>>> +
>>> +	/* Handle V3 additions */
>>> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_HW_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V3_OUT_DATAPATH_HW_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_HW,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_FW_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V3_OUT_DATAPATH_FW_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_FW,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (outlength < MC_CMD_GET_VERSION_V4_OUT_LEN)
>>> +		return;
>>> +
>>> +	/* Handle V4 additions */
>>> +	if (flags & BIT(EFX_VER_FLAG(SOC_BOOT_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V4_OUT_SOC_BOOT_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_SOC_BOOT,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(SOC_UBOOT_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V4_OUT_SOC_UBOOT_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_SOC_UBOOT,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(SOC_MAIN_ROOTFS_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V4_OUT_SOC_MAIN_ROOTFS_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_SOC_MAIN,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(SOC_RECOVERY_BUILDROOT_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V4_OUT_SOC_RECOVERY_BUILDROOT_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_VERSION)) &&
>>> +	    ~flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V4_OUT_SUCFW_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (outlength < MC_CMD_GET_VERSION_V5_OUT_LEN)
>>> +		return;
>>> +
>>> +	/* Handle V5 additions */
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V5_OUT_BOARD_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(BUNDLE_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V5_OUT_BUNDLE_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
>>> +						 buf);
>>> +	}
>>> +}
>>> +
>>> +#undef EFX_VER_FLAG
>>> +
>>> +static void efx_devlink_info_query_all(struct efx_nic *efx,
>>> +				       struct devlink_info_req *req)
>>> +{
>>> +	efx_devlink_info_board_cfg(efx, req);
>>> +	efx_devlink_info_stored_versions(efx, req);
>>> +	efx_devlink_info_running_versions(efx, req);
>>> +}
>>> +
>>> +struct efx_devlink {
>>> +	struct efx_nic *efx;
>>> +};
>>> +
>>> +static int efx_devlink_info_get(struct devlink *devlink,
>>> +				struct devlink_info_req *req,
>>> +				struct netlink_ext_ack *extack)
>>> +{
>>> +	struct efx_devlink *devlink_private = devlink_priv(devlink);
>>> +	struct efx_nic *efx = devlink_private->efx;
>>> +
>>> +	efx_devlink_info_query_all(efx, req);
>> I don't understand the reason for having efx_devlink_info_query_all() as
>> a separate function in compare to inline its code here.
>>
> Yes, it could be do as you say. I'll do.
>
> Thanks
>
>>> +	return 0;
>>> +}
>>> +
>>> +static const struct devlink_ops sfc_devlink_ops = {
>>> +	.info_get			= efx_devlink_info_get,
>>> +};
>>> +
>>> +void efx_fini_devlink(struct efx_nic *efx)
>>> +{
>>> +	if (efx->devlink) {
>>> +		struct efx_devlink *devlink_private;
>>> +
>>> +		devlink_private = devlink_priv(efx->devlink);
>>> +
>>> +		devlink_unregister(efx->devlink);
>>> +		devlink_free(efx->devlink);
>>> +		efx->devlink = NULL;
>>> +	}
>>> +}
>>> +
>>> +int efx_probe_devlink(struct efx_nic *efx)
>>> +{
>>> +	struct efx_devlink *devlink_private;
>>> +
>>> +	efx->devlink = devlink_alloc(&sfc_devlink_ops,
>>> +				     sizeof(struct efx_devlink),
>>> +				     &efx->pci_dev->dev);
>>> +	if (!efx->devlink)
>>> +		return -ENOMEM;
>>> +	devlink_private = devlink_priv(efx->devlink);
>>> +	devlink_private->efx = efx;
>>> +
>>> +	devlink_register(efx->devlink);
>>> +
>>> +	return 0;
>>> +}
>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.h b/drivers/net/ethernet/sfc/efx_devlink.h
>>> new file mode 100644
>>> index 000000000000..997f878aea93
>>> --- /dev/null
>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.h
>>> @@ -0,0 +1,20 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-only */
>>> +/****************************************************************************
>>> + * Driver for AMD network controllers and boards
>>> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify it
>>> + * under the terms of the GNU General Public License version 2 as published
>>> + * by the Free Software Foundation, incorporated herein by reference.
>>> + */
>>> +
>>> +#ifndef _EFX_DEVLINK_H
>>> +#define _EFX_DEVLINK_H
>>> +
>>> +#include "net_driver.h"
>>> +#include <net/devlink.h>
>>> +
>>> +int efx_probe_devlink(struct efx_nic *efx);
>>> +void efx_fini_devlink(struct efx_nic *efx);
>>> +
>>> +#endif	/* _EFX_DEVLINK_H */
>>> diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
>>> index af338208eae9..328cae82a7d8 100644
>>> --- a/drivers/net/ethernet/sfc/mcdi.c
>>> +++ b/drivers/net/ethernet/sfc/mcdi.c
>>> @@ -2308,6 +2308,78 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
>>> 	return rc;
>>> }
>>>
>>> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>>> +			    u32 *subtype, u16 version[4], char *desc,
>>> +			    size_t descsize)
>>> +{
>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN);
>>> +	efx_dword_t *outbuf;
>>> +	size_t outlen;
>>> +	u32 flags;
>>> +	int rc;
>>> +
>>> +	outbuf = kzalloc(MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2, GFP_KERNEL);
>>> +	if (!outbuf)
>>> +		return -ENOMEM;
>>> +
>>> +	MCDI_SET_DWORD(inbuf, NVRAM_METADATA_IN_TYPE, type);
>>> +
>>> +	rc = efx_mcdi_rpc_quiet(efx, MC_CMD_NVRAM_METADATA, inbuf,
>>> +				sizeof(inbuf), outbuf,
>>> +				MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2,
>>> +				&outlen);
>>> +	if (rc)
>>> +		goto out_free;
>>> +	if (outlen < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
>>> +		rc = -EIO;
>>> +		goto out_free;
>>> +	}
>>> +
>>> +	flags = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_FLAGS);
>>> +
>>> +	if (desc && descsize > 0) {
>>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_VALID_LBN)) {
>>> +			if (descsize <=
>>> +			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)) {
>>> +				rc = -E2BIG;
>>> +				goto out_free;
>>> +			}
>>> +
>>> +			strncpy(desc,
>>> +				MCDI_PTR(outbuf, NVRAM_METADATA_OUT_DESCRIPTION),
>>> +				MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen));
>>> +			desc[MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)] = '\0';
>>> +		} else {
>>> +			desc[0] = '\0';
>>> +		}
>>> +	}
>>> +
>>> +	if (subtype) {
>>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_SUBTYPE_VALID_LBN))
>>> +			*subtype = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_SUBTYPE);
>>> +		else
>>> +			*subtype = 0;
>>> +	}
>>> +
>>> +	if (version) {
>>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_VERSION_VALID_LBN)) {
>>> +			version[0] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_W);
>>> +			version[1] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_X);
>>> +			version[2] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Y);
>>> +			version[3] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Z);
>>> +		} else {
>>> +			version[0] = 0;
>>> +			version[1] = 0;
>>> +			version[2] = 0;
>>> +			version[3] = 0;
>>> +		}
>>> +	}
>>> +
>>> +out_free:
>>> +	kfree(outbuf);
>>> +	return rc;
>>> +}
>>> +
>>> int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
>>> 		      size_t len, size_t *retlen, u8 *buffer)
>>> {
>>> diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
>>> index 7e35fec9da35..63b090587f7a 100644
>>> --- a/drivers/net/ethernet/sfc/mcdi.h
>>> +++ b/drivers/net/ethernet/sfc/mcdi.h
>>> @@ -379,6 +379,9 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
>>> 			bool *protected_out);
>>> int efx_new_mcdi_nvram_test_all(struct efx_nic *efx);
>>> int efx_mcdi_nvram_test_all(struct efx_nic *efx);
>>> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>>> +			    u32 *subtype, u16 version[4], char *desc,
>>> +			    size_t descsize);
>>> int efx_mcdi_handle_assertion(struct efx_nic *efx);
>>> int efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
>>> int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac,
>>> diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
>>> index 3b49e216768b..d036641dc043 100644
>>> --- a/drivers/net/ethernet/sfc/net_driver.h
>>> +++ b/drivers/net/ethernet/sfc/net_driver.h
>>> @@ -994,6 +994,7 @@ enum efx_xdp_tx_queues_mode {
>>>    *      xdp_rxq_info structures?
>>>    * @netdev_notifier: Netdevice notifier.
>>>    * @tc: state for TC offload (EF100).
>>> + * @devlink: reference to devlink structure owned by this device
>>>    * @mem_bar: The BAR that is mapped into membase.
>>>    * @reg_base: Offset from the start of the bar to the function control window.
>>>    * @monitor_work: Hardware monitor workitem
>>> @@ -1179,6 +1180,7 @@ struct efx_nic {
>>> 	struct notifier_block netdev_notifier;
>>> 	struct efx_tc_state *tc;
>>>
>>> +	struct devlink *devlink;
>>> 	unsigned int mem_bar;
>>> 	u32 reg_base;
>>>
>>> -- 
>>> 2.17.1
>>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 11:31 ` [PATCH net-next 1/7] sfc: add " alejandro.lucero-palau
  2023-01-19 12:14   ` Jiri Pirko
  2023-01-19 15:50   ` kernel test robot
@ 2023-01-19 17:16   ` Jakub Kicinski
  2023-01-19 17:52     ` Lucero Palau, Alejandro
  2023-01-19 23:40   ` Jacob Keller
  2023-01-20 13:59   ` kernel test robot
  4 siblings, 1 reply; 52+ messages in thread
From: Jakub Kicinski @ 2023-01-19 17:16 UTC (permalink / raw)
  To: alejandro.lucero-palau
  Cc: netdev, linux-net-drivers, davem, pabeni, edumazet, habetsm,
	ecree.xilinx

On Thu, 19 Jan 2023 11:31:34 +0000 alejandro.lucero-palau@amd.com wrote:
> +		devlink_unregister(efx->devlink);
> +		devlink_free(efx->devlink);

Please use the devl_ APIs and take the devl_lock() explicitly.
Once you start adding sub-objects the API with implicit locking
gets racy.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 17:16   ` Jakub Kicinski
@ 2023-01-19 17:52     ` Lucero Palau, Alejandro
  2023-01-19 18:44       ` Jakub Kicinski
  0 siblings, 1 reply; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-19 17:52 UTC (permalink / raw)
  To: Jakub Kicinski, Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, pabeni, edumazet, ecree.xilinx


On 1/19/23 17:16, Jakub Kicinski wrote:
> On Thu, 19 Jan 2023 11:31:34 +0000 alejandro.lucero-palau@amd.com wrote:
>> +		devlink_unregister(efx->devlink);
>> +		devlink_free(efx->devlink);
> Please use the devl_ APIs and take the devl_lock() explicitly.
> Once you start adding sub-objects the API with implicit locking
> gets racy.


I need more help here.

The explicit locking you refer to, is it for this specific code only?

Also, I can not see all drivers locking/unlocking when doing 
devlink_unregister. Those doing it are calling code which invoke 
unregister devlink ports, like the NFP and I think ml5x as well.

In this case, no devlink port remains at this point, and no netdev either.

What is the potential race against?



^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 17:52     ` Lucero Palau, Alejandro
@ 2023-01-19 18:44       ` Jakub Kicinski
  2023-01-19 19:08         ` Lucero Palau, Alejandro
  0 siblings, 1 reply; 52+ messages in thread
From: Jakub Kicinski @ 2023-01-19 18:44 UTC (permalink / raw)
  To: Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, pabeni, edumazet, ecree.xilinx

On Thu, 19 Jan 2023 17:52:42 +0000 Lucero Palau, Alejandro wrote:
> On 1/19/23 17:16, Jakub Kicinski wrote:
> > On Thu, 19 Jan 2023 11:31:34 +0000 alejandro.lucero-palau@amd.com wrote:  
> >> +		devlink_unregister(efx->devlink);
> >> +		devlink_free(efx->devlink);  
> > Please use the devl_ APIs and take the devl_lock() explicitly.
> > Once you start adding sub-objects the API with implicit locking
> > gets racy.  
> 
> I need more help here.
> 
> The explicit locking you refer to, is it for this specific code only?

I only had a quick look at the series, but I saw you add ports.
So the locking should be something like:

  devlink = devlink_alloc();
  devl_lock(devlink);
  ...
  devl_register(devlink);
  ...
  netdev_register(netdev);
  devl_port_register(port_for_the_netdev);
  ...
  devl_unlock();

And the inverse on the .remove path.
Basically you want to hold the devlink instance lock for most of 
the .probe and .remove. That way nothing can bother the devlink
instance and the driver while the driver is initializing/finalizing.

Without holding the lock the linking between the devlink port and 
the netdev gets a bit iffy. It's a circular dependency of sorts
because both the netdev carries a link to the port and the port
carries info about the netdev.

We've been figuring out workarounds for subtle ordering and locking
problems since devlink ports were created. Recently we just gave up
and started asking drivers to hold the instance lock across .probe/
/.remove.

> Also, I can not see all drivers locking/unlocking when doing 
> devlink_unregister. Those doing it are calling code which invoke 
> unregister devlink ports, like the NFP and I think ml5x as well.

Right, only netdevsim was fully converted so far. The syzbot and other
testers use netdevsim mostly. We'll push actual HW drivers towards this
locking slowly.

> In this case, no devlink port remains at this point, and no netdev either.
> 
> What is the potential race against?

Right, I don't mean this particular spot, just over-trimmed the quote.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 18:44       ` Jakub Kicinski
@ 2023-01-19 19:08         ` Lucero Palau, Alejandro
  0 siblings, 0 replies; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-19 19:08 UTC (permalink / raw)
  To: Jakub Kicinski, Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, pabeni, edumazet, ecree.xilinx


On 1/19/23 18:44, Jakub Kicinski wrote:
> On Thu, 19 Jan 2023 17:52:42 +0000 Lucero Palau, Alejandro wrote:
>> On 1/19/23 17:16, Jakub Kicinski wrote:
>>> On Thu, 19 Jan 2023 11:31:34 +0000 alejandro.lucero-palau@amd.com wrote:
>>>> +		devlink_unregister(efx->devlink);
>>>> +		devlink_free(efx->devlink);
>>> Please use the devl_ APIs and take the devl_lock() explicitly.
>>> Once you start adding sub-objects the API with implicit locking
>>> gets racy.
>> I need more help here.
>>
>> The explicit locking you refer to, is it for this specific code only?
> I only had a quick look at the series, but I saw you add ports.
> So the locking should be something like:
>
>    devlink = devlink_alloc();
>    devl_lock(devlink);
>    ...
>    devl_register(devlink);
>    ...
>    netdev_register(netdev);
>    devl_port_register(port_for_the_netdev);
>    ...
>    devl_unlock();
>
> And the inverse on the .remove path.
> Basically you want to hold the devlink instance lock for most of
> the .probe and .remove. That way nothing can bother the devlink
> instance and the driver while the driver is initializing/finalizing.
>
> Without holding the lock the linking between the devlink port and
> the netdev gets a bit iffy. It's a circular dependency of sorts
> because both the netdev carries a link to the port and the port
> carries info about the netdev.
>
> We've been figuring out workarounds for subtle ordering and locking
> problems since devlink ports were created. Recently we just gave up
> and started asking drivers to hold the instance lock across .probe/
> /.remove.


OK. Thanks for the explanation.

I will add the locking.

>> Also, I can not see all drivers locking/unlocking when doing
>> devlink_unregister. Those doing it are calling code which invoke
>> unregister devlink ports, like the NFP and I think ml5x as well.
> Right, only netdevsim was fully converted so far. The syzbot and other
> testers use netdevsim mostly. We'll push actual HW drivers towards this
> locking slowly.
>
>> In this case, no devlink port remains at this point, and no netdev either.
>>
>> What is the potential race against?
> Right, I don't mean this particular spot, just over-trimmed the quote.


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 5/7] sfc: obtain device mac address based on firmware handle for ef100
  2023-01-19 11:31 ` [PATCH net-next 5/7] sfc: obtain device mac address based on firmware handle " alejandro.lucero-palau
@ 2023-01-19 19:47   ` kernel test robot
  2023-01-20  0:03   ` Jacob Keller
  1 sibling, 0 replies; 52+ messages in thread
From: kernel test robot @ 2023-01-19 19:47 UTC (permalink / raw)
  To: alejandro.lucero-palau, netdev, linux-net-drivers
  Cc: llvm, oe-kbuild-all, davem, kuba, pabeni, edumazet, habetsm,
	ecree.xilinx, Alejandro Lucero

Hi,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/alejandro-lucero-palau-amd-com/sfc-add-devlink-support-for-ef100/20230119-193440
patch link:    https://lore.kernel.org/r/20230119113140.20208-6-alejandro.lucero-palau%40amd.com
patch subject: [PATCH net-next 5/7] sfc: obtain device mac address based on firmware handle for ef100
config: i386-randconfig-a015 (https://download.01.org/0day-ci/archive/20230120/202301200333.BjjkOStI-lkp@intel.com/config)
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/94535fc2c87743925490d5ce0573b8e9b4b2690c
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review alejandro-lucero-palau-amd-com/sfc-add-devlink-support-for-ef100/20230119-193440
        git checkout 94535fc2c87743925490d5ce0573b8e9b4b2690c
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash drivers/net/ethernet/sfc/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/net/ethernet/sfc/ef100_nic.c:1127:21: warning: unused variable 'net_dev' [-Wunused-variable]
           struct net_device *net_dev = efx->net_dev;
                              ^
>> drivers/net/ethernet/sfc/ef100_nic.c:1172:9: warning: variable 'rc' is uninitialized when used here [-Wuninitialized]
           return rc;
                  ^~
   drivers/net/ethernet/sfc/ef100_nic.c:1128:8: note: initialize the variable 'rc' to silence this warning
           int rc;
                 ^
                  = 0
   2 warnings generated.


vim +/net_dev +1127 drivers/net/ethernet/sfc/ef100_nic.c

51b35a454efdcd Edward Cree      2020-07-27  1123  
98ff4c7c8ac7f5 Jonathan Cooper  2022-06-28  1124  int ef100_probe_netdev_pf(struct efx_nic *efx)
51b35a454efdcd Edward Cree      2020-07-27  1125  {
98ff4c7c8ac7f5 Jonathan Cooper  2022-06-28  1126  	struct ef100_nic_data *nic_data = efx->nic_data;
29ec1b27e73990 Edward Cree      2020-07-27 @1127  	struct net_device *net_dev = efx->net_dev;
98ff4c7c8ac7f5 Jonathan Cooper  2022-06-28  1128  	int rc;
29ec1b27e73990 Edward Cree      2020-07-27  1129  
6f6838aabff5ea Edward Cree      2022-07-28  1130  	if (!nic_data->grp_mae)
6f6838aabff5ea Edward Cree      2022-07-28  1131  		return 0;
6f6838aabff5ea Edward Cree      2022-07-28  1132  
6f6838aabff5ea Edward Cree      2022-07-28  1133  #ifdef CONFIG_SFC_SRIOV
67ab160ed08f5b Edward Cree      2022-07-28  1134  	rc = efx_init_struct_tc(efx);
67ab160ed08f5b Edward Cree      2022-07-28  1135  	if (rc)
67ab160ed08f5b Edward Cree      2022-07-28  1136  		return rc;
67ab160ed08f5b Edward Cree      2022-07-28  1137  
6f6838aabff5ea Edward Cree      2022-07-28  1138  	rc = efx_ef100_get_base_mport(efx);
6f6838aabff5ea Edward Cree      2022-07-28  1139  	if (rc) {
6f6838aabff5ea Edward Cree      2022-07-28  1140  		netif_warn(efx, probe, net_dev,
6f6838aabff5ea Edward Cree      2022-07-28  1141  			   "Failed to probe base mport rc %d; representors will not function\n",
6f6838aabff5ea Edward Cree      2022-07-28  1142  			   rc);
f393f2642abb0e Alejandro Lucero 2023-01-19  1143  	} else {
f393f2642abb0e Alejandro Lucero 2023-01-19  1144  		if (efx_probe_devlink(efx))
f393f2642abb0e Alejandro Lucero 2023-01-19  1145  			netif_warn(efx, probe, net_dev,
f393f2642abb0e Alejandro Lucero 2023-01-19  1146  				   "Failed to register devlink\n");
1542af777ce523 Alejandro Lucero 2023-01-19  1147  		rc = efx_init_mae(efx);
1542af777ce523 Alejandro Lucero 2023-01-19  1148  		if (rc)
1542af777ce523 Alejandro Lucero 2023-01-19  1149  			pci_warn(efx->pci_dev,
1542af777ce523 Alejandro Lucero 2023-01-19  1150  				 "Failed to init MAE rc %d; representors will not function\n",
1542af777ce523 Alejandro Lucero 2023-01-19  1151  				 rc);
1542af777ce523 Alejandro Lucero 2023-01-19  1152  		else
1542af777ce523 Alejandro Lucero 2023-01-19  1153  			efx_ef100_init_reps(efx);
6f6838aabff5ea Edward Cree      2022-07-28  1154  	}
67ab160ed08f5b Edward Cree      2022-07-28  1155  
67ab160ed08f5b Edward Cree      2022-07-28  1156  	rc = efx_init_tc(efx);
67ab160ed08f5b Edward Cree      2022-07-28  1157  	if (rc) {
67ab160ed08f5b Edward Cree      2022-07-28  1158  		/* Either we don't have an MAE at all (i.e. legacy v-switching),
67ab160ed08f5b Edward Cree      2022-07-28  1159  		 * or we do but we failed to probe it.  In the latter case, we
67ab160ed08f5b Edward Cree      2022-07-28  1160  		 * may not have set up default rules, in which case we won't be
67ab160ed08f5b Edward Cree      2022-07-28  1161  		 * able to pass any traffic.  However, we don't fail the probe,
67ab160ed08f5b Edward Cree      2022-07-28  1162  		 * because the user might need to use the netdevice to apply
67ab160ed08f5b Edward Cree      2022-07-28  1163  		 * configuration changes to fix whatever's wrong with the MAE.
67ab160ed08f5b Edward Cree      2022-07-28  1164  		 */
67ab160ed08f5b Edward Cree      2022-07-28  1165  		netif_warn(efx, probe, net_dev, "Failed to probe MAE rc %d\n",
67ab160ed08f5b Edward Cree      2022-07-28  1166  			   rc);
9dc0cad203ab57 Edward Cree      2022-09-26  1167  	} else {
9dc0cad203ab57 Edward Cree      2022-09-26  1168  		net_dev->features |= NETIF_F_HW_TC;
9dc0cad203ab57 Edward Cree      2022-09-26  1169  		efx->fixed_features |= NETIF_F_HW_TC;
67ab160ed08f5b Edward Cree      2022-07-28  1170  	}
6f6838aabff5ea Edward Cree      2022-07-28  1171  #endif
29ec1b27e73990 Edward Cree      2020-07-27 @1172  	return rc;
51b35a454efdcd Edward Cree      2020-07-27  1173  }
51b35a454efdcd Edward Cree      2020-07-27  1174  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 11:31 ` [PATCH net-next 1/7] sfc: add " alejandro.lucero-palau
                     ` (2 preceding siblings ...)
  2023-01-19 17:16   ` Jakub Kicinski
@ 2023-01-19 23:40   ` Jacob Keller
  2023-01-20 14:11     ` Lucero Palau, Alejandro
  2023-01-24 11:05     ` Lucero Palau, Alejandro
  2023-01-20 13:59   ` kernel test robot
  4 siblings, 2 replies; 52+ messages in thread
From: Jacob Keller @ 2023-01-19 23:40 UTC (permalink / raw)
  To: alejandro.lucero-palau, netdev, linux-net-drivers
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx



On 1/19/2023 3:31 AM, alejandro.lucero-palau@amd.com wrote:
> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
> 
> Basic support for devlink info command.
> 
> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
> ---
>  drivers/net/ethernet/sfc/Kconfig       |   1 +
>  drivers/net/ethernet/sfc/Makefile      |   3 +-
>  drivers/net/ethernet/sfc/ef100_nic.c   |   6 +
>  drivers/net/ethernet/sfc/efx_devlink.c | 427 +++++++++++++++++++++++++
>  drivers/net/ethernet/sfc/efx_devlink.h |  20 ++
>  drivers/net/ethernet/sfc/mcdi.c        |  72 +++++
>  drivers/net/ethernet/sfc/mcdi.h        |   3 +
>  drivers/net/ethernet/sfc/net_driver.h  |   2 +
>  8 files changed, 533 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/net/ethernet/sfc/efx_devlink.c
>  create mode 100644 drivers/net/ethernet/sfc/efx_devlink.h
> 
> diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
> index 0950e6b0508f..4af36ba8906b 100644
> --- a/drivers/net/ethernet/sfc/Kconfig
> +++ b/drivers/net/ethernet/sfc/Kconfig
> @@ -22,6 +22,7 @@ config SFC
>  	depends on PTP_1588_CLOCK_OPTIONAL
>  	select MDIO
>  	select CRC32
> +	select NET_DEVLINK
>  	help
>  	  This driver supports 10/40-gigabit Ethernet cards based on
>  	  the Solarflare SFC9100-family controllers.
> diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
> index 712a48d00069..55b9c73cd8ef 100644
> --- a/drivers/net/ethernet/sfc/Makefile
> +++ b/drivers/net/ethernet/sfc/Makefile
> @@ -6,7 +6,8 @@ sfc-y			+= efx.o efx_common.o efx_channels.o nic.o \
>  			   mcdi.o mcdi_port.o mcdi_port_common.o \
>  			   mcdi_functions.o mcdi_filters.o mcdi_mon.o \
>  			   ef100.o ef100_nic.o ef100_netdev.o \
> -			   ef100_ethtool.o ef100_rx.o ef100_tx.o
> +			   ef100_ethtool.o ef100_rx.o ef100_tx.o \
> +			   efx_devlink.o
>  sfc-$(CONFIG_SFC_MTD)	+= mtd.o
>  sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
>                             mae.o tc.o tc_bindings.o tc_counters.o
> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
> index ad686c671ab8..14af8f314b83 100644
> --- a/drivers/net/ethernet/sfc/ef100_nic.c
> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
> @@ -27,6 +27,7 @@
>  #include "tc.h"
>  #include "mae.h"
>  #include "rx_common.h"
> +#include "efx_devlink.h"
>  
>  #define EF100_MAX_VIS 4096
>  #define EF100_NUM_MCDI_BUFFERS	1
> @@ -1124,6 +1125,10 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
>  		netif_warn(efx, probe, net_dev,
>  			   "Failed to probe base mport rc %d; representors will not function\n",
>  			   rc);
> +	} else {
> +		if (efx_probe_devlink(efx))
> +			netif_warn(efx, probe, net_dev,
> +				   "Failed to register devlink\n");
>  	}
>  

A bit of a weird construction here with the next step in an else block?
I guess this is being treated as an optional feature, and depends on
efx_ef100_get_base_mport succeeding?

It reads a little awkward, but I can't think of a better way to arrange
this unless another helper function was used to combine these two calls
in order to avoid the extra indentation.


>  	rc = efx_init_tc(efx);
> @@ -1157,6 +1162,7 @@ void ef100_remove(struct efx_nic *efx)
>  {
>  	struct ef100_nic_data *nic_data = efx->nic_data;
>  
> +	efx_fini_devlink(efx);
>  	efx_mcdi_detach(efx);
>  	efx_mcdi_fini(efx);
>  	if (nic_data)
> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
> new file mode 100644
> index 000000000000..c506f8f35d25
> --- /dev/null
> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
> @@ -0,0 +1,427 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/****************************************************************************
> + * Driver for AMD network controllers and boards
> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published
> + * by the Free Software Foundation, incorporated herein by reference.
> + */
> +
> +#include <linux/rtc.h>
> +#include "net_driver.h"
> +#include "ef100_nic.h"
> +#include "efx_devlink.h"
> +#include "nic.h"
> +#include "mcdi.h"
> +#include "mcdi_functions.h"
> +#include "mcdi_pcol.h"
> +
> +/* Custom devlink-info version object names for details that do not map to the
> + * generic standardized names.
> + */
> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC	"fw.mgmt.suc"
> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC	"fw.mgmt.cmc"
> +#define EFX_DEVLINK_INFO_VERSION_FPGA_REV	"fpga.rev"
> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_HW	"fpga.app"
> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_FW	DEVLINK_INFO_VERSION_GENERIC_FW_APP
> +#define EFX_DEVLINK_INFO_VERSION_SOC_BOOT	"coproc.boot"
> +#define EFX_DEVLINK_INFO_VERSION_SOC_UBOOT	"coproc.uboot"
> +#define EFX_DEVLINK_INFO_VERSION_SOC_MAIN	"coproc.main"
> +#define EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY	"coproc.recovery"
> +#define EFX_DEVLINK_INFO_VERSION_FW_EXPROM	"fw.exprom"
> +#define EFX_DEVLINK_INFO_VERSION_FW_UEFI	"fw.uefi"

Here, you've defined several new versions, only one of which is
standard. I don't see an associated documentation addition. Please add a
ef100.rst file to Documentation/networking/devlink

It is also preferred to use the standard names or extend the set of
standard names where appropriate first. Can you explain why you didn't
do that here?

For example, the documentation for "fw.undi" indicates it may include
the UEFI driver, and I would expect your UEFI version to be something
like fw.undi or fw.undi.uefi if its distinct...

> +
> +#define EFX_MAX_VERSION_INFO_LEN	64
> +
> +static int efx_devlink_info_nvram_partition(struct efx_nic *efx,
> +					    struct devlink_info_req *req,
> +					    unsigned int partition_type,
> +					    const char *version_name)
> +{
> +	char buf[EFX_MAX_VERSION_INFO_LEN];
> +	u16 version[4];
> +	int rc;
> +
> +	rc = efx_mcdi_nvram_metadata(efx, partition_type, NULL, version, NULL,
> +				     0);
> +	if (rc)
> +		return rc;
> +
> +	snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u", version[0],
> +		 version[1], version[2], version[3]);
> +	devlink_info_version_stored_put(req, version_name, buf);
> +
> +	return 0;
> +}
> +
> +static void efx_devlink_info_stored_versions(struct efx_nic *efx,
> +					     struct devlink_info_req *req)
> +{
> +	efx_devlink_info_nvram_partition(efx, req, NVRAM_PARTITION_TYPE_BUNDLE,
> +					 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID);
> +	efx_devlink_info_nvram_partition(efx, req,
> +					 NVRAM_PARTITION_TYPE_MC_FIRMWARE,
> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT);
> +	efx_devlink_info_nvram_partition(efx, req,
> +					 NVRAM_PARTITION_TYPE_SUC_FIRMWARE,
> +					 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC);
> +	efx_devlink_info_nvram_partition(efx, req,
> +					 NVRAM_PARTITION_TYPE_EXPANSION_ROM,
> +					 EFX_DEVLINK_INFO_VERSION_FW_EXPROM);
> +	efx_devlink_info_nvram_partition(efx, req,
> +					 NVRAM_PARTITION_TYPE_EXPANSION_UEFI,
> +					 EFX_DEVLINK_INFO_VERSION_FW_UEFI);
> +}
> +
> +#define EFX_MAX_SERIALNUM_LEN	(ETH_ALEN * 2 + 1)
> +
> +static void efx_devlink_info_board_cfg(struct efx_nic *efx,
> +				       struct devlink_info_req *req)
> +{
> +	char sn[EFX_MAX_SERIALNUM_LEN];
> +	u8 mac_address[ETH_ALEN];
> +	int rc;
> +
> +	rc = efx_mcdi_get_board_cfg(efx, (u8 *)mac_address, NULL, NULL);
> +	if (!rc) {
> +		snprintf(sn, EFX_MAX_SERIALNUM_LEN, "%pm", mac_address);
> +		devlink_info_serial_number_put(req, sn);
> +	}
> +}
> +
> +#define EFX_VER_FLAG(_f)	\
> +	(MC_CMD_GET_VERSION_V5_OUT_ ## _f ## _PRESENT_LBN)
> +
> +static void efx_devlink_info_running_versions(struct efx_nic *efx,
> +					      struct devlink_info_req *req)
> +{

This function for doing running versions is very long, and seems quite
complicated. It's difficult to parse what versions are being reported.

I saw that your stored version used a helper function to separate each
thing out nicely. Is there any way to do that here?

> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_V5_OUT_LEN);
> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_VERSION_EXT_IN_LEN);
> +	char buf[EFX_MAX_VERSION_INFO_LEN];
> +	unsigned int flags, build_id;
> +	union {
> +		const __le32 *dwords;
> +		const __le16 *words;
> +		const char *str;
> +	} ver;

For example, you've got this local union on the stack that seems to be
reused a bunch...

> +	struct rtc_time build_date;
> +	size_t outlength, offset;
> +	u64 tstamp;
> +	int rc;
> +
> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, inbuf, sizeof(inbuf),
> +			  outbuf, sizeof(outbuf), &outlength);
> +	if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN)
> +		return;
> +
> +	/* Handle previous output */
> +	if (outlength < MC_CMD_GET_VERSION_V2_OUT_LEN) {
> +		ver.words = (__le16 *)MCDI_PTR(outbuf,
> +					       GET_VERSION_EXT_OUT_VERSION);
> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
> +				  le16_to_cpu(ver.words[0]),
> +				  le16_to_cpu(ver.words[1]),
> +				  le16_to_cpu(ver.words[2]),
> +				  le16_to_cpu(ver.words[3]));
> +
> +		devlink_info_version_running_put(req,
> +						 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
> +						 buf);
> +		return;
> +	}
> +
> +	/* Handle V2 additions */
> +	flags = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_FLAGS);
> +	if (flags & BIT(EFX_VER_FLAG(BOARD_EXT_INFO))) {
> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%s",
> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_NAME));
> +		devlink_info_version_fixed_put(req,
> +					       DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
> +					       buf);
> +
> +		/* Favour full board version if present (in V5 or later) */
> +		if (~flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
> +			snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u",
> +				 MCDI_DWORD(outbuf,
> +					    GET_VERSION_V2_OUT_BOARD_REVISION));
> +			devlink_info_version_fixed_put(req,
> +						       DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
> +						       buf);
> +		}
> +
> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_SERIAL);
> +		if (ver.str[0])
> +			devlink_info_board_serial_number_put(req, ver.str);
> +	}
> +
> +	if (flags & BIT(EFX_VER_FLAG(FPGA_EXT_INFO))) {
> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
> +						GET_VERSION_V2_OUT_FPGA_VERSION);
> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u_%c%u",
> +				  le32_to_cpu(ver.dwords[0]),
> +				  'A' + le32_to_cpu(ver.dwords[1]),
> +				  le32_to_cpu(ver.dwords[2]));
> +
> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_FPGA_EXTRA);
> +		if (ver.str[0])
> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
> +				 " (%s)", ver.str);
> +
> +		devlink_info_version_running_put(req,
> +						 EFX_DEVLINK_INFO_VERSION_FPGA_REV,
> +						 buf);
> +	}
> +
> +	if (flags & BIT(EFX_VER_FLAG(CMC_EXT_INFO))) {
> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
> +						GET_VERSION_V2_OUT_CMCFW_VERSION);
> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
> +				  le32_to_cpu(ver.dwords[0]),
> +				  le32_to_cpu(ver.dwords[1]),
> +				  le32_to_cpu(ver.dwords[2]),
> +				  le32_to_cpu(ver.dwords[3]));
> +
> +		tstamp = MCDI_QWORD(outbuf,
> +				    GET_VERSION_V2_OUT_CMCFW_BUILD_DATE);
> +		if (tstamp) {
> +			rtc_time64_to_tm(tstamp, &build_date);
> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
> +				 " (%ptRd)", &build_date);
> +		}
> +
> +		devlink_info_version_running_put(req,
> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC,
> +						 buf);
> +	}
> +
> +	ver.words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_V2_OUT_VERSION);
> +	offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
> +			  le16_to_cpu(ver.words[0]), le16_to_cpu(ver.words[1]),
> +			  le16_to_cpu(ver.words[2]), le16_to_cpu(ver.words[3]));
> +	if (flags & BIT(EFX_VER_FLAG(MCFW_EXT_INFO))) {
> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_ID);
> +		snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
> +			 " (%x) %s", build_id,
> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_NAME));
> +	}
> +	devlink_info_version_running_put(req,
> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
> +					 buf);
> +
> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
> +						GET_VERSION_V2_OUT_SUCFW_VERSION);
> +		tstamp = MCDI_QWORD(outbuf,
> +				    GET_VERSION_V2_OUT_SUCFW_BUILD_DATE);
> +		rtc_time64_to_tm(tstamp, &build_date);
> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_SUCFW_CHIP_ID);
> +
> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN,
> +			 "%u.%u.%u.%u type %x (%ptRd)",
> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
> +			 le32_to_cpu(ver.dwords[2]), le32_to_cpu(ver.dwords[3]),
> +			 build_id, &build_date);
> +
> +		devlink_info_version_running_put(req,
> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
> +						 buf);
> +	}
> +
> +	if (outlength < MC_CMD_GET_VERSION_V3_OUT_LEN)
> +		return;
> +
> +	/* Handle V3 additions */
> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_HW_VERSION))) {
> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
> +						GET_VERSION_V3_OUT_DATAPATH_HW_VERSION);
> +
> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
> +			 le32_to_cpu(ver.dwords[2]));
> +
> +		devlink_info_version_running_put(req,
> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_HW,
> +						 buf);
> +	}
> +
> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_FW_VERSION))) {
> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
> +						GET_VERSION_V3_OUT_DATAPATH_FW_VERSION);
> +
> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
> +			 le32_to_cpu(ver.dwords[2]));
> +
> +		devlink_info_version_running_put(req,
> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_FW,
> +						 buf);
> +	}
> +
> +	if (outlength < MC_CMD_GET_VERSION_V4_OUT_LEN)
> +		return;
> +
> +	/* Handle V4 additions */
> +	if (flags & BIT(EFX_VER_FLAG(SOC_BOOT_VERSION))) {
> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
> +						GET_VERSION_V4_OUT_SOC_BOOT_VERSION);
> +
> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
> +			 le32_to_cpu(ver.dwords[2]),
> +			 le32_to_cpu(ver.dwords[3]));
> +
> +		devlink_info_version_running_put(req,
> +						 EFX_DEVLINK_INFO_VERSION_SOC_BOOT,
> +						 buf);
> +	}
> +
> +	if (flags & BIT(EFX_VER_FLAG(SOC_UBOOT_VERSION))) {
> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
> +						GET_VERSION_V4_OUT_SOC_UBOOT_VERSION);
> +
> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
> +			 le32_to_cpu(ver.dwords[2]),
> +			 le32_to_cpu(ver.dwords[3]));
> +
> +		devlink_info_version_running_put(req,
> +						 EFX_DEVLINK_INFO_VERSION_SOC_UBOOT,
> +						 buf);
> +	}
> +
> +	if (flags & BIT(EFX_VER_FLAG(SOC_MAIN_ROOTFS_VERSION))) {
> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
> +						GET_VERSION_V4_OUT_SOC_MAIN_ROOTFS_VERSION);
> +
> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
> +			 le32_to_cpu(ver.dwords[2]),
> +			 le32_to_cpu(ver.dwords[3]));
> +
> +		devlink_info_version_running_put(req,
> +						 EFX_DEVLINK_INFO_VERSION_SOC_MAIN,
> +						 buf);
> +	}
> +
> +	if (flags & BIT(EFX_VER_FLAG(SOC_RECOVERY_BUILDROOT_VERSION))) {
> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
> +						GET_VERSION_V4_OUT_SOC_RECOVERY_BUILDROOT_VERSION);
> +
> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
> +			 le32_to_cpu(ver.dwords[2]),
> +			 le32_to_cpu(ver.dwords[3]));
> +
> +		devlink_info_version_running_put(req,
> +						 EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY,
> +						 buf);
> +	}
> +
> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_VERSION)) &&
> +	    ~flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
> +						GET_VERSION_V4_OUT_SUCFW_VERSION);
> +
> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
> +			 le32_to_cpu(ver.dwords[2]),
> +			 le32_to_cpu(ver.dwords[3]));
> +
> +		devlink_info_version_running_put(req,
> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
> +						 buf);
> +	}
> +
> +	if (outlength < MC_CMD_GET_VERSION_V5_OUT_LEN)
> +		return;
> +
> +	/* Handle V5 additions */
> +
> +	if (flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
> +						GET_VERSION_V5_OUT_BOARD_VERSION);
> +
> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
> +			 le32_to_cpu(ver.dwords[2]),
> +			 le32_to_cpu(ver.dwords[3]));
> +
> +		devlink_info_version_running_put(req,
> +						 DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
> +						 buf);
> +	}
> +
> +	if (flags & BIT(EFX_VER_FLAG(BUNDLE_VERSION))) {
> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
> +						GET_VERSION_V5_OUT_BUNDLE_VERSION);
> +
> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
> +			 le32_to_cpu(ver.dwords[2]),
> +			 le32_to_cpu(ver.dwords[3]));
> +
> +		devlink_info_version_running_put(req,
> +						 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
> +						 buf);
> +	}
> +}

In the ice driver I implemented each version extraction as a separate
function to make it more clear which versions where which. This running
function could benefit from some organization like that.

> +
> +#undef EFX_VER_FLAG
> +
> +static void efx_devlink_info_query_all(struct efx_nic *efx,
> +				       struct devlink_info_req *req)
> +{
> +	efx_devlink_info_board_cfg(efx, req);
> +	efx_devlink_info_stored_versions(efx, req);
> +	efx_devlink_info_running_versions(efx, req);
> +}

Do you really need this to be a separate function and not just inlined
into the caller, efx_devlink_info_get.

> +
> +struct efx_devlink {
> +	struct efx_nic *efx;
> +};
> +
> +static int efx_devlink_info_get(struct devlink *devlink,
> +				struct devlink_info_req *req,
> +				struct netlink_ext_ack *extack)
> +{
> +	struct efx_devlink *devlink_private = devlink_priv(devlink);
> +	struct efx_nic *efx = devlink_private->efx;
> +
> +	efx_devlink_info_query_all(efx, req);
> +	return 0;
> +}
> +
> +static const struct devlink_ops sfc_devlink_ops = {
> +	.info_get			= efx_devlink_info_get,
> +};
> +
> +void efx_fini_devlink(struct efx_nic *efx)
> +{
> +	if (efx->devlink) {
> +		struct efx_devlink *devlink_private;
> +
> +		devlink_private = devlink_priv(efx->devlink);
> +
> +		devlink_unregister(efx->devlink);
> +		devlink_free(efx->devlink);
> +		efx->devlink = NULL;
> +	}
> +}
> +
> +int efx_probe_devlink(struct efx_nic *efx)
> +{
> +	struct efx_devlink *devlink_private;
> +
> +	efx->devlink = devlink_alloc(&sfc_devlink_ops,
> +				     sizeof(struct efx_devlink),
> +				     &efx->pci_dev->dev);
> +	if (!efx->devlink)
> +		return -ENOMEM;
> +	devlink_private = devlink_priv(efx->devlink);
> +	devlink_private->efx = efx;
> +
> +	devlink_register(efx->devlink);
> +

So drivers implementing devlink typically would allocate the devlink
early (almost the first thing it does) and make its private field
something like their main private data structure.

Obviously you're adding this to a pre-existing driver and it is
initially simpler and easier to keep it separate. I'm not sure what
other reviewers' stance on this is, but I think its preferable to
allocate as an early stage and register once the driver is ready to
accept requests from user space.

As for a reason why, implementing reload support effectively requires this.

> +	return 0;
> +}
> diff --git a/drivers/net/ethernet/sfc/efx_devlink.h b/drivers/net/ethernet/sfc/efx_devlink.h
> new file mode 100644
> index 000000000000..997f878aea93
> --- /dev/null
> +++ b/drivers/net/ethernet/sfc/efx_devlink.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/****************************************************************************
> + * Driver for AMD network controllers and boards
> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published
> + * by the Free Software Foundation, incorporated herein by reference.
> + */
> +
> +#ifndef _EFX_DEVLINK_H
> +#define _EFX_DEVLINK_H
> +
> +#include "net_driver.h"
> +#include <net/devlink.h>
> +
> +int efx_probe_devlink(struct efx_nic *efx);
> +void efx_fini_devlink(struct efx_nic *efx);
> +
> +#endif	/* _EFX_DEVLINK_H */
> diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
> index af338208eae9..328cae82a7d8 100644
> --- a/drivers/net/ethernet/sfc/mcdi.c
> +++ b/drivers/net/ethernet/sfc/mcdi.c
> @@ -2308,6 +2308,78 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
>  	return rc;
>  }
>  
> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
> +			    u32 *subtype, u16 version[4], char *desc,
> +			    size_t descsize)
> +{
> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN);
> +	efx_dword_t *outbuf;
> +	size_t outlen;
> +	u32 flags;
> +	int rc;
> +
> +	outbuf = kzalloc(MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2, GFP_KERNEL);
> +	if (!outbuf)
> +		return -ENOMEM;
> +
> +	MCDI_SET_DWORD(inbuf, NVRAM_METADATA_IN_TYPE, type);
> +
> +	rc = efx_mcdi_rpc_quiet(efx, MC_CMD_NVRAM_METADATA, inbuf,
> +				sizeof(inbuf), outbuf,
> +				MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2,
> +				&outlen);
> +	if (rc)
> +		goto out_free;
> +	if (outlen < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
> +		rc = -EIO;
> +		goto out_free;
> +	}
> +
> +	flags = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_FLAGS);
> +
> +	if (desc && descsize > 0) {
> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_VALID_LBN)) {
> +			if (descsize <=
> +			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)) {
> +				rc = -E2BIG;
> +				goto out_free;
> +			}
> +
> +			strncpy(desc,
> +				MCDI_PTR(outbuf, NVRAM_METADATA_OUT_DESCRIPTION),
> +				MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen));
> +			desc[MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)] = '\0';
> +		} else {
> +			desc[0] = '\0';
> +		}
> +	}
> +
> +	if (subtype) {
> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_SUBTYPE_VALID_LBN))
> +			*subtype = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_SUBTYPE);
> +		else
> +			*subtype = 0;
> +	}
> +
> +	if (version) {
> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_VERSION_VALID_LBN)) {
> +			version[0] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_W);
> +			version[1] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_X);
> +			version[2] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Y);
> +			version[3] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Z);
> +		} else {
> +			version[0] = 0;
> +			version[1] = 0;
> +			version[2] = 0;
> +			version[3] = 0;
> +		}
> +	}
> +
> +out_free:
> +	kfree(outbuf);
> +	return rc;
> +}
> +
>  int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
>  		      size_t len, size_t *retlen, u8 *buffer)
>  {
> diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
> index 7e35fec9da35..63b090587f7a 100644
> --- a/drivers/net/ethernet/sfc/mcdi.h
> +++ b/drivers/net/ethernet/sfc/mcdi.h
> @@ -379,6 +379,9 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
>  			bool *protected_out);
>  int efx_new_mcdi_nvram_test_all(struct efx_nic *efx);
>  int efx_mcdi_nvram_test_all(struct efx_nic *efx);
> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
> +			    u32 *subtype, u16 version[4], char *desc,
> +			    size_t descsize);
>  int efx_mcdi_handle_assertion(struct efx_nic *efx);
>  int efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
>  int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac,
> diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
> index 3b49e216768b..d036641dc043 100644
> --- a/drivers/net/ethernet/sfc/net_driver.h
> +++ b/drivers/net/ethernet/sfc/net_driver.h
> @@ -994,6 +994,7 @@ enum efx_xdp_tx_queues_mode {
>   *      xdp_rxq_info structures?
>   * @netdev_notifier: Netdevice notifier.
>   * @tc: state for TC offload (EF100).
> + * @devlink: reference to devlink structure owned by this device
>   * @mem_bar: The BAR that is mapped into membase.
>   * @reg_base: Offset from the start of the bar to the function control window.
>   * @monitor_work: Hardware monitor workitem
> @@ -1179,6 +1180,7 @@ struct efx_nic {
>  	struct notifier_block netdev_notifier;
>  	struct efx_tc_state *tc;
>  
> +	struct devlink *devlink;
>  	unsigned int mem_bar;
>  	u32 reg_base;
>  

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 2/7] sfc: enumerate mports in ef100
  2023-01-19 11:31 ` [PATCH net-next 2/7] sfc: enumerate mports in ef100 alejandro.lucero-palau
@ 2023-01-19 23:48   ` Jacob Keller
  2023-01-20 14:13     ` Lucero Palau, Alejandro
  2023-01-20 12:47   ` kernel test robot
  1 sibling, 1 reply; 52+ messages in thread
From: Jacob Keller @ 2023-01-19 23:48 UTC (permalink / raw)
  To: alejandro.lucero-palau, netdev, linux-net-drivers
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx



On 1/19/2023 3:31 AM, alejandro.lucero-palau@amd.com wrote:
> +
> +int efx_mae_enumerate_mports(struct efx_nic *efx)
> +{
> +#define MCDI_MPORT_JOURNAL_LEN \
> +	sizeof(efx_dword_t[DIV_ROUND_UP(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4)])

Please keep #define like this outside the function block. This is really
hard to read. It's also not clear to me what exactly this define is
doing.. you're accessing an array and using a DIV_ROUND_UP...

> +	efx_dword_t *outbuf = kzalloc(MCDI_MPORT_JOURNAL_LEN, GFP_KERNEL);
> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN);
> +	MCDI_DECLARE_STRUCT_PTR(desc);
> +	size_t outlen, stride, count;
> +	int rc = 0, i;

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 3/7] sfc: add mport lookup based on driver's mport data
  2023-01-19 11:31 ` [PATCH net-next 3/7] sfc: add mport lookup based on driver's mport data alejandro.lucero-palau
@ 2023-01-19 23:57   ` Jacob Keller
  2023-01-20  9:34     ` Lucero Palau, Alejandro
  0 siblings, 1 reply; 52+ messages in thread
From: Jacob Keller @ 2023-01-19 23:57 UTC (permalink / raw)
  To: alejandro.lucero-palau, netdev, linux-net-drivers
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx



On 1/19/2023 3:31 AM, alejandro.lucero-palau@amd.com wrote:
> +int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id)
> +{
> +	struct ef100_nic_data *nic_data = efx->nic_data;
> +	struct efx_mae *mae = efx->mae;
> +	struct rhashtable_iter walk;
> +	struct mae_mport_desc *m;
> +	int rc = -ENOENT;
> +
> +	rhashtable_walk_enter(&mae->mports_ht, &walk);
> +	rhashtable_walk_start(&walk);
> +	while ((m = rhashtable_walk_next(&walk)) != NULL) {
> +		if (m->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC &&
> +		    m->interface_idx == nic_data->local_mae_intf &&
> +		    m->pf_idx == 0 &&
> +		    m->vf_idx == vf_idx) {
> +			*id = m->mport_id;
> +			rc = 0;
> +			break;
> +		}
> +	}
> +	rhashtable_walk_stop(&walk);
> +	rhashtable_walk_exit(&walk);

Curious if you have any reasoning for why you chose rhashtable vs
another structure (such as a simpler hash table of linked lists or xarray).

At any rate,

Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 5/7] sfc: obtain device mac address based on firmware handle for ef100
  2023-01-19 11:31 ` [PATCH net-next 5/7] sfc: obtain device mac address based on firmware handle " alejandro.lucero-palau
  2023-01-19 19:47   ` kernel test robot
@ 2023-01-20  0:03   ` Jacob Keller
  1 sibling, 0 replies; 52+ messages in thread
From: Jacob Keller @ 2023-01-20  0:03 UTC (permalink / raw)
  To: alejandro.lucero-palau, netdev, linux-net-drivers
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx



On 1/19/2023 3:31 AM, alejandro.lucero-palau@amd.com wrote:
> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
> 
> Getting device mac address is currently based on a specific MCDI command
> only available for the PF. This patch changes the MCDI command to a
> generic one for PFs and VFs based on a client handle. This allows both
> PFs and VFs to ask for their mac address during initialization using the
> CLIENT_HANDLE_SELF.
> 
> Moreover, the patch allows other client handles which will be used by
> the PF to ask for mac addresses linked to VFs. This is necessary for
> suporting the port_function_hw_addr_get devlink function in further
> patches.
> 
> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
> ---

Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 0/7] sfc: devlink support for ef100
  2023-01-19 11:31 [PATCH net-next 0/7] sfc: devlink support for ef100 alejandro.lucero-palau
                   ` (6 preceding siblings ...)
  2023-01-19 11:31 ` [PATCH net-next 7/7] sfc: add support for devlink port_function_hw_addr_set " alejandro.lucero-palau
@ 2023-01-20  8:55 ` Martin Habets
  7 siblings, 0 replies; 52+ messages in thread
From: Martin Habets @ 2023-01-20  8:55 UTC (permalink / raw)
  To: alejandro.lucero-palau
  Cc: netdev, linux-net-drivers, davem, kuba, pabeni, edumazet, ecree.xilinx

Please fix my email address as per the MAINTAINTERS file:
 habetsm.xilinx@gmail.com

On Thu, Jan 19, 2023 at 11:31:33AM +0000, alejandro.lucero-palau@amd.com wrote:
> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
> 
> This patchset adds devlink port support for ef100 allowing setting VFs
> mac addresses through the VF representors netdevs.
> 
> Basic devlink support is first introduced for info command. Then changes
> for enumerating MAE ports which will be used for devlik port creation

Typo: devlink.

> when netdevs are register.

.. are registered.

> 
> Adding support for devlink port_function_hw_addr_get requires changes in
> the ef100 driver for getting the mac address based on a client handle.
> This allows to obtain VFs mac address during netdev initialization as
> well what is included in patch 5.
> 
> Such client handle is used in patches 6 and 7 for getting and setting
> devlink ports addresses.

port in stead of ports.

Martin

> 
> Alejandro Lucero (7):
>   sfc: add devlink support for ef100
>   sfc: enumerate mports in ef100
>   sfc: add mport lookup based on driver's mport data
>   sfc: add devlink port support for ef100
>   sfc: obtain device mac address based on firmware handle for ef100
>   sfc: add support for port_function_hw_addr_get devlink in ef100
>   sfc: add support for devlink port_function_hw_addr_set in ef100
> 
>  drivers/net/ethernet/sfc/Kconfig        |   1 +
>  drivers/net/ethernet/sfc/Makefile       |   3 +-
>  drivers/net/ethernet/sfc/ef100_netdev.c |  20 +-
>  drivers/net/ethernet/sfc/ef100_nic.c    |  96 +++-
>  drivers/net/ethernet/sfc/ef100_nic.h    |   7 +
>  drivers/net/ethernet/sfc/ef100_rep.c    |  58 ++-
>  drivers/net/ethernet/sfc/ef100_rep.h    |   9 +
>  drivers/net/ethernet/sfc/efx_devlink.c  | 629 ++++++++++++++++++++++++
>  drivers/net/ethernet/sfc/efx_devlink.h  |  27 +
>  drivers/net/ethernet/sfc/mae.c          | 212 +++++++-
>  drivers/net/ethernet/sfc/mae.h          |  39 ++
>  drivers/net/ethernet/sfc/mcdi.c         |  72 +++
>  drivers/net/ethernet/sfc/mcdi.h         |  10 +
>  drivers/net/ethernet/sfc/net_driver.h   |   7 +
>  14 files changed, 1162 insertions(+), 28 deletions(-)
>  create mode 100644 drivers/net/ethernet/sfc/efx_devlink.c
>  create mode 100644 drivers/net/ethernet/sfc/efx_devlink.h
> 
> -- 
> 2.17.1

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 3/7] sfc: add mport lookup based on driver's mport data
  2023-01-19 23:57   ` Jacob Keller
@ 2023-01-20  9:34     ` Lucero Palau, Alejandro
  2023-01-20 18:36       ` Keller, Jacob E
  0 siblings, 1 reply; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-20  9:34 UTC (permalink / raw)
  To: Jacob Keller, Lucero Palau, Alejandro, netdev,
	linux-net-drivers (AMD-Xilinx)
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx


On 1/19/23 23:57, Jacob Keller wrote:
>
> On 1/19/2023 3:31 AM, alejandro.lucero-palau@amd.com wrote:
>> +int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id)
>> +{
>> +	struct ef100_nic_data *nic_data = efx->nic_data;
>> +	struct efx_mae *mae = efx->mae;
>> +	struct rhashtable_iter walk;
>> +	struct mae_mport_desc *m;
>> +	int rc = -ENOENT;
>> +
>> +	rhashtable_walk_enter(&mae->mports_ht, &walk);
>> +	rhashtable_walk_start(&walk);
>> +	while ((m = rhashtable_walk_next(&walk)) != NULL) {
>> +		if (m->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC &&
>> +		    m->interface_idx == nic_data->local_mae_intf &&
>> +		    m->pf_idx == 0 &&
>> +		    m->vf_idx == vf_idx) {
>> +			*id = m->mport_id;
>> +			rc = 0;
>> +			break;
>> +		}
>> +	}
>> +	rhashtable_walk_stop(&walk);
>> +	rhashtable_walk_exit(&walk);
> Curious if you have any reasoning for why you chose rhashtable vs
> another structure (such as a simpler hash table of linked lists or xarray).


The mports can appear and disappear (although it is not supported by the 
code yet nor by current firmware/hardware) so something resizable was 
needed for supporting this in the near future.


> At any rate,
>
> Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 14:51     ` Lucero Palau, Alejandro
  2023-01-19 16:29       ` Lucero Palau, Alejandro
@ 2023-01-20 11:00       ` Jiri Pirko
  1 sibling, 0 replies; 52+ messages in thread
From: Jiri Pirko @ 2023-01-20 11:00 UTC (permalink / raw)
  To: Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx

Thu, Jan 19, 2023 at 03:51:53PM CET, alejandro.lucero-palau@amd.com wrote:
>
>On 1/19/23 12:14, Jiri Pirko wrote:
>> Thu, Jan 19, 2023 at 12:31:34PM CET, alejandro.lucero-palau@amd.com wrote:
>>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>
>>> Basic support for devlink info command.
>>>
>>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>> ---
>>> drivers/net/ethernet/sfc/Kconfig       |   1 +
>>> drivers/net/ethernet/sfc/Makefile      |   3 +-
>>> drivers/net/ethernet/sfc/ef100_nic.c   |   6 +
>>> drivers/net/ethernet/sfc/efx_devlink.c | 427 +++++++++++++++++++++++++
>>> drivers/net/ethernet/sfc/efx_devlink.h |  20 ++
>>> drivers/net/ethernet/sfc/mcdi.c        |  72 +++++
>>> drivers/net/ethernet/sfc/mcdi.h        |   3 +
>>> drivers/net/ethernet/sfc/net_driver.h  |   2 +
>>> 8 files changed, 533 insertions(+), 1 deletion(-)
>>> create mode 100644 drivers/net/ethernet/sfc/efx_devlink.c
>>> create mode 100644 drivers/net/ethernet/sfc/efx_devlink.h
>> Could you please split?
>>
>> At least the devlink introduction part and info implementation.
>> 
>
>Sure.
>
>>> diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
>>> index 0950e6b0508f..4af36ba8906b 100644
>>> --- a/drivers/net/ethernet/sfc/Kconfig
>>> +++ b/drivers/net/ethernet/sfc/Kconfig
>>> @@ -22,6 +22,7 @@ config SFC
>>> 	depends on PTP_1588_CLOCK_OPTIONAL
>>> 	select MDIO
>>> 	select CRC32
>>> +	select NET_DEVLINK
>>> 	help
>>> 	  This driver supports 10/40-gigabit Ethernet cards based on
>>> 	  the Solarflare SFC9100-family controllers.
>>> diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
>>> index 712a48d00069..55b9c73cd8ef 100644
>>> --- a/drivers/net/ethernet/sfc/Makefile
>>> +++ b/drivers/net/ethernet/sfc/Makefile
>>> @@ -6,7 +6,8 @@ sfc-y			+= efx.o efx_common.o efx_channels.o nic.o \
>>> 			   mcdi.o mcdi_port.o mcdi_port_common.o \
>>> 			   mcdi_functions.o mcdi_filters.o mcdi_mon.o \
>>> 			   ef100.o ef100_nic.o ef100_netdev.o \
>>> -			   ef100_ethtool.o ef100_rx.o ef100_tx.o
>>> +			   ef100_ethtool.o ef100_rx.o ef100_tx.o \
>>> +			   efx_devlink.o
>>> sfc-$(CONFIG_SFC_MTD)	+= mtd.o
>>> sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
>>>                             mae.o tc.o tc_bindings.o tc_counters.o
>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>>> index ad686c671ab8..14af8f314b83 100644
>>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>>> @@ -27,6 +27,7 @@
>>> #include "tc.h"
>>> #include "mae.h"
>>> #include "rx_common.h"
>>> +#include "efx_devlink.h"
>>>
>>> #define EF100_MAX_VIS 4096
>>> #define EF100_NUM_MCDI_BUFFERS	1
>>> @@ -1124,6 +1125,10 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
>>> 		netif_warn(efx, probe, net_dev,
>>> 			   "Failed to probe base mport rc %d; representors will not function\n",
>>> 			   rc);
>>> +	} else {
>>> +		if (efx_probe_devlink(efx))
>> I don't understand why the devlink register call is here.
>> 1) You can registers it for PF and VF. I don't follow why you do it only
>>     for PF.
>
>We discuss the possibility of creating the devlink interface for VFs, 
>but we decided not to. Arguably, this should not be available for VFs 
>owned by VMs/containers, or at least in our case, since the interface is 
>being used for getting information about the whole device or for 
>getting/setting the MAC address. We plan to support more devlink 
>functionalities in the near future, so maybe we add such support then if 
>we consider it is needed.

Okay.


>
>> 2) It should be done as the first thing in the probe flow. Then devlink
>>     port register, only after that netdev. It makes sense from the
>>     perspective of object hierarchy.
>
>I can not see a problem here. It is not the first thing done in the 
>probe function, but I can not see any dependency for being so. And it is 
>done before the devlink port registration and before the netdev 
>registration what seems to be what other drivers do. What am I missing 
>here?

Yep, currently, it does not matter for you, but when you implement
devlink reload for example, it will become a problem. Better to have it
done correctly from the beginning. Up to you.

Remember, what other drivers do does not mean it is a good practise :


>
>>
>>     It is also usual to have the devlink priv as the "main" driver
>>     structure storage, see how that is done in mlx5 of mlxsw for example.
>
>I will check the way others drivers use the devlink priv.
>
>>
>>
>>> +			netif_warn(efx, probe, net_dev,
>>> +				   "Failed to register devlink\n");
>>> 	}
>>>
>>> 	rc = efx_init_tc(efx);
>>> @@ -1157,6 +1162,7 @@ void ef100_remove(struct efx_nic *efx)
>>> {
>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>
>>> +	efx_fini_devlink(efx);
>>> 	efx_mcdi_detach(efx);
>>> 	efx_mcdi_fini(efx);
>>> 	if (nic_data)
>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>>> new file mode 100644
>>> index 000000000000..c506f8f35d25
>>> --- /dev/null
>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>>> @@ -0,0 +1,427 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only
>>> +/****************************************************************************
>>> + * Driver for AMD network controllers and boards
>>> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify it
>>> + * under the terms of the GNU General Public License version 2 as published
>>> + * by the Free Software Foundation, incorporated herein by reference.
>>> + */
>>> +
>>> +#include <linux/rtc.h>
>>> +#include "net_driver.h"
>>> +#include "ef100_nic.h"
>>> +#include "efx_devlink.h"
>>> +#include "nic.h"
>>> +#include "mcdi.h"
>>> +#include "mcdi_functions.h"
>>> +#include "mcdi_pcol.h"
>>> +
>>> +/* Custom devlink-info version object names for details that do not map to the
>>> + * generic standardized names.
>>> + */
>>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC	"fw.mgmt.suc"
>>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC	"fw.mgmt.cmc"
>>> +#define EFX_DEVLINK_INFO_VERSION_FPGA_REV	"fpga.rev"
>>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_HW	"fpga.app"
>>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_FW	DEVLINK_INFO_VERSION_GENERIC_FW_APP
>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_BOOT	"coproc.boot"
>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_UBOOT	"coproc.uboot"
>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_MAIN	"coproc.main"
>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY	"coproc.recovery"
>>> +#define EFX_DEVLINK_INFO_VERSION_FW_EXPROM	"fw.exprom"
>>> +#define EFX_DEVLINK_INFO_VERSION_FW_UEFI	"fw.uefi"
>>> +
>>> +#define EFX_MAX_VERSION_INFO_LEN	64
>>> +
>>> +static int efx_devlink_info_nvram_partition(struct efx_nic *efx,
>>> +					    struct devlink_info_req *req,
>>> +					    unsigned int partition_type,
>>> +					    const char *version_name)
>>> +{
>>> +	char buf[EFX_MAX_VERSION_INFO_LEN];
>>> +	u16 version[4];
>>> +	int rc;
>>> +
>>> +	rc = efx_mcdi_nvram_metadata(efx, partition_type, NULL, version, NULL,
>>> +				     0);
>>> +	if (rc)
>>> +		return rc;
>>> +
>>> +	snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u", version[0],
>>> +		 version[1], version[2], version[3]);
>>> +	devlink_info_version_stored_put(req, version_name, buf);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void efx_devlink_info_stored_versions(struct efx_nic *efx,
>>> +					     struct devlink_info_req *req)
>>> +{
>>> +	efx_devlink_info_nvram_partition(efx, req, NVRAM_PARTITION_TYPE_BUNDLE,
>>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID);
>>> +	efx_devlink_info_nvram_partition(efx, req,
>>> +					 NVRAM_PARTITION_TYPE_MC_FIRMWARE,
>>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT);
>>> +	efx_devlink_info_nvram_partition(efx, req,
>>> +					 NVRAM_PARTITION_TYPE_SUC_FIRMWARE,
>>> +					 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC);
>>> +	efx_devlink_info_nvram_partition(efx, req,
>>> +					 NVRAM_PARTITION_TYPE_EXPANSION_ROM,
>>> +					 EFX_DEVLINK_INFO_VERSION_FW_EXPROM);
>>> +	efx_devlink_info_nvram_partition(efx, req,
>>> +					 NVRAM_PARTITION_TYPE_EXPANSION_UEFI,
>>> +					 EFX_DEVLINK_INFO_VERSION_FW_UEFI);
>>> +}
>>> +
>>> +#define EFX_MAX_SERIALNUM_LEN	(ETH_ALEN * 2 + 1)
>>> +
>>> +static void efx_devlink_info_board_cfg(struct efx_nic *efx,
>>> +				       struct devlink_info_req *req)
>>> +{
>>> +	char sn[EFX_MAX_SERIALNUM_LEN];
>>> +	u8 mac_address[ETH_ALEN];
>>> +	int rc;
>>> +
>>> +	rc = efx_mcdi_get_board_cfg(efx, (u8 *)mac_address, NULL, NULL);
>>> +	if (!rc) {
>>> +		snprintf(sn, EFX_MAX_SERIALNUM_LEN, "%pm", mac_address);
>>> +		devlink_info_serial_number_put(req, sn);
>>> +	}
>>> +}
>>> +
>>> +#define EFX_VER_FLAG(_f)	\
>>> +	(MC_CMD_GET_VERSION_V5_OUT_ ## _f ## _PRESENT_LBN)
>>> +
>>> +static void efx_devlink_info_running_versions(struct efx_nic *efx,
>>> +					      struct devlink_info_req *req)
>>> +{
>>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_V5_OUT_LEN);
>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_VERSION_EXT_IN_LEN);
>>> +	char buf[EFX_MAX_VERSION_INFO_LEN];
>>> +	unsigned int flags, build_id;
>>> +	union {
>>> +		const __le32 *dwords;
>>> +		const __le16 *words;
>>> +		const char *str;
>>> +	} ver;
>>> +	struct rtc_time build_date;
>>> +	size_t outlength, offset;
>>> +	u64 tstamp;
>>> +	int rc;
>>> +
>>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, inbuf, sizeof(inbuf),
>>> +			  outbuf, sizeof(outbuf), &outlength);
>>> +	if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN)
>>> +		return;
>>> +
>>> +	/* Handle previous output */
>>> +	if (outlength < MC_CMD_GET_VERSION_V2_OUT_LEN) {
>>> +		ver.words = (__le16 *)MCDI_PTR(outbuf,
>>> +					       GET_VERSION_EXT_OUT_VERSION);
>>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +				  le16_to_cpu(ver.words[0]),
>>> +				  le16_to_cpu(ver.words[1]),
>>> +				  le16_to_cpu(ver.words[2]),
>>> +				  le16_to_cpu(ver.words[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>>> +						 buf);
>>> +		return;
>>> +	}
>>> +
>>> +	/* Handle V2 additions */
>>> +	flags = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_FLAGS);
>>> +	if (flags & BIT(EFX_VER_FLAG(BOARD_EXT_INFO))) {
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%s",
>>> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_NAME));
>>> +		devlink_info_version_fixed_put(req,
>>> +					       DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
>>> +					       buf);
>>> +
>>> +		/* Favour full board version if present (in V5 or later) */
>>> +		if (~flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>>> +			snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u",
>>> +				 MCDI_DWORD(outbuf,
>>> +					    GET_VERSION_V2_OUT_BOARD_REVISION));
>>> +			devlink_info_version_fixed_put(req,
>>> +						       DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>>> +						       buf);
>>> +		}
>>> +
>>> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_SERIAL);
>>> +		if (ver.str[0])
>>> +			devlink_info_board_serial_number_put(req, ver.str);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(FPGA_EXT_INFO))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V2_OUT_FPGA_VERSION);
>>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u_%c%u",
>>> +				  le32_to_cpu(ver.dwords[0]),
>>> +				  'A' + le32_to_cpu(ver.dwords[1]),
>>> +				  le32_to_cpu(ver.dwords[2]));
>>> +
>>> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_FPGA_EXTRA);
>>> +		if (ver.str[0])
>>> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>>> +				 " (%s)", ver.str);
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_FPGA_REV,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(CMC_EXT_INFO))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V2_OUT_CMCFW_VERSION);
>>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +				  le32_to_cpu(ver.dwords[0]),
>>> +				  le32_to_cpu(ver.dwords[1]),
>>> +				  le32_to_cpu(ver.dwords[2]),
>>> +				  le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		tstamp = MCDI_QWORD(outbuf,
>>> +				    GET_VERSION_V2_OUT_CMCFW_BUILD_DATE);
>>> +		if (tstamp) {
>>> +			rtc_time64_to_tm(tstamp, &build_date);
>>> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>>> +				 " (%ptRd)", &build_date);
>>> +		}
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC,
>>> +						 buf);
>>> +	}
>>> +
>>> +	ver.words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_V2_OUT_VERSION);
>>> +	offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			  le16_to_cpu(ver.words[0]), le16_to_cpu(ver.words[1]),
>>> +			  le16_to_cpu(ver.words[2]), le16_to_cpu(ver.words[3]));
>>> +	if (flags & BIT(EFX_VER_FLAG(MCFW_EXT_INFO))) {
>>> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_ID);
>>> +		snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>>> +			 " (%x) %s", build_id,
>>> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_NAME));
>>> +	}
>>> +	devlink_info_version_running_put(req,
>>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>>> +					 buf);
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V2_OUT_SUCFW_VERSION);
>>> +		tstamp = MCDI_QWORD(outbuf,
>>> +				    GET_VERSION_V2_OUT_SUCFW_BUILD_DATE);
>>> +		rtc_time64_to_tm(tstamp, &build_date);
>>> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_SUCFW_CHIP_ID);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN,
>>> +			 "%u.%u.%u.%u type %x (%ptRd)",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]), le32_to_cpu(ver.dwords[3]),
>>> +			 build_id, &build_date);
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (outlength < MC_CMD_GET_VERSION_V3_OUT_LEN)
>>> +		return;
>>> +
>>> +	/* Handle V3 additions */
>>> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_HW_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V3_OUT_DATAPATH_HW_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_HW,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_FW_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V3_OUT_DATAPATH_FW_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_FW,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (outlength < MC_CMD_GET_VERSION_V4_OUT_LEN)
>>> +		return;
>>> +
>>> +	/* Handle V4 additions */
>>> +	if (flags & BIT(EFX_VER_FLAG(SOC_BOOT_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V4_OUT_SOC_BOOT_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_SOC_BOOT,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(SOC_UBOOT_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V4_OUT_SOC_UBOOT_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_SOC_UBOOT,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(SOC_MAIN_ROOTFS_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V4_OUT_SOC_MAIN_ROOTFS_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_SOC_MAIN,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(SOC_RECOVERY_BUILDROOT_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V4_OUT_SOC_RECOVERY_BUILDROOT_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_VERSION)) &&
>>> +	    ~flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V4_OUT_SUCFW_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (outlength < MC_CMD_GET_VERSION_V5_OUT_LEN)
>>> +		return;
>>> +
>>> +	/* Handle V5 additions */
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V5_OUT_BOARD_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>>> +						 buf);
>>> +	}
>>> +
>>> +	if (flags & BIT(EFX_VER_FLAG(BUNDLE_VERSION))) {
>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>> +						GET_VERSION_V5_OUT_BUNDLE_VERSION);
>>> +
>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>> +			 le32_to_cpu(ver.dwords[2]),
>>> +			 le32_to_cpu(ver.dwords[3]));
>>> +
>>> +		devlink_info_version_running_put(req,
>>> +						 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
>>> +						 buf);
>>> +	}
>>> +}
>>> +
>>> +#undef EFX_VER_FLAG
>>> +
>>> +static void efx_devlink_info_query_all(struct efx_nic *efx,
>>> +				       struct devlink_info_req *req)
>>> +{
>>> +	efx_devlink_info_board_cfg(efx, req);
>>> +	efx_devlink_info_stored_versions(efx, req);
>>> +	efx_devlink_info_running_versions(efx, req);
>>> +}
>>> +
>>> +struct efx_devlink {
>>> +	struct efx_nic *efx;
>>> +};
>>> +
>>> +static int efx_devlink_info_get(struct devlink *devlink,
>>> +				struct devlink_info_req *req,
>>> +				struct netlink_ext_ack *extack)
>>> +{
>>> +	struct efx_devlink *devlink_private = devlink_priv(devlink);
>>> +	struct efx_nic *efx = devlink_private->efx;
>>> +
>>> +	efx_devlink_info_query_all(efx, req);
>> I don't understand the reason for having efx_devlink_info_query_all() as
>> a separate function in compare to inline its code here.
>>
>
>Yes, it could be do as you say. I'll do.
>
>Thanks
>
>>> +	return 0;
>>> +}
>>> +
>>> +static const struct devlink_ops sfc_devlink_ops = {
>>> +	.info_get			= efx_devlink_info_get,
>>> +};
>>> +
>>> +void efx_fini_devlink(struct efx_nic *efx)
>>> +{
>>> +	if (efx->devlink) {
>>> +		struct efx_devlink *devlink_private;
>>> +
>>> +		devlink_private = devlink_priv(efx->devlink);
>>> +
>>> +		devlink_unregister(efx->devlink);
>>> +		devlink_free(efx->devlink);
>>> +		efx->devlink = NULL;
>>> +	}
>>> +}
>>> +
>>> +int efx_probe_devlink(struct efx_nic *efx)
>>> +{
>>> +	struct efx_devlink *devlink_private;
>>> +
>>> +	efx->devlink = devlink_alloc(&sfc_devlink_ops,
>>> +				     sizeof(struct efx_devlink),
>>> +				     &efx->pci_dev->dev);
>>> +	if (!efx->devlink)
>>> +		return -ENOMEM;
>>> +	devlink_private = devlink_priv(efx->devlink);
>>> +	devlink_private->efx = efx;
>>> +
>>> +	devlink_register(efx->devlink);
>>> +
>>> +	return 0;
>>> +}
>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.h b/drivers/net/ethernet/sfc/efx_devlink.h
>>> new file mode 100644
>>> index 000000000000..997f878aea93
>>> --- /dev/null
>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.h
>>> @@ -0,0 +1,20 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-only */
>>> +/****************************************************************************
>>> + * Driver for AMD network controllers and boards
>>> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify it
>>> + * under the terms of the GNU General Public License version 2 as published
>>> + * by the Free Software Foundation, incorporated herein by reference.
>>> + */
>>> +
>>> +#ifndef _EFX_DEVLINK_H
>>> +#define _EFX_DEVLINK_H
>>> +
>>> +#include "net_driver.h"
>>> +#include <net/devlink.h>
>>> +
>>> +int efx_probe_devlink(struct efx_nic *efx);
>>> +void efx_fini_devlink(struct efx_nic *efx);
>>> +
>>> +#endif	/* _EFX_DEVLINK_H */
>>> diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
>>> index af338208eae9..328cae82a7d8 100644
>>> --- a/drivers/net/ethernet/sfc/mcdi.c
>>> +++ b/drivers/net/ethernet/sfc/mcdi.c
>>> @@ -2308,6 +2308,78 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
>>> 	return rc;
>>> }
>>>
>>> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>>> +			    u32 *subtype, u16 version[4], char *desc,
>>> +			    size_t descsize)
>>> +{
>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN);
>>> +	efx_dword_t *outbuf;
>>> +	size_t outlen;
>>> +	u32 flags;
>>> +	int rc;
>>> +
>>> +	outbuf = kzalloc(MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2, GFP_KERNEL);
>>> +	if (!outbuf)
>>> +		return -ENOMEM;
>>> +
>>> +	MCDI_SET_DWORD(inbuf, NVRAM_METADATA_IN_TYPE, type);
>>> +
>>> +	rc = efx_mcdi_rpc_quiet(efx, MC_CMD_NVRAM_METADATA, inbuf,
>>> +				sizeof(inbuf), outbuf,
>>> +				MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2,
>>> +				&outlen);
>>> +	if (rc)
>>> +		goto out_free;
>>> +	if (outlen < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
>>> +		rc = -EIO;
>>> +		goto out_free;
>>> +	}
>>> +
>>> +	flags = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_FLAGS);
>>> +
>>> +	if (desc && descsize > 0) {
>>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_VALID_LBN)) {
>>> +			if (descsize <=
>>> +			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)) {
>>> +				rc = -E2BIG;
>>> +				goto out_free;
>>> +			}
>>> +
>>> +			strncpy(desc,
>>> +				MCDI_PTR(outbuf, NVRAM_METADATA_OUT_DESCRIPTION),
>>> +				MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen));
>>> +			desc[MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)] = '\0';
>>> +		} else {
>>> +			desc[0] = '\0';
>>> +		}
>>> +	}
>>> +
>>> +	if (subtype) {
>>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_SUBTYPE_VALID_LBN))
>>> +			*subtype = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_SUBTYPE);
>>> +		else
>>> +			*subtype = 0;
>>> +	}
>>> +
>>> +	if (version) {
>>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_VERSION_VALID_LBN)) {
>>> +			version[0] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_W);
>>> +			version[1] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_X);
>>> +			version[2] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Y);
>>> +			version[3] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Z);
>>> +		} else {
>>> +			version[0] = 0;
>>> +			version[1] = 0;
>>> +			version[2] = 0;
>>> +			version[3] = 0;
>>> +		}
>>> +	}
>>> +
>>> +out_free:
>>> +	kfree(outbuf);
>>> +	return rc;
>>> +}
>>> +
>>> int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
>>> 		      size_t len, size_t *retlen, u8 *buffer)
>>> {
>>> diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
>>> index 7e35fec9da35..63b090587f7a 100644
>>> --- a/drivers/net/ethernet/sfc/mcdi.h
>>> +++ b/drivers/net/ethernet/sfc/mcdi.h
>>> @@ -379,6 +379,9 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
>>> 			bool *protected_out);
>>> int efx_new_mcdi_nvram_test_all(struct efx_nic *efx);
>>> int efx_mcdi_nvram_test_all(struct efx_nic *efx);
>>> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>>> +			    u32 *subtype, u16 version[4], char *desc,
>>> +			    size_t descsize);
>>> int efx_mcdi_handle_assertion(struct efx_nic *efx);
>>> int efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
>>> int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac,
>>> diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
>>> index 3b49e216768b..d036641dc043 100644
>>> --- a/drivers/net/ethernet/sfc/net_driver.h
>>> +++ b/drivers/net/ethernet/sfc/net_driver.h
>>> @@ -994,6 +994,7 @@ enum efx_xdp_tx_queues_mode {
>>>   *      xdp_rxq_info structures?
>>>   * @netdev_notifier: Netdevice notifier.
>>>   * @tc: state for TC offload (EF100).
>>> + * @devlink: reference to devlink structure owned by this device
>>>   * @mem_bar: The BAR that is mapped into membase.
>>>   * @reg_base: Offset from the start of the bar to the function control window.
>>>   * @monitor_work: Hardware monitor workitem
>>> @@ -1179,6 +1180,7 @@ struct efx_nic {
>>> 	struct notifier_block netdev_notifier;
>>> 	struct efx_tc_state *tc;
>>>
>>> +	struct devlink *devlink;
>>> 	unsigned int mem_bar;
>>> 	u32 reg_base;
>>>
>>> -- 
>>> 2.17.1
>>>
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 16:29       ` Lucero Palau, Alejandro
@ 2023-01-20 11:02         ` Jiri Pirko
  0 siblings, 0 replies; 52+ messages in thread
From: Jiri Pirko @ 2023-01-20 11:02 UTC (permalink / raw)
  To: Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx

Thu, Jan 19, 2023 at 05:29:37PM CET, alejandro.lucero-palau@amd.com wrote:
>
>On 1/19/23 14:51, Lucero Palau, Alejandro wrote:
>> On 1/19/23 12:14, Jiri Pirko wrote:
>>> Thu, Jan 19, 2023 at 12:31:34PM CET, alejandro.lucero-palau@amd.com wrote:
>>>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>>
>>>> Basic support for devlink info command.
>>>>
>>>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>> ---
>>>> drivers/net/ethernet/sfc/Kconfig       |   1 +
>>>> drivers/net/ethernet/sfc/Makefile      |   3 +-
>>>> drivers/net/ethernet/sfc/ef100_nic.c   |   6 +
>>>> drivers/net/ethernet/sfc/efx_devlink.c | 427 +++++++++++++++++++++++++
>>>> drivers/net/ethernet/sfc/efx_devlink.h |  20 ++
>>>> drivers/net/ethernet/sfc/mcdi.c        |  72 +++++
>>>> drivers/net/ethernet/sfc/mcdi.h        |   3 +
>>>> drivers/net/ethernet/sfc/net_driver.h  |   2 +
>>>> 8 files changed, 533 insertions(+), 1 deletion(-)
>>>> create mode 100644 drivers/net/ethernet/sfc/efx_devlink.c
>>>> create mode 100644 drivers/net/ethernet/sfc/efx_devlink.h
>>> Could you please split?
>>>
>>> At least the devlink introduction part and info implementation.
>>>
>> Sure.
>
>Just for being sure, would it be fine to have a simple info 
>implementation first along with the devlink infrastructure then a second 
>patch adding the more complex devlink info support? I guess I need at 
>least one operation supported initially.

No, it does not need to support any op.


>
>>>> diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
>>>> index 0950e6b0508f..4af36ba8906b 100644
>>>> --- a/drivers/net/ethernet/sfc/Kconfig
>>>> +++ b/drivers/net/ethernet/sfc/Kconfig
>>>> @@ -22,6 +22,7 @@ config SFC
>>>> 	depends on PTP_1588_CLOCK_OPTIONAL
>>>> 	select MDIO
>>>> 	select CRC32
>>>> +	select NET_DEVLINK
>>>> 	help
>>>> 	  This driver supports 10/40-gigabit Ethernet cards based on
>>>> 	  the Solarflare SFC9100-family controllers.
>>>> diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
>>>> index 712a48d00069..55b9c73cd8ef 100644
>>>> --- a/drivers/net/ethernet/sfc/Makefile
>>>> +++ b/drivers/net/ethernet/sfc/Makefile
>>>> @@ -6,7 +6,8 @@ sfc-y			+= efx.o efx_common.o efx_channels.o nic.o \
>>>> 			   mcdi.o mcdi_port.o mcdi_port_common.o \
>>>> 			   mcdi_functions.o mcdi_filters.o mcdi_mon.o \
>>>> 			   ef100.o ef100_nic.o ef100_netdev.o \
>>>> -			   ef100_ethtool.o ef100_rx.o ef100_tx.o
>>>> +			   ef100_ethtool.o ef100_rx.o ef100_tx.o \
>>>> +			   efx_devlink.o
>>>> sfc-$(CONFIG_SFC_MTD)	+= mtd.o
>>>> sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
>>>>                              mae.o tc.o tc_bindings.o tc_counters.o
>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>>>> index ad686c671ab8..14af8f314b83 100644
>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>>>> @@ -27,6 +27,7 @@
>>>> #include "tc.h"
>>>> #include "mae.h"
>>>> #include "rx_common.h"
>>>> +#include "efx_devlink.h"
>>>>
>>>> #define EF100_MAX_VIS 4096
>>>> #define EF100_NUM_MCDI_BUFFERS	1
>>>> @@ -1124,6 +1125,10 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
>>>> 		netif_warn(efx, probe, net_dev,
>>>> 			   "Failed to probe base mport rc %d; representors will not function\n",
>>>> 			   rc);
>>>> +	} else {
>>>> +		if (efx_probe_devlink(efx))
>>> I don't understand why the devlink register call is here.
>>> 1) You can registers it for PF and VF. I don't follow why you do it only
>>>      for PF.
>> We discuss the possibility of creating the devlink interface for VFs,
>> but we decided not to. Arguably, this should not be available for VFs
>> owned by VMs/containers, or at least in our case, since the interface is
>> being used for getting information about the whole device or for
>> getting/setting the MAC address. We plan to support more devlink
>> functionalities in the near future, so maybe we add such support then if
>> we consider it is needed.
>>
>>> 2) It should be done as the first thing in the probe flow. Then devlink
>>>      port register, only after that netdev. It makes sense from the
>>>      perspective of object hierarchy.
>> I can not see a problem here. It is not the first thing done in the
>> probe function, but I can not see any dependency for being so. And it is
>> done before the devlink port registration and before the netdev
>> registration what seems to be what other drivers do. What am I missing
>> here?
>>
>>>      It is also usual to have the devlink priv as the "main" driver
>>>      structure storage, see how that is done in mlx5 of mlxsw for example.
>> I will check the way others drivers use the devlink priv.
>
>
>Interestingly, there are 26 calls to devlink_alloc with half of them 
>using the main driver structure and the other half using a specific 
>devlink private struct. This is a huge responsibility now for me!
>
>I'm afraid, for the shake of having this merged as soon as possible, 
>I'll keep the current allocation. I did not suffer any problem with this 
>approach while implementing the current support. If, for the further 
>devlink support we plan to add, it turns out to be an issue, we will to 
>the changes then. I would say it is a main change now or then, and 
>current work does not justify it now.

Up to you, it will eventualy bite you in the *** when you implement
devlink reload for example.

>
>
>>>
>>>> +			netif_warn(efx, probe, net_dev,
>>>> +				   "Failed to register devlink\n");
>>>> 	}
>>>>
>>>> 	rc = efx_init_tc(efx);
>>>> @@ -1157,6 +1162,7 @@ void ef100_remove(struct efx_nic *efx)
>>>> {
>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>>
>>>> +	efx_fini_devlink(efx);
>>>> 	efx_mcdi_detach(efx);
>>>> 	efx_mcdi_fini(efx);
>>>> 	if (nic_data)
>>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>>>> new file mode 100644
>>>> index 000000000000..c506f8f35d25
>>>> --- /dev/null
>>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>>>> @@ -0,0 +1,427 @@
>>>> +// SPDX-License-Identifier: GPL-2.0-only
>>>> +/****************************************************************************
>>>> + * Driver for AMD network controllers and boards
>>>> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify it
>>>> + * under the terms of the GNU General Public License version 2 as published
>>>> + * by the Free Software Foundation, incorporated herein by reference.
>>>> + */
>>>> +
>>>> +#include <linux/rtc.h>
>>>> +#include "net_driver.h"
>>>> +#include "ef100_nic.h"
>>>> +#include "efx_devlink.h"
>>>> +#include "nic.h"
>>>> +#include "mcdi.h"
>>>> +#include "mcdi_functions.h"
>>>> +#include "mcdi_pcol.h"
>>>> +
>>>> +/* Custom devlink-info version object names for details that do not map to the
>>>> + * generic standardized names.
>>>> + */
>>>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC	"fw.mgmt.suc"
>>>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC	"fw.mgmt.cmc"
>>>> +#define EFX_DEVLINK_INFO_VERSION_FPGA_REV	"fpga.rev"
>>>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_HW	"fpga.app"
>>>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_FW	DEVLINK_INFO_VERSION_GENERIC_FW_APP
>>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_BOOT	"coproc.boot"
>>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_UBOOT	"coproc.uboot"
>>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_MAIN	"coproc.main"
>>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY	"coproc.recovery"
>>>> +#define EFX_DEVLINK_INFO_VERSION_FW_EXPROM	"fw.exprom"
>>>> +#define EFX_DEVLINK_INFO_VERSION_FW_UEFI	"fw.uefi"
>>>> +
>>>> +#define EFX_MAX_VERSION_INFO_LEN	64
>>>> +
>>>> +static int efx_devlink_info_nvram_partition(struct efx_nic *efx,
>>>> +					    struct devlink_info_req *req,
>>>> +					    unsigned int partition_type,
>>>> +					    const char *version_name)
>>>> +{
>>>> +	char buf[EFX_MAX_VERSION_INFO_LEN];
>>>> +	u16 version[4];
>>>> +	int rc;
>>>> +
>>>> +	rc = efx_mcdi_nvram_metadata(efx, partition_type, NULL, version, NULL,
>>>> +				     0);
>>>> +	if (rc)
>>>> +		return rc;
>>>> +
>>>> +	snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u", version[0],
>>>> +		 version[1], version[2], version[3]);
>>>> +	devlink_info_version_stored_put(req, version_name, buf);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static void efx_devlink_info_stored_versions(struct efx_nic *efx,
>>>> +					     struct devlink_info_req *req)
>>>> +{
>>>> +	efx_devlink_info_nvram_partition(efx, req, NVRAM_PARTITION_TYPE_BUNDLE,
>>>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID);
>>>> +	efx_devlink_info_nvram_partition(efx, req,
>>>> +					 NVRAM_PARTITION_TYPE_MC_FIRMWARE,
>>>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT);
>>>> +	efx_devlink_info_nvram_partition(efx, req,
>>>> +					 NVRAM_PARTITION_TYPE_SUC_FIRMWARE,
>>>> +					 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC);
>>>> +	efx_devlink_info_nvram_partition(efx, req,
>>>> +					 NVRAM_PARTITION_TYPE_EXPANSION_ROM,
>>>> +					 EFX_DEVLINK_INFO_VERSION_FW_EXPROM);
>>>> +	efx_devlink_info_nvram_partition(efx, req,
>>>> +					 NVRAM_PARTITION_TYPE_EXPANSION_UEFI,
>>>> +					 EFX_DEVLINK_INFO_VERSION_FW_UEFI);
>>>> +}
>>>> +
>>>> +#define EFX_MAX_SERIALNUM_LEN	(ETH_ALEN * 2 + 1)
>>>> +
>>>> +static void efx_devlink_info_board_cfg(struct efx_nic *efx,
>>>> +				       struct devlink_info_req *req)
>>>> +{
>>>> +	char sn[EFX_MAX_SERIALNUM_LEN];
>>>> +	u8 mac_address[ETH_ALEN];
>>>> +	int rc;
>>>> +
>>>> +	rc = efx_mcdi_get_board_cfg(efx, (u8 *)mac_address, NULL, NULL);
>>>> +	if (!rc) {
>>>> +		snprintf(sn, EFX_MAX_SERIALNUM_LEN, "%pm", mac_address);
>>>> +		devlink_info_serial_number_put(req, sn);
>>>> +	}
>>>> +}
>>>> +
>>>> +#define EFX_VER_FLAG(_f)	\
>>>> +	(MC_CMD_GET_VERSION_V5_OUT_ ## _f ## _PRESENT_LBN)
>>>> +
>>>> +static void efx_devlink_info_running_versions(struct efx_nic *efx,
>>>> +					      struct devlink_info_req *req)
>>>> +{
>>>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_V5_OUT_LEN);
>>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_VERSION_EXT_IN_LEN);
>>>> +	char buf[EFX_MAX_VERSION_INFO_LEN];
>>>> +	unsigned int flags, build_id;
>>>> +	union {
>>>> +		const __le32 *dwords;
>>>> +		const __le16 *words;
>>>> +		const char *str;
>>>> +	} ver;
>>>> +	struct rtc_time build_date;
>>>> +	size_t outlength, offset;
>>>> +	u64 tstamp;
>>>> +	int rc;
>>>> +
>>>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, inbuf, sizeof(inbuf),
>>>> +			  outbuf, sizeof(outbuf), &outlength);
>>>> +	if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN)
>>>> +		return;
>>>> +
>>>> +	/* Handle previous output */
>>>> +	if (outlength < MC_CMD_GET_VERSION_V2_OUT_LEN) {
>>>> +		ver.words = (__le16 *)MCDI_PTR(outbuf,
>>>> +					       GET_VERSION_EXT_OUT_VERSION);
>>>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>>> +				  le16_to_cpu(ver.words[0]),
>>>> +				  le16_to_cpu(ver.words[1]),
>>>> +				  le16_to_cpu(ver.words[2]),
>>>> +				  le16_to_cpu(ver.words[3]));
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>>>> +						 buf);
>>>> +		return;
>>>> +	}
>>>> +
>>>> +	/* Handle V2 additions */
>>>> +	flags = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_FLAGS);
>>>> +	if (flags & BIT(EFX_VER_FLAG(BOARD_EXT_INFO))) {
>>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%s",
>>>> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_NAME));
>>>> +		devlink_info_version_fixed_put(req,
>>>> +					       DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
>>>> +					       buf);
>>>> +
>>>> +		/* Favour full board version if present (in V5 or later) */
>>>> +		if (~flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>>>> +			snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u",
>>>> +				 MCDI_DWORD(outbuf,
>>>> +					    GET_VERSION_V2_OUT_BOARD_REVISION));
>>>> +			devlink_info_version_fixed_put(req,
>>>> +						       DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>>>> +						       buf);
>>>> +		}
>>>> +
>>>> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_SERIAL);
>>>> +		if (ver.str[0])
>>>> +			devlink_info_board_serial_number_put(req, ver.str);
>>>> +	}
>>>> +
>>>> +	if (flags & BIT(EFX_VER_FLAG(FPGA_EXT_INFO))) {
>>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>>> +						GET_VERSION_V2_OUT_FPGA_VERSION);
>>>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u_%c%u",
>>>> +				  le32_to_cpu(ver.dwords[0]),
>>>> +				  'A' + le32_to_cpu(ver.dwords[1]),
>>>> +				  le32_to_cpu(ver.dwords[2]));
>>>> +
>>>> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_FPGA_EXTRA);
>>>> +		if (ver.str[0])
>>>> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>>>> +				 " (%s)", ver.str);
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 EFX_DEVLINK_INFO_VERSION_FPGA_REV,
>>>> +						 buf);
>>>> +	}
>>>> +
>>>> +	if (flags & BIT(EFX_VER_FLAG(CMC_EXT_INFO))) {
>>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>>> +						GET_VERSION_V2_OUT_CMCFW_VERSION);
>>>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>>> +				  le32_to_cpu(ver.dwords[0]),
>>>> +				  le32_to_cpu(ver.dwords[1]),
>>>> +				  le32_to_cpu(ver.dwords[2]),
>>>> +				  le32_to_cpu(ver.dwords[3]));
>>>> +
>>>> +		tstamp = MCDI_QWORD(outbuf,
>>>> +				    GET_VERSION_V2_OUT_CMCFW_BUILD_DATE);
>>>> +		if (tstamp) {
>>>> +			rtc_time64_to_tm(tstamp, &build_date);
>>>> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>>>> +				 " (%ptRd)", &build_date);
>>>> +		}
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC,
>>>> +						 buf);
>>>> +	}
>>>> +
>>>> +	ver.words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_V2_OUT_VERSION);
>>>> +	offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>>> +			  le16_to_cpu(ver.words[0]), le16_to_cpu(ver.words[1]),
>>>> +			  le16_to_cpu(ver.words[2]), le16_to_cpu(ver.words[3]));
>>>> +	if (flags & BIT(EFX_VER_FLAG(MCFW_EXT_INFO))) {
>>>> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_ID);
>>>> +		snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>>>> +			 " (%x) %s", build_id,
>>>> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_NAME));
>>>> +	}
>>>> +	devlink_info_version_running_put(req,
>>>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>>>> +					 buf);
>>>> +
>>>> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>>> +						GET_VERSION_V2_OUT_SUCFW_VERSION);
>>>> +		tstamp = MCDI_QWORD(outbuf,
>>>> +				    GET_VERSION_V2_OUT_SUCFW_BUILD_DATE);
>>>> +		rtc_time64_to_tm(tstamp, &build_date);
>>>> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_SUCFW_CHIP_ID);
>>>> +
>>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN,
>>>> +			 "%u.%u.%u.%u type %x (%ptRd)",
>>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>>> +			 le32_to_cpu(ver.dwords[2]), le32_to_cpu(ver.dwords[3]),
>>>> +			 build_id, &build_date);
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>>>> +						 buf);
>>>> +	}
>>>> +
>>>> +	if (outlength < MC_CMD_GET_VERSION_V3_OUT_LEN)
>>>> +		return;
>>>> +
>>>> +	/* Handle V3 additions */
>>>> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_HW_VERSION))) {
>>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>>> +						GET_VERSION_V3_OUT_DATAPATH_HW_VERSION);
>>>> +
>>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>>> +			 le32_to_cpu(ver.dwords[2]));
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_HW,
>>>> +						 buf);
>>>> +	}
>>>> +
>>>> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_FW_VERSION))) {
>>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>>> +						GET_VERSION_V3_OUT_DATAPATH_FW_VERSION);
>>>> +
>>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>>> +			 le32_to_cpu(ver.dwords[2]));
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_FW,
>>>> +						 buf);
>>>> +	}
>>>> +
>>>> +	if (outlength < MC_CMD_GET_VERSION_V4_OUT_LEN)
>>>> +		return;
>>>> +
>>>> +	/* Handle V4 additions */
>>>> +	if (flags & BIT(EFX_VER_FLAG(SOC_BOOT_VERSION))) {
>>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>>> +						GET_VERSION_V4_OUT_SOC_BOOT_VERSION);
>>>> +
>>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>>> +			 le32_to_cpu(ver.dwords[2]),
>>>> +			 le32_to_cpu(ver.dwords[3]));
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 EFX_DEVLINK_INFO_VERSION_SOC_BOOT,
>>>> +						 buf);
>>>> +	}
>>>> +
>>>> +	if (flags & BIT(EFX_VER_FLAG(SOC_UBOOT_VERSION))) {
>>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>>> +						GET_VERSION_V4_OUT_SOC_UBOOT_VERSION);
>>>> +
>>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>>> +			 le32_to_cpu(ver.dwords[2]),
>>>> +			 le32_to_cpu(ver.dwords[3]));
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 EFX_DEVLINK_INFO_VERSION_SOC_UBOOT,
>>>> +						 buf);
>>>> +	}
>>>> +
>>>> +	if (flags & BIT(EFX_VER_FLAG(SOC_MAIN_ROOTFS_VERSION))) {
>>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>>> +						GET_VERSION_V4_OUT_SOC_MAIN_ROOTFS_VERSION);
>>>> +
>>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>>> +			 le32_to_cpu(ver.dwords[2]),
>>>> +			 le32_to_cpu(ver.dwords[3]));
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 EFX_DEVLINK_INFO_VERSION_SOC_MAIN,
>>>> +						 buf);
>>>> +	}
>>>> +
>>>> +	if (flags & BIT(EFX_VER_FLAG(SOC_RECOVERY_BUILDROOT_VERSION))) {
>>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>>> +						GET_VERSION_V4_OUT_SOC_RECOVERY_BUILDROOT_VERSION);
>>>> +
>>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>>> +			 le32_to_cpu(ver.dwords[2]),
>>>> +			 le32_to_cpu(ver.dwords[3]));
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY,
>>>> +						 buf);
>>>> +	}
>>>> +
>>>> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_VERSION)) &&
>>>> +	    ~flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>>> +						GET_VERSION_V4_OUT_SUCFW_VERSION);
>>>> +
>>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>>> +			 le32_to_cpu(ver.dwords[2]),
>>>> +			 le32_to_cpu(ver.dwords[3]));
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>>>> +						 buf);
>>>> +	}
>>>> +
>>>> +	if (outlength < MC_CMD_GET_VERSION_V5_OUT_LEN)
>>>> +		return;
>>>> +
>>>> +	/* Handle V5 additions */
>>>> +
>>>> +	if (flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>>> +						GET_VERSION_V5_OUT_BOARD_VERSION);
>>>> +
>>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>>> +			 le32_to_cpu(ver.dwords[2]),
>>>> +			 le32_to_cpu(ver.dwords[3]));
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>>>> +						 buf);
>>>> +	}
>>>> +
>>>> +	if (flags & BIT(EFX_VER_FLAG(BUNDLE_VERSION))) {
>>>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>>>> +						GET_VERSION_V5_OUT_BUNDLE_VERSION);
>>>> +
>>>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>>>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>>>> +			 le32_to_cpu(ver.dwords[2]),
>>>> +			 le32_to_cpu(ver.dwords[3]));
>>>> +
>>>> +		devlink_info_version_running_put(req,
>>>> +						 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
>>>> +						 buf);
>>>> +	}
>>>> +}
>>>> +
>>>> +#undef EFX_VER_FLAG
>>>> +
>>>> +static void efx_devlink_info_query_all(struct efx_nic *efx,
>>>> +				       struct devlink_info_req *req)
>>>> +{
>>>> +	efx_devlink_info_board_cfg(efx, req);
>>>> +	efx_devlink_info_stored_versions(efx, req);
>>>> +	efx_devlink_info_running_versions(efx, req);
>>>> +}
>>>> +
>>>> +struct efx_devlink {
>>>> +	struct efx_nic *efx;
>>>> +};
>>>> +
>>>> +static int efx_devlink_info_get(struct devlink *devlink,
>>>> +				struct devlink_info_req *req,
>>>> +				struct netlink_ext_ack *extack)
>>>> +{
>>>> +	struct efx_devlink *devlink_private = devlink_priv(devlink);
>>>> +	struct efx_nic *efx = devlink_private->efx;
>>>> +
>>>> +	efx_devlink_info_query_all(efx, req);
>>> I don't understand the reason for having efx_devlink_info_query_all() as
>>> a separate function in compare to inline its code here.
>>>
>> Yes, it could be do as you say. I'll do.
>>
>> Thanks
>>
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static const struct devlink_ops sfc_devlink_ops = {
>>>> +	.info_get			= efx_devlink_info_get,
>>>> +};
>>>> +
>>>> +void efx_fini_devlink(struct efx_nic *efx)
>>>> +{
>>>> +	if (efx->devlink) {
>>>> +		struct efx_devlink *devlink_private;
>>>> +
>>>> +		devlink_private = devlink_priv(efx->devlink);
>>>> +
>>>> +		devlink_unregister(efx->devlink);
>>>> +		devlink_free(efx->devlink);
>>>> +		efx->devlink = NULL;
>>>> +	}
>>>> +}
>>>> +
>>>> +int efx_probe_devlink(struct efx_nic *efx)
>>>> +{
>>>> +	struct efx_devlink *devlink_private;
>>>> +
>>>> +	efx->devlink = devlink_alloc(&sfc_devlink_ops,
>>>> +				     sizeof(struct efx_devlink),
>>>> +				     &efx->pci_dev->dev);
>>>> +	if (!efx->devlink)
>>>> +		return -ENOMEM;
>>>> +	devlink_private = devlink_priv(efx->devlink);
>>>> +	devlink_private->efx = efx;
>>>> +
>>>> +	devlink_register(efx->devlink);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.h b/drivers/net/ethernet/sfc/efx_devlink.h
>>>> new file mode 100644
>>>> index 000000000000..997f878aea93
>>>> --- /dev/null
>>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.h
>>>> @@ -0,0 +1,20 @@
>>>> +/* SPDX-License-Identifier: GPL-2.0-only */
>>>> +/****************************************************************************
>>>> + * Driver for AMD network controllers and boards
>>>> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify it
>>>> + * under the terms of the GNU General Public License version 2 as published
>>>> + * by the Free Software Foundation, incorporated herein by reference.
>>>> + */
>>>> +
>>>> +#ifndef _EFX_DEVLINK_H
>>>> +#define _EFX_DEVLINK_H
>>>> +
>>>> +#include "net_driver.h"
>>>> +#include <net/devlink.h>
>>>> +
>>>> +int efx_probe_devlink(struct efx_nic *efx);
>>>> +void efx_fini_devlink(struct efx_nic *efx);
>>>> +
>>>> +#endif	/* _EFX_DEVLINK_H */
>>>> diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
>>>> index af338208eae9..328cae82a7d8 100644
>>>> --- a/drivers/net/ethernet/sfc/mcdi.c
>>>> +++ b/drivers/net/ethernet/sfc/mcdi.c
>>>> @@ -2308,6 +2308,78 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
>>>> 	return rc;
>>>> }
>>>>
>>>> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>>>> +			    u32 *subtype, u16 version[4], char *desc,
>>>> +			    size_t descsize)
>>>> +{
>>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN);
>>>> +	efx_dword_t *outbuf;
>>>> +	size_t outlen;
>>>> +	u32 flags;
>>>> +	int rc;
>>>> +
>>>> +	outbuf = kzalloc(MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2, GFP_KERNEL);
>>>> +	if (!outbuf)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	MCDI_SET_DWORD(inbuf, NVRAM_METADATA_IN_TYPE, type);
>>>> +
>>>> +	rc = efx_mcdi_rpc_quiet(efx, MC_CMD_NVRAM_METADATA, inbuf,
>>>> +				sizeof(inbuf), outbuf,
>>>> +				MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2,
>>>> +				&outlen);
>>>> +	if (rc)
>>>> +		goto out_free;
>>>> +	if (outlen < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
>>>> +		rc = -EIO;
>>>> +		goto out_free;
>>>> +	}
>>>> +
>>>> +	flags = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_FLAGS);
>>>> +
>>>> +	if (desc && descsize > 0) {
>>>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_VALID_LBN)) {
>>>> +			if (descsize <=
>>>> +			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)) {
>>>> +				rc = -E2BIG;
>>>> +				goto out_free;
>>>> +			}
>>>> +
>>>> +			strncpy(desc,
>>>> +				MCDI_PTR(outbuf, NVRAM_METADATA_OUT_DESCRIPTION),
>>>> +				MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen));
>>>> +			desc[MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)] = '\0';
>>>> +		} else {
>>>> +			desc[0] = '\0';
>>>> +		}
>>>> +	}
>>>> +
>>>> +	if (subtype) {
>>>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_SUBTYPE_VALID_LBN))
>>>> +			*subtype = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_SUBTYPE);
>>>> +		else
>>>> +			*subtype = 0;
>>>> +	}
>>>> +
>>>> +	if (version) {
>>>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_VERSION_VALID_LBN)) {
>>>> +			version[0] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_W);
>>>> +			version[1] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_X);
>>>> +			version[2] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Y);
>>>> +			version[3] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Z);
>>>> +		} else {
>>>> +			version[0] = 0;
>>>> +			version[1] = 0;
>>>> +			version[2] = 0;
>>>> +			version[3] = 0;
>>>> +		}
>>>> +	}
>>>> +
>>>> +out_free:
>>>> +	kfree(outbuf);
>>>> +	return rc;
>>>> +}
>>>> +
>>>> int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
>>>> 		      size_t len, size_t *retlen, u8 *buffer)
>>>> {
>>>> diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
>>>> index 7e35fec9da35..63b090587f7a 100644
>>>> --- a/drivers/net/ethernet/sfc/mcdi.h
>>>> +++ b/drivers/net/ethernet/sfc/mcdi.h
>>>> @@ -379,6 +379,9 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
>>>> 			bool *protected_out);
>>>> int efx_new_mcdi_nvram_test_all(struct efx_nic *efx);
>>>> int efx_mcdi_nvram_test_all(struct efx_nic *efx);
>>>> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>>>> +			    u32 *subtype, u16 version[4], char *desc,
>>>> +			    size_t descsize);
>>>> int efx_mcdi_handle_assertion(struct efx_nic *efx);
>>>> int efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
>>>> int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac,
>>>> diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
>>>> index 3b49e216768b..d036641dc043 100644
>>>> --- a/drivers/net/ethernet/sfc/net_driver.h
>>>> +++ b/drivers/net/ethernet/sfc/net_driver.h
>>>> @@ -994,6 +994,7 @@ enum efx_xdp_tx_queues_mode {
>>>>    *      xdp_rxq_info structures?
>>>>    * @netdev_notifier: Netdevice notifier.
>>>>    * @tc: state for TC offload (EF100).
>>>> + * @devlink: reference to devlink structure owned by this device
>>>>    * @mem_bar: The BAR that is mapped into membase.
>>>>    * @reg_base: Offset from the start of the bar to the function control window.
>>>>    * @monitor_work: Hardware monitor workitem
>>>> @@ -1179,6 +1180,7 @@ struct efx_nic {
>>>> 	struct notifier_block netdev_notifier;
>>>> 	struct efx_tc_state *tc;
>>>>
>>>> +	struct devlink *devlink;
>>>> 	unsigned int mem_bar;
>>>> 	u32 reg_base;
>>>>
>>>> -- 
>>>> 2.17.1
>>>>
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-19 14:59     ` Lucero Palau, Alejandro
@ 2023-01-20 11:05       ` Jiri Pirko
  2023-01-22 16:41         ` Lucero Palau, Alejandro
  0 siblings, 1 reply; 52+ messages in thread
From: Jiri Pirko @ 2023-01-20 11:05 UTC (permalink / raw)
  To: Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx

Thu, Jan 19, 2023 at 03:59:40PM CET, alejandro.lucero-palau@amd.com wrote:
>
>On 1/19/23 12:25, Jiri Pirko wrote:
>> Thu, Jan 19, 2023 at 12:31:39PM CET, alejandro.lucero-palau@amd.com wrote:
>>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>
>>> Using the builtin client handle id infrastructure, this patch adds
>>> support for obtaining the mac address linked to mports in ef100. This
>>> implies to execute an MCDI command for getting the data from the
>>> firmware for each devlink port.
>>>
>>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>> ---
>>> drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
>>> drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
>>> drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
>>> drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
>>> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
>>> 5 files changed, 81 insertions(+)
>>>
>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>>> index f4e913593f2b..4400ce622228 100644
>>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>>> @@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
>>> 	return rc;
>>> }
>>>
>>> +/* MCDI commands are related to the same device issuing them. This function
>>> + * allows to do an MCDI command on behalf of another device, mainly PFs setting
>>> + * things for VFs.
>>> + */
>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
>>> +{
>>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
>>> +	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
>>> +	size_t outlen;
>>> +	int rc;
>>> +
>>> +	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
>>> +		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
>>> +	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
>>> +		       pciefn_flat);
>>> +
>>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
>>> +			  outbuf, sizeof(outbuf), &outlen);
>>> +	if (rc)
>>> +		return rc;
>>> +	if (outlen < sizeof(outbuf))
>>> +		return -EIO;
>>> +	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
>>> +	return 0;
>>> +}
>>> +
>>> int ef100_probe_netdev_pf(struct efx_nic *efx)
>>> {
>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>>> index e59044072333..f1ed481c1260 100644
>>> --- a/drivers/net/ethernet/sfc/ef100_nic.h
>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.h
>>> @@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
>>>
>>> int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
>>> 			  int client_handle, bool empty_ok);
>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
>>> #endif	/* EFX_EF100_NIC_H */
>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>>> index ff0c8da61919..974c9ff901a0 100644
>>> --- a/drivers/net/ethernet/sfc/ef100_rep.c
>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.c
>>> @@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>> 		     mport_desc->interface_idx == nic_data->local_mae_intf;
>>> }
>>>
>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
>>> +{
>>> +	bool pcie_func;
>>> +
>>> +	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>>> +	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
>>> +}
>>> +
>>> void efx_ef100_init_reps(struct efx_nic *efx)
>>> {
>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>>> index 9cca41614982..74853ccbc937 100644
>>> --- a/drivers/net/ethernet/sfc/ef100_rep.h
>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.h
>>> @@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
>>> struct mae_mport_desc;
>>> bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>> 			       struct mae_mport_desc *mport_desc);
>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
>>> #endif /* EF100_REP_H */
>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>>> index bb19d3ad7ffd..2a57c4f6d2b2 100644
>>> --- a/drivers/net/ethernet/sfc/efx_devlink.c
>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>>> @@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
>>> 	return err;
>>> }
>>>
>>> +static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>>> +				     int *hw_addr_len,
>>> +				     struct netlink_ext_ack *extack)
>>> +{
>>> +	struct efx_devlink *devlink = devlink_priv(port->devlink);
>>> +	struct mae_mport_desc *mport_desc;
>>> +	efx_qword_t pciefn;
>>> +	u32 client_id;
>>> +	int rc = 0;
>>> +
>>> +	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
>> Dont use port->index, never. It's devlink internal. You have port
>> pointer passed here. Usually, what drivers do is to embed
>> the struct devlink_port in the driver port struct. Then you do just
>> simple container of to get it here. Mlxsw example:
>
>I do not understand this. Port index is set by the driver not by the 
>devlink interface implementation.
>
>Why can I not use it?

Well you can, but things could be done much nicer, when you use
devlink_port pointer. Also, better not to access devlink_port struct
internals, driver should never need it.


>
>> static void *__dl_port(struct devlink_port *devlink_port)
>> {
>>          return container_of(devlink_port, struct mlxsw_core_port, devlink_port);
>> }
>>
>> static int mlxsw_devlink_port_split(struct devlink *devlink,
>>                                      struct devlink_port *port,
>>                                      unsigned int count,
>>                                      struct netlink_ext_ack *extack)
>> {
>>          struct mlxsw_core_port *mlxsw_core_port = __dl_port(port);
>> ...
>>
>>
>>
>>> +	if (!mport_desc)
>> Tell the user what's wrong, extack is here for that.
>>
>I'll do.
>>
>>> +		return -EINVAL;
>>> +
>>> +	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
>>> +		goto out;
>>> +
>>> +	if (ef100_mport_is_vf(mport_desc))
>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>> +				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>>> +				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>> +	else
>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>> +				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
>>> +				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>> +
>>> +	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>>> +	if (rc) {
>>> +		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>>> +			  "Failed to get client ID for port index %u, rc %d\n",
>>> +			  port->index, rc);
>> Don't write to dmesg, use extack msg instead.
>
>
>I'll do.
>
>Thanks
>
>>
>>> +		return rc;
>>> +	}
>>> +
>>> +	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
>> Again, extack would be nice here if (rc)
>>
>Again, I'll do.
>>> +out:
>>> +	*hw_addr_len = ETH_ALEN;
>>> +
>>> +	return rc;
>>> +}
>>> +
>>> static int efx_devlink_info_get(struct devlink *devlink,
>>> 				struct devlink_info_req *req,
>>> 				struct netlink_ext_ack *extack)
>>> @@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
>>>
>>> static const struct devlink_ops sfc_devlink_ops = {
>>> 	.info_get			= efx_devlink_info_get,
>>> +	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
>>> };
>>>
>>> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>>> -- 
>>> 2.17.1
>>>
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-19 15:09     ` Lucero Palau, Alejandro
@ 2023-01-20 11:08       ` Jiri Pirko
  2023-01-20 12:48         ` Lucero Palau, Alejandro
  0 siblings, 1 reply; 52+ messages in thread
From: Jiri Pirko @ 2023-01-20 11:08 UTC (permalink / raw)
  To: Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx

Thu, Jan 19, 2023 at 04:09:27PM CET, alejandro.lucero-palau@amd.com wrote:
>
>On 1/19/23 12:37, Jiri Pirko wrote:
>> Thu, Jan 19, 2023 at 12:31:39PM CET, alejandro.lucero-palau@amd.com wrote:
>>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>
>>> Using the builtin client handle id infrastructure, this patch adds
>>> support for obtaining the mac address linked to mports in ef100. This
>>> implies to execute an MCDI command for getting the data from the
>>> firmware for each devlink port.
>>>
>>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>> ---
>>> drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
>>> drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
>>> drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
>>> drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
>>> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
>>> 5 files changed, 81 insertions(+)
>>>
>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>>> index f4e913593f2b..4400ce622228 100644
>>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>>> @@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
>>> 	return rc;
>>> }
>>>
>>> +/* MCDI commands are related to the same device issuing them. This function
>>> + * allows to do an MCDI command on behalf of another device, mainly PFs setting
>>> + * things for VFs.
>>> + */
>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
>>> +{
>>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
>>> +	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
>>> +	size_t outlen;
>>> +	int rc;
>>> +
>>> +	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
>>> +		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
>>> +	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
>>> +		       pciefn_flat);
>>> +
>>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
>>> +			  outbuf, sizeof(outbuf), &outlen);
>>> +	if (rc)
>>> +		return rc;
>>> +	if (outlen < sizeof(outbuf))
>>> +		return -EIO;
>>> +	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
>>> +	return 0;
>>> +}
>>> +
>>> int ef100_probe_netdev_pf(struct efx_nic *efx)
>>> {
>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>>> index e59044072333..f1ed481c1260 100644
>>> --- a/drivers/net/ethernet/sfc/ef100_nic.h
>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.h
>>> @@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
>>>
>>> int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
>>> 			  int client_handle, bool empty_ok);
>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
>>> #endif	/* EFX_EF100_NIC_H */
>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>>> index ff0c8da61919..974c9ff901a0 100644
>>> --- a/drivers/net/ethernet/sfc/ef100_rep.c
>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.c
>>> @@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>> 		     mport_desc->interface_idx == nic_data->local_mae_intf;
>>> }
>>>
>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
>>> +{
>>> +	bool pcie_func;
>>> +
>>> +	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>>> +	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
>>> +}
>>> +
>>> void efx_ef100_init_reps(struct efx_nic *efx)
>>> {
>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>>> index 9cca41614982..74853ccbc937 100644
>>> --- a/drivers/net/ethernet/sfc/ef100_rep.h
>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.h
>>> @@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
>>> struct mae_mport_desc;
>>> bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>> 			       struct mae_mport_desc *mport_desc);
>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
>>> #endif /* EF100_REP_H */
>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>>> index bb19d3ad7ffd..2a57c4f6d2b2 100644
>>> --- a/drivers/net/ethernet/sfc/efx_devlink.c
>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>>> @@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
>>> 	return err;
>>> }
>>>
>>> +static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>>> +				     int *hw_addr_len,
>>> +				     struct netlink_ext_ack *extack)
>>> +{
>>> +	struct efx_devlink *devlink = devlink_priv(port->devlink);
>>> +	struct mae_mport_desc *mport_desc;
>>> +	efx_qword_t pciefn;
>>> +	u32 client_id;
>>> +	int rc = 0;
>>> +
>>> +	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
>> I may be missing something, where do you fail with -EOPNOTSUPP
>> in case this is called for PHYSICAL port ?
>>
>
>We do not create a devlink port for the physical port.

Well, you do:

+       switch (mport->mport_type) {
+       case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
+               attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;

                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


+               attrs.phys.port_number = mport->port_idx;
+               devlink_port_attrs_set(dl_port, &attrs);
+               break;
+       case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
+               if (mport->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL) {
+                       devlink_port_attrs_pci_vf_set(dl_port, 0, mport->pf_idx,
+                                                     mport->vf_idx,
+                                                     external);
+               } else {
+                       devlink_port_attrs_pci_pf_set(dl_port, 0, mport->pf_idx,
+                                                     external);
+               }
+               break;




>
>I'm aware this is not "fully compliant" with devlink design idea, just 
>trying to use it for our current urgent necessities by now.
>
>Do you think this could be a problem?

If you create port flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL and it is not
uplink, it is a problem :)



>
>
>>
>>> +	if (!mport_desc)
>>> +		return -EINVAL;
>>> +
>>> +	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
>>> +		goto out;
>>> +
>>> +	if (ef100_mport_is_vf(mport_desc))
>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>> +				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>>> +				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>> +	else
>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>> +				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
>>> +				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>> +
>>> +	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>>> +	if (rc) {
>>> +		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>>> +			  "Failed to get client ID for port index %u, rc %d\n",
>>> +			  port->index, rc);
>>> +		return rc;
>>> +	}
>>> +
>>> +	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
>>> +out:
>>> +	*hw_addr_len = ETH_ALEN;
>>> +
>>> +	return rc;
>>> +}
>>> +
>>> static int efx_devlink_info_get(struct devlink *devlink,
>>> 				struct devlink_info_req *req,
>>> 				struct netlink_ext_ack *extack)
>>> @@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
>>>
>>> static const struct devlink_ops sfc_devlink_ops = {
>>> 	.info_get			= efx_devlink_info_get,
>>> +	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
>>> };
>>>
>>> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>>> -- 
>>> 2.17.1
>>>
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 2/7] sfc: enumerate mports in ef100
  2023-01-19 11:31 ` [PATCH net-next 2/7] sfc: enumerate mports in ef100 alejandro.lucero-palau
  2023-01-19 23:48   ` Jacob Keller
@ 2023-01-20 12:47   ` kernel test robot
  1 sibling, 0 replies; 52+ messages in thread
From: kernel test robot @ 2023-01-20 12:47 UTC (permalink / raw)
  To: alejandro.lucero-palau, netdev, linux-net-drivers
  Cc: llvm, oe-kbuild-all, davem, kuba, pabeni, edumazet, habetsm,
	ecree.xilinx, Alejandro Lucero

Hi,

Thank you for the patch! Yet something to improve:

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

url:    https://github.com/intel-lab-lkp/linux/commits/alejandro-lucero-palau-amd-com/sfc-add-devlink-support-for-ef100/20230119-193440
patch link:    https://lore.kernel.org/r/20230119113140.20208-3-alejandro.lucero-palau%40amd.com
patch subject: [PATCH net-next 2/7] sfc: enumerate mports in ef100
config: i386-randconfig-a015 (https://download.01.org/0day-ci/archive/20230120/202301202052.7U4BpPHW-lkp@intel.com/config)
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/1542af777ce523b4aab61fcb7c17d63a68db4cea
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review alejandro-lucero-palau-amd-com/sfc-add-devlink-support-for-ef100/20230119-193440
        git checkout 1542af777ce523b4aab61fcb7c17d63a68db4cea
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "efx_ef100_fini_reps" [drivers/net/ethernet/sfc/sfc.ko] undefined!
>> ERROR: modpost: "efx_fini_mae" [drivers/net/ethernet/sfc/sfc.ko] undefined!

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-20 11:08       ` Jiri Pirko
@ 2023-01-20 12:48         ` Lucero Palau, Alejandro
  2023-01-22 16:36           ` Lucero Palau, Alejandro
  0 siblings, 1 reply; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-20 12:48 UTC (permalink / raw)
  To: Jiri Pirko, Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx


On 1/20/23 11:08, Jiri Pirko wrote:
> Thu, Jan 19, 2023 at 04:09:27PM CET, alejandro.lucero-palau@amd.com wrote:
>> On 1/19/23 12:37, Jiri Pirko wrote:
>>> Thu, Jan 19, 2023 at 12:31:39PM CET, alejandro.lucero-palau@amd.com wrote:
>>>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>>
>>>> Using the builtin client handle id infrastructure, this patch adds
>>>> support for obtaining the mac address linked to mports in ef100. This
>>>> implies to execute an MCDI command for getting the data from the
>>>> firmware for each devlink port.
>>>>
>>>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>> ---
>>>> drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
>>>> drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
>>>> drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
>>>> drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
>>>> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
>>>> 5 files changed, 81 insertions(+)
>>>>
>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>>>> index f4e913593f2b..4400ce622228 100644
>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>>>> @@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
>>>> 	return rc;
>>>> }
>>>>
>>>> +/* MCDI commands are related to the same device issuing them. This function
>>>> + * allows to do an MCDI command on behalf of another device, mainly PFs setting
>>>> + * things for VFs.
>>>> + */
>>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
>>>> +{
>>>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
>>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
>>>> +	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
>>>> +	size_t outlen;
>>>> +	int rc;
>>>> +
>>>> +	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
>>>> +		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
>>>> +	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
>>>> +		       pciefn_flat);
>>>> +
>>>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
>>>> +			  outbuf, sizeof(outbuf), &outlen);
>>>> +	if (rc)
>>>> +		return rc;
>>>> +	if (outlen < sizeof(outbuf))
>>>> +		return -EIO;
>>>> +	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
>>>> +	return 0;
>>>> +}
>>>> +
>>>> int ef100_probe_netdev_pf(struct efx_nic *efx)
>>>> {
>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>>>> index e59044072333..f1ed481c1260 100644
>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.h
>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.h
>>>> @@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
>>>>
>>>> int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
>>>> 			  int client_handle, bool empty_ok);
>>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
>>>> #endif	/* EFX_EF100_NIC_H */
>>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>>>> index ff0c8da61919..974c9ff901a0 100644
>>>> --- a/drivers/net/ethernet/sfc/ef100_rep.c
>>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.c
>>>> @@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>>> 		     mport_desc->interface_idx == nic_data->local_mae_intf;
>>>> }
>>>>
>>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
>>>> +{
>>>> +	bool pcie_func;
>>>> +
>>>> +	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>>>> +	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
>>>> +}
>>>> +
>>>> void efx_ef100_init_reps(struct efx_nic *efx)
>>>> {
>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>>>> index 9cca41614982..74853ccbc937 100644
>>>> --- a/drivers/net/ethernet/sfc/ef100_rep.h
>>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.h
>>>> @@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
>>>> struct mae_mport_desc;
>>>> bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>>> 			       struct mae_mport_desc *mport_desc);
>>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
>>>> #endif /* EF100_REP_H */
>>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>>>> index bb19d3ad7ffd..2a57c4f6d2b2 100644
>>>> --- a/drivers/net/ethernet/sfc/efx_devlink.c
>>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>>>> @@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
>>>> 	return err;
>>>> }
>>>>
>>>> +static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>>>> +				     int *hw_addr_len,
>>>> +				     struct netlink_ext_ack *extack)
>>>> +{
>>>> +	struct efx_devlink *devlink = devlink_priv(port->devlink);
>>>> +	struct mae_mport_desc *mport_desc;
>>>> +	efx_qword_t pciefn;
>>>> +	u32 client_id;
>>>> +	int rc = 0;
>>>> +
>>>> +	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
>>> I may be missing something, where do you fail with -EOPNOTSUPP
>>> in case this is called for PHYSICAL port ?
>>>
>> We do not create a devlink port for the physical port.
> Well, you do:
>
> +       switch (mport->mport_type) {
> +       case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
> +               attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
>
>                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Right.

I was relying on devlink-port output which does not show the physical 
port in my machine and completely forgot about it.

I'm a bit confused at this point. Let me look at this further.


>
> +               attrs.phys.port_number = mport->port_idx;
> +               devlink_port_attrs_set(dl_port, &attrs);
> +               break;
> +       case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
> +               if (mport->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL) {
> +                       devlink_port_attrs_pci_vf_set(dl_port, 0, mport->pf_idx,
> +                                                     mport->vf_idx,
> +                                                     external);
> +               } else {
> +                       devlink_port_attrs_pci_pf_set(dl_port, 0, mport->pf_idx,
> +                                                     external);
> +               }
> +               break;
>
>
>
>
>> I'm aware this is not "fully compliant" with devlink design idea, just
>> trying to use it for our current urgent necessities by now.
>>
>> Do you think this could be a problem?
> If you create port flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL and it is not
> uplink, it is a problem :)
>
>
>
>>
>>>> +	if (!mport_desc)
>>>> +		return -EINVAL;
>>>> +
>>>> +	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
>>>> +		goto out;
>>>> +
>>>> +	if (ef100_mport_is_vf(mport_desc))
>>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>>> +				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>>>> +				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>>> +	else
>>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>>> +				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
>>>> +				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
>>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>>> +
>>>> +	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>>>> +	if (rc) {
>>>> +		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>>>> +			  "Failed to get client ID for port index %u, rc %d\n",
>>>> +			  port->index, rc);
>>>> +		return rc;
>>>> +	}
>>>> +
>>>> +	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
>>>> +out:
>>>> +	*hw_addr_len = ETH_ALEN;
>>>> +
>>>> +	return rc;
>>>> +}
>>>> +
>>>> static int efx_devlink_info_get(struct devlink *devlink,
>>>> 				struct devlink_info_req *req,
>>>> 				struct netlink_ext_ack *extack)
>>>> @@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
>>>>
>>>> static const struct devlink_ops sfc_devlink_ops = {
>>>> 	.info_get			= efx_devlink_info_get,
>>>> +	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
>>>> };
>>>>
>>>> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>>>> -- 
>>>> 2.17.1
>>>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 11:31 ` [PATCH net-next 1/7] sfc: add " alejandro.lucero-palau
                     ` (3 preceding siblings ...)
  2023-01-19 23:40   ` Jacob Keller
@ 2023-01-20 13:59   ` kernel test robot
  4 siblings, 0 replies; 52+ messages in thread
From: kernel test robot @ 2023-01-20 13:59 UTC (permalink / raw)
  To: alejandro.lucero-palau, netdev, linux-net-drivers
  Cc: oe-kbuild-all, davem, kuba, pabeni, edumazet, habetsm,
	ecree.xilinx, Alejandro Lucero

Hi,

Thank you for the patch! Yet something to improve:

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

url:    https://github.com/intel-lab-lkp/linux/commits/alejandro-lucero-palau-amd-com/sfc-add-devlink-support-for-ef100/20230119-193440
patch link:    https://lore.kernel.org/r/20230119113140.20208-2-alejandro.lucero-palau%40amd.com
patch subject: [PATCH net-next 1/7] sfc: add devlink support for ef100
config: i386-randconfig-a013-20221205 (https://download.01.org/0day-ci/archive/20230120/202301202124.sfqty0op-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-8) 11.3.0
reproduce (this is a W=1 build):
        # https://github.com/intel-lab-lkp/linux/commit/f393f2642abb0e7536df6f9f08e0d69ecfd5b435
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review alejandro-lucero-palau-amd-com/sfc-add-devlink-support-for-ef100/20230119-193440
        git checkout f393f2642abb0e7536df6f9f08e0d69ecfd5b435
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        make W=1 O=build_dir ARCH=i386 olddefconfig
        make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>, old ones prefixed by <<):

>> ERROR: modpost: "efx_mcdi_nvram_metadata" [drivers/net/ethernet/sfc/sfc.ko] undefined!

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 23:40   ` Jacob Keller
@ 2023-01-20 14:11     ` Lucero Palau, Alejandro
  2023-01-24  6:13       ` Edward Cree
  2023-01-24 11:05     ` Lucero Palau, Alejandro
  1 sibling, 1 reply; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-20 14:11 UTC (permalink / raw)
  To: Jacob Keller, Lucero Palau, Alejandro, netdev,
	linux-net-drivers (AMD-Xilinx)
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx


On 1/19/23 23:40, Jacob Keller wrote:
>
> On 1/19/2023 3:31 AM, alejandro.lucero-palau@amd.com wrote:
>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>
>> Basic support for devlink info command.
>>
>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>> ---
>>   drivers/net/ethernet/sfc/Kconfig       |   1 +
>>   drivers/net/ethernet/sfc/Makefile      |   3 +-
>>   drivers/net/ethernet/sfc/ef100_nic.c   |   6 +
>>   drivers/net/ethernet/sfc/efx_devlink.c | 427 +++++++++++++++++++++++++
>>   drivers/net/ethernet/sfc/efx_devlink.h |  20 ++
>>   drivers/net/ethernet/sfc/mcdi.c        |  72 +++++
>>   drivers/net/ethernet/sfc/mcdi.h        |   3 +
>>   drivers/net/ethernet/sfc/net_driver.h  |   2 +
>>   8 files changed, 533 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/net/ethernet/sfc/efx_devlink.c
>>   create mode 100644 drivers/net/ethernet/sfc/efx_devlink.h
>>
>> diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
>> index 0950e6b0508f..4af36ba8906b 100644
>> --- a/drivers/net/ethernet/sfc/Kconfig
>> +++ b/drivers/net/ethernet/sfc/Kconfig
>> @@ -22,6 +22,7 @@ config SFC
>>   	depends on PTP_1588_CLOCK_OPTIONAL
>>   	select MDIO
>>   	select CRC32
>> +	select NET_DEVLINK
>>   	help
>>   	  This driver supports 10/40-gigabit Ethernet cards based on
>>   	  the Solarflare SFC9100-family controllers.
>> diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
>> index 712a48d00069..55b9c73cd8ef 100644
>> --- a/drivers/net/ethernet/sfc/Makefile
>> +++ b/drivers/net/ethernet/sfc/Makefile
>> @@ -6,7 +6,8 @@ sfc-y			+= efx.o efx_common.o efx_channels.o nic.o \
>>   			   mcdi.o mcdi_port.o mcdi_port_common.o \
>>   			   mcdi_functions.o mcdi_filters.o mcdi_mon.o \
>>   			   ef100.o ef100_nic.o ef100_netdev.o \
>> -			   ef100_ethtool.o ef100_rx.o ef100_tx.o
>> +			   ef100_ethtool.o ef100_rx.o ef100_tx.o \
>> +			   efx_devlink.o
>>   sfc-$(CONFIG_SFC_MTD)	+= mtd.o
>>   sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
>>                              mae.o tc.o tc_bindings.o tc_counters.o
>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>> index ad686c671ab8..14af8f314b83 100644
>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>> @@ -27,6 +27,7 @@
>>   #include "tc.h"
>>   #include "mae.h"
>>   #include "rx_common.h"
>> +#include "efx_devlink.h"
>>   
>>   #define EF100_MAX_VIS 4096
>>   #define EF100_NUM_MCDI_BUFFERS	1
>> @@ -1124,6 +1125,10 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
>>   		netif_warn(efx, probe, net_dev,
>>   			   "Failed to probe base mport rc %d; representors will not function\n",
>>   			   rc);
>> +	} else {
>> +		if (efx_probe_devlink(efx))
>> +			netif_warn(efx, probe, net_dev,
>> +				   "Failed to register devlink\n");
>>   	}
>>   
> A bit of a weird construction here with the next step in an else block?
> I guess this is being treated as an optional feature, and depends on
> efx_ef100_get_base_mport succeeding?


Right. The mae ports initialization can fail but the driver can still 
initialize the device with limited functionality.


>
> It reads a little awkward, but I can't think of a better way to arrange
> this unless another helper function was used to combine these two calls
> in order to avoid the extra indentation.
>

I could add some check at the beginning of those functions and returning 
doing nothing if the checks fails. That would avoid this ugliness.

>>   	rc = efx_init_tc(efx);
>> @@ -1157,6 +1162,7 @@ void ef100_remove(struct efx_nic *efx)
>>   {
>>   	struct ef100_nic_data *nic_data = efx->nic_data;
>>   
>> +	efx_fini_devlink(efx);
>>   	efx_mcdi_detach(efx);
>>   	efx_mcdi_fini(efx);
>>   	if (nic_data)
>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>> new file mode 100644
>> index 000000000000..c506f8f35d25
>> --- /dev/null
>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>> @@ -0,0 +1,427 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/****************************************************************************
>> + * Driver for AMD network controllers and boards
>> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published
>> + * by the Free Software Foundation, incorporated herein by reference.
>> + */
>> +
>> +#include <linux/rtc.h>
>> +#include "net_driver.h"
>> +#include "ef100_nic.h"
>> +#include "efx_devlink.h"
>> +#include "nic.h"
>> +#include "mcdi.h"
>> +#include "mcdi_functions.h"
>> +#include "mcdi_pcol.h"
>> +
>> +/* Custom devlink-info version object names for details that do not map to the
>> + * generic standardized names.
>> + */
>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC	"fw.mgmt.suc"
>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC	"fw.mgmt.cmc"
>> +#define EFX_DEVLINK_INFO_VERSION_FPGA_REV	"fpga.rev"
>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_HW	"fpga.app"
>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_FW	DEVLINK_INFO_VERSION_GENERIC_FW_APP
>> +#define EFX_DEVLINK_INFO_VERSION_SOC_BOOT	"coproc.boot"
>> +#define EFX_DEVLINK_INFO_VERSION_SOC_UBOOT	"coproc.uboot"
>> +#define EFX_DEVLINK_INFO_VERSION_SOC_MAIN	"coproc.main"
>> +#define EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY	"coproc.recovery"
>> +#define EFX_DEVLINK_INFO_VERSION_FW_EXPROM	"fw.exprom"
>> +#define EFX_DEVLINK_INFO_VERSION_FW_UEFI	"fw.uefi"
> Here, you've defined several new versions, only one of which is
> standard. I don't see an associated documentation addition. Please add a
> ef100.rst file to Documentation/networking/devlink
>
> It is also preferred to use the standard names or extend the set of
> standard names where appropriate first. Can you explain why you didn't
> do that here?
>
> For example, the documentation for "fw.undi" indicates it may include
> the UEFI driver, and I would expect your UEFI version to be something
> like fw.undi or fw.undi.uefi if its distinct...


OK. I'll add that doc file in the next version and use those standard 
definitions when possible.

>> +
>> +#define EFX_MAX_VERSION_INFO_LEN	64
>> +
>> +static int efx_devlink_info_nvram_partition(struct efx_nic *efx,
>> +					    struct devlink_info_req *req,
>> +					    unsigned int partition_type,
>> +					    const char *version_name)
>> +{
>> +	char buf[EFX_MAX_VERSION_INFO_LEN];
>> +	u16 version[4];
>> +	int rc;
>> +
>> +	rc = efx_mcdi_nvram_metadata(efx, partition_type, NULL, version, NULL,
>> +				     0);
>> +	if (rc)
>> +		return rc;
>> +
>> +	snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u", version[0],
>> +		 version[1], version[2], version[3]);
>> +	devlink_info_version_stored_put(req, version_name, buf);
>> +
>> +	return 0;
>> +}
>> +
>> +static void efx_devlink_info_stored_versions(struct efx_nic *efx,
>> +					     struct devlink_info_req *req)
>> +{
>> +	efx_devlink_info_nvram_partition(efx, req, NVRAM_PARTITION_TYPE_BUNDLE,
>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID);
>> +	efx_devlink_info_nvram_partition(efx, req,
>> +					 NVRAM_PARTITION_TYPE_MC_FIRMWARE,
>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT);
>> +	efx_devlink_info_nvram_partition(efx, req,
>> +					 NVRAM_PARTITION_TYPE_SUC_FIRMWARE,
>> +					 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC);
>> +	efx_devlink_info_nvram_partition(efx, req,
>> +					 NVRAM_PARTITION_TYPE_EXPANSION_ROM,
>> +					 EFX_DEVLINK_INFO_VERSION_FW_EXPROM);
>> +	efx_devlink_info_nvram_partition(efx, req,
>> +					 NVRAM_PARTITION_TYPE_EXPANSION_UEFI,
>> +					 EFX_DEVLINK_INFO_VERSION_FW_UEFI);
>> +}
>> +
>> +#define EFX_MAX_SERIALNUM_LEN	(ETH_ALEN * 2 + 1)
>> +
>> +static void efx_devlink_info_board_cfg(struct efx_nic *efx,
>> +				       struct devlink_info_req *req)
>> +{
>> +	char sn[EFX_MAX_SERIALNUM_LEN];
>> +	u8 mac_address[ETH_ALEN];
>> +	int rc;
>> +
>> +	rc = efx_mcdi_get_board_cfg(efx, (u8 *)mac_address, NULL, NULL);
>> +	if (!rc) {
>> +		snprintf(sn, EFX_MAX_SERIALNUM_LEN, "%pm", mac_address);
>> +		devlink_info_serial_number_put(req, sn);
>> +	}
>> +}
>> +
>> +#define EFX_VER_FLAG(_f)	\
>> +	(MC_CMD_GET_VERSION_V5_OUT_ ## _f ## _PRESENT_LBN)
>> +
>> +static void efx_devlink_info_running_versions(struct efx_nic *efx,
>> +					      struct devlink_info_req *req)
>> +{
> This function for doing running versions is very long, and seems quite
> complicated. It's difficult to parse what versions are being reported.
>
> I saw that your stored version used a helper function to separate each
> thing out nicely. Is there any way to do that here?
>

OK. I'll split it up based on the handling per version.

>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_V5_OUT_LEN);
>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_VERSION_EXT_IN_LEN);
>> +	char buf[EFX_MAX_VERSION_INFO_LEN];
>> +	unsigned int flags, build_id;
>> +	union {
>> +		const __le32 *dwords;
>> +		const __le16 *words;
>> +		const char *str;
>> +	} ver;
> For example, you've got this local union on the stack that seems to be
> reused a bunch...
>
>> +	struct rtc_time build_date;
>> +	size_t outlength, offset;
>> +	u64 tstamp;
>> +	int rc;
>> +
>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, inbuf, sizeof(inbuf),
>> +			  outbuf, sizeof(outbuf), &outlength);
>> +	if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN)
>> +		return;
>> +
>> +	/* Handle previous output */
>> +	if (outlength < MC_CMD_GET_VERSION_V2_OUT_LEN) {
>> +		ver.words = (__le16 *)MCDI_PTR(outbuf,
>> +					       GET_VERSION_EXT_OUT_VERSION);
>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +				  le16_to_cpu(ver.words[0]),
>> +				  le16_to_cpu(ver.words[1]),
>> +				  le16_to_cpu(ver.words[2]),
>> +				  le16_to_cpu(ver.words[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>> +						 buf);
>> +		return;
>> +	}
>> +
>> +	/* Handle V2 additions */
>> +	flags = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_FLAGS);
>> +	if (flags & BIT(EFX_VER_FLAG(BOARD_EXT_INFO))) {
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%s",
>> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_NAME));
>> +		devlink_info_version_fixed_put(req,
>> +					       DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
>> +					       buf);
>> +
>> +		/* Favour full board version if present (in V5 or later) */
>> +		if (~flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>> +			snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u",
>> +				 MCDI_DWORD(outbuf,
>> +					    GET_VERSION_V2_OUT_BOARD_REVISION));
>> +			devlink_info_version_fixed_put(req,
>> +						       DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>> +						       buf);
>> +		}
>> +
>> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_SERIAL);
>> +		if (ver.str[0])
>> +			devlink_info_board_serial_number_put(req, ver.str);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(FPGA_EXT_INFO))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V2_OUT_FPGA_VERSION);
>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u_%c%u",
>> +				  le32_to_cpu(ver.dwords[0]),
>> +				  'A' + le32_to_cpu(ver.dwords[1]),
>> +				  le32_to_cpu(ver.dwords[2]));
>> +
>> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_FPGA_EXTRA);
>> +		if (ver.str[0])
>> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>> +				 " (%s)", ver.str);
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_FPGA_REV,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(CMC_EXT_INFO))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V2_OUT_CMCFW_VERSION);
>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +				  le32_to_cpu(ver.dwords[0]),
>> +				  le32_to_cpu(ver.dwords[1]),
>> +				  le32_to_cpu(ver.dwords[2]),
>> +				  le32_to_cpu(ver.dwords[3]));
>> +
>> +		tstamp = MCDI_QWORD(outbuf,
>> +				    GET_VERSION_V2_OUT_CMCFW_BUILD_DATE);
>> +		if (tstamp) {
>> +			rtc_time64_to_tm(tstamp, &build_date);
>> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>> +				 " (%ptRd)", &build_date);
>> +		}
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC,
>> +						 buf);
>> +	}
>> +
>> +	ver.words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_V2_OUT_VERSION);
>> +	offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			  le16_to_cpu(ver.words[0]), le16_to_cpu(ver.words[1]),
>> +			  le16_to_cpu(ver.words[2]), le16_to_cpu(ver.words[3]));
>> +	if (flags & BIT(EFX_VER_FLAG(MCFW_EXT_INFO))) {
>> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_ID);
>> +		snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>> +			 " (%x) %s", build_id,
>> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_NAME));
>> +	}
>> +	devlink_info_version_running_put(req,
>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>> +					 buf);
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V2_OUT_SUCFW_VERSION);
>> +		tstamp = MCDI_QWORD(outbuf,
>> +				    GET_VERSION_V2_OUT_SUCFW_BUILD_DATE);
>> +		rtc_time64_to_tm(tstamp, &build_date);
>> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_SUCFW_CHIP_ID);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN,
>> +			 "%u.%u.%u.%u type %x (%ptRd)",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]), le32_to_cpu(ver.dwords[3]),
>> +			 build_id, &build_date);
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>> +						 buf);
>> +	}
>> +
>> +	if (outlength < MC_CMD_GET_VERSION_V3_OUT_LEN)
>> +		return;
>> +
>> +	/* Handle V3 additions */
>> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_HW_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V3_OUT_DATAPATH_HW_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_HW,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_FW_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V3_OUT_DATAPATH_FW_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_FW,
>> +						 buf);
>> +	}
>> +
>> +	if (outlength < MC_CMD_GET_VERSION_V4_OUT_LEN)
>> +		return;
>> +
>> +	/* Handle V4 additions */
>> +	if (flags & BIT(EFX_VER_FLAG(SOC_BOOT_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SOC_BOOT_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_SOC_BOOT,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SOC_UBOOT_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SOC_UBOOT_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_SOC_UBOOT,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SOC_MAIN_ROOTFS_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SOC_MAIN_ROOTFS_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_SOC_MAIN,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SOC_RECOVERY_BUILDROOT_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SOC_RECOVERY_BUILDROOT_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_VERSION)) &&
>> +	    ~flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SUCFW_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>> +						 buf);
>> +	}
>> +
>> +	if (outlength < MC_CMD_GET_VERSION_V5_OUT_LEN)
>> +		return;
>> +
>> +	/* Handle V5 additions */
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V5_OUT_BOARD_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(BUNDLE_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V5_OUT_BUNDLE_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
>> +						 buf);
>> +	}
>> +}
> In the ice driver I implemented each version extraction as a separate
> function to make it more clear which versions where which. This running
> function could benefit from some organization like that.
>
>> +
>> +#undef EFX_VER_FLAG
>> +
>> +static void efx_devlink_info_query_all(struct efx_nic *efx,
>> +				       struct devlink_info_req *req)
>> +{
>> +	efx_devlink_info_board_cfg(efx, req);
>> +	efx_devlink_info_stored_versions(efx, req);
>> +	efx_devlink_info_running_versions(efx, req);
>> +}
> Do you really need this to be a separate function and not just inlined
> into the caller, efx_devlink_info_get.


That was also pointed out by Jiri Pirko and I agree this is not necessary.

>> +
>> +struct efx_devlink {
>> +	struct efx_nic *efx;
>> +};
>> +
>> +static int efx_devlink_info_get(struct devlink *devlink,
>> +				struct devlink_info_req *req,
>> +				struct netlink_ext_ack *extack)
>> +{
>> +	struct efx_devlink *devlink_private = devlink_priv(devlink);
>> +	struct efx_nic *efx = devlink_private->efx;
>> +
>> +	efx_devlink_info_query_all(efx, req);
>> +	return 0;
>> +}
>> +
>> +static const struct devlink_ops sfc_devlink_ops = {
>> +	.info_get			= efx_devlink_info_get,
>> +};
>> +
>> +void efx_fini_devlink(struct efx_nic *efx)
>> +{
>> +	if (efx->devlink) {
>> +		struct efx_devlink *devlink_private;
>> +
>> +		devlink_private = devlink_priv(efx->devlink);
>> +
>> +		devlink_unregister(efx->devlink);
>> +		devlink_free(efx->devlink);
>> +		efx->devlink = NULL;
>> +	}
>> +}
>> +
>> +int efx_probe_devlink(struct efx_nic *efx)
>> +{
>> +	struct efx_devlink *devlink_private;
>> +
>> +	efx->devlink = devlink_alloc(&sfc_devlink_ops,
>> +				     sizeof(struct efx_devlink),
>> +				     &efx->pci_dev->dev);
>> +	if (!efx->devlink)
>> +		return -ENOMEM;
>> +	devlink_private = devlink_priv(efx->devlink);
>> +	devlink_private->efx = efx;
>> +
>> +	devlink_register(efx->devlink);
>> +
> So drivers implementing devlink typically would allocate the devlink
> early (almost the first thing it does) and make its private field
> something like their main private data structure.
>
> Obviously you're adding this to a pre-existing driver and it is
> initially simpler and easier to keep it separate. I'm not sure what
> other reviewers' stance on this is, but I think its preferable to
> allocate as an early stage and register once the driver is ready to
> accept requests from user space.
>
> As for a reason why, implementing reload support effectively requires this.
>

We have discussed this internally and we do not plan to support reload.


>> +	return 0;
>> +}
>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.h b/drivers/net/ethernet/sfc/efx_devlink.h
>> new file mode 100644
>> index 000000000000..997f878aea93
>> --- /dev/null
>> +++ b/drivers/net/ethernet/sfc/efx_devlink.h
>> @@ -0,0 +1,20 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/****************************************************************************
>> + * Driver for AMD network controllers and boards
>> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published
>> + * by the Free Software Foundation, incorporated herein by reference.
>> + */
>> +
>> +#ifndef _EFX_DEVLINK_H
>> +#define _EFX_DEVLINK_H
>> +
>> +#include "net_driver.h"
>> +#include <net/devlink.h>
>> +
>> +int efx_probe_devlink(struct efx_nic *efx);
>> +void efx_fini_devlink(struct efx_nic *efx);
>> +
>> +#endif	/* _EFX_DEVLINK_H */
>> diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
>> index af338208eae9..328cae82a7d8 100644
>> --- a/drivers/net/ethernet/sfc/mcdi.c
>> +++ b/drivers/net/ethernet/sfc/mcdi.c
>> @@ -2308,6 +2308,78 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
>>   	return rc;
>>   }
>>   
>> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>> +			    u32 *subtype, u16 version[4], char *desc,
>> +			    size_t descsize)
>> +{
>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN);
>> +	efx_dword_t *outbuf;
>> +	size_t outlen;
>> +	u32 flags;
>> +	int rc;
>> +
>> +	outbuf = kzalloc(MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2, GFP_KERNEL);
>> +	if (!outbuf)
>> +		return -ENOMEM;
>> +
>> +	MCDI_SET_DWORD(inbuf, NVRAM_METADATA_IN_TYPE, type);
>> +
>> +	rc = efx_mcdi_rpc_quiet(efx, MC_CMD_NVRAM_METADATA, inbuf,
>> +				sizeof(inbuf), outbuf,
>> +				MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2,
>> +				&outlen);
>> +	if (rc)
>> +		goto out_free;
>> +	if (outlen < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
>> +		rc = -EIO;
>> +		goto out_free;
>> +	}
>> +
>> +	flags = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_FLAGS);
>> +
>> +	if (desc && descsize > 0) {
>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_VALID_LBN)) {
>> +			if (descsize <=
>> +			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)) {
>> +				rc = -E2BIG;
>> +				goto out_free;
>> +			}
>> +
>> +			strncpy(desc,
>> +				MCDI_PTR(outbuf, NVRAM_METADATA_OUT_DESCRIPTION),
>> +				MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen));
>> +			desc[MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)] = '\0';
>> +		} else {
>> +			desc[0] = '\0';
>> +		}
>> +	}
>> +
>> +	if (subtype) {
>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_SUBTYPE_VALID_LBN))
>> +			*subtype = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_SUBTYPE);
>> +		else
>> +			*subtype = 0;
>> +	}
>> +
>> +	if (version) {
>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_VERSION_VALID_LBN)) {
>> +			version[0] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_W);
>> +			version[1] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_X);
>> +			version[2] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Y);
>> +			version[3] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Z);
>> +		} else {
>> +			version[0] = 0;
>> +			version[1] = 0;
>> +			version[2] = 0;
>> +			version[3] = 0;
>> +		}
>> +	}
>> +
>> +out_free:
>> +	kfree(outbuf);
>> +	return rc;
>> +}
>> +
>>   int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
>>   		      size_t len, size_t *retlen, u8 *buffer)
>>   {
>> diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
>> index 7e35fec9da35..63b090587f7a 100644
>> --- a/drivers/net/ethernet/sfc/mcdi.h
>> +++ b/drivers/net/ethernet/sfc/mcdi.h
>> @@ -379,6 +379,9 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
>>   			bool *protected_out);
>>   int efx_new_mcdi_nvram_test_all(struct efx_nic *efx);
>>   int efx_mcdi_nvram_test_all(struct efx_nic *efx);
>> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>> +			    u32 *subtype, u16 version[4], char *desc,
>> +			    size_t descsize);
>>   int efx_mcdi_handle_assertion(struct efx_nic *efx);
>>   int efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
>>   int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac,
>> diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
>> index 3b49e216768b..d036641dc043 100644
>> --- a/drivers/net/ethernet/sfc/net_driver.h
>> +++ b/drivers/net/ethernet/sfc/net_driver.h
>> @@ -994,6 +994,7 @@ enum efx_xdp_tx_queues_mode {
>>    *      xdp_rxq_info structures?
>>    * @netdev_notifier: Netdevice notifier.
>>    * @tc: state for TC offload (EF100).
>> + * @devlink: reference to devlink structure owned by this device
>>    * @mem_bar: The BAR that is mapped into membase.
>>    * @reg_base: Offset from the start of the bar to the function control window.
>>    * @monitor_work: Hardware monitor workitem
>> @@ -1179,6 +1180,7 @@ struct efx_nic {
>>   	struct notifier_block netdev_notifier;
>>   	struct efx_tc_state *tc;
>>   
>> +	struct devlink *devlink;
>>   	unsigned int mem_bar;
>>   	u32 reg_base;
>>   


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 2/7] sfc: enumerate mports in ef100
  2023-01-19 23:48   ` Jacob Keller
@ 2023-01-20 14:13     ` Lucero Palau, Alejandro
  0 siblings, 0 replies; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-20 14:13 UTC (permalink / raw)
  To: Jacob Keller, Lucero Palau, Alejandro, netdev,
	linux-net-drivers (AMD-Xilinx)
  Cc: davem, kuba, pabeni, edumazet, ecree.xilinx


On 1/19/23 23:48, Jacob Keller wrote:
>
> On 1/19/2023 3:31 AM, alejandro.lucero-palau@amd.com wrote:
>> +
>> +int efx_mae_enumerate_mports(struct efx_nic *efx)
>> +{
>> +#define MCDI_MPORT_JOURNAL_LEN \
>> +	sizeof(efx_dword_t[DIV_ROUND_UP(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4)])
> Please keep #define like this outside the function block. This is really
> hard to read. It's also not clear to me what exactly this define is
> doing.. you're accessing an array and using a DIV_ROUND_UP...


Thank you for pointing this out. It does not make sense at all.

I'll fix this in the next version.


>> +	efx_dword_t *outbuf = kzalloc(MCDI_MPORT_JOURNAL_LEN, GFP_KERNEL);
>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN);
>> +	MCDI_DECLARE_STRUCT_PTR(desc);
>> +	size_t outlen, stride, count;
>> +	int rc = 0, i;


^ permalink raw reply	[flat|nested] 52+ messages in thread

* RE: [PATCH net-next 3/7] sfc: add mport lookup based on driver's mport data
  2023-01-20  9:34     ` Lucero Palau, Alejandro
@ 2023-01-20 18:36       ` Keller, Jacob E
  0 siblings, 0 replies; 52+ messages in thread
From: Keller, Jacob E @ 2023-01-20 18:36 UTC (permalink / raw)
  To: Lucero Palau, Alejandro, netdev, linux-net-drivers (AMD-Xilinx)
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx



> -----Original Message-----
> From: Lucero Palau, Alejandro <alejandro.lucero-palau@amd.com>
> Sent: Friday, January 20, 2023 1:35 AM
> To: Keller, Jacob E <jacob.e.keller@intel.com>; Lucero Palau, Alejandro
> <alejandro.lucero-palau@amd.com>; netdev@vger.kernel.org; linux-net-drivers
> (AMD-Xilinx) <linux-net-drivers@amd.com>
> Cc: davem@davemloft.net; kuba@kernel.org; pabeni@redhat.com;
> edumazet@google.com; habetsm@gmail.com; ecree.xilinx@gmail.com
> Subject: Re: [PATCH net-next 3/7] sfc: add mport lookup based on driver's mport
> data
> 
> 
> On 1/19/23 23:57, Jacob Keller wrote:
> >
> > On 1/19/2023 3:31 AM, alejandro.lucero-palau@amd.com wrote:
> >> +int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id)
> >> +{
> >> +	struct ef100_nic_data *nic_data = efx->nic_data;
> >> +	struct efx_mae *mae = efx->mae;
> >> +	struct rhashtable_iter walk;
> >> +	struct mae_mport_desc *m;
> >> +	int rc = -ENOENT;
> >> +
> >> +	rhashtable_walk_enter(&mae->mports_ht, &walk);
> >> +	rhashtable_walk_start(&walk);
> >> +	while ((m = rhashtable_walk_next(&walk)) != NULL) {
> >> +		if (m->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC
> &&
> >> +		    m->interface_idx == nic_data->local_mae_intf &&
> >> +		    m->pf_idx == 0 &&
> >> +		    m->vf_idx == vf_idx) {
> >> +			*id = m->mport_id;
> >> +			rc = 0;
> >> +			break;
> >> +		}
> >> +	}
> >> +	rhashtable_walk_stop(&walk);
> >> +	rhashtable_walk_exit(&walk);
> > Curious if you have any reasoning for why you chose rhashtable vs
> > another structure (such as a simpler hash table of linked lists or xarray).
> 
> 
> The mports can appear and disappear (although it is not supported by the
> code yet nor by current firmware/hardware) so something resizable was
> needed for supporting this in the near future.
> 
> 

Right. Xarray feels like it would fit the bill too. I don't know what the advantage/disadvantage would be compared to rhashtable.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 4/7] sfc: add devlink port support for ef100
  2023-01-19 11:31 ` [PATCH net-next 4/7] sfc: add devlink port support for ef100 alejandro.lucero-palau
  2023-01-19 12:33   ` Jiri Pirko
  2023-01-19 13:37   ` kernel test robot
@ 2023-01-20 21:21   ` kernel test robot
  2 siblings, 0 replies; 52+ messages in thread
From: kernel test robot @ 2023-01-20 21:21 UTC (permalink / raw)
  To: alejandro.lucero-palau, netdev, linux-net-drivers
  Cc: llvm, oe-kbuild-all, davem, kuba, pabeni, edumazet, habetsm,
	ecree.xilinx, Alejandro Lucero

Hi,

Thank you for the patch! Yet something to improve:

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

url:    https://github.com/intel-lab-lkp/linux/commits/alejandro-lucero-palau-amd-com/sfc-add-devlink-support-for-ef100/20230119-193440
patch link:    https://lore.kernel.org/r/20230119113140.20208-5-alejandro.lucero-palau%40amd.com
patch subject: [PATCH net-next 4/7] sfc: add devlink port support for ef100
config: i386-randconfig-a015 (https://download.01.org/0day-ci/archive/20230121/202301210559.Gj6wK4CN-lkp@intel.com/config)
compiler: clang version 14.0.6 (https://github.com/llvm/llvm-project f28c006a5895fc0e329fe15fead81e37457cb1d1)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/5b06b1ae6605af55ed8127878054f8d69046b83c
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review alejandro-lucero-palau-amd-com/sfc-add-devlink-support-for-ef100/20230119-193440
        git checkout 5b06b1ae6605af55ed8127878054f8d69046b83c
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>, old ones prefixed by <<):

ERROR: modpost: "efx_ef100_fini_reps" [drivers/net/ethernet/sfc/sfc.ko] undefined!
ERROR: modpost: "efx_fini_mae" [drivers/net/ethernet/sfc/sfc.ko] undefined!
>> ERROR: modpost: "efx_mae_lookup_mport" [drivers/net/ethernet/sfc/sfc.ko] undefined!
>> ERROR: modpost: "efx_mae_get_mport" [drivers/net/ethernet/sfc/sfc.ko] undefined!
>> ERROR: modpost: "ef100_mport_on_local_intf" [drivers/net/ethernet/sfc/sfc.ko] undefined!

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-20 12:48         ` Lucero Palau, Alejandro
@ 2023-01-22 16:36           ` Lucero Palau, Alejandro
  2023-01-23  8:38             ` Jiri Pirko
  0 siblings, 1 reply; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-22 16:36 UTC (permalink / raw)
  To: Lucero Palau, Alejandro, Jiri Pirko
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx


On 1/20/23 12:48, Lucero Palau, Alejandro wrote:
> On 1/20/23 11:08, Jiri Pirko wrote:
>> Thu, Jan 19, 2023 at 04:09:27PM CET, alejandro.lucero-palau@amd.com wrote:
>>> On 1/19/23 12:37, Jiri Pirko wrote:
>>>> Thu, Jan 19, 2023 at 12:31:39PM CET, alejandro.lucero-palau@amd.com wrote:
>>>>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>>>
>>>>> Using the builtin client handle id infrastructure, this patch adds
>>>>> support for obtaining the mac address linked to mports in ef100. This
>>>>> implies to execute an MCDI command for getting the data from the
>>>>> firmware for each devlink port.
>>>>>
>>>>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>>> ---
>>>>> drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
>>>>> drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
>>>>> drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
>>>>> drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
>>>>> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
>>>>> 5 files changed, 81 insertions(+)
>>>>>
>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>>>>> index f4e913593f2b..4400ce622228 100644
>>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>>>>> @@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
>>>>> 	return rc;
>>>>> }
>>>>>
>>>>> +/* MCDI commands are related to the same device issuing them. This function
>>>>> + * allows to do an MCDI command on behalf of another device, mainly PFs setting
>>>>> + * things for VFs.
>>>>> + */
>>>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
>>>>> +{
>>>>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
>>>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
>>>>> +	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
>>>>> +	size_t outlen;
>>>>> +	int rc;
>>>>> +
>>>>> +	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
>>>>> +		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
>>>>> +	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
>>>>> +		       pciefn_flat);
>>>>> +
>>>>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
>>>>> +			  outbuf, sizeof(outbuf), &outlen);
>>>>> +	if (rc)
>>>>> +		return rc;
>>>>> +	if (outlen < sizeof(outbuf))
>>>>> +		return -EIO;
>>>>> +	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>> int ef100_probe_netdev_pf(struct efx_nic *efx)
>>>>> {
>>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>>>>> index e59044072333..f1ed481c1260 100644
>>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.h
>>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.h
>>>>> @@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
>>>>>
>>>>> int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
>>>>> 			  int client_handle, bool empty_ok);
>>>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
>>>>> #endif	/* EFX_EF100_NIC_H */
>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>>>>> index ff0c8da61919..974c9ff901a0 100644
>>>>> --- a/drivers/net/ethernet/sfc/ef100_rep.c
>>>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.c
>>>>> @@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>>>> 		     mport_desc->interface_idx == nic_data->local_mae_intf;
>>>>> }
>>>>>
>>>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
>>>>> +{
>>>>> +	bool pcie_func;
>>>>> +
>>>>> +	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>>>>> +	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
>>>>> +}
>>>>> +
>>>>> void efx_ef100_init_reps(struct efx_nic *efx)
>>>>> {
>>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>>>>> index 9cca41614982..74853ccbc937 100644
>>>>> --- a/drivers/net/ethernet/sfc/ef100_rep.h
>>>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.h
>>>>> @@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
>>>>> struct mae_mport_desc;
>>>>> bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>>>> 			       struct mae_mport_desc *mport_desc);
>>>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
>>>>> #endif /* EF100_REP_H */
>>>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>>>>> index bb19d3ad7ffd..2a57c4f6d2b2 100644
>>>>> --- a/drivers/net/ethernet/sfc/efx_devlink.c
>>>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>>>>> @@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
>>>>> 	return err;
>>>>> }
>>>>>
>>>>> +static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>>>>> +				     int *hw_addr_len,
>>>>> +				     struct netlink_ext_ack *extack)
>>>>> +{
>>>>> +	struct efx_devlink *devlink = devlink_priv(port->devlink);
>>>>> +	struct mae_mport_desc *mport_desc;
>>>>> +	efx_qword_t pciefn;
>>>>> +	u32 client_id;
>>>>> +	int rc = 0;
>>>>> +
>>>>> +	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
>>>> I may be missing something, where do you fail with -EOPNOTSUPP
>>>> in case this is called for PHYSICAL port ?
>>>>
>>> We do not create a devlink port for the physical port.
>> Well, you do:
>>
>> +       switch (mport->mport_type) {
>> +       case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
>> +               attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
>>
>>                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Right.
>
> I was relying on devlink-port output which does not show the physical
> port in my machine and completely forgot about it.
>
> I'm a bit confused at this point. Let me look at this further.
>
The reason devlink show/info does not report the PHYSICAL port is 
simple: current code does not create a devlink port for such mport.

I say current code because in my first implementation (not upstreamed) I 
just created devlink ports when the mports where enumerated, what turned 
out to be a bit complicated for dealing with VFs creation/destruction, 
and after looking at how other drivers do this, just before the related 
netdev is registered, I went for that same approach. That leaves no 
option for the physical mport registered.

I could add that creation at PF devlink port creation, if we consider 
this a necessity. I know the ideal devlink support in our driver should 
likely be more devlink design compliant, but it is also true drivers 
should make use of it as decided for fulfilling their necessities as 
long as it does not create confusion to users. Our current devlink 
necessity is for dealing with setting VFs mac address as required during 
previous representors patchset review:

https://lore.kernel.org/netdev/20220728092008.2117846e@kernel.org/

Do you see a problem not creating such a devlink port by now?

>> +               attrs.phys.port_number = mport->port_idx;
>> +               devlink_port_attrs_set(dl_port, &attrs);
>> +               break;
>> +       case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
>> +               if (mport->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL) {
>> +                       devlink_port_attrs_pci_vf_set(dl_port, 0, mport->pf_idx,
>> +                                                     mport->vf_idx,
>> +                                                     external);
>> +               } else {
>> +                       devlink_port_attrs_pci_pf_set(dl_port, 0, mport->pf_idx,
>> +                                                     external);
>> +               }
>> +               break;
>>
>>
>>
>>
>>> I'm aware this is not "fully compliant" with devlink design idea, just
>>> trying to use it for our current urgent necessities by now.
>>>
>>> Do you think this could be a problem?
>> If you create port flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL and it is not
>> uplink, it is a problem :)
>>
>>
>>
>>>>> +	if (!mport_desc)
>>>>> +		return -EINVAL;
>>>>> +
>>>>> +	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
>>>>> +		goto out;
>>>>> +
>>>>> +	if (ef100_mport_is_vf(mport_desc))
>>>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>>>> +				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>>>>> +				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>>>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>>>> +	else
>>>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>>>> +				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
>>>>> +				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
>>>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>>>> +
>>>>> +	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>>>>> +	if (rc) {
>>>>> +		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>>>>> +			  "Failed to get client ID for port index %u, rc %d\n",
>>>>> +			  port->index, rc);
>>>>> +		return rc;
>>>>> +	}
>>>>> +
>>>>> +	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
>>>>> +out:
>>>>> +	*hw_addr_len = ETH_ALEN;
>>>>> +
>>>>> +	return rc;
>>>>> +}
>>>>> +
>>>>> static int efx_devlink_info_get(struct devlink *devlink,
>>>>> 				struct devlink_info_req *req,
>>>>> 				struct netlink_ext_ack *extack)
>>>>> @@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
>>>>>
>>>>> static const struct devlink_ops sfc_devlink_ops = {
>>>>> 	.info_get			= efx_devlink_info_get,
>>>>> +	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
>>>>> };
>>>>>
>>>>> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>>>>> -- 
>>>>> 2.17.1
>>>>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-20 11:05       ` Jiri Pirko
@ 2023-01-22 16:41         ` Lucero Palau, Alejandro
  0 siblings, 0 replies; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-22 16:41 UTC (permalink / raw)
  To: Jiri Pirko, Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, ecree.xilinx


On 1/20/23 11:05, Jiri Pirko wrote:
> Thu, Jan 19, 2023 at 03:59:40PM CET, alejandro.lucero-palau@amd.com wrote:
>> On 1/19/23 12:25, Jiri Pirko wrote:
>>> Thu, Jan 19, 2023 at 12:31:39PM CET, alejandro.lucero-palau@amd.com wrote:
>>>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>>
>>>> Using the builtin client handle id infrastructure, this patch adds
>>>> support for obtaining the mac address linked to mports in ef100. This
>>>> implies to execute an MCDI command for getting the data from the
>>>> firmware for each devlink port.
>>>>
>>>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>> ---
>>>> drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
>>>> drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
>>>> drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
>>>> drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
>>>> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
>>>> 5 files changed, 81 insertions(+)
>>>>
>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>>>> index f4e913593f2b..4400ce622228 100644
>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>>>> @@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
>>>> 	return rc;
>>>> }
>>>>
>>>> +/* MCDI commands are related to the same device issuing them. This function
>>>> + * allows to do an MCDI command on behalf of another device, mainly PFs setting
>>>> + * things for VFs.
>>>> + */
>>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
>>>> +{
>>>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
>>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
>>>> +	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
>>>> +	size_t outlen;
>>>> +	int rc;
>>>> +
>>>> +	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
>>>> +		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
>>>> +	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
>>>> +		       pciefn_flat);
>>>> +
>>>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
>>>> +			  outbuf, sizeof(outbuf), &outlen);
>>>> +	if (rc)
>>>> +		return rc;
>>>> +	if (outlen < sizeof(outbuf))
>>>> +		return -EIO;
>>>> +	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
>>>> +	return 0;
>>>> +}
>>>> +
>>>> int ef100_probe_netdev_pf(struct efx_nic *efx)
>>>> {
>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>>>> index e59044072333..f1ed481c1260 100644
>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.h
>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.h
>>>> @@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
>>>>
>>>> int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
>>>> 			  int client_handle, bool empty_ok);
>>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
>>>> #endif	/* EFX_EF100_NIC_H */
>>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>>>> index ff0c8da61919..974c9ff901a0 100644
>>>> --- a/drivers/net/ethernet/sfc/ef100_rep.c
>>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.c
>>>> @@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>>> 		     mport_desc->interface_idx == nic_data->local_mae_intf;
>>>> }
>>>>
>>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
>>>> +{
>>>> +	bool pcie_func;
>>>> +
>>>> +	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>>>> +	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
>>>> +}
>>>> +
>>>> void efx_ef100_init_reps(struct efx_nic *efx)
>>>> {
>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>>>> index 9cca41614982..74853ccbc937 100644
>>>> --- a/drivers/net/ethernet/sfc/ef100_rep.h
>>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.h
>>>> @@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
>>>> struct mae_mport_desc;
>>>> bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>>> 			       struct mae_mport_desc *mport_desc);
>>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
>>>> #endif /* EF100_REP_H */
>>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>>>> index bb19d3ad7ffd..2a57c4f6d2b2 100644
>>>> --- a/drivers/net/ethernet/sfc/efx_devlink.c
>>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>>>> @@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
>>>> 	return err;
>>>> }
>>>>
>>>> +static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>>>> +				     int *hw_addr_len,
>>>> +				     struct netlink_ext_ack *extack)
>>>> +{
>>>> +	struct efx_devlink *devlink = devlink_priv(port->devlink);
>>>> +	struct mae_mport_desc *mport_desc;
>>>> +	efx_qword_t pciefn;
>>>> +	u32 client_id;
>>>> +	int rc = 0;
>>>> +
>>>> +	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
>>> Dont use port->index, never. It's devlink internal. You have port
>>> pointer passed here. Usually, what drivers do is to embed
>>> the struct devlink_port in the driver port struct. Then you do just
>>> simple container of to get it here. Mlxsw example:
>> I do not understand this. Port index is set by the driver not by the
>> devlink interface implementation.
>>
>> Why can I not use it?
> Well you can, but things could be done much nicer, when you use
> devlink_port pointer. Also, better not to access devlink_port struct
> internals, driver should never need it.
>

I think adding a new field in mport struct for this is not hard, so I'll 
follow your advice and change it in the next patchset version.

Thanks.

>>> static void *__dl_port(struct devlink_port *devlink_port)
>>> {
>>>           return container_of(devlink_port, struct mlxsw_core_port, devlink_port);
>>> }
>>>
>>> static int mlxsw_devlink_port_split(struct devlink *devlink,
>>>                                       struct devlink_port *port,
>>>                                       unsigned int count,
>>>                                       struct netlink_ext_ack *extack)
>>> {
>>>           struct mlxsw_core_port *mlxsw_core_port = __dl_port(port);
>>> ...
>>>
>>>
>>>
>>>> +	if (!mport_desc)
>>> Tell the user what's wrong, extack is here for that.
>>>
>> I'll do.
>>>> +		return -EINVAL;
>>>> +
>>>> +	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
>>>> +		goto out;
>>>> +
>>>> +	if (ef100_mport_is_vf(mport_desc))
>>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>>> +				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>>>> +				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>>> +	else
>>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>>> +				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
>>>> +				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
>>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>>> +
>>>> +	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>>>> +	if (rc) {
>>>> +		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>>>> +			  "Failed to get client ID for port index %u, rc %d\n",
>>>> +			  port->index, rc);
>>> Don't write to dmesg, use extack msg instead.
>>
>> I'll do.
>>
>> Thanks
>>
>>>> +		return rc;
>>>> +	}
>>>> +
>>>> +	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
>>> Again, extack would be nice here if (rc)
>>>
>> Again, I'll do.
>>>> +out:
>>>> +	*hw_addr_len = ETH_ALEN;
>>>> +
>>>> +	return rc;
>>>> +}
>>>> +
>>>> static int efx_devlink_info_get(struct devlink *devlink,
>>>> 				struct devlink_info_req *req,
>>>> 				struct netlink_ext_ack *extack)
>>>> @@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
>>>>
>>>> static const struct devlink_ops sfc_devlink_ops = {
>>>> 	.info_get			= efx_devlink_info_get,
>>>> +	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
>>>> };
>>>>
>>>> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>>>> -- 
>>>> 2.17.1
>>>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-22 16:36           ` Lucero Palau, Alejandro
@ 2023-01-23  8:38             ` Jiri Pirko
  2023-01-23  9:45               ` Lucero Palau, Alejandro
  0 siblings, 1 reply; 52+ messages in thread
From: Jiri Pirko @ 2023-01-23  8:38 UTC (permalink / raw)
  To: Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx

Sun, Jan 22, 2023 at 05:36:14PM CET, alejandro.lucero-palau@amd.com wrote:
>
>On 1/20/23 12:48, Lucero Palau, Alejandro wrote:
>> On 1/20/23 11:08, Jiri Pirko wrote:
>>> Thu, Jan 19, 2023 at 04:09:27PM CET, alejandro.lucero-palau@amd.com wrote:
>>>> On 1/19/23 12:37, Jiri Pirko wrote:
>>>>> Thu, Jan 19, 2023 at 12:31:39PM CET, alejandro.lucero-palau@amd.com wrote:
>>>>>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>>>>
>>>>>> Using the builtin client handle id infrastructure, this patch adds
>>>>>> support for obtaining the mac address linked to mports in ef100. This
>>>>>> implies to execute an MCDI command for getting the data from the
>>>>>> firmware for each devlink port.
>>>>>>
>>>>>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>>>> ---
>>>>>> drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
>>>>>> drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
>>>>>> drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
>>>>>> drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
>>>>>> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
>>>>>> 5 files changed, 81 insertions(+)
>>>>>>
>>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>>>>>> index f4e913593f2b..4400ce622228 100644
>>>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>>>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>>>>>> @@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
>>>>>> 	return rc;
>>>>>> }
>>>>>>
>>>>>> +/* MCDI commands are related to the same device issuing them. This function
>>>>>> + * allows to do an MCDI command on behalf of another device, mainly PFs setting
>>>>>> + * things for VFs.
>>>>>> + */
>>>>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
>>>>>> +{
>>>>>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
>>>>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
>>>>>> +	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
>>>>>> +	size_t outlen;
>>>>>> +	int rc;
>>>>>> +
>>>>>> +	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
>>>>>> +		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
>>>>>> +	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
>>>>>> +		       pciefn_flat);
>>>>>> +
>>>>>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
>>>>>> +			  outbuf, sizeof(outbuf), &outlen);
>>>>>> +	if (rc)
>>>>>> +		return rc;
>>>>>> +	if (outlen < sizeof(outbuf))
>>>>>> +		return -EIO;
>>>>>> +	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
>>>>>> +	return 0;
>>>>>> +}
>>>>>> +
>>>>>> int ef100_probe_netdev_pf(struct efx_nic *efx)
>>>>>> {
>>>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>>>>>> index e59044072333..f1ed481c1260 100644
>>>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.h
>>>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.h
>>>>>> @@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
>>>>>>
>>>>>> int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
>>>>>> 			  int client_handle, bool empty_ok);
>>>>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
>>>>>> #endif	/* EFX_EF100_NIC_H */
>>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>>>>>> index ff0c8da61919..974c9ff901a0 100644
>>>>>> --- a/drivers/net/ethernet/sfc/ef100_rep.c
>>>>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.c
>>>>>> @@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>>>>> 		     mport_desc->interface_idx == nic_data->local_mae_intf;
>>>>>> }
>>>>>>
>>>>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
>>>>>> +{
>>>>>> +	bool pcie_func;
>>>>>> +
>>>>>> +	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>>>>>> +	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
>>>>>> +}
>>>>>> +
>>>>>> void efx_ef100_init_reps(struct efx_nic *efx)
>>>>>> {
>>>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>>>>>> index 9cca41614982..74853ccbc937 100644
>>>>>> --- a/drivers/net/ethernet/sfc/ef100_rep.h
>>>>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.h
>>>>>> @@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
>>>>>> struct mae_mport_desc;
>>>>>> bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>>>>> 			       struct mae_mport_desc *mport_desc);
>>>>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
>>>>>> #endif /* EF100_REP_H */
>>>>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>>>>>> index bb19d3ad7ffd..2a57c4f6d2b2 100644
>>>>>> --- a/drivers/net/ethernet/sfc/efx_devlink.c
>>>>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>>>>>> @@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
>>>>>> 	return err;
>>>>>> }
>>>>>>
>>>>>> +static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>>>>>> +				     int *hw_addr_len,
>>>>>> +				     struct netlink_ext_ack *extack)
>>>>>> +{
>>>>>> +	struct efx_devlink *devlink = devlink_priv(port->devlink);
>>>>>> +	struct mae_mport_desc *mport_desc;
>>>>>> +	efx_qword_t pciefn;
>>>>>> +	u32 client_id;
>>>>>> +	int rc = 0;
>>>>>> +
>>>>>> +	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
>>>>> I may be missing something, where do you fail with -EOPNOTSUPP
>>>>> in case this is called for PHYSICAL port ?
>>>>>
>>>> We do not create a devlink port for the physical port.
>>> Well, you do:
>>>
>>> +       switch (mport->mport_type) {
>>> +       case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
>>> +               attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
>>>
>>>                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> Right.
>>
>> I was relying on devlink-port output which does not show the physical
>> port in my machine and completely forgot about it.
>>
>> I'm a bit confused at this point. Let me look at this further.
>>
>The reason devlink show/info does not report the PHYSICAL port is 
>simple: current code does not create a devlink port for such mport.
>
>I say current code because in my first implementation (not upstreamed) I 
>just created devlink ports when the mports where enumerated, what turned 
>out to be a bit complicated for dealing with VFs creation/destruction, 
>and after looking at how other drivers do this, just before the related 
>netdev is registered, I went for that same approach. That leaves no 
>option for the physical mport registered.
>
>I could add that creation at PF devlink port creation, if we consider 
>this a necessity. I know the ideal devlink support in our driver should 
>likely be more devlink design compliant, but it is also true drivers 
>should make use of it as decided for fulfilling their necessities as 
>long as it does not create confusion to users. Our current devlink 
>necessity is for dealing with setting VFs mac address as required during 
>previous representors patchset review:
>
>https://lore.kernel.org/netdev/20220728092008.2117846e@kernel.org/
>
>Do you see a problem not creating such a devlink port by now?

You don't have to create it. But loose the code setting PHYSICAL
flavour.



>
>>> +               attrs.phys.port_number = mport->port_idx;
>>> +               devlink_port_attrs_set(dl_port, &attrs);
>>> +               break;
>>> +       case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
>>> +               if (mport->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL) {
>>> +                       devlink_port_attrs_pci_vf_set(dl_port, 0, mport->pf_idx,
>>> +                                                     mport->vf_idx,
>>> +                                                     external);
>>> +               } else {
>>> +                       devlink_port_attrs_pci_pf_set(dl_port, 0, mport->pf_idx,
>>> +                                                     external);
>>> +               }
>>> +               break;
>>>
>>>
>>>
>>>
>>>> I'm aware this is not "fully compliant" with devlink design idea, just
>>>> trying to use it for our current urgent necessities by now.
>>>>
>>>> Do you think this could be a problem?
>>> If you create port flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL and it is not
>>> uplink, it is a problem :)
>>>
>>>
>>>
>>>>>> +	if (!mport_desc)
>>>>>> +		return -EINVAL;
>>>>>> +
>>>>>> +	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
>>>>>> +		goto out;
>>>>>> +
>>>>>> +	if (ef100_mport_is_vf(mport_desc))
>>>>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>>>>> +				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>>>>>> +				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>>>>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>>>>> +	else
>>>>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>>>>> +				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
>>>>>> +				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
>>>>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>>>>> +
>>>>>> +	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>>>>>> +	if (rc) {
>>>>>> +		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>>>>>> +			  "Failed to get client ID for port index %u, rc %d\n",
>>>>>> +			  port->index, rc);
>>>>>> +		return rc;
>>>>>> +	}
>>>>>> +
>>>>>> +	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
>>>>>> +out:
>>>>>> +	*hw_addr_len = ETH_ALEN;
>>>>>> +
>>>>>> +	return rc;
>>>>>> +}
>>>>>> +
>>>>>> static int efx_devlink_info_get(struct devlink *devlink,
>>>>>> 				struct devlink_info_req *req,
>>>>>> 				struct netlink_ext_ack *extack)
>>>>>> @@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
>>>>>>
>>>>>> static const struct devlink_ops sfc_devlink_ops = {
>>>>>> 	.info_get			= efx_devlink_info_get,
>>>>>> +	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
>>>>>> };
>>>>>>
>>>>>> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>>>>>> -- 
>>>>>> 2.17.1
>>>>>>
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-23  8:38             ` Jiri Pirko
@ 2023-01-23  9:45               ` Lucero Palau, Alejandro
  2023-01-23 10:18                 ` Jiri Pirko
  0 siblings, 1 reply; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-23  9:45 UTC (permalink / raw)
  To: Jiri Pirko, Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx


On 1/23/23 08:38, Jiri Pirko wrote:
> Sun, Jan 22, 2023 at 05:36:14PM CET, alejandro.lucero-palau@amd.com wrote:
>> On 1/20/23 12:48, Lucero Palau, Alejandro wrote:
>>> On 1/20/23 11:08, Jiri Pirko wrote:
>>>> Thu, Jan 19, 2023 at 04:09:27PM CET, alejandro.lucero-palau@amd.com wrote:
>>>>> On 1/19/23 12:37, Jiri Pirko wrote:
>>>>>> Thu, Jan 19, 2023 at 12:31:39PM CET, alejandro.lucero-palau@amd.com wrote:
>>>>>>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>>>>>
>>>>>>> Using the builtin client handle id infrastructure, this patch adds
>>>>>>> support for obtaining the mac address linked to mports in ef100. This
>>>>>>> implies to execute an MCDI command for getting the data from the
>>>>>>> firmware for each devlink port.
>>>>>>>
>>>>>>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>>>>> ---
>>>>>>> drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
>>>>>>> drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
>>>>>>> drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
>>>>>>> drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
>>>>>>> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
>>>>>>> 5 files changed, 81 insertions(+)
>>>>>>>
>>>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>>>>>>> index f4e913593f2b..4400ce622228 100644
>>>>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>>>>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>>>>>>> @@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
>>>>>>> 	return rc;
>>>>>>> }
>>>>>>>
>>>>>>> +/* MCDI commands are related to the same device issuing them. This function
>>>>>>> + * allows to do an MCDI command on behalf of another device, mainly PFs setting
>>>>>>> + * things for VFs.
>>>>>>> + */
>>>>>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
>>>>>>> +{
>>>>>>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
>>>>>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
>>>>>>> +	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
>>>>>>> +	size_t outlen;
>>>>>>> +	int rc;
>>>>>>> +
>>>>>>> +	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
>>>>>>> +		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
>>>>>>> +	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
>>>>>>> +		       pciefn_flat);
>>>>>>> +
>>>>>>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
>>>>>>> +			  outbuf, sizeof(outbuf), &outlen);
>>>>>>> +	if (rc)
>>>>>>> +		return rc;
>>>>>>> +	if (outlen < sizeof(outbuf))
>>>>>>> +		return -EIO;
>>>>>>> +	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
>>>>>>> +	return 0;
>>>>>>> +}
>>>>>>> +
>>>>>>> int ef100_probe_netdev_pf(struct efx_nic *efx)
>>>>>>> {
>>>>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>>>>>>> index e59044072333..f1ed481c1260 100644
>>>>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.h
>>>>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.h
>>>>>>> @@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
>>>>>>>
>>>>>>> int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
>>>>>>> 			  int client_handle, bool empty_ok);
>>>>>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
>>>>>>> #endif	/* EFX_EF100_NIC_H */
>>>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>>>>>>> index ff0c8da61919..974c9ff901a0 100644
>>>>>>> --- a/drivers/net/ethernet/sfc/ef100_rep.c
>>>>>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.c
>>>>>>> @@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>>>>>> 		     mport_desc->interface_idx == nic_data->local_mae_intf;
>>>>>>> }
>>>>>>>
>>>>>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
>>>>>>> +{
>>>>>>> +	bool pcie_func;
>>>>>>> +
>>>>>>> +	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>>>>>>> +	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
>>>>>>> +}
>>>>>>> +
>>>>>>> void efx_ef100_init_reps(struct efx_nic *efx)
>>>>>>> {
>>>>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>>>>>>> index 9cca41614982..74853ccbc937 100644
>>>>>>> --- a/drivers/net/ethernet/sfc/ef100_rep.h
>>>>>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.h
>>>>>>> @@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
>>>>>>> struct mae_mport_desc;
>>>>>>> bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>>>>>> 			       struct mae_mport_desc *mport_desc);
>>>>>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
>>>>>>> #endif /* EF100_REP_H */
>>>>>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>>>>>>> index bb19d3ad7ffd..2a57c4f6d2b2 100644
>>>>>>> --- a/drivers/net/ethernet/sfc/efx_devlink.c
>>>>>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>>>>>>> @@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
>>>>>>> 	return err;
>>>>>>> }
>>>>>>>
>>>>>>> +static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>>>>>>> +				     int *hw_addr_len,
>>>>>>> +				     struct netlink_ext_ack *extack)
>>>>>>> +{
>>>>>>> +	struct efx_devlink *devlink = devlink_priv(port->devlink);
>>>>>>> +	struct mae_mport_desc *mport_desc;
>>>>>>> +	efx_qword_t pciefn;
>>>>>>> +	u32 client_id;
>>>>>>> +	int rc = 0;
>>>>>>> +
>>>>>>> +	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
>>>>>> I may be missing something, where do you fail with -EOPNOTSUPP
>>>>>> in case this is called for PHYSICAL port ?
>>>>>>
>>>>> We do not create a devlink port for the physical port.
>>>> Well, you do:
>>>>
>>>> +       switch (mport->mport_type) {
>>>> +       case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
>>>> +               attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
>>>>
>>>>                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> Right.
>>>
>>> I was relying on devlink-port output which does not show the physical
>>> port in my machine and completely forgot about it.
>>>
>>> I'm a bit confused at this point. Let me look at this further.
>>>
>> The reason devlink show/info does not report the PHYSICAL port is
>> simple: current code does not create a devlink port for such mport.
>>
>> I say current code because in my first implementation (not upstreamed) I
>> just created devlink ports when the mports where enumerated, what turned
>> out to be a bit complicated for dealing with VFs creation/destruction,
>> and after looking at how other drivers do this, just before the related
>> netdev is registered, I went for that same approach. That leaves no
>> option for the physical mport registered.
>>
>> I could add that creation at PF devlink port creation, if we consider
>> this a necessity. I know the ideal devlink support in our driver should
>> likely be more devlink design compliant, but it is also true drivers
>> should make use of it as decided for fulfilling their necessities as
>> long as it does not create confusion to users. Our current devlink
>> necessity is for dealing with setting VFs mac address as required during
>> previous representors patchset review:
>>
>> https://lore.kernel.org/netdev/20220728092008.2117846e@kernel.org/
>>
>> Do you see a problem not creating such a devlink port by now?
> You don't have to create it. But loose the code setting PHYSICAL
> flavour.
>
I'll do so adding a comment discarding the physical port creation.


Thanks.

>
>>>> +               attrs.phys.port_number = mport->port_idx;
>>>> +               devlink_port_attrs_set(dl_port, &attrs);
>>>> +               break;
>>>> +       case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
>>>> +               if (mport->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL) {
>>>> +                       devlink_port_attrs_pci_vf_set(dl_port, 0, mport->pf_idx,
>>>> +                                                     mport->vf_idx,
>>>> +                                                     external);
>>>> +               } else {
>>>> +                       devlink_port_attrs_pci_pf_set(dl_port, 0, mport->pf_idx,
>>>> +                                                     external);
>>>> +               }
>>>> +               break;
>>>>
>>>>
>>>>
>>>>
>>>>> I'm aware this is not "fully compliant" with devlink design idea, just
>>>>> trying to use it for our current urgent necessities by now.
>>>>>
>>>>> Do you think this could be a problem?
>>>> If you create port flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL and it is not
>>>> uplink, it is a problem :)
>>>>
>>>>
>>>>
>>>>>>> +	if (!mport_desc)
>>>>>>> +		return -EINVAL;
>>>>>>> +
>>>>>>> +	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
>>>>>>> +		goto out;
>>>>>>> +
>>>>>>> +	if (ef100_mport_is_vf(mport_desc))
>>>>>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>>>>>> +				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>>>>>>> +				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>>>>>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>>>>>> +	else
>>>>>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>>>>>> +				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
>>>>>>> +				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
>>>>>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>>>>>> +
>>>>>>> +	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>>>>>>> +	if (rc) {
>>>>>>> +		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>>>>>>> +			  "Failed to get client ID for port index %u, rc %d\n",
>>>>>>> +			  port->index, rc);
>>>>>>> +		return rc;
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
>>>>>>> +out:
>>>>>>> +	*hw_addr_len = ETH_ALEN;
>>>>>>> +
>>>>>>> +	return rc;
>>>>>>> +}
>>>>>>> +
>>>>>>> static int efx_devlink_info_get(struct devlink *devlink,
>>>>>>> 				struct devlink_info_req *req,
>>>>>>> 				struct netlink_ext_ack *extack)
>>>>>>> @@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
>>>>>>>
>>>>>>> static const struct devlink_ops sfc_devlink_ops = {
>>>>>>> 	.info_get			= efx_devlink_info_get,
>>>>>>> +	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
>>>>>>> };
>>>>>>>
>>>>>>> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>>>>>>> -- 
>>>>>>> 2.17.1
>>>>>>>


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100
  2023-01-23  9:45               ` Lucero Palau, Alejandro
@ 2023-01-23 10:18                 ` Jiri Pirko
  0 siblings, 0 replies; 52+ messages in thread
From: Jiri Pirko @ 2023-01-23 10:18 UTC (permalink / raw)
  To: Lucero Palau, Alejandro
  Cc: netdev, linux-net-drivers (AMD-Xilinx),
	davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx

Mon, Jan 23, 2023 at 10:45:47AM CET, alejandro.lucero-palau@amd.com wrote:
>
>On 1/23/23 08:38, Jiri Pirko wrote:
>> Sun, Jan 22, 2023 at 05:36:14PM CET, alejandro.lucero-palau@amd.com wrote:
>>> On 1/20/23 12:48, Lucero Palau, Alejandro wrote:
>>>> On 1/20/23 11:08, Jiri Pirko wrote:
>>>>> Thu, Jan 19, 2023 at 04:09:27PM CET, alejandro.lucero-palau@amd.com wrote:
>>>>>> On 1/19/23 12:37, Jiri Pirko wrote:
>>>>>>> Thu, Jan 19, 2023 at 12:31:39PM CET, alejandro.lucero-palau@amd.com wrote:
>>>>>>>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>>>>>>
>>>>>>>> Using the builtin client handle id infrastructure, this patch adds
>>>>>>>> support for obtaining the mac address linked to mports in ef100. This
>>>>>>>> implies to execute an MCDI command for getting the data from the
>>>>>>>> firmware for each devlink port.
>>>>>>>>
>>>>>>>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>>>>>>> ---
>>>>>>>> drivers/net/ethernet/sfc/ef100_nic.c   | 27 ++++++++++++++++
>>>>>>>> drivers/net/ethernet/sfc/ef100_nic.h   |  1 +
>>>>>>>> drivers/net/ethernet/sfc/ef100_rep.c   |  8 +++++
>>>>>>>> drivers/net/ethernet/sfc/ef100_rep.h   |  1 +
>>>>>>>> drivers/net/ethernet/sfc/efx_devlink.c | 44 ++++++++++++++++++++++++++
>>>>>>>> 5 files changed, 81 insertions(+)
>>>>>>>>
>>>>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>>>>>>>> index f4e913593f2b..4400ce622228 100644
>>>>>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>>>>>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>>>>>>>> @@ -1121,6 +1121,33 @@ static int ef100_probe_main(struct efx_nic *efx)
>>>>>>>> 	return rc;
>>>>>>>> }
>>>>>>>>
>>>>>>>> +/* MCDI commands are related to the same device issuing them. This function
>>>>>>>> + * allows to do an MCDI command on behalf of another device, mainly PFs setting
>>>>>>>> + * things for VFs.
>>>>>>>> + */
>>>>>>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id)
>>>>>>>> +{
>>>>>>>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CLIENT_HANDLE_OUT_LEN);
>>>>>>>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_CLIENT_HANDLE_IN_LEN);
>>>>>>>> +	u64 pciefn_flat = le64_to_cpu(pciefn.u64[0]);
>>>>>>>> +	size_t outlen;
>>>>>>>> +	int rc;
>>>>>>>> +
>>>>>>>> +	MCDI_SET_DWORD(inbuf, GET_CLIENT_HANDLE_IN_TYPE,
>>>>>>>> +		       MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC);
>>>>>>>> +	MCDI_SET_QWORD(inbuf, GET_CLIENT_HANDLE_IN_FUNC,
>>>>>>>> +		       pciefn_flat);
>>>>>>>> +
>>>>>>>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_CLIENT_HANDLE, inbuf, sizeof(inbuf),
>>>>>>>> +			  outbuf, sizeof(outbuf), &outlen);
>>>>>>>> +	if (rc)
>>>>>>>> +		return rc;
>>>>>>>> +	if (outlen < sizeof(outbuf))
>>>>>>>> +		return -EIO;
>>>>>>>> +	*id = MCDI_DWORD(outbuf, GET_CLIENT_HANDLE_OUT_HANDLE);
>>>>>>>> +	return 0;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> int ef100_probe_netdev_pf(struct efx_nic *efx)
>>>>>>>> {
>>>>>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.h b/drivers/net/ethernet/sfc/ef100_nic.h
>>>>>>>> index e59044072333..f1ed481c1260 100644
>>>>>>>> --- a/drivers/net/ethernet/sfc/ef100_nic.h
>>>>>>>> +++ b/drivers/net/ethernet/sfc/ef100_nic.h
>>>>>>>> @@ -94,4 +94,5 @@ int ef100_filter_table_probe(struct efx_nic *efx);
>>>>>>>>
>>>>>>>> int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address,
>>>>>>>> 			  int client_handle, bool empty_ok);
>>>>>>>> +int efx_ef100_lookup_client_id(struct efx_nic *efx, efx_qword_t pciefn, u32 *id);
>>>>>>>> #endif	/* EFX_EF100_NIC_H */
>>>>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.c b/drivers/net/ethernet/sfc/ef100_rep.c
>>>>>>>> index ff0c8da61919..974c9ff901a0 100644
>>>>>>>> --- a/drivers/net/ethernet/sfc/ef100_rep.c
>>>>>>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.c
>>>>>>>> @@ -362,6 +362,14 @@ bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>>>>>>> 		     mport_desc->interface_idx == nic_data->local_mae_intf;
>>>>>>>> }
>>>>>>>>
>>>>>>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc)
>>>>>>>> +{
>>>>>>>> +	bool pcie_func;
>>>>>>>> +
>>>>>>>> +	pcie_func = ef100_mport_is_pcie_vnic(mport_desc);
>>>>>>>> +	return pcie_func && (mport_desc->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL);
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> void efx_ef100_init_reps(struct efx_nic *efx)
>>>>>>>> {
>>>>>>>> 	struct ef100_nic_data *nic_data = efx->nic_data;
>>>>>>>> diff --git a/drivers/net/ethernet/sfc/ef100_rep.h b/drivers/net/ethernet/sfc/ef100_rep.h
>>>>>>>> index 9cca41614982..74853ccbc937 100644
>>>>>>>> --- a/drivers/net/ethernet/sfc/ef100_rep.h
>>>>>>>> +++ b/drivers/net/ethernet/sfc/ef100_rep.h
>>>>>>>> @@ -75,4 +75,5 @@ void efx_ef100_fini_reps(struct efx_nic *efx);
>>>>>>>> struct mae_mport_desc;
>>>>>>>> bool ef100_mport_on_local_intf(struct efx_nic *efx,
>>>>>>>> 			       struct mae_mport_desc *mport_desc);
>>>>>>>> +bool ef100_mport_is_vf(struct mae_mport_desc *mport_desc);
>>>>>>>> #endif /* EF100_REP_H */
>>>>>>>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>>>>>>>> index bb19d3ad7ffd..2a57c4f6d2b2 100644
>>>>>>>> --- a/drivers/net/ethernet/sfc/efx_devlink.c
>>>>>>>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>>>>>>>> @@ -429,6 +429,49 @@ static int efx_devlink_add_port(struct efx_nic *efx,
>>>>>>>> 	return err;
>>>>>>>> }
>>>>>>>>
>>>>>>>> +static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
>>>>>>>> +				     int *hw_addr_len,
>>>>>>>> +				     struct netlink_ext_ack *extack)
>>>>>>>> +{
>>>>>>>> +	struct efx_devlink *devlink = devlink_priv(port->devlink);
>>>>>>>> +	struct mae_mport_desc *mport_desc;
>>>>>>>> +	efx_qword_t pciefn;
>>>>>>>> +	u32 client_id;
>>>>>>>> +	int rc = 0;
>>>>>>>> +
>>>>>>>> +	mport_desc = efx_mae_get_mport(devlink->efx, port->index);
>>>>>>> I may be missing something, where do you fail with -EOPNOTSUPP
>>>>>>> in case this is called for PHYSICAL port ?
>>>>>>>
>>>>>> We do not create a devlink port for the physical port.
>>>>> Well, you do:
>>>>>
>>>>> +       switch (mport->mport_type) {
>>>>> +       case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
>>>>> +               attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
>>>>>
>>>>>                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>>> Right.
>>>>
>>>> I was relying on devlink-port output which does not show the physical
>>>> port in my machine and completely forgot about it.
>>>>
>>>> I'm a bit confused at this point. Let me look at this further.
>>>>
>>> The reason devlink show/info does not report the PHYSICAL port is
>>> simple: current code does not create a devlink port for such mport.
>>>
>>> I say current code because in my first implementation (not upstreamed) I
>>> just created devlink ports when the mports where enumerated, what turned
>>> out to be a bit complicated for dealing with VFs creation/destruction,
>>> and after looking at how other drivers do this, just before the related
>>> netdev is registered, I went for that same approach. That leaves no
>>> option for the physical mport registered.
>>>
>>> I could add that creation at PF devlink port creation, if we consider
>>> this a necessity. I know the ideal devlink support in our driver should
>>> likely be more devlink design compliant, but it is also true drivers
>>> should make use of it as decided for fulfilling their necessities as
>>> long as it does not create confusion to users. Our current devlink
>>> necessity is for dealing with setting VFs mac address as required during
>>> previous representors patchset review:
>>>
>>> https://lore.kernel.org/netdev/20220728092008.2117846e@kernel.org/
>>>
>>> Do you see a problem not creating such a devlink port by now?
>> You don't have to create it. But loose the code setting PHYSICAL
>> flavour.
>>
>I'll do so adding a comment discarding the physical port creation.

Yes, and remove the related code.

>
>
>Thanks.
>
>>
>>>>> +               attrs.phys.port_number = mport->port_idx;
>>>>> +               devlink_port_attrs_set(dl_port, &attrs);
>>>>> +               break;
>>>>> +       case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
>>>>> +               if (mport->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL) {
>>>>> +                       devlink_port_attrs_pci_vf_set(dl_port, 0, mport->pf_idx,
>>>>> +                                                     mport->vf_idx,
>>>>> +                                                     external);
>>>>> +               } else {
>>>>> +                       devlink_port_attrs_pci_pf_set(dl_port, 0, mport->pf_idx,
>>>>> +                                                     external);
>>>>> +               }
>>>>> +               break;
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> I'm aware this is not "fully compliant" with devlink design idea, just
>>>>>> trying to use it for our current urgent necessities by now.
>>>>>>
>>>>>> Do you think this could be a problem?
>>>>> If you create port flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL and it is not
>>>>> uplink, it is a problem :)
>>>>>
>>>>>
>>>>>
>>>>>>>> +	if (!mport_desc)
>>>>>>>> +		return -EINVAL;
>>>>>>>> +
>>>>>>>> +	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc))
>>>>>>>> +		goto out;
>>>>>>>> +
>>>>>>>> +	if (ef100_mport_is_vf(mport_desc))
>>>>>>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>>>>>>> +				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
>>>>>>>> +				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
>>>>>>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>>>>>>> +	else
>>>>>>>> +		EFX_POPULATE_QWORD_3(pciefn,
>>>>>>>> +				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
>>>>>>>> +				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
>>>>>>>> +				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
>>>>>>>> +
>>>>>>>> +	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
>>>>>>>> +	if (rc) {
>>>>>>>> +		netif_err(devlink->efx, drv, devlink->efx->net_dev,
>>>>>>>> +			  "Failed to get client ID for port index %u, rc %d\n",
>>>>>>>> +			  port->index, rc);
>>>>>>>> +		return rc;
>>>>>>>> +	}
>>>>>>>> +
>>>>>>>> +	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
>>>>>>>> +out:
>>>>>>>> +	*hw_addr_len = ETH_ALEN;
>>>>>>>> +
>>>>>>>> +	return rc;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> static int efx_devlink_info_get(struct devlink *devlink,
>>>>>>>> 				struct devlink_info_req *req,
>>>>>>>> 				struct netlink_ext_ack *extack)
>>>>>>>> @@ -442,6 +485,7 @@ static int efx_devlink_info_get(struct devlink *devlink,
>>>>>>>>
>>>>>>>> static const struct devlink_ops sfc_devlink_ops = {
>>>>>>>> 	.info_get			= efx_devlink_info_get,
>>>>>>>> +	.port_function_hw_addr_get	= efx_devlink_port_addr_get,
>>>>>>>> };
>>>>>>>>
>>>>>>>> static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
>>>>>>>> -- 
>>>>>>>> 2.17.1
>>>>>>>>
>

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-20 14:11     ` Lucero Palau, Alejandro
@ 2023-01-24  6:13       ` Edward Cree
  2023-01-24  7:31         ` Lucero Palau, Alejandro
  0 siblings, 1 reply; 52+ messages in thread
From: Edward Cree @ 2023-01-24  6:13 UTC (permalink / raw)
  To: Lucero Palau, Alejandro, Jacob Keller, netdev,
	linux-net-drivers (AMD-Xilinx)
  Cc: davem, kuba, pabeni, edumazet, habetsm

On 20/01/2023 14:11, Lucero Palau, Alejandro wrote:
> 
> On 1/19/23 23:40, Jacob Keller wrote:
>>
>> On 1/19/2023 3:31 AM, alejandro.lucero-palau@amd.com wrote:
>>> @@ -1124,6 +1125,10 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
>>>   		netif_warn(efx, probe, net_dev,
>>>   			   "Failed to probe base mport rc %d; representors will not function\n",
>>>   			   rc);
>>> +	} else {
>>> +		if (efx_probe_devlink(efx))
>>> +			netif_warn(efx, probe, net_dev,
>>> +				   "Failed to register devlink\n");
>>>   	}
>>>   
>> A bit of a weird construction here with the next step in an else block?
>> I guess this is being treated as an optional feature, and depends on
>> efx_ef100_get_base_mport succeeding?
> 
> Right. The mae ports initialization can fail but the driver can still 
> initialize the device with limited functionality.

But in that case, we probably should support e.g. devlink info, even
 though without the MAE ports we can't support devlink port.

^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-24  6:13       ` Edward Cree
@ 2023-01-24  7:31         ` Lucero Palau, Alejandro
  0 siblings, 0 replies; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-24  7:31 UTC (permalink / raw)
  To: Edward Cree, Lucero Palau, Alejandro, Jacob Keller, netdev,
	linux-net-drivers (AMD-Xilinx)
  Cc: davem, kuba, pabeni, edumazet


On 1/24/23 06:13, Edward Cree wrote:
> On 20/01/2023 14:11, Lucero Palau, Alejandro wrote:
>> On 1/19/23 23:40, Jacob Keller wrote:
>>> On 1/19/2023 3:31 AM, alejandro.lucero-palau@amd.com wrote:
>>>> @@ -1124,6 +1125,10 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
>>>>    		netif_warn(efx, probe, net_dev,
>>>>    			   "Failed to probe base mport rc %d; representors will not function\n",
>>>>    			   rc);
>>>> +	} else {
>>>> +		if (efx_probe_devlink(efx))
>>>> +			netif_warn(efx, probe, net_dev,
>>>> +				   "Failed to register devlink\n");
>>>>    	}
>>>>    
>>> A bit of a weird construction here with the next step in an else block?
>>> I guess this is being treated as an optional feature, and depends on
>>> efx_ef100_get_base_mport succeeding?
>> Right. The mae ports initialization can fail but the driver can still
>> initialize the device with limited functionality.
> But in that case, we probably should support e.g. devlink info, even
>   though without the MAE ports we can't support devlink port.


Good point.

I've already modified the code for avoiding the weirdness and this 
should not be hard to do.

Thanks



^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-19 23:40   ` Jacob Keller
  2023-01-20 14:11     ` Lucero Palau, Alejandro
@ 2023-01-24 11:05     ` Lucero Palau, Alejandro
  2023-01-24 22:12       ` Jacob Keller
  1 sibling, 1 reply; 52+ messages in thread
From: Lucero Palau, Alejandro @ 2023-01-24 11:05 UTC (permalink / raw)
  To: Jacob Keller, Lucero Palau, Alejandro, netdev,
	linux-net-drivers (AMD-Xilinx)
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx


On 1/19/23 23:40, Jacob Keller wrote:
>
> On 1/19/2023 3:31 AM, alejandro.lucero-palau@amd.com wrote:
>> From: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>>
>> Basic support for devlink info command.
>>
>> Signed-off-by: Alejandro Lucero <alejandro.lucero-palau@amd.com>
>> ---
>>   drivers/net/ethernet/sfc/Kconfig       |   1 +
>>   drivers/net/ethernet/sfc/Makefile      |   3 +-
>>   drivers/net/ethernet/sfc/ef100_nic.c   |   6 +
>>   drivers/net/ethernet/sfc/efx_devlink.c | 427 +++++++++++++++++++++++++
>>   drivers/net/ethernet/sfc/efx_devlink.h |  20 ++
>>   drivers/net/ethernet/sfc/mcdi.c        |  72 +++++
>>   drivers/net/ethernet/sfc/mcdi.h        |   3 +
>>   drivers/net/ethernet/sfc/net_driver.h  |   2 +
>>   8 files changed, 533 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/net/ethernet/sfc/efx_devlink.c
>>   create mode 100644 drivers/net/ethernet/sfc/efx_devlink.h
>>
>> diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
>> index 0950e6b0508f..4af36ba8906b 100644
>> --- a/drivers/net/ethernet/sfc/Kconfig
>> +++ b/drivers/net/ethernet/sfc/Kconfig
>> @@ -22,6 +22,7 @@ config SFC
>>   	depends on PTP_1588_CLOCK_OPTIONAL
>>   	select MDIO
>>   	select CRC32
>> +	select NET_DEVLINK
>>   	help
>>   	  This driver supports 10/40-gigabit Ethernet cards based on
>>   	  the Solarflare SFC9100-family controllers.
>> diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
>> index 712a48d00069..55b9c73cd8ef 100644
>> --- a/drivers/net/ethernet/sfc/Makefile
>> +++ b/drivers/net/ethernet/sfc/Makefile
>> @@ -6,7 +6,8 @@ sfc-y			+= efx.o efx_common.o efx_channels.o nic.o \
>>   			   mcdi.o mcdi_port.o mcdi_port_common.o \
>>   			   mcdi_functions.o mcdi_filters.o mcdi_mon.o \
>>   			   ef100.o ef100_nic.o ef100_netdev.o \
>> -			   ef100_ethtool.o ef100_rx.o ef100_tx.o
>> +			   ef100_ethtool.o ef100_rx.o ef100_tx.o \
>> +			   efx_devlink.o
>>   sfc-$(CONFIG_SFC_MTD)	+= mtd.o
>>   sfc-$(CONFIG_SFC_SRIOV)	+= sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
>>                              mae.o tc.o tc_bindings.o tc_counters.o
>> diff --git a/drivers/net/ethernet/sfc/ef100_nic.c b/drivers/net/ethernet/sfc/ef100_nic.c
>> index ad686c671ab8..14af8f314b83 100644
>> --- a/drivers/net/ethernet/sfc/ef100_nic.c
>> +++ b/drivers/net/ethernet/sfc/ef100_nic.c
>> @@ -27,6 +27,7 @@
>>   #include "tc.h"
>>   #include "mae.h"
>>   #include "rx_common.h"
>> +#include "efx_devlink.h"
>>   
>>   #define EF100_MAX_VIS 4096
>>   #define EF100_NUM_MCDI_BUFFERS	1
>> @@ -1124,6 +1125,10 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
>>   		netif_warn(efx, probe, net_dev,
>>   			   "Failed to probe base mport rc %d; representors will not function\n",
>>   			   rc);
>> +	} else {
>> +		if (efx_probe_devlink(efx))
>> +			netif_warn(efx, probe, net_dev,
>> +				   "Failed to register devlink\n");
>>   	}
>>   
> A bit of a weird construction here with the next step in an else block?
> I guess this is being treated as an optional feature, and depends on
> efx_ef100_get_base_mport succeeding?
>
> It reads a little awkward, but I can't think of a better way to arrange
> this unless another helper function was used to combine these two calls
> in order to avoid the extra indentation.
>
>
>>   	rc = efx_init_tc(efx);
>> @@ -1157,6 +1162,7 @@ void ef100_remove(struct efx_nic *efx)
>>   {
>>   	struct ef100_nic_data *nic_data = efx->nic_data;
>>   
>> +	efx_fini_devlink(efx);
>>   	efx_mcdi_detach(efx);
>>   	efx_mcdi_fini(efx);
>>   	if (nic_data)
>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.c b/drivers/net/ethernet/sfc/efx_devlink.c
>> new file mode 100644
>> index 000000000000..c506f8f35d25
>> --- /dev/null
>> +++ b/drivers/net/ethernet/sfc/efx_devlink.c
>> @@ -0,0 +1,427 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/****************************************************************************
>> + * Driver for AMD network controllers and boards
>> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published
>> + * by the Free Software Foundation, incorporated herein by reference.
>> + */
>> +
>> +#include <linux/rtc.h>
>> +#include "net_driver.h"
>> +#include "ef100_nic.h"
>> +#include "efx_devlink.h"
>> +#include "nic.h"
>> +#include "mcdi.h"
>> +#include "mcdi_functions.h"
>> +#include "mcdi_pcol.h"
>> +
>> +/* Custom devlink-info version object names for details that do not map to the
>> + * generic standardized names.
>> + */
>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC	"fw.mgmt.suc"
>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC	"fw.mgmt.cmc"
>> +#define EFX_DEVLINK_INFO_VERSION_FPGA_REV	"fpga.rev"
>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_HW	"fpga.app"
>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_FW	DEVLINK_INFO_VERSION_GENERIC_FW_APP
>> +#define EFX_DEVLINK_INFO_VERSION_SOC_BOOT	"coproc.boot"
>> +#define EFX_DEVLINK_INFO_VERSION_SOC_UBOOT	"coproc.uboot"
>> +#define EFX_DEVLINK_INFO_VERSION_SOC_MAIN	"coproc.main"
>> +#define EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY	"coproc.recovery"
>> +#define EFX_DEVLINK_INFO_VERSION_FW_EXPROM	"fw.exprom"
>> +#define EFX_DEVLINK_INFO_VERSION_FW_UEFI	"fw.uefi"
> Here, you've defined several new versions, only one of which is
> standard. I don't see an associated documentation addition. Please add a
> ef100.rst file to Documentation/networking/devlink
>
> It is also preferred to use the standard names or extend the set of
> standard names where appropriate first. Can you explain why you didn't
> do that here?
>
> For example, the documentation for "fw.undi" indicates it may include
> the UEFI driver, and I would expect your UEFI version to be something
> like fw.undi or fw.undi.uefi if its distinct...


I'm adding the doc file for v2.

About uefi/undi, we have uefi but not undi.

>> +
>> +#define EFX_MAX_VERSION_INFO_LEN	64
>> +
>> +static int efx_devlink_info_nvram_partition(struct efx_nic *efx,
>> +					    struct devlink_info_req *req,
>> +					    unsigned int partition_type,
>> +					    const char *version_name)
>> +{
>> +	char buf[EFX_MAX_VERSION_INFO_LEN];
>> +	u16 version[4];
>> +	int rc;
>> +
>> +	rc = efx_mcdi_nvram_metadata(efx, partition_type, NULL, version, NULL,
>> +				     0);
>> +	if (rc)
>> +		return rc;
>> +
>> +	snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u", version[0],
>> +		 version[1], version[2], version[3]);
>> +	devlink_info_version_stored_put(req, version_name, buf);
>> +
>> +	return 0;
>> +}
>> +
>> +static void efx_devlink_info_stored_versions(struct efx_nic *efx,
>> +					     struct devlink_info_req *req)
>> +{
>> +	efx_devlink_info_nvram_partition(efx, req, NVRAM_PARTITION_TYPE_BUNDLE,
>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID);
>> +	efx_devlink_info_nvram_partition(efx, req,
>> +					 NVRAM_PARTITION_TYPE_MC_FIRMWARE,
>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT);
>> +	efx_devlink_info_nvram_partition(efx, req,
>> +					 NVRAM_PARTITION_TYPE_SUC_FIRMWARE,
>> +					 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC);
>> +	efx_devlink_info_nvram_partition(efx, req,
>> +					 NVRAM_PARTITION_TYPE_EXPANSION_ROM,
>> +					 EFX_DEVLINK_INFO_VERSION_FW_EXPROM);
>> +	efx_devlink_info_nvram_partition(efx, req,
>> +					 NVRAM_PARTITION_TYPE_EXPANSION_UEFI,
>> +					 EFX_DEVLINK_INFO_VERSION_FW_UEFI);
>> +}
>> +
>> +#define EFX_MAX_SERIALNUM_LEN	(ETH_ALEN * 2 + 1)
>> +
>> +static void efx_devlink_info_board_cfg(struct efx_nic *efx,
>> +				       struct devlink_info_req *req)
>> +{
>> +	char sn[EFX_MAX_SERIALNUM_LEN];
>> +	u8 mac_address[ETH_ALEN];
>> +	int rc;
>> +
>> +	rc = efx_mcdi_get_board_cfg(efx, (u8 *)mac_address, NULL, NULL);
>> +	if (!rc) {
>> +		snprintf(sn, EFX_MAX_SERIALNUM_LEN, "%pm", mac_address);
>> +		devlink_info_serial_number_put(req, sn);
>> +	}
>> +}
>> +
>> +#define EFX_VER_FLAG(_f)	\
>> +	(MC_CMD_GET_VERSION_V5_OUT_ ## _f ## _PRESENT_LBN)
>> +
>> +static void efx_devlink_info_running_versions(struct efx_nic *efx,
>> +					      struct devlink_info_req *req)
>> +{
> This function for doing running versions is very long, and seems quite
> complicated. It's difficult to parse what versions are being reported.
>
> I saw that your stored version used a helper function to separate each
> thing out nicely. Is there any way to do that here?
>
>> +	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_V5_OUT_LEN);
>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_VERSION_EXT_IN_LEN);
>> +	char buf[EFX_MAX_VERSION_INFO_LEN];
>> +	unsigned int flags, build_id;
>> +	union {
>> +		const __le32 *dwords;
>> +		const __le16 *words;
>> +		const char *str;
>> +	} ver;
> For example, you've got this local union on the stack that seems to be
> reused a bunch...
>
>> +	struct rtc_time build_date;
>> +	size_t outlength, offset;
>> +	u64 tstamp;
>> +	int rc;
>> +
>> +	rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, inbuf, sizeof(inbuf),
>> +			  outbuf, sizeof(outbuf), &outlength);
>> +	if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN)
>> +		return;
>> +
>> +	/* Handle previous output */
>> +	if (outlength < MC_CMD_GET_VERSION_V2_OUT_LEN) {
>> +		ver.words = (__le16 *)MCDI_PTR(outbuf,
>> +					       GET_VERSION_EXT_OUT_VERSION);
>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +				  le16_to_cpu(ver.words[0]),
>> +				  le16_to_cpu(ver.words[1]),
>> +				  le16_to_cpu(ver.words[2]),
>> +				  le16_to_cpu(ver.words[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>> +						 buf);
>> +		return;
>> +	}
>> +
>> +	/* Handle V2 additions */
>> +	flags = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_FLAGS);
>> +	if (flags & BIT(EFX_VER_FLAG(BOARD_EXT_INFO))) {
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%s",
>> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_NAME));
>> +		devlink_info_version_fixed_put(req,
>> +					       DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
>> +					       buf);
>> +
>> +		/* Favour full board version if present (in V5 or later) */
>> +		if (~flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>> +			snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u",
>> +				 MCDI_DWORD(outbuf,
>> +					    GET_VERSION_V2_OUT_BOARD_REVISION));
>> +			devlink_info_version_fixed_put(req,
>> +						       DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>> +						       buf);
>> +		}
>> +
>> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_SERIAL);
>> +		if (ver.str[0])
>> +			devlink_info_board_serial_number_put(req, ver.str);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(FPGA_EXT_INFO))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V2_OUT_FPGA_VERSION);
>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u_%c%u",
>> +				  le32_to_cpu(ver.dwords[0]),
>> +				  'A' + le32_to_cpu(ver.dwords[1]),
>> +				  le32_to_cpu(ver.dwords[2]));
>> +
>> +		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_FPGA_EXTRA);
>> +		if (ver.str[0])
>> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>> +				 " (%s)", ver.str);
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_FPGA_REV,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(CMC_EXT_INFO))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V2_OUT_CMCFW_VERSION);
>> +		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +				  le32_to_cpu(ver.dwords[0]),
>> +				  le32_to_cpu(ver.dwords[1]),
>> +				  le32_to_cpu(ver.dwords[2]),
>> +				  le32_to_cpu(ver.dwords[3]));
>> +
>> +		tstamp = MCDI_QWORD(outbuf,
>> +				    GET_VERSION_V2_OUT_CMCFW_BUILD_DATE);
>> +		if (tstamp) {
>> +			rtc_time64_to_tm(tstamp, &build_date);
>> +			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>> +				 " (%ptRd)", &build_date);
>> +		}
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC,
>> +						 buf);
>> +	}
>> +
>> +	ver.words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_V2_OUT_VERSION);
>> +	offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			  le16_to_cpu(ver.words[0]), le16_to_cpu(ver.words[1]),
>> +			  le16_to_cpu(ver.words[2]), le16_to_cpu(ver.words[3]));
>> +	if (flags & BIT(EFX_VER_FLAG(MCFW_EXT_INFO))) {
>> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_ID);
>> +		snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
>> +			 " (%x) %s", build_id,
>> +			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_NAME));
>> +	}
>> +	devlink_info_version_running_put(req,
>> +					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
>> +					 buf);
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V2_OUT_SUCFW_VERSION);
>> +		tstamp = MCDI_QWORD(outbuf,
>> +				    GET_VERSION_V2_OUT_SUCFW_BUILD_DATE);
>> +		rtc_time64_to_tm(tstamp, &build_date);
>> +		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_SUCFW_CHIP_ID);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN,
>> +			 "%u.%u.%u.%u type %x (%ptRd)",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]), le32_to_cpu(ver.dwords[3]),
>> +			 build_id, &build_date);
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>> +						 buf);
>> +	}
>> +
>> +	if (outlength < MC_CMD_GET_VERSION_V3_OUT_LEN)
>> +		return;
>> +
>> +	/* Handle V3 additions */
>> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_HW_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V3_OUT_DATAPATH_HW_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_HW,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(DATAPATH_FW_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V3_OUT_DATAPATH_FW_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_DATAPATH_FW,
>> +						 buf);
>> +	}
>> +
>> +	if (outlength < MC_CMD_GET_VERSION_V4_OUT_LEN)
>> +		return;
>> +
>> +	/* Handle V4 additions */
>> +	if (flags & BIT(EFX_VER_FLAG(SOC_BOOT_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SOC_BOOT_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_SOC_BOOT,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SOC_UBOOT_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SOC_UBOOT_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_SOC_UBOOT,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SOC_MAIN_ROOTFS_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SOC_MAIN_ROOTFS_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_SOC_MAIN,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SOC_RECOVERY_BUILDROOT_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SOC_RECOVERY_BUILDROOT_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(SUCFW_VERSION)) &&
>> +	    ~flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V4_OUT_SUCFW_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
>> +						 buf);
>> +	}
>> +
>> +	if (outlength < MC_CMD_GET_VERSION_V5_OUT_LEN)
>> +		return;
>> +
>> +	/* Handle V5 additions */
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V5_OUT_BOARD_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
>> +						 buf);
>> +	}
>> +
>> +	if (flags & BIT(EFX_VER_FLAG(BUNDLE_VERSION))) {
>> +		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
>> +						GET_VERSION_V5_OUT_BUNDLE_VERSION);
>> +
>> +		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
>> +			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
>> +			 le32_to_cpu(ver.dwords[2]),
>> +			 le32_to_cpu(ver.dwords[3]));
>> +
>> +		devlink_info_version_running_put(req,
>> +						 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
>> +						 buf);
>> +	}
>> +}
> In the ice driver I implemented each version extraction as a separate
> function to make it more clear which versions where which. This running
> function could benefit from some organization like that.
>
>> +
>> +#undef EFX_VER_FLAG
>> +
>> +static void efx_devlink_info_query_all(struct efx_nic *efx,
>> +				       struct devlink_info_req *req)
>> +{
>> +	efx_devlink_info_board_cfg(efx, req);
>> +	efx_devlink_info_stored_versions(efx, req);
>> +	efx_devlink_info_running_versions(efx, req);
>> +}
> Do you really need this to be a separate function and not just inlined
> into the caller, efx_devlink_info_get.
>
>> +
>> +struct efx_devlink {
>> +	struct efx_nic *efx;
>> +};
>> +
>> +static int efx_devlink_info_get(struct devlink *devlink,
>> +				struct devlink_info_req *req,
>> +				struct netlink_ext_ack *extack)
>> +{
>> +	struct efx_devlink *devlink_private = devlink_priv(devlink);
>> +	struct efx_nic *efx = devlink_private->efx;
>> +
>> +	efx_devlink_info_query_all(efx, req);
>> +	return 0;
>> +}
>> +
>> +static const struct devlink_ops sfc_devlink_ops = {
>> +	.info_get			= efx_devlink_info_get,
>> +};
>> +
>> +void efx_fini_devlink(struct efx_nic *efx)
>> +{
>> +	if (efx->devlink) {
>> +		struct efx_devlink *devlink_private;
>> +
>> +		devlink_private = devlink_priv(efx->devlink);
>> +
>> +		devlink_unregister(efx->devlink);
>> +		devlink_free(efx->devlink);
>> +		efx->devlink = NULL;
>> +	}
>> +}
>> +
>> +int efx_probe_devlink(struct efx_nic *efx)
>> +{
>> +	struct efx_devlink *devlink_private;
>> +
>> +	efx->devlink = devlink_alloc(&sfc_devlink_ops,
>> +				     sizeof(struct efx_devlink),
>> +				     &efx->pci_dev->dev);
>> +	if (!efx->devlink)
>> +		return -ENOMEM;
>> +	devlink_private = devlink_priv(efx->devlink);
>> +	devlink_private->efx = efx;
>> +
>> +	devlink_register(efx->devlink);
>> +
> So drivers implementing devlink typically would allocate the devlink
> early (almost the first thing it does) and make its private field
> something like their main private data structure.
>
> Obviously you're adding this to a pre-existing driver and it is
> initially simpler and easier to keep it separate. I'm not sure what
> other reviewers' stance on this is, but I think its preferable to
> allocate as an early stage and register once the driver is ready to
> accept requests from user space.
>
> As for a reason why, implementing reload support effectively requires this.
>
>> +	return 0;
>> +}
>> diff --git a/drivers/net/ethernet/sfc/efx_devlink.h b/drivers/net/ethernet/sfc/efx_devlink.h
>> new file mode 100644
>> index 000000000000..997f878aea93
>> --- /dev/null
>> +++ b/drivers/net/ethernet/sfc/efx_devlink.h
>> @@ -0,0 +1,20 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/****************************************************************************
>> + * Driver for AMD network controllers and boards
>> + * Copyright (C) 2023, Advanced Micro Devices, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published
>> + * by the Free Software Foundation, incorporated herein by reference.
>> + */
>> +
>> +#ifndef _EFX_DEVLINK_H
>> +#define _EFX_DEVLINK_H
>> +
>> +#include "net_driver.h"
>> +#include <net/devlink.h>
>> +
>> +int efx_probe_devlink(struct efx_nic *efx);
>> +void efx_fini_devlink(struct efx_nic *efx);
>> +
>> +#endif	/* _EFX_DEVLINK_H */
>> diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
>> index af338208eae9..328cae82a7d8 100644
>> --- a/drivers/net/ethernet/sfc/mcdi.c
>> +++ b/drivers/net/ethernet/sfc/mcdi.c
>> @@ -2308,6 +2308,78 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
>>   	return rc;
>>   }
>>   
>> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>> +			    u32 *subtype, u16 version[4], char *desc,
>> +			    size_t descsize)
>> +{
>> +	MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_METADATA_IN_LEN);
>> +	efx_dword_t *outbuf;
>> +	size_t outlen;
>> +	u32 flags;
>> +	int rc;
>> +
>> +	outbuf = kzalloc(MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2, GFP_KERNEL);
>> +	if (!outbuf)
>> +		return -ENOMEM;
>> +
>> +	MCDI_SET_DWORD(inbuf, NVRAM_METADATA_IN_TYPE, type);
>> +
>> +	rc = efx_mcdi_rpc_quiet(efx, MC_CMD_NVRAM_METADATA, inbuf,
>> +				sizeof(inbuf), outbuf,
>> +				MC_CMD_NVRAM_METADATA_OUT_LENMAX_MCDI2,
>> +				&outlen);
>> +	if (rc)
>> +		goto out_free;
>> +	if (outlen < MC_CMD_NVRAM_METADATA_OUT_LENMIN) {
>> +		rc = -EIO;
>> +		goto out_free;
>> +	}
>> +
>> +	flags = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_FLAGS);
>> +
>> +	if (desc && descsize > 0) {
>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_VALID_LBN)) {
>> +			if (descsize <=
>> +			    MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)) {
>> +				rc = -E2BIG;
>> +				goto out_free;
>> +			}
>> +
>> +			strncpy(desc,
>> +				MCDI_PTR(outbuf, NVRAM_METADATA_OUT_DESCRIPTION),
>> +				MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen));
>> +			desc[MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_NUM(outlen)] = '\0';
>> +		} else {
>> +			desc[0] = '\0';
>> +		}
>> +	}
>> +
>> +	if (subtype) {
>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_SUBTYPE_VALID_LBN))
>> +			*subtype = MCDI_DWORD(outbuf, NVRAM_METADATA_OUT_SUBTYPE);
>> +		else
>> +			*subtype = 0;
>> +	}
>> +
>> +	if (version) {
>> +		if (flags & BIT(MC_CMD_NVRAM_METADATA_OUT_VERSION_VALID_LBN)) {
>> +			version[0] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_W);
>> +			version[1] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_X);
>> +			version[2] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Y);
>> +			version[3] = MCDI_WORD(outbuf, NVRAM_METADATA_OUT_VERSION_Z);
>> +		} else {
>> +			version[0] = 0;
>> +			version[1] = 0;
>> +			version[2] = 0;
>> +			version[3] = 0;
>> +		}
>> +	}
>> +
>> +out_free:
>> +	kfree(outbuf);
>> +	return rc;
>> +}
>> +
>>   int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start,
>>   		      size_t len, size_t *retlen, u8 *buffer)
>>   {
>> diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
>> index 7e35fec9da35..63b090587f7a 100644
>> --- a/drivers/net/ethernet/sfc/mcdi.h
>> +++ b/drivers/net/ethernet/sfc/mcdi.h
>> @@ -379,6 +379,9 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
>>   			bool *protected_out);
>>   int efx_new_mcdi_nvram_test_all(struct efx_nic *efx);
>>   int efx_mcdi_nvram_test_all(struct efx_nic *efx);
>> +int efx_mcdi_nvram_metadata(struct efx_nic *efx, unsigned int type,
>> +			    u32 *subtype, u16 version[4], char *desc,
>> +			    size_t descsize);
>>   int efx_mcdi_handle_assertion(struct efx_nic *efx);
>>   int efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
>>   int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac,
>> diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
>> index 3b49e216768b..d036641dc043 100644
>> --- a/drivers/net/ethernet/sfc/net_driver.h
>> +++ b/drivers/net/ethernet/sfc/net_driver.h
>> @@ -994,6 +994,7 @@ enum efx_xdp_tx_queues_mode {
>>    *      xdp_rxq_info structures?
>>    * @netdev_notifier: Netdevice notifier.
>>    * @tc: state for TC offload (EF100).
>> + * @devlink: reference to devlink structure owned by this device
>>    * @mem_bar: The BAR that is mapped into membase.
>>    * @reg_base: Offset from the start of the bar to the function control window.
>>    * @monitor_work: Hardware monitor workitem
>> @@ -1179,6 +1180,7 @@ struct efx_nic {
>>   	struct notifier_block netdev_notifier;
>>   	struct efx_tc_state *tc;
>>   
>> +	struct devlink *devlink;
>>   	unsigned int mem_bar;
>>   	u32 reg_base;
>>   


^ permalink raw reply	[flat|nested] 52+ messages in thread

* Re: [PATCH net-next 1/7] sfc: add devlink support for ef100
  2023-01-24 11:05     ` Lucero Palau, Alejandro
@ 2023-01-24 22:12       ` Jacob Keller
  0 siblings, 0 replies; 52+ messages in thread
From: Jacob Keller @ 2023-01-24 22:12 UTC (permalink / raw)
  To: Lucero Palau, Alejandro, netdev, linux-net-drivers (AMD-Xilinx)
  Cc: davem, kuba, pabeni, edumazet, habetsm, ecree.xilinx



On 1/24/2023 3:05 AM, Lucero Palau, Alejandro wrote:
> 
> On 1/19/23 23:40, Jacob Keller wrote:
>>
>> On 1/19/2023 3:31 AM, alejandro.lucero-palau@amd.com wrote:
>>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC	"fw.mgmt.suc"
>>> +#define EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC	"fw.mgmt.cmc"
>>> +#define EFX_DEVLINK_INFO_VERSION_FPGA_REV	"fpga.rev"
>>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_HW	"fpga.app"
>>> +#define EFX_DEVLINK_INFO_VERSION_DATAPATH_FW	DEVLINK_INFO_VERSION_GENERIC_FW_APP
>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_BOOT	"coproc.boot"
>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_UBOOT	"coproc.uboot"
>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_MAIN	"coproc.main"
>>> +#define EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY	"coproc.recovery"
>>> +#define EFX_DEVLINK_INFO_VERSION_FW_EXPROM	"fw.exprom"
>>> +#define EFX_DEVLINK_INFO_VERSION_FW_UEFI	"fw.uefi"
>> Here, you've defined several new versions, only one of which is
>> standard. I don't see an associated documentation addition. Please add a
>> ef100.rst file to Documentation/networking/devlink
>>
>> It is also preferred to use the standard names or extend the set of
>> standard names where appropriate first. Can you explain why you didn't
>> do that here?
>>
>> For example, the documentation for "fw.undi" indicates it may include
>> the UEFI driver, and I would expect your UEFI version to be something
>> like fw.undi or fw.undi.uefi if its distinct...
> 
> 
> I'm adding the doc file for v2.
> 
> About uefi/undi, we have uefi but not undi.
>

I believe this is the same as ice, and we still used fw.undi. From the doc:

UNDI software, may include the UEFI driver, firmware or both.

Basically whether it includes the UEFI driver, firmware, or both it
should still be fw.undi, and i would expect if you really must
separately version the components those would need sub-fields added to
the devlink-info.rst

^ permalink raw reply	[flat|nested] 52+ messages in thread

end of thread, other threads:[~2023-01-24 22:13 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-19 11:31 [PATCH net-next 0/7] sfc: devlink support for ef100 alejandro.lucero-palau
2023-01-19 11:31 ` [PATCH net-next 1/7] sfc: add " alejandro.lucero-palau
2023-01-19 12:14   ` Jiri Pirko
2023-01-19 14:51     ` Lucero Palau, Alejandro
2023-01-19 16:29       ` Lucero Palau, Alejandro
2023-01-20 11:02         ` Jiri Pirko
2023-01-20 11:00       ` Jiri Pirko
2023-01-19 15:50   ` kernel test robot
2023-01-19 17:16   ` Jakub Kicinski
2023-01-19 17:52     ` Lucero Palau, Alejandro
2023-01-19 18:44       ` Jakub Kicinski
2023-01-19 19:08         ` Lucero Palau, Alejandro
2023-01-19 23:40   ` Jacob Keller
2023-01-20 14:11     ` Lucero Palau, Alejandro
2023-01-24  6:13       ` Edward Cree
2023-01-24  7:31         ` Lucero Palau, Alejandro
2023-01-24 11:05     ` Lucero Palau, Alejandro
2023-01-24 22:12       ` Jacob Keller
2023-01-20 13:59   ` kernel test robot
2023-01-19 11:31 ` [PATCH net-next 2/7] sfc: enumerate mports in ef100 alejandro.lucero-palau
2023-01-19 23:48   ` Jacob Keller
2023-01-20 14:13     ` Lucero Palau, Alejandro
2023-01-20 12:47   ` kernel test robot
2023-01-19 11:31 ` [PATCH net-next 3/7] sfc: add mport lookup based on driver's mport data alejandro.lucero-palau
2023-01-19 23:57   ` Jacob Keller
2023-01-20  9:34     ` Lucero Palau, Alejandro
2023-01-20 18:36       ` Keller, Jacob E
2023-01-19 11:31 ` [PATCH net-next 4/7] sfc: add devlink port support for ef100 alejandro.lucero-palau
2023-01-19 12:33   ` Jiri Pirko
2023-01-19 15:03     ` Lucero Palau, Alejandro
2023-01-19 13:37   ` kernel test robot
2023-01-20 21:21   ` kernel test robot
2023-01-19 11:31 ` [PATCH net-next 5/7] sfc: obtain device mac address based on firmware handle " alejandro.lucero-palau
2023-01-19 19:47   ` kernel test robot
2023-01-20  0:03   ` Jacob Keller
2023-01-19 11:31 ` [PATCH net-next 6/7] sfc: add support for port_function_hw_addr_get devlink in ef100 alejandro.lucero-palau
2023-01-19 12:25   ` Jiri Pirko
2023-01-19 14:59     ` Lucero Palau, Alejandro
2023-01-20 11:05       ` Jiri Pirko
2023-01-22 16:41         ` Lucero Palau, Alejandro
2023-01-19 12:37   ` Jiri Pirko
2023-01-19 15:09     ` Lucero Palau, Alejandro
2023-01-20 11:08       ` Jiri Pirko
2023-01-20 12:48         ` Lucero Palau, Alejandro
2023-01-22 16:36           ` Lucero Palau, Alejandro
2023-01-23  8:38             ` Jiri Pirko
2023-01-23  9:45               ` Lucero Palau, Alejandro
2023-01-23 10:18                 ` Jiri Pirko
2023-01-19 11:31 ` [PATCH net-next 7/7] sfc: add support for devlink port_function_hw_addr_set " alejandro.lucero-palau
2023-01-19 12:27   ` Jiri Pirko
2023-01-19 15:10     ` Lucero Palau, Alejandro
2023-01-20  8:55 ` [PATCH net-next 0/7] sfc: devlink support for ef100 Martin Habets

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.