linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RESEND PATCH 0/3] virtio: vdpa: new SolidNET DPU driver
@ 2022-12-19  8:35 Alvaro Karsz
  2022-12-19  8:35 ` [RESEND PATCH 1/3] Add SolidRun vendor id Alvaro Karsz
                   ` (2 more replies)
  0 siblings, 3 replies; 26+ messages in thread
From: Alvaro Karsz @ 2022-12-19  8:35 UTC (permalink / raw)
  To: virtualization, linux-pci; +Cc: bhelgaas, Alvaro Karsz

This series adds a vDPA driver for SolidNET DPU.

Patch 1 adds SolidRun vendor id to pci_ids.
Patch 2 adds a pci quirk needed by the DPU.
Patch 3 has the driver source code.

Patch 1 is prerequisite for both patch 2 and patch 3.

Alvaro Karsz (3):
  Add SolidRun vendor id
  New PCI quirk for SolidRun SNET DPU.
  virtio: vdpa: new SolidNET DPU driver.

 MAINTAINERS                        |    4 +
 drivers/pci/quirks.c               |    8 +
 drivers/vdpa/Kconfig               |   10 +
 drivers/vdpa/Makefile              |    1 +
 drivers/vdpa/solidrun/Makefile     |    6 +
 drivers/vdpa/solidrun/snet_hwmon.c |  188 +++++
 drivers/vdpa/solidrun/snet_main.c  | 1111 ++++++++++++++++++++++++++++
 drivers/vdpa/solidrun/snet_vdpa.h  |  196 +++++
 include/linux/pci_ids.h            |    2 +
 9 files changed, 1526 insertions(+)
 create mode 100644 drivers/vdpa/solidrun/Makefile
 create mode 100644 drivers/vdpa/solidrun/snet_hwmon.c
 create mode 100644 drivers/vdpa/solidrun/snet_main.c
 create mode 100644 drivers/vdpa/solidrun/snet_vdpa.h

-- 
2.32.0


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

* [RESEND PATCH 1/3] Add SolidRun vendor id
  2022-12-19  8:35 [RESEND PATCH 0/3] virtio: vdpa: new SolidNET DPU driver Alvaro Karsz
@ 2022-12-19  8:35 ` Alvaro Karsz
  2022-12-29 19:55   ` Bjorn Helgaas
  2022-12-19  8:35 ` [RESEND PATCH 2/3] New PCI quirk for SolidRun SNET DPU Alvaro Karsz
  2022-12-19  8:35 ` [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver Alvaro Karsz
  2 siblings, 1 reply; 26+ messages in thread
From: Alvaro Karsz @ 2022-12-19  8:35 UTC (permalink / raw)
  To: virtualization, linux-pci; +Cc: bhelgaas, Alvaro Karsz

The vendor id is used in 2 differrent source files,
the SNET vdpa driver and pci quirks.

Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>
---
 include/linux/pci_ids.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index b362d90eb9b..33bbe3160b4 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -3115,4 +3115,6 @@
 
 #define PCI_VENDOR_ID_NCUBE		0x10ff
 
+#define PCI_VENDOR_ID_SOLIDRUN		0xd063
+
 #endif /* _LINUX_PCI_IDS_H */
-- 
2.32.0


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

* [RESEND PATCH 2/3] New PCI quirk for SolidRun SNET DPU.
  2022-12-19  8:35 [RESEND PATCH 0/3] virtio: vdpa: new SolidNET DPU driver Alvaro Karsz
  2022-12-19  8:35 ` [RESEND PATCH 1/3] Add SolidRun vendor id Alvaro Karsz
@ 2022-12-19  8:35 ` Alvaro Karsz
  2022-12-29 19:55   ` Bjorn Helgaas
  2022-12-19  8:35 ` [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver Alvaro Karsz
  2 siblings, 1 reply; 26+ messages in thread
From: Alvaro Karsz @ 2022-12-19  8:35 UTC (permalink / raw)
  To: virtualization, linux-pci; +Cc: bhelgaas, Alvaro Karsz

The DPU advertises FLR, but it may cause the device to hang.
This only happens with revision 0x1.

Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>
---
 drivers/pci/quirks.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 285acc4aacc..809d03272c2 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -5343,6 +5343,14 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x149c, quirk_no_flr);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_no_flr);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_no_flr);
 
+/* FLR may cause the SolidRun SNET DPU (rev 0x1) to hang */
+static void quirk_no_flr_snet(struct pci_dev *dev)
+{
+	if (dev->revision == 0x1)
+		quirk_no_flr(dev);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SOLIDRUN, 0x1000, quirk_no_flr_snet);
+
 static void quirk_no_ext_tags(struct pci_dev *pdev)
 {
 	struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
-- 
2.32.0


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

* [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-19  8:35 [RESEND PATCH 0/3] virtio: vdpa: new SolidNET DPU driver Alvaro Karsz
  2022-12-19  8:35 ` [RESEND PATCH 1/3] Add SolidRun vendor id Alvaro Karsz
  2022-12-19  8:35 ` [RESEND PATCH 2/3] New PCI quirk for SolidRun SNET DPU Alvaro Karsz
@ 2022-12-19  8:35 ` Alvaro Karsz
  2022-12-19 10:43   ` Michael S. Tsirkin
                     ` (3 more replies)
  2 siblings, 4 replies; 26+ messages in thread
From: Alvaro Karsz @ 2022-12-19  8:35 UTC (permalink / raw)
  To: virtualization, linux-pci
  Cc: bhelgaas, Alvaro Karsz, Michael S. Tsirkin, Jason Wang,
	Jean Delvare, Guenter Roeck

This commit includes:
 1) The driver to manage the controlplane over vDPA bus.
 2) A HW monitor device to read health values from the DPU.

Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>
--
v2:
	- Auto detect the BAR used for communication.
	- When waiting for the DPU to write a config, wait for 5secs
	  before giving up on the device.
	- Return EOPNOTSUPP error code in vDPA set_vq_state callback if
	  the vq state is not the same as the initial one.
	- Implement a vDPA reset callback.
	- Wait for an ACK when sending a message to the DPU.
	- Add endianness comments on 64bit read/write functions.
	- Remove the get_iova_range and free vDPA callbacks.
	- Usage of managed device functions to ioremap a region.
	- Call pci_set_drvdata and pci_set_master before
	  vdpa_register_device.
	- Create DMA isolation between the vDPA devices by using the
	  chip SR-IOV feature.
	  Every vDPA device gets a PCIe VF with its own DMA device.

v3:
	- Validate vDPA config length while receiving the DPU's config,
	  not while trying to write the vDPA config to the DPU.
	- Request IRQs when vDPA status is set to
	  VIRTIO_CONFIG_S_DRIVER_OK.
	- Remove snet_reset_dev() from the PCI remove function for a VF.
v4:
	- Get SolidRun vendor ID from pci_ids
v5:
	- Remove "select HWMON" from Kconfig.
	  Usage of "depends on HWMON || HWMON=n" instead and usage of
	  IS_ENABLED(CONFIG_HWMON) when calling to snet hwmon functions.
	  snet_hwmon.c is compiled only if CONFIG_HWMON is defined.
	- Remove the  #include <linux/hwmon-sysfs.h> from snet_hwmon.c.
	- Remove the unnecessary (long) casting from snet_hwmon_read_reg.
	- Remove the "_hwmon" ending from the hwmon name.
	- Usage of IS_ERR macro to check if devm_hwmon_device_register_with_info
	  failed.
	- Replace schedule() with usleep_range() in the "hot loop" in
	  psnet_detect_bar.
	- Remove the logging of memory allocation failures.
	- Add parenthesis to arguments in SNET_* macros.
	- Prefer sizeof(*variable) instead of sizeof(struct x) when allocating
	  memory.
v6:
	- SNET_WRN -> SNET_WARN.
---
 MAINTAINERS                        |    4 +
 drivers/vdpa/Kconfig               |   10 +
 drivers/vdpa/Makefile              |    1 +
 drivers/vdpa/solidrun/Makefile     |    6 +
 drivers/vdpa/solidrun/snet_hwmon.c |  188 +++++
 drivers/vdpa/solidrun/snet_main.c  | 1111 ++++++++++++++++++++++++++++
 drivers/vdpa/solidrun/snet_vdpa.h  |  196 +++++
 7 files changed, 1516 insertions(+)
 create mode 100644 drivers/vdpa/solidrun/Makefile
 create mode 100644 drivers/vdpa/solidrun/snet_hwmon.c
 create mode 100644 drivers/vdpa/solidrun/snet_main.c
 create mode 100644 drivers/vdpa/solidrun/snet_vdpa.h

diff --git a/MAINTAINERS b/MAINTAINERS
index a608f19da3a..7f4d9dcb760 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21955,6 +21955,10 @@ IFCVF VIRTIO DATA PATH ACCELERATOR
 R:	Zhu Lingshan <lingshan.zhu@intel.com>
 F:	drivers/vdpa/ifcvf/
 
+SNET DPU VIRTIO DATA PATH ACCELERATOR
+R:	Alvaro Karsz <alvaro.karsz@solid-run.com>
+F:	drivers/vdpa/solidrun/
+
 VIRTIO BALLOON
 M:	"Michael S. Tsirkin" <mst@redhat.com>
 M:	David Hildenbrand <david@redhat.com>
diff --git a/drivers/vdpa/Kconfig b/drivers/vdpa/Kconfig
index 50f45d03761..79625c7cc46 100644
--- a/drivers/vdpa/Kconfig
+++ b/drivers/vdpa/Kconfig
@@ -86,4 +86,14 @@ config ALIBABA_ENI_VDPA
 	  VDPA driver for Alibaba ENI (Elastic Network Interface) which is built upon
 	  virtio 0.9.5 specification.
 
+ config SNET_VDPA
+	tristate "SolidRun's vDPA driver for SolidNET"
+	depends on PCI_MSI && PCI_IOV && (HWMON || HWMON=n)
+	help
+	  vDPA driver for SolidNET DPU.
+	  With this driver, the VirtIO dataplane can be
+	  offloaded to a SolidNET DPU.
+	  This driver includes a HW monitor device that
+	  reads health values from the DPU.
+
 endif # VDPA
diff --git a/drivers/vdpa/Makefile b/drivers/vdpa/Makefile
index 15665563a7f..59396ff2a31 100644
--- a/drivers/vdpa/Makefile
+++ b/drivers/vdpa/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_IFCVF)    += ifcvf/
 obj-$(CONFIG_MLX5_VDPA) += mlx5/
 obj-$(CONFIG_VP_VDPA)    += virtio_pci/
 obj-$(CONFIG_ALIBABA_ENI_VDPA) += alibaba/
+obj-$(CONFIG_SNET_VDPA) += solidrun/
diff --git a/drivers/vdpa/solidrun/Makefile b/drivers/vdpa/solidrun/Makefile
new file mode 100644
index 00000000000..c0aa3415bf7
--- /dev/null
+++ b/drivers/vdpa/solidrun/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_SNET_VDPA) += snet_vdpa.o
+snet_vdpa-$(CONFIG_SNET_VDPA) += snet_main.o
+ifdef CONFIG_HWMON
+snet_vdpa-$(CONFIG_SNET_VDPA) += snet_hwmon.o
+endif
diff --git a/drivers/vdpa/solidrun/snet_hwmon.c b/drivers/vdpa/solidrun/snet_hwmon.c
new file mode 100644
index 00000000000..e695e36ff75
--- /dev/null
+++ b/drivers/vdpa/solidrun/snet_hwmon.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SolidRun DPU driver for control plane
+ *
+ * Copyright (C) 2022 SolidRun
+ *
+ * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>
+ *
+ */
+#include <linux/hwmon.h>
+
+#include "snet_vdpa.h"
+
+/* Monitor offsets */
+#define SNET_MON_TMP0_IN_OFF      0x00
+#define SNET_MON_TMP0_MAX_OFF     0x08
+#define SNET_MON_TMP0_CRIT_OFF    0x10
+#define SNET_MON_TMP1_IN_OFF      0x18
+#define SNET_MON_TMP1_CRIT_OFF    0x20
+#define SNET_MON_CURR_IN_OFF      0x28
+#define SNET_MON_CURR_MAX_OFF     0x30
+#define SNET_MON_CURR_CRIT_OFF    0x38
+#define SNET_MON_PWR_IN_OFF       0x40
+#define SNET_MON_VOLT_IN_OFF      0x48
+#define SNET_MON_VOLT_CRIT_OFF    0x50
+#define SNET_MON_VOLT_LCRIT_OFF   0x58
+
+static void snet_hwmon_read_reg(struct psnet *psnet, u32 reg, long *out)
+{
+	*out = psnet_read64(psnet, psnet->cfg.hwmon_off + reg);
+}
+
+static umode_t snet_howmon_is_visible(const void *data,
+				      enum hwmon_sensor_types type,
+				      u32 attr, int channel)
+{
+	return 0444;
+}
+
+static int snet_howmon_read(struct device *dev, enum hwmon_sensor_types type,
+			    u32 attr, int channel, long *val)
+{
+	struct psnet *psnet = dev_get_drvdata(dev);
+	int ret = 0;
+
+	switch (type) {
+	case hwmon_in:
+		switch (attr) {
+		case hwmon_in_lcrit:
+			snet_hwmon_read_reg(psnet, SNET_MON_VOLT_LCRIT_OFF, val);
+			break;
+		case hwmon_in_crit:
+			snet_hwmon_read_reg(psnet, SNET_MON_VOLT_CRIT_OFF, val);
+			break;
+		case hwmon_in_input:
+			snet_hwmon_read_reg(psnet, SNET_MON_VOLT_IN_OFF, val);
+			break;
+		default:
+			ret = -EOPNOTSUPP;
+			break;
+		}
+		break;
+
+	case hwmon_power:
+		switch (attr) {
+		case hwmon_power_input:
+			snet_hwmon_read_reg(psnet, SNET_MON_PWR_IN_OFF, val);
+			break;
+
+		default:
+			ret = -EOPNOTSUPP;
+			break;
+		}
+		break;
+
+	case hwmon_curr:
+		switch (attr) {
+		case hwmon_curr_input:
+			snet_hwmon_read_reg(psnet, SNET_MON_CURR_IN_OFF, val);
+			break;
+		case hwmon_curr_max:
+			snet_hwmon_read_reg(psnet, SNET_MON_CURR_MAX_OFF, val);
+			break;
+		case hwmon_curr_crit:
+			snet_hwmon_read_reg(psnet, SNET_MON_CURR_CRIT_OFF, val);
+			break;
+		default:
+			ret = -EOPNOTSUPP;
+			break;
+		}
+		break;
+
+	case hwmon_temp:
+		switch (attr) {
+		case hwmon_temp_input:
+			if (channel == 0)
+				snet_hwmon_read_reg(psnet, SNET_MON_TMP0_IN_OFF, val);
+			else
+				snet_hwmon_read_reg(psnet, SNET_MON_TMP1_IN_OFF, val);
+			break;
+		case hwmon_temp_max:
+			if (channel == 0)
+				snet_hwmon_read_reg(psnet, SNET_MON_TMP0_MAX_OFF, val);
+			else
+				ret = -EOPNOTSUPP;
+			break;
+		case hwmon_temp_crit:
+			if (channel == 0)
+				snet_hwmon_read_reg(psnet, SNET_MON_TMP0_CRIT_OFF, val);
+			else
+				snet_hwmon_read_reg(psnet, SNET_MON_TMP1_CRIT_OFF, val);
+			break;
+
+		default:
+			ret = -EOPNOTSUPP;
+			break;
+		}
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+	return ret;
+}
+
+static int snet_hwmon_read_string(struct device *dev,
+				  enum hwmon_sensor_types type, u32 attr,
+				  int channel, const char **str)
+{
+	int ret = 0;
+
+	switch (type) {
+	case hwmon_in:
+		*str = "main_vin";
+		break;
+	case hwmon_power:
+		*str = "soc_pin";
+		break;
+	case hwmon_curr:
+		*str = "soc_iin";
+		break;
+	case hwmon_temp:
+		if (channel == 0)
+			*str = "power_stage_temp";
+		else
+			*str = "ic_junction_temp";
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+	return ret;
+}
+
+static const struct hwmon_ops snet_hwmon_ops = {
+	.is_visible = snet_howmon_is_visible,
+	.read = snet_howmon_read,
+	.read_string = snet_hwmon_read_string
+};
+
+static const struct hwmon_channel_info *snet_hwmon_info[] = {
+	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_LABEL,
+			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL),
+	HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_LABEL),
+	HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | HWMON_C_LABEL),
+	HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_CRIT | HWMON_I_LCRIT | HWMON_I_LABEL),
+			   NULL
+};
+
+static const struct hwmon_chip_info snet_hwmono_info = {
+	.ops = &snet_hwmon_ops,
+	.info = snet_hwmon_info,
+};
+
+/* Create an HW monitor device */
+void psnet_create_hwmon(struct pci_dev *pdev)
+{
+	struct device *hwmon;
+	struct psnet *psnet = pci_get_drvdata(pdev);
+
+	snprintf(psnet->hwmon_name, SNET_NAME_SIZE, "snet_%s", pci_name(pdev));
+	hwmon = devm_hwmon_device_register_with_info(&pdev->dev, psnet->hwmon_name, psnet,
+						     &snet_hwmono_info, NULL);
+	/* The monitor is not mandatory, Just alert user in case of an error */
+	if (IS_ERR(hwmon))
+		SNET_WARN(pdev, "Failed to create SNET hwmon, error %ld\n", PTR_ERR(hwmon));
+}
diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c
new file mode 100644
index 00000000000..d438a89b359
--- /dev/null
+++ b/drivers/vdpa/solidrun/snet_main.c
@@ -0,0 +1,1111 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SolidRun DPU driver for control plane
+ *
+ * Copyright (C) 2022 SolidRun
+ *
+ * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>
+ *
+ */
+#include <linux/iopoll.h>
+
+#include "snet_vdpa.h"
+
+/* SNET DPU device ID */
+#define SNET_DEVICE_ID          0x1000
+/* SNET signature */
+#define SNET_SIGNATURE          0xD0D06363
+/* Max. config version that we can work with */
+#define SNET_CFG_VERSION        0x1
+/* Queue align */
+#define SNET_QUEUE_ALIGNMENT    PAGE_SIZE
+/* Kick value to notify that new data is available */
+#define SNET_KICK_VAL           0x1
+#define SNET_CONFIG_OFF         0x0
+/* ACK timeout for a message */
+#define SNET_ACK_TIMEOUT	2000000
+/* How long we are willing to wait for a SNET device */
+#define SNET_DETECT_TIMEOUT	5000000
+/* How long should we wait for the DPU to read our config */
+#define SNET_READ_CFG_TIMEOUT	3000000
+/* Size of configs written to the DPU */
+#define SNET_GENERAL_CFG_LEN	36
+#define SNET_GENERAL_CFG_VQ_LEN	40
+
+enum snet_msg {
+	SNET_MSG_DESTROY = 1,
+};
+
+static struct snet *vdpa_to_snet(struct vdpa_device *vdpa)
+{
+	return container_of(vdpa, struct snet, vdpa);
+}
+
+static int snet_wait_for_msg_ack(struct snet *snet)
+{
+	struct pci_dev *pdev = snet->pdev;
+	int ret;
+	u32 val;
+
+	/* The DPU will clear the messages offset once messages
+	 * are processed.
+	 */
+	ret = readx_poll_timeout(ioread32, snet->bar + snet->psnet->cfg.msg_off,
+				 val, !val, 10, SNET_ACK_TIMEOUT);
+	if (ret)
+		SNET_WARN(pdev, "Timeout waiting for message ACK\n");
+
+	return ret;
+}
+
+/* Sends a message to the DPU.
+ * If blocking is set, the function will return once the
+ * message was processed by the DPU (or timeout).
+ */
+static int snet_send_msg(struct snet *snet, u32 msg, bool blocking)
+{
+	int ret = 0;
+
+	/* Make sure the DPU acked last message before issuing a new one */
+	ret = snet_wait_for_msg_ack(snet);
+	if (ret)
+		return ret;
+
+	/* Write the message */
+	snet_write32(snet, snet->psnet->cfg.msg_off, msg);
+
+	if (blocking)
+		ret = snet_wait_for_msg_ack(snet);
+	else /* If non-blocking, flush the write by issuing a read */
+		snet_read32(snet, snet->psnet->cfg.msg_off);
+
+	return ret;
+}
+
+static irqreturn_t snet_cfg_irq_hndlr(int irq, void *data)
+{
+	struct snet *snet = data;
+	/* Call callback if any */
+	if (snet->cb.callback)
+		return snet->cb.callback(snet->cb.private);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t snet_vq_irq_hndlr(int irq, void *data)
+{
+	struct snet_vq *vq = data;
+	/* Call callback if any */
+	if (vq->cb.callback)
+		return vq->cb.callback(vq->cb.private);
+
+	return IRQ_HANDLED;
+}
+
+static void snet_free_irqs(struct snet *snet)
+{
+	struct psnet *psnet = snet->psnet;
+	struct pci_dev *pdev;
+	u32 i;
+
+	/* Which Device allcoated the IRQs? */
+	if (PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF))
+		pdev = snet->pdev->physfn;
+	else
+		pdev = snet->pdev;
+
+	/* Free config's IRQ */
+	if (snet->cfg_irq != -1) {
+		devm_free_irq(&pdev->dev, snet->cfg_irq, snet);
+		snet->cfg_irq = -1;
+	}
+	/* Free VQ IRQs */
+	for (i = 0; i < snet->cfg->vq_num; i++) {
+		if (snet->vqs[i] && snet->vqs[i]->irq != -1) {
+			devm_free_irq(&pdev->dev, snet->vqs[i]->irq, snet->vqs[i]);
+			snet->vqs[i]->irq = -1;
+		}
+	}
+
+	/* IRQ vectors are freed when the pci remove callback is called */
+}
+
+static int snet_set_vq_address(struct vdpa_device *vdev, u16 idx, u64 desc_area,
+			       u64 driver_area, u64 device_area)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+	/* save received parameters in vqueue sturct */
+	snet->vqs[idx]->desc_area = desc_area;
+	snet->vqs[idx]->driver_area = driver_area;
+	snet->vqs[idx]->device_area = device_area;
+
+	return 0;
+}
+
+static void snet_set_vq_num(struct vdpa_device *vdev, u16 idx, u32 num)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+	/* save num in vqueue */
+	snet->vqs[idx]->num = num;
+}
+
+static void snet_kick_vq(struct vdpa_device *vdev, u16 idx)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+	/* not ready - ignore */
+	if (!snet->vqs[idx]->ready)
+		return;
+
+	iowrite32(SNET_KICK_VAL, snet->vqs[idx]->kick_ptr);
+}
+
+static void snet_set_vq_cb(struct vdpa_device *vdev, u16 idx, struct vdpa_callback *cb)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	snet->vqs[idx]->cb.callback = cb->callback;
+	snet->vqs[idx]->cb.private = cb->private;
+}
+
+static void snet_set_vq_ready(struct vdpa_device *vdev, u16 idx, bool ready)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	snet->vqs[idx]->ready = ready;
+}
+
+static bool snet_get_vq_ready(struct vdpa_device *vdev, u16 idx)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	return snet->vqs[idx]->ready;
+}
+
+static int snet_set_vq_state(struct vdpa_device *vdev, u16 idx, const struct vdpa_vq_state *state)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+	/* Setting the VQ state is not supported.
+	 * If the asked state is the same as the initial one
+	 * we can ignore it.
+	 */
+	if (SNET_HAS_FEATURE(snet, VIRTIO_F_RING_PACKED)) {
+		const struct vdpa_vq_state_packed *p = &state->packed;
+
+		if (p->last_avail_counter == 1 && p->last_used_counter == 1 &&
+		    p->last_avail_idx == 0 && p->last_used_idx == 0)
+			return 0;
+	} else {
+		const struct vdpa_vq_state_split *s = &state->split;
+
+		if (s->avail_index == 0)
+			return 0;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int snet_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa_vq_state *state)
+{
+	/* Not supported */
+	return -EOPNOTSUPP;
+}
+
+static int snet_get_vq_irq(struct vdpa_device *vdev, u16 idx)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	return snet->vqs[idx]->irq;
+}
+
+static u32 snet_get_vq_align(struct vdpa_device *vdev)
+{
+	return (u32)SNET_QUEUE_ALIGNMENT;
+}
+
+static int snet_reset_dev(struct snet *snet)
+{
+	struct pci_dev *pdev = snet->pdev;
+	int ret = 0;
+	u32 i;
+
+	/* If status is 0, nothing to do */
+	if (!snet->status)
+		return 0;
+
+	/* If DPU started, send a destroy message */
+	if (snet->status & VIRTIO_CONFIG_S_DRIVER_OK)
+		ret = snet_send_msg(snet, SNET_MSG_DESTROY, true);
+
+	/* Clear VQs */
+	for (i = 0; i < snet->cfg->vq_num; i++) {
+		if (!snet->vqs[i])
+			continue;
+		snet->vqs[i]->cb.callback = NULL;
+		snet->vqs[i]->cb.private = NULL;
+		snet->vqs[i]->desc_area = 0;
+		snet->vqs[i]->device_area = 0;
+		snet->vqs[i]->driver_area = 0;
+		snet->vqs[i]->ready = false;
+	}
+
+	/* Clear config callback */
+	snet->cb.callback = NULL;
+	snet->cb.private = NULL;
+	/* Free IRQs */
+	snet_free_irqs(snet);
+	/* Reset status */
+	snet->status = 0;
+
+	if (ret)
+		SNET_WARN(pdev, "Incomplete reset to SNET[%u] device\n", snet->sid);
+	else
+		SNET_DBG(pdev, "Reset SNET[%u] device\n", snet->sid);
+
+	return 0;
+}
+
+static int snet_reset(struct vdpa_device *vdev)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	return snet_reset_dev(snet);
+}
+
+static size_t snet_get_config_size(struct vdpa_device *vdev)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	return (size_t)snet->cfg->cfg_size;
+}
+
+static u64 snet_get_features(struct vdpa_device *vdev)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	return snet->cfg->features;
+}
+
+static int snet_set_drv_features(struct vdpa_device *vdev, u64 features)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	snet->negotiated_features = snet->cfg->features & features;
+	return 0;
+}
+
+static u64 snet_get_drv_features(struct vdpa_device *vdev)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	return snet->negotiated_features;
+}
+
+static u16 snet_get_vq_num_max(struct vdpa_device *vdev)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	return (u16)snet->cfg->vq_size;
+}
+
+static void snet_set_config_cb(struct vdpa_device *vdev, struct vdpa_callback *cb)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	snet->cb.callback = cb->callback;
+	snet->cb.private = cb->private;
+}
+
+static u32 snet_get_device_id(struct vdpa_device *vdev)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	return snet->cfg->virtio_id;
+}
+
+static u32 snet_get_vendor_id(struct vdpa_device *vdev)
+{
+	return (u32)PCI_VENDOR_ID_SOLIDRUN;
+}
+
+static u8 snet_get_status(struct vdpa_device *vdev)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+
+	return snet->status;
+}
+
+static int snet_write_conf(struct snet *snet)
+{
+	u32 off, i, tmp;
+	int ret;
+
+	/* No need to write the config twice */
+	if (snet->dpu_ready)
+		return true;
+
+	/* Snet data :
+	 *
+	 * General data: SNET_GENERAL_CFG_LEN bytes long
+	 *  0             0x4       0x8        0xC               0x10      0x14        0x1C     0x24
+	 *  | MAGIC NUMBER | CFG VER | SNET SID | NUMBER OF QUEUES | IRQ IDX | FEATURES |  RSVD  |
+	 *
+	 * For every VQ: SNET_GENERAL_CFG_VQ_LEN bytes long
+	 * 0                          0x4        0x8
+	 * |  VQ SID  AND  QUEUE SIZE | IRQ Index |
+	 * |             DESC AREA                |
+	 * |            DEVICE AREA               |
+	 * |            DRIVER AREA               |
+	 * |             RESERVED                 |
+	 *
+	 * Magic number should be written last, this is the DPU indication that the data is ready
+	 */
+
+	/* Init offset */
+	off = snet->psnet->cfg.host_cfg_off;
+
+	/* Ignore magic number for now */
+	off += 4;
+	snet_write32(snet, off, snet->psnet->negotiated_cfg_ver);
+	off += 4;
+	snet_write32(snet, off, snet->sid);
+	off += 4;
+	snet_write32(snet, off, snet->cfg->vq_num);
+	off += 4;
+	snet_write32(snet, off, snet->cfg_irq_idx);
+	off += 4;
+	snet_write64(snet, off, snet->negotiated_features);
+	off += 8;
+	/* Ignore reserved */
+	off += 8;
+	/* Write VQs */
+	for (i = 0 ; i < snet->cfg->vq_num ; i++) {
+		tmp = (i << 16) | (snet->vqs[i]->num & 0xFFFF);
+		snet_write32(snet, off, tmp);
+		off += 4;
+		snet_write32(snet, off, snet->vqs[i]->irq_idx);
+		off += 4;
+		snet_write64(snet, off, snet->vqs[i]->desc_area);
+		off += 8;
+		snet_write64(snet, off, snet->vqs[i]->device_area);
+		off += 8;
+		snet_write64(snet, off, snet->vqs[i]->driver_area);
+		off += 8;
+		/* Ignore reserved */
+		off += 8;
+	}
+
+	/* Clear snet messages address for this device */
+	snet_write32(snet, snet->psnet->cfg.msg_off, 0);
+	/* Write magic number - data is ready */
+	snet_write32(snet, snet->psnet->cfg.host_cfg_off, SNET_SIGNATURE);
+
+	/* The DPU will ACK the config by clearing the signature */
+	ret = readx_poll_timeout(ioread32, snet->bar + snet->psnet->cfg.host_cfg_off,
+				 tmp, !tmp, 10, SNET_READ_CFG_TIMEOUT);
+	if (ret) {
+		SNET_ERR(snet->pdev, "Timeout waiting for the DPU to read the config\n");
+		return false;
+	}
+
+	/* set DPU flag */
+	snet->dpu_ready = true;
+
+	return true;
+}
+
+static int snet_request_irqs(struct pci_dev *pdev, struct snet *snet)
+{
+	int ret, i, irq;
+
+	/* Request config IRQ */
+	irq = pci_irq_vector(pdev, snet->cfg_irq_idx);
+	ret = devm_request_irq(&pdev->dev, irq, snet_cfg_irq_hndlr, 0,
+			       snet->cfg_irq_name, snet);
+	if (ret) {
+		SNET_ERR(pdev, "Failed to request IRQ\n");
+		return ret;
+	}
+	snet->cfg_irq = irq;
+
+	/* Request IRQ for every VQ */
+	for (i = 0; i < snet->cfg->vq_num; i++) {
+		irq = pci_irq_vector(pdev, snet->vqs[i]->irq_idx);
+		ret = devm_request_irq(&pdev->dev, irq, snet_vq_irq_hndlr, 0,
+				       snet->vqs[i]->irq_name, snet->vqs[i]);
+		if (ret) {
+			SNET_ERR(pdev, "Failed to request IRQ\n");
+			return ret;
+		}
+		snet->vqs[i]->irq = irq;
+	}
+	return 0;
+}
+
+static void snet_set_status(struct vdpa_device *vdev, u8 status)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+	struct psnet *psnet = snet->psnet;
+	struct pci_dev *pdev = snet->pdev;
+	int ret;
+	bool pf_irqs;
+
+	if (status == snet->status)
+		return;
+
+	if ((status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+	    !(snet->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+		/* Request IRQs */
+		pf_irqs = PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF);
+		ret = snet_request_irqs(pf_irqs ? pdev->physfn : pdev, snet);
+		if (ret)
+			goto set_err;
+
+		/* Write config to the DPU */
+		if (snet_write_conf(snet)) {
+			SNET_INFO(pdev, "Create SNET[%u] device\n", snet->sid);
+		} else {
+			snet_free_irqs(snet);
+			goto set_err;
+		}
+	}
+
+	/* Save the new status */
+	snet->status = status;
+	return;
+
+set_err:
+	snet->status |= VIRTIO_CONFIG_S_FAILED;
+}
+
+static void snet_get_config(struct vdpa_device *vdev, unsigned int offset,
+			    void *buf, unsigned int len)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+	void __iomem *cfg_ptr = snet->cfg->virtio_cfg + offset;
+	u8 *buf_ptr = buf;
+	u32 i;
+
+	/* check for offset error */
+	if (offset + len > snet->cfg->cfg_size)
+		return;
+
+	/* Write into buffer */
+	for (i = 0; i < len; i++)
+		*buf_ptr++ = ioread8(cfg_ptr + i);
+}
+
+static void snet_set_config(struct vdpa_device *vdev, unsigned int offset,
+			    const void *buf, unsigned int len)
+{
+	struct snet *snet = vdpa_to_snet(vdev);
+	void __iomem *cfg_ptr = snet->cfg->virtio_cfg + offset;
+	const u8 *buf_ptr = buf;
+	u32 i;
+
+	/* check for offset error */
+	if (offset + len > snet->cfg->cfg_size)
+		return;
+
+	/* Write into PCI BAR */
+	for (i = 0; i < len; i++)
+		iowrite8(*buf_ptr++, cfg_ptr + i);
+}
+
+static const struct vdpa_config_ops snet_config_ops = {
+	.set_vq_address         = snet_set_vq_address,
+	.set_vq_num             = snet_set_vq_num,
+	.kick_vq                = snet_kick_vq,
+	.set_vq_cb              = snet_set_vq_cb,
+	.set_vq_ready           = snet_set_vq_ready,
+	.get_vq_ready           = snet_get_vq_ready,
+	.set_vq_state           = snet_set_vq_state,
+	.get_vq_state           = snet_get_vq_state,
+	.get_vq_irq		= snet_get_vq_irq,
+	.get_vq_align           = snet_get_vq_align,
+	.reset                  = snet_reset,
+	.get_config_size        = snet_get_config_size,
+	.get_device_features    = snet_get_features,
+	.set_driver_features    = snet_set_drv_features,
+	.get_driver_features    = snet_get_drv_features,
+	.get_vq_num_min         = snet_get_vq_num_max,
+	.get_vq_num_max         = snet_get_vq_num_max,
+	.set_config_cb          = snet_set_config_cb,
+	.get_device_id          = snet_get_device_id,
+	.get_vendor_id          = snet_get_vendor_id,
+	.get_status             = snet_get_status,
+	.set_status             = snet_set_status,
+	.get_config             = snet_get_config,
+	.set_config             = snet_set_config,
+};
+
+static int psnet_open_pf_bar(struct pci_dev *pdev, struct psnet *psnet)
+{
+	char name[25];
+	int ret, i, mask = 0;
+	/* We don't know which BAR will be used to communicate..
+	 * We will map every bar with len > 0.
+	 *
+	 * Later, we will discover the BAR and unmap all other BARs.
+	 */
+	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+		if (pci_resource_len(pdev, i))
+			mask |= (1 << i);
+	}
+
+	/* No BAR can be used.. */
+	if (!mask) {
+		SNET_ERR(pdev, "Failed to find a PCI BAR\n");
+		return -ENODEV;
+	}
+
+	snprintf(name, SNET_NAME_SIZE, "psnet[%s]-bars", pci_name(pdev));
+	ret = pcim_iomap_regions(pdev, mask, name);
+	if (ret) {
+		SNET_ERR(pdev, "Failed to request and map PCI BARs\n");
+		return ret;
+	}
+
+	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+		if (mask & (1 << i))
+			psnet->bars[i] = pcim_iomap_table(pdev)[i];
+	}
+
+	return 0;
+}
+
+static int snet_open_vf_bar(struct pci_dev *pdev, struct snet *snet)
+{
+	char name[20];
+	int ret;
+
+	snprintf(name, SNET_NAME_SIZE, "snet[%s]-bar", pci_name(pdev));
+	/* Request and map BAR */
+	ret = pcim_iomap_regions(pdev, BIT(snet->psnet->cfg.vf_bar), name);
+	if (ret) {
+		SNET_ERR(pdev, "Failed to request and map PCI BAR for a VF\n");
+		return ret;
+	}
+
+	snet->bar = pcim_iomap_table(pdev)[snet->psnet->cfg.vf_bar];
+
+	return 0;
+}
+
+static void snet_free_cfg(struct snet_cfg *cfg)
+{
+	u32 i;
+
+	if (!cfg->devs)
+		return;
+
+	/* Free devices */
+	for (i = 0; i < cfg->devices_num; i++) {
+		if (!cfg->devs[i])
+			break;
+
+		kfree(cfg->devs[i]);
+	}
+	/* Free pointers to devices */
+	kfree(cfg->devs);
+}
+
+/* Detect which BAR is used for communication with the device. */
+static int psnet_detect_bar(struct psnet *psnet, u32 off)
+{
+	unsigned long exit_time;
+	int i;
+
+	exit_time = jiffies + usecs_to_jiffies(SNET_DETECT_TIMEOUT);
+
+	/* SNET DPU will write SNET's signature when the config is ready. */
+	while (time_before(jiffies, exit_time)) {
+		for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+			/* Is this BAR mapped? */
+			if (!psnet->bars[i])
+				continue;
+
+			if (ioread32(psnet->bars[i] + off) == SNET_SIGNATURE)
+				return i;
+		}
+		usleep_range(1000, 10000);
+	}
+
+	return -ENODEV;
+}
+
+static void psnet_unmap_unused_bars(struct pci_dev *pdev, struct psnet *psnet)
+{
+	int i, mask = 0;
+
+	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
+		if (psnet->bars[i] && i != psnet->barno)
+			mask |= (1 << i);
+	}
+
+	if (mask)
+		pcim_iounmap_regions(pdev, mask);
+}
+
+/* Read SNET config from PCI BAR */
+static int psnet_read_cfg(struct pci_dev *pdev, struct psnet *psnet)
+{
+	struct snet_cfg *cfg = &psnet->cfg;
+	u32 i, off;
+	int barno;
+
+	/* Move to where the config starts */
+	off = SNET_CONFIG_OFF;
+
+	/* Find BAR used for communication */
+	barno = psnet_detect_bar(psnet, off);
+	if (barno < 0) {
+		SNET_ERR(pdev, "SNET config is not ready.\n");
+		return barno;
+	}
+
+	/* Save used BAR number and unmap all other BARs */
+	psnet->barno = barno;
+	SNET_DBG(pdev, "Using BAR number %d\n", barno);
+
+	psnet_unmap_unused_bars(pdev, psnet);
+
+	/* load config from BAR */
+	cfg->key = psnet_read32(psnet, off);
+	off += 4;
+	cfg->cfg_size = psnet_read32(psnet, off);
+	off += 4;
+	cfg->cfg_ver = psnet_read32(psnet, off);
+	off += 4;
+	/* The negotiated config version is the lower one between this driver's config
+	 * and the DPU's.
+	 */
+	psnet->negotiated_cfg_ver = min_t(u32, cfg->cfg_ver, SNET_CFG_VERSION);
+	SNET_DBG(pdev, "SNET config version %u\n", psnet->negotiated_cfg_ver);
+
+	cfg->vf_num = psnet_read32(psnet, off);
+	off += 4;
+	cfg->vf_bar = psnet_read32(psnet, off);
+	off += 4;
+	cfg->host_cfg_off = psnet_read32(psnet, off);
+	off += 4;
+	cfg->max_size_host_cfg = psnet_read32(psnet, off);
+	off += 4;
+	cfg->virtio_cfg_off = psnet_read32(psnet, off);
+	off += 4;
+	cfg->kick_off = psnet_read32(psnet, off);
+	off += 4;
+	cfg->hwmon_off = psnet_read32(psnet, off);
+	off += 4;
+	cfg->msg_off = psnet_read32(psnet, off);
+	off += 4;
+	cfg->flags = psnet_read32(psnet, off);
+	off += 4;
+	/* Ignore Reserved */
+	off += sizeof(cfg->rsvd);
+
+	cfg->devices_num = psnet_read32(psnet, off);
+	off += 4;
+	/* Allocate memory to hold pointer to the devices */
+	cfg->devs = kcalloc(cfg->devices_num, sizeof(void *), GFP_KERNEL);
+	if (!cfg->devs)
+		return -ENOMEM;
+
+	/* Load device configuration from BAR */
+	for (i = 0; i < cfg->devices_num; i++) {
+		cfg->devs[i] = kzalloc(sizeof(*cfg->devs[i]), GFP_KERNEL);
+		if (!cfg->devs[i]) {
+			snet_free_cfg(cfg);
+			return -ENOMEM;
+		}
+		/* Read device config */
+		cfg->devs[i]->virtio_id = psnet_read32(psnet, off);
+		off += 4;
+		cfg->devs[i]->vq_num = psnet_read32(psnet, off);
+		off += 4;
+		cfg->devs[i]->vq_size = psnet_read32(psnet, off);
+		off += 4;
+		cfg->devs[i]->vfid = psnet_read32(psnet, off);
+		off += 4;
+		cfg->devs[i]->features = psnet_read64(psnet, off);
+		off += 8;
+		/* Ignore Reserved */
+		off += sizeof(cfg->devs[i]->rsvd);
+
+		cfg->devs[i]->cfg_size = psnet_read32(psnet, off);
+		off += 4;
+
+		/* Is the config witten to the DPU going to be too big? */
+		if (SNET_GENERAL_CFG_LEN + SNET_GENERAL_CFG_VQ_LEN * cfg->devs[i]->vq_num >
+		    cfg->max_size_host_cfg) {
+			SNET_ERR(pdev, "Failed to read SNET config, the config is too big..\n");
+			snet_free_cfg(cfg);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static int psnet_alloc_irq_vector(struct pci_dev *pdev, struct psnet *psnet)
+{
+	int ret = 0;
+	u32 i, irq_num = 0;
+
+	/* Let's count how many IRQs we need, 1 for every VQ + 1 for config change */
+	for (i = 0; i < psnet->cfg.devices_num; i++)
+		irq_num += psnet->cfg.devs[i]->vq_num + 1;
+
+	ret = pci_alloc_irq_vectors(pdev, irq_num, irq_num, PCI_IRQ_MSIX);
+	if (ret != irq_num) {
+		SNET_ERR(pdev, "Failed to allocate IRQ vectors\n");
+		return ret;
+	}
+	SNET_DBG(pdev, "Allocated %u IRQ vectors from physical function\n", irq_num);
+
+	return 0;
+}
+
+static int snet_alloc_irq_vector(struct pci_dev *pdev, struct snet_dev_cfg *snet_cfg)
+{
+	int ret = 0;
+	u32 irq_num;
+
+	/* We want 1 IRQ for every VQ + 1 for config change events */
+	irq_num = snet_cfg->vq_num + 1;
+
+	ret = pci_alloc_irq_vectors(pdev, irq_num, irq_num, PCI_IRQ_MSIX);
+	if (ret <= 0) {
+		SNET_ERR(pdev, "Failed to allocate IRQ vectors\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void snet_free_vqs(struct snet *snet)
+{
+	u32 i;
+
+	if (!snet->vqs)
+		return;
+
+	for (i = 0 ; i < snet->cfg->vq_num ; i++) {
+		if (!snet->vqs[i])
+			break;
+
+		kfree(snet->vqs[i]);
+	}
+	kfree(snet->vqs);
+}
+
+static int snet_build_vqs(struct snet *snet)
+{
+	u32 i;
+	/* Allocate the VQ pointers array */
+	snet->vqs = kcalloc(snet->cfg->vq_num, sizeof(void *), GFP_KERNEL);
+	if (!snet->vqs)
+		return -ENOMEM;
+
+	/* Allocate the VQs */
+	for (i = 0; i < snet->cfg->vq_num; i++) {
+		snet->vqs[i] = kzalloc(sizeof(*snet->vqs[i]), GFP_KERNEL);
+		if (!snet->vqs[i]) {
+			snet_free_vqs(snet);
+			return -ENOMEM;
+		}
+		/* Reset IRQ num */
+		snet->vqs[i]->irq = -1;
+		/* VQ serial ID */
+		snet->vqs[i]->sid = i;
+		/* Kick address - every VQ gets 4B */
+		snet->vqs[i]->kick_ptr = snet->bar + snet->psnet->cfg.kick_off +
+					 snet->vqs[i]->sid * 4;
+		/* Clear kick address for this VQ */
+		iowrite32(0, snet->vqs[i]->kick_ptr);
+	}
+	return 0;
+}
+
+static int psnet_get_next_irq_num(struct psnet *psnet)
+{
+	int irq;
+
+	spin_lock(&psnet->lock);
+	irq = psnet->next_irq++;
+	spin_unlock(&psnet->lock);
+
+	return irq;
+}
+
+static void snet_reserve_irq_idx(struct pci_dev *pdev, struct snet *snet)
+{
+	struct psnet *psnet = snet->psnet;
+	int  i;
+
+	/* one IRQ for every VQ, and one for config changes */
+	snet->cfg_irq_idx = psnet_get_next_irq_num(psnet);
+	snprintf(snet->cfg_irq_name, SNET_NAME_SIZE, "snet[%s]-cfg[%d]",
+		 pci_name(pdev), snet->cfg_irq_idx);
+
+	for (i = 0; i < snet->cfg->vq_num; i++) {
+		/* Get next free IRQ ID */
+		snet->vqs[i]->irq_idx = psnet_get_next_irq_num(psnet);
+		/* Write IRQ name */
+		snprintf(snet->vqs[i]->irq_name, SNET_NAME_SIZE, "snet[%s]-vq[%d]",
+			 pci_name(pdev), snet->vqs[i]->irq_idx);
+	}
+}
+
+/* Find a device config based on virtual function id */
+static struct snet_dev_cfg *snet_find_dev_cfg(struct snet_cfg *cfg, u32 vfid)
+{
+	u32 i;
+
+	for (i = 0; i < cfg->devices_num; i++) {
+		if (cfg->devs[i]->vfid == vfid)
+			return cfg->devs[i];
+	}
+	/* Oppss.. no config found.. */
+	return NULL;
+}
+
+/* Probe function for a physical PCI function */
+static int snet_vdpa_probe_pf(struct pci_dev *pdev)
+{
+	struct psnet *psnet;
+	int ret = 0;
+	bool pf_irqs = false;
+
+	ret = pcim_enable_device(pdev);
+	if (ret) {
+		SNET_ERR(pdev, "Failed to enable PCI device\n");
+		return ret;
+	}
+
+	/* Allocate a PCI physical function device */
+	psnet = kzalloc(sizeof(*psnet), GFP_KERNEL);
+	if (!psnet)
+		return -ENOMEM;
+
+	/* Init PSNET spinlock */
+	spin_lock_init(&psnet->lock);
+
+	pci_set_master(pdev);
+	pci_set_drvdata(pdev, psnet);
+
+	/* Open SNET MAIN BAR */
+	ret = psnet_open_pf_bar(pdev, psnet);
+	if (ret)
+		goto free_psnet;
+
+	/* Try to read SNET's config from PCI BAR */
+	ret = psnet_read_cfg(pdev, psnet);
+	if (ret)
+		goto free_psnet;
+
+	/* If SNET_CFG_FLAG_IRQ_PF flag is set, we should use
+	 * PF MSI-X vectors
+	 */
+	pf_irqs = PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF);
+
+	if (pf_irqs) {
+		ret = psnet_alloc_irq_vector(pdev, psnet);
+		if (ret)
+			goto free_cfg;
+	}
+
+	SNET_DBG(pdev, "Enable %u virtual functions\n", psnet->cfg.vf_num);
+	ret = pci_enable_sriov(pdev, psnet->cfg.vf_num);
+	if (ret) {
+		SNET_ERR(pdev, "Failed to enable SR-IOV\n");
+		goto free_irq;
+	}
+
+	/* Create HW monitor device */
+	if (PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_HWMON)) {
+#if IS_ENABLED(CONFIG_HWMON)
+		psnet_create_hwmon(pdev);
+#else
+		SNET_WARN(pdev, "Can't start HWMON, CONFIG_HWMON is not enabled\n");
+#endif
+	}
+
+	return 0;
+
+free_irq:
+	if (pf_irqs)
+		pci_free_irq_vectors(pdev);
+free_cfg:
+	snet_free_cfg(&psnet->cfg);
+free_psnet:
+	kfree(psnet);
+	return ret;
+}
+
+/* Probe function for a virtual PCI function */
+static int snet_vdpa_probe_vf(struct pci_dev *pdev)
+{
+	struct pci_dev *pdev_pf = pdev->physfn;
+	struct psnet *psnet = pci_get_drvdata(pdev_pf);
+	struct snet_dev_cfg *dev_cfg;
+	struct snet *snet;
+	u32 vfid;
+	int ret;
+	bool pf_irqs = false;
+
+	/* Get virtual function id.
+	 * (the DPU counts the VFs from 1)
+	 */
+	ret = pci_iov_vf_id(pdev);
+	if (ret < 0) {
+		SNET_ERR(pdev, "Failed to find a VF id\n");
+		return ret;
+	}
+	vfid = ret + 1;
+
+	/* Find the snet_dev_cfg based on vfid */
+	dev_cfg = snet_find_dev_cfg(&psnet->cfg, vfid);
+	if (!dev_cfg) {
+		SNET_WARN(pdev, "Failed to find a VF config..\n");
+		return -ENODEV;
+	}
+
+	/* Which PCI device should allocate the IRQs?
+	 * If the SNET_CFG_FLAG_IRQ_PF flag set, the PF device allocates the IRQs
+	 */
+	pf_irqs = PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF);
+
+	ret = pcim_enable_device(pdev);
+	if (ret) {
+		SNET_ERR(pdev, "Failed to enable PCI VF device\n");
+		return ret;
+	}
+
+	/* Request for MSI-X IRQs */
+	if (!pf_irqs) {
+		ret = snet_alloc_irq_vector(pdev, dev_cfg);
+		if (ret)
+			return ret;
+	}
+
+	/* Allocate vdpa device */
+	snet = vdpa_alloc_device(struct snet, vdpa, &pdev->dev, &snet_config_ops, 1, 1, NULL,
+				 false);
+	if (!snet) {
+		SNET_ERR(pdev, "Failed to allocate a vdpa device\n");
+		ret = -ENOMEM;
+		goto free_irqs;
+	}
+
+	/* Save pci device pointer */
+	snet->pdev = pdev;
+	snet->psnet = psnet;
+	snet->cfg = dev_cfg;
+	snet->dpu_ready = false;
+	snet->sid = vfid;
+	/* Reset IRQ value */
+	snet->cfg_irq = -1;
+
+	ret = snet_open_vf_bar(pdev, snet);
+	if (ret)
+		goto put_device;
+
+	/* Create a VirtIO config pointer */
+	snet->cfg->virtio_cfg = snet->bar + snet->psnet->cfg.virtio_cfg_off;
+
+	pci_set_master(pdev);
+	pci_set_drvdata(pdev, snet);
+
+	ret = snet_build_vqs(snet);
+	if (ret)
+		goto put_device;
+
+	/* Reserve IRQ indexes,
+	 * The IRQs may be requested and freed multiple times,
+	 * but the indexes won't change.
+	 */
+	snet_reserve_irq_idx(pf_irqs ? pdev_pf : pdev, snet);
+
+	/*set DMA device*/
+	snet->vdpa.dma_dev = &pdev->dev;
+
+	/* Register VDPA device */
+	ret = vdpa_register_device(&snet->vdpa, snet->cfg->vq_num);
+	if (ret) {
+		SNET_ERR(pdev, "Failed to register vdpa device\n");
+		goto free_vqs;
+	}
+
+	return 0;
+
+free_vqs:
+	snet_free_vqs(snet);
+put_device:
+	put_device(&snet->vdpa.dev);
+free_irqs:
+	if (!pf_irqs)
+		pci_free_irq_vectors(pdev);
+	return ret;
+}
+
+static int snet_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	if (pdev->is_virtfn)
+		return snet_vdpa_probe_vf(pdev);
+	else
+		return snet_vdpa_probe_pf(pdev);
+}
+
+static void snet_vdpa_remove_pf(struct pci_dev *pdev)
+{
+	struct psnet *psnet = pci_get_drvdata(pdev);
+
+	pci_disable_sriov(pdev);
+	/* If IRQs are allocated from the PF, we should free the IRQs */
+	if (PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF))
+		pci_free_irq_vectors(pdev);
+
+	snet_free_cfg(&psnet->cfg);
+	kfree(psnet);
+}
+
+static void snet_vdpa_remove_vf(struct pci_dev *pdev)
+{
+	struct snet *snet = pci_get_drvdata(pdev);
+	struct psnet *psnet = snet->psnet;
+
+	/* If IRQs are allocated from the VF, we should free the IRQs */
+	if (!PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF))
+		pci_free_irq_vectors(pdev);
+
+	vdpa_unregister_device(&snet->vdpa);
+	snet_free_vqs(snet);
+}
+
+static void snet_vdpa_remove(struct pci_dev *pdev)
+{
+	if (pdev->is_virtfn)
+		snet_vdpa_remove_vf(pdev);
+	else
+		snet_vdpa_remove_pf(pdev);
+}
+
+static struct pci_device_id snet_driver_pci_ids[] = {
+	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_SOLIDRUN, SNET_DEVICE_ID,
+			 PCI_VENDOR_ID_SOLIDRUN, SNET_DEVICE_ID) },
+	{ 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, snet_driver_pci_ids);
+
+static struct pci_driver snet_vdpa_driver = {
+	.name		= "snet-vdpa-driver",
+	.id_table	= snet_driver_pci_ids,
+	.probe		= snet_vdpa_probe,
+	.remove		= snet_vdpa_remove,
+};
+
+module_pci_driver(snet_vdpa_driver);
+
+MODULE_AUTHOR("Alvaro Karsz <alvaro.karsz@solid-run.com>");
+MODULE_DESCRIPTION("SolidRun vDPA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/vdpa/solidrun/snet_vdpa.h b/drivers/vdpa/solidrun/snet_vdpa.h
new file mode 100644
index 00000000000..3ebfb7deec4
--- /dev/null
+++ b/drivers/vdpa/solidrun/snet_vdpa.h
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * SolidRun DPU driver for control plane
+ *
+ * Copyright (C) 2022 SolidRun
+ *
+ * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>
+ *
+ */
+#ifndef _SNET_VDPA_H_
+#define _SNET_VDPA_H_
+
+#include <linux/vdpa.h>
+#include <linux/pci.h>
+
+#define SNET_NAME_SIZE 256
+
+#define SNET_ERR(pdev, fmt, ...) dev_err(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
+#define SNET_WARN(pdev, fmt, ...) dev_warn(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
+#define SNET_INFO(pdev, fmt, ...) dev_info(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
+#define SNET_DBG(pdev, fmt, ...) dev_dbg(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
+#define SNET_HAS_FEATURE(s, f) ((s)->negotiated_features & BIT_ULL(f))
+/* VQ struct */
+struct snet_vq {
+	/* VQ callback */
+	struct vdpa_callback cb;
+	/* desc base address */
+	u64 desc_area;
+	/* device base address */
+	u64 device_area;
+	/* driver base address */
+	u64 driver_area;
+	/* Queue size */
+	u32 num;
+	/* Serial ID for VQ */
+	u32 sid;
+	/* is ready flag */
+	bool ready;
+	/* IRQ number */
+	u32 irq;
+	/* IRQ index, DPU uses this to parse data from MSI-X table */
+	u32 irq_idx;
+	/* IRQ name */
+	char irq_name[SNET_NAME_SIZE];
+	/* pointer to mapped PCI BAR register used by this VQ to kick */
+	void __iomem *kick_ptr;
+};
+
+struct snet {
+	/* vdpa device */
+	struct vdpa_device vdpa;
+	/* Config callback */
+	struct vdpa_callback cb;
+	/* array of virqueues */
+	struct snet_vq **vqs;
+	/* Used features */
+	u64 negotiated_features;
+	/* Device serial ID */
+	u32 sid;
+	/* device status */
+	u8 status;
+	/* boolean indicating if snet config was passed to the device */
+	bool dpu_ready;
+	/* IRQ number */
+	u32 cfg_irq;
+	/* IRQ index, DPU uses this to parse data from MSI-X table */
+	u32 cfg_irq_idx;
+	/* IRQ name */
+	char cfg_irq_name[SNET_NAME_SIZE];
+	/* BAR to access the VF */
+	void __iomem *bar;
+	/* PCI device */
+	struct pci_dev *pdev;
+	/* Pointer to snet pdev parent device */
+	struct psnet *psnet;
+	/* Pointer to snet config device */
+	struct snet_dev_cfg *cfg;
+};
+
+struct snet_dev_cfg {
+	/* Device ID following VirtIO spec. */
+	u32 virtio_id;
+	/* Number of VQs for this device */
+	u32 vq_num;
+	/* Size of every VQ */
+	u32 vq_size;
+	/* Virtual Function id */
+	u32 vfid;
+	/* Device features, following VirtIO spec */
+	u64 features;
+	/* Reserved for future usage */
+	u32 rsvd[6];
+	/* VirtIO device specific config size */
+	u32 cfg_size;
+	/* VirtIO device specific config address */
+	void __iomem *virtio_cfg;
+} __packed;
+
+struct snet_cfg {
+	/* Magic key */
+	u32 key;
+	/* Size of total config in bytes */
+	u32 cfg_size;
+	/* Config version */
+	u32 cfg_ver;
+	/* Number of Virtual Functions to create */
+	u32 vf_num;
+	/* BAR to use for the VFs */
+	u32 vf_bar;
+	/* Where should we write the SNET's config */
+	u32 host_cfg_off;
+	/* Max. allowed size for a SNET's config */
+	u32 max_size_host_cfg;
+	/* VirtIO config offset in BAR */
+	u32 virtio_cfg_off;
+	/* Offset in PCI BAR for VQ kicks */
+	u32 kick_off;
+	/* Offset in PCI BAR for HW monitoring */
+	u32 hwmon_off;
+	/* Offset in PCI BAR for SNET messages */
+	u32 msg_off;
+	/* Config general flags - enum snet_cfg_flags */
+	u32 flags;
+	/* Reserved for future usage */
+	u32 rsvd[6];
+	/* Number of snet devices */
+	u32 devices_num;
+	/* The actual devices */
+	struct snet_dev_cfg **devs;
+} __packed;
+
+/* SolidNET PCIe device, one device per PCIe physical function */
+struct psnet {
+	/* PCI BARs */
+	void __iomem *bars[PCI_STD_NUM_BARS];
+	/* Negotiated config version */
+	u32 negotiated_cfg_ver;
+	/* Next IRQ index to use in case when the IRQs are allocated from this device */
+	u32 next_irq;
+	/* BAR number used to communicate with the device */
+	u8 barno;
+	/* spinlock to protect data that can be changed by SNET devices */
+	spinlock_t lock;
+	/* Pointer to the device's config read from BAR */
+	struct snet_cfg cfg;
+	/* Name of monitor device */
+	char hwmon_name[SNET_NAME_SIZE];
+};
+
+enum snet_cfg_flags {
+	/* Create a HWMON device */
+	SNET_CFG_FLAG_HWMON = BIT(0),
+	/* USE IRQs from the physical function */
+	SNET_CFG_FLAG_IRQ_PF = BIT(1),
+};
+
+#define PSNET_FLAG_ON(p, f)	((p)->cfg.flags & (f))
+
+static inline u32 psnet_read32(struct psnet *psnet, u32 off)
+{
+	return ioread32(psnet->bars[psnet->barno] + off);
+}
+
+static inline u32 snet_read32(struct snet *snet, u32 off)
+{
+	return ioread32(snet->bar + off);
+}
+
+static inline void snet_write32(struct snet *snet, u32 off, u32 val)
+{
+	iowrite32(val, snet->bar + off);
+}
+
+static inline u64 psnet_read64(struct psnet *psnet, u32 off)
+{
+	u64 val;
+	/* 64bits are written in 2 halves, low part first */
+	val = (u64)psnet_read32(psnet, off);
+	val |= ((u64)psnet_read32(psnet, off + 4) << 32);
+	return val;
+}
+
+static inline void snet_write64(struct snet *snet, u32 off, u64 val)
+{
+	/* The DPU expects a 64bit integer in 2 halves, the low part first */
+	snet_write32(snet, off, (u32)val);
+	snet_write32(snet, off + 4, (u32)(val >> 32));
+}
+
+#if IS_ENABLED(CONFIG_HWMON)
+void psnet_create_hwmon(struct pci_dev *pdev);
+#else
+void psnet_create_hwmon(struct pci_dev *pdev) {}
+#endif
+
+#endif //_SNET_VDPA_H_
-- 
2.32.0


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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-19  8:35 ` [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver Alvaro Karsz
@ 2022-12-19 10:43   ` Michael S. Tsirkin
  2022-12-19 10:44     ` Michael S. Tsirkin
  2022-12-19 10:49   ` Michael S. Tsirkin
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2022-12-19 10:43 UTC (permalink / raw)
  To: Alvaro Karsz
  Cc: virtualization, linux-pci, Jean Delvare, bhelgaas, Guenter Roeck

On Mon, Dec 19, 2022 at 10:35:11AM +0200, Alvaro Karsz wrote:
> This commit includes:
>  1) The driver to manage the controlplane over vDPA bus.
>  2) A HW monitor device to read health values from the DPU.
> 
> Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>

As far as I can tell patches 1,2 are upstream right?
So you can just post patch 3.


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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-19 10:43   ` Michael S. Tsirkin
@ 2022-12-19 10:44     ` Michael S. Tsirkin
  0 siblings, 0 replies; 26+ messages in thread
From: Michael S. Tsirkin @ 2022-12-19 10:44 UTC (permalink / raw)
  To: Alvaro Karsz
  Cc: virtualization, linux-pci, Jean Delvare, bhelgaas, Guenter Roeck

On Mon, Dec 19, 2022 at 05:43:55AM -0500, Michael S. Tsirkin wrote:
> On Mon, Dec 19, 2022 at 10:35:11AM +0200, Alvaro Karsz wrote:
> > This commit includes:
> >  1) The driver to manage the controlplane over vDPA bus.
> >  2) A HW monitor device to read health values from the DPU.
> > 
> > Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>
> 
> As far as I can tell patches 1,2 are upstream right?
> So you can just post patch 3.

Oh my bad pls ignore.


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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-19  8:35 ` [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver Alvaro Karsz
  2022-12-19 10:43   ` Michael S. Tsirkin
@ 2022-12-19 10:49   ` Michael S. Tsirkin
  2022-12-19 10:55     ` Alvaro Karsz
  2022-12-20  6:50   ` Jason Wang
  2022-12-20 16:32   ` Nathan Chancellor
  3 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2022-12-19 10:49 UTC (permalink / raw)
  To: Alvaro Karsz
  Cc: virtualization, linux-pci, Jean Delvare, bhelgaas, Guenter Roeck

On Mon, Dec 19, 2022 at 10:35:11AM +0200, Alvaro Karsz wrote:
> This commit includes:
>  1) The driver to manage the controlplane over vDPA bus.
>  2) A HW monitor device to read health values from the DPU.
> 
> Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>
> --
> v2:
> 	- Auto detect the BAR used for communication.
> 	- When waiting for the DPU to write a config, wait for 5secs
> 	  before giving up on the device.
> 	- Return EOPNOTSUPP error code in vDPA set_vq_state callback if
> 	  the vq state is not the same as the initial one.
> 	- Implement a vDPA reset callback.
> 	- Wait for an ACK when sending a message to the DPU.
> 	- Add endianness comments on 64bit read/write functions.
> 	- Remove the get_iova_range and free vDPA callbacks.
> 	- Usage of managed device functions to ioremap a region.
> 	- Call pci_set_drvdata and pci_set_master before
> 	  vdpa_register_device.
> 	- Create DMA isolation between the vDPA devices by using the
> 	  chip SR-IOV feature.
> 	  Every vDPA device gets a PCIe VF with its own DMA device.
> 
> v3:
> 	- Validate vDPA config length while receiving the DPU's config,
> 	  not while trying to write the vDPA config to the DPU.
> 	- Request IRQs when vDPA status is set to
> 	  VIRTIO_CONFIG_S_DRIVER_OK.
> 	- Remove snet_reset_dev() from the PCI remove function for a VF.
> v4:
> 	- Get SolidRun vendor ID from pci_ids
> v5:
> 	- Remove "select HWMON" from Kconfig.
> 	  Usage of "depends on HWMON || HWMON=n" instead and usage of
> 	  IS_ENABLED(CONFIG_HWMON) when calling to snet hwmon functions.
> 	  snet_hwmon.c is compiled only if CONFIG_HWMON is defined.
> 	- Remove the  #include <linux/hwmon-sysfs.h> from snet_hwmon.c.
> 	- Remove the unnecessary (long) casting from snet_hwmon_read_reg.
> 	- Remove the "_hwmon" ending from the hwmon name.
> 	- Usage of IS_ERR macro to check if devm_hwmon_device_register_with_info
> 	  failed.
> 	- Replace schedule() with usleep_range() in the "hot loop" in
> 	  psnet_detect_bar.
> 	- Remove the logging of memory allocation failures.
> 	- Add parenthesis to arguments in SNET_* macros.
> 	- Prefer sizeof(*variable) instead of sizeof(struct x) when allocating
> 	  memory.
> v6:
> 	- SNET_WRN -> SNET_WARN.
> ---
>  MAINTAINERS                        |    4 +
>  drivers/vdpa/Kconfig               |   10 +
>  drivers/vdpa/Makefile              |    1 +
>  drivers/vdpa/solidrun/Makefile     |    6 +
>  drivers/vdpa/solidrun/snet_hwmon.c |  188 +++++
>  drivers/vdpa/solidrun/snet_main.c  | 1111 ++++++++++++++++++++++++++++
>  drivers/vdpa/solidrun/snet_vdpa.h  |  196 +++++
>  7 files changed, 1516 insertions(+)
>  create mode 100644 drivers/vdpa/solidrun/Makefile
>  create mode 100644 drivers/vdpa/solidrun/snet_hwmon.c
>  create mode 100644 drivers/vdpa/solidrun/snet_main.c
>  create mode 100644 drivers/vdpa/solidrun/snet_vdpa.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a608f19da3a..7f4d9dcb760 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -21955,6 +21955,10 @@ IFCVF VIRTIO DATA PATH ACCELERATOR
>  R:	Zhu Lingshan <lingshan.zhu@intel.com>
>  F:	drivers/vdpa/ifcvf/
>  
> +SNET DPU VIRTIO DATA PATH ACCELERATOR
> +R:	Alvaro Karsz <alvaro.karsz@solid-run.com>
> +F:	drivers/vdpa/solidrun/
> +
>  VIRTIO BALLOON
>  M:	"Michael S. Tsirkin" <mst@redhat.com>
>  M:	David Hildenbrand <david@redhat.com>
> diff --git a/drivers/vdpa/Kconfig b/drivers/vdpa/Kconfig
> index 50f45d03761..79625c7cc46 100644
> --- a/drivers/vdpa/Kconfig
> +++ b/drivers/vdpa/Kconfig
> @@ -86,4 +86,14 @@ config ALIBABA_ENI_VDPA
>  	  VDPA driver for Alibaba ENI (Elastic Network Interface) which is built upon
>  	  virtio 0.9.5 specification.
>  
> + config SNET_VDPA
> +	tristate "SolidRun's vDPA driver for SolidNET"
> +	depends on PCI_MSI && PCI_IOV && (HWMON || HWMON=n)

could we add a comment explaining this trick please?
can be patch on top ...

> +	help
> +	  vDPA driver for SolidNET DPU.
> +	  With this driver, the VirtIO dataplane can be
> +	  offloaded to a SolidNET DPU.
> +	  This driver includes a HW monitor device that
> +	  reads health values from the DPU.
> +
>  endif # VDPA
> diff --git a/drivers/vdpa/Makefile b/drivers/vdpa/Makefile
> index 15665563a7f..59396ff2a31 100644
> --- a/drivers/vdpa/Makefile
> +++ b/drivers/vdpa/Makefile
> @@ -6,3 +6,4 @@ obj-$(CONFIG_IFCVF)    += ifcvf/
>  obj-$(CONFIG_MLX5_VDPA) += mlx5/
>  obj-$(CONFIG_VP_VDPA)    += virtio_pci/
>  obj-$(CONFIG_ALIBABA_ENI_VDPA) += alibaba/
> +obj-$(CONFIG_SNET_VDPA) += solidrun/
> diff --git a/drivers/vdpa/solidrun/Makefile b/drivers/vdpa/solidrun/Makefile
> new file mode 100644
> index 00000000000..c0aa3415bf7
> --- /dev/null
> +++ b/drivers/vdpa/solidrun/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0
> +obj-$(CONFIG_SNET_VDPA) += snet_vdpa.o
> +snet_vdpa-$(CONFIG_SNET_VDPA) += snet_main.o
> +ifdef CONFIG_HWMON
> +snet_vdpa-$(CONFIG_SNET_VDPA) += snet_hwmon.o
> +endif
> diff --git a/drivers/vdpa/solidrun/snet_hwmon.c b/drivers/vdpa/solidrun/snet_hwmon.c
> new file mode 100644
> index 00000000000..e695e36ff75
> --- /dev/null
> +++ b/drivers/vdpa/solidrun/snet_hwmon.c
> @@ -0,0 +1,188 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * SolidRun DPU driver for control plane
> + *
> + * Copyright (C) 2022 SolidRun
> + *
> + * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>
> + *
> + */
> +#include <linux/hwmon.h>
> +
> +#include "snet_vdpa.h"
> +
> +/* Monitor offsets */
> +#define SNET_MON_TMP0_IN_OFF      0x00
> +#define SNET_MON_TMP0_MAX_OFF     0x08
> +#define SNET_MON_TMP0_CRIT_OFF    0x10
> +#define SNET_MON_TMP1_IN_OFF      0x18
> +#define SNET_MON_TMP1_CRIT_OFF    0x20
> +#define SNET_MON_CURR_IN_OFF      0x28
> +#define SNET_MON_CURR_MAX_OFF     0x30
> +#define SNET_MON_CURR_CRIT_OFF    0x38
> +#define SNET_MON_PWR_IN_OFF       0x40
> +#define SNET_MON_VOLT_IN_OFF      0x48
> +#define SNET_MON_VOLT_CRIT_OFF    0x50
> +#define SNET_MON_VOLT_LCRIT_OFF   0x58
> +
> +static void snet_hwmon_read_reg(struct psnet *psnet, u32 reg, long *out)
> +{
> +	*out = psnet_read64(psnet, psnet->cfg.hwmon_off + reg);
> +}
> +
> +static umode_t snet_howmon_is_visible(const void *data,
> +				      enum hwmon_sensor_types type,
> +				      u32 attr, int channel)
> +{
> +	return 0444;
> +}
> +
> +static int snet_howmon_read(struct device *dev, enum hwmon_sensor_types type,
> +			    u32 attr, int channel, long *val)
> +{
> +	struct psnet *psnet = dev_get_drvdata(dev);
> +	int ret = 0;
> +
> +	switch (type) {
> +	case hwmon_in:
> +		switch (attr) {
> +		case hwmon_in_lcrit:
> +			snet_hwmon_read_reg(psnet, SNET_MON_VOLT_LCRIT_OFF, val);
> +			break;
> +		case hwmon_in_crit:
> +			snet_hwmon_read_reg(psnet, SNET_MON_VOLT_CRIT_OFF, val);
> +			break;
> +		case hwmon_in_input:
> +			snet_hwmon_read_reg(psnet, SNET_MON_VOLT_IN_OFF, val);
> +			break;
> +		default:
> +			ret = -EOPNOTSUPP;
> +			break;
> +		}
> +		break;
> +
> +	case hwmon_power:
> +		switch (attr) {
> +		case hwmon_power_input:
> +			snet_hwmon_read_reg(psnet, SNET_MON_PWR_IN_OFF, val);
> +			break;
> +
> +		default:
> +			ret = -EOPNOTSUPP;
> +			break;
> +		}
> +		break;
> +
> +	case hwmon_curr:
> +		switch (attr) {
> +		case hwmon_curr_input:
> +			snet_hwmon_read_reg(psnet, SNET_MON_CURR_IN_OFF, val);
> +			break;
> +		case hwmon_curr_max:
> +			snet_hwmon_read_reg(psnet, SNET_MON_CURR_MAX_OFF, val);
> +			break;
> +		case hwmon_curr_crit:
> +			snet_hwmon_read_reg(psnet, SNET_MON_CURR_CRIT_OFF, val);
> +			break;
> +		default:
> +			ret = -EOPNOTSUPP;
> +			break;
> +		}
> +		break;
> +
> +	case hwmon_temp:
> +		switch (attr) {
> +		case hwmon_temp_input:
> +			if (channel == 0)
> +				snet_hwmon_read_reg(psnet, SNET_MON_TMP0_IN_OFF, val);
> +			else
> +				snet_hwmon_read_reg(psnet, SNET_MON_TMP1_IN_OFF, val);
> +			break;
> +		case hwmon_temp_max:
> +			if (channel == 0)
> +				snet_hwmon_read_reg(psnet, SNET_MON_TMP0_MAX_OFF, val);
> +			else
> +				ret = -EOPNOTSUPP;
> +			break;
> +		case hwmon_temp_crit:
> +			if (channel == 0)
> +				snet_hwmon_read_reg(psnet, SNET_MON_TMP0_CRIT_OFF, val);
> +			else
> +				snet_hwmon_read_reg(psnet, SNET_MON_TMP1_CRIT_OFF, val);
> +			break;
> +
> +		default:
> +			ret = -EOPNOTSUPP;
> +			break;
> +		}
> +		break;
> +
> +	default:
> +		ret = -EOPNOTSUPP;
> +		break;
> +	}
> +	return ret;
> +}
> +
> +static int snet_hwmon_read_string(struct device *dev,
> +				  enum hwmon_sensor_types type, u32 attr,
> +				  int channel, const char **str)
> +{
> +	int ret = 0;
> +
> +	switch (type) {
> +	case hwmon_in:
> +		*str = "main_vin";
> +		break;
> +	case hwmon_power:
> +		*str = "soc_pin";
> +		break;
> +	case hwmon_curr:
> +		*str = "soc_iin";
> +		break;
> +	case hwmon_temp:
> +		if (channel == 0)
> +			*str = "power_stage_temp";
> +		else
> +			*str = "ic_junction_temp";
> +		break;
> +	default:
> +		ret = -EOPNOTSUPP;
> +		break;
> +	}
> +	return ret;
> +}
> +
> +static const struct hwmon_ops snet_hwmon_ops = {
> +	.is_visible = snet_howmon_is_visible,
> +	.read = snet_howmon_read,
> +	.read_string = snet_hwmon_read_string
> +};
> +
> +static const struct hwmon_channel_info *snet_hwmon_info[] = {
> +	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_LABEL,
> +			   HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL),
> +	HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_LABEL),
> +	HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | HWMON_C_LABEL),
> +	HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_CRIT | HWMON_I_LCRIT | HWMON_I_LABEL),
> +			   NULL
> +};
> +
> +static const struct hwmon_chip_info snet_hwmono_info = {
> +	.ops = &snet_hwmon_ops,
> +	.info = snet_hwmon_info,
> +};
> +
> +/* Create an HW monitor device */
> +void psnet_create_hwmon(struct pci_dev *pdev)
> +{
> +	struct device *hwmon;
> +	struct psnet *psnet = pci_get_drvdata(pdev);
> +
> +	snprintf(psnet->hwmon_name, SNET_NAME_SIZE, "snet_%s", pci_name(pdev));
> +	hwmon = devm_hwmon_device_register_with_info(&pdev->dev, psnet->hwmon_name, psnet,
> +						     &snet_hwmono_info, NULL);
> +	/* The monitor is not mandatory, Just alert user in case of an error */
> +	if (IS_ERR(hwmon))
> +		SNET_WARN(pdev, "Failed to create SNET hwmon, error %ld\n", PTR_ERR(hwmon));
> +}
> diff --git a/drivers/vdpa/solidrun/snet_main.c b/drivers/vdpa/solidrun/snet_main.c
> new file mode 100644
> index 00000000000..d438a89b359
> --- /dev/null
> +++ b/drivers/vdpa/solidrun/snet_main.c
> @@ -0,0 +1,1111 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * SolidRun DPU driver for control plane
> + *
> + * Copyright (C) 2022 SolidRun
> + *
> + * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>
> + *
> + */
> +#include <linux/iopoll.h>
> +
> +#include "snet_vdpa.h"
> +
> +/* SNET DPU device ID */
> +#define SNET_DEVICE_ID          0x1000
> +/* SNET signature */
> +#define SNET_SIGNATURE          0xD0D06363
> +/* Max. config version that we can work with */
> +#define SNET_CFG_VERSION        0x1
> +/* Queue align */
> +#define SNET_QUEUE_ALIGNMENT    PAGE_SIZE
> +/* Kick value to notify that new data is available */
> +#define SNET_KICK_VAL           0x1
> +#define SNET_CONFIG_OFF         0x0
> +/* ACK timeout for a message */
> +#define SNET_ACK_TIMEOUT	2000000
> +/* How long we are willing to wait for a SNET device */
> +#define SNET_DETECT_TIMEOUT	5000000
> +/* How long should we wait for the DPU to read our config */
> +#define SNET_READ_CFG_TIMEOUT	3000000
> +/* Size of configs written to the DPU */
> +#define SNET_GENERAL_CFG_LEN	36
> +#define SNET_GENERAL_CFG_VQ_LEN	40
> +
> +enum snet_msg {
> +	SNET_MSG_DESTROY = 1,
> +};
> +
> +static struct snet *vdpa_to_snet(struct vdpa_device *vdpa)
> +{
> +	return container_of(vdpa, struct snet, vdpa);
> +}
> +
> +static int snet_wait_for_msg_ack(struct snet *snet)
> +{
> +	struct pci_dev *pdev = snet->pdev;
> +	int ret;
> +	u32 val;
> +
> +	/* The DPU will clear the messages offset once messages
> +	 * are processed.
> +	 */
> +	ret = readx_poll_timeout(ioread32, snet->bar + snet->psnet->cfg.msg_off,
> +				 val, !val, 10, SNET_ACK_TIMEOUT);
> +	if (ret)
> +		SNET_WARN(pdev, "Timeout waiting for message ACK\n");
> +
> +	return ret;
> +}
> +
> +/* Sends a message to the DPU.
> + * If blocking is set, the function will return once the
> + * message was processed by the DPU (or timeout).
> + */
> +static int snet_send_msg(struct snet *snet, u32 msg, bool blocking)
> +{
> +	int ret = 0;
> +
> +	/* Make sure the DPU acked last message before issuing a new one */
> +	ret = snet_wait_for_msg_ack(snet);
> +	if (ret)
> +		return ret;
> +
> +	/* Write the message */
> +	snet_write32(snet, snet->psnet->cfg.msg_off, msg);
> +
> +	if (blocking)
> +		ret = snet_wait_for_msg_ack(snet);
> +	else /* If non-blocking, flush the write by issuing a read */
> +		snet_read32(snet, snet->psnet->cfg.msg_off);
> +
> +	return ret;
> +}
> +
> +static irqreturn_t snet_cfg_irq_hndlr(int irq, void *data)
> +{
> +	struct snet *snet = data;
> +	/* Call callback if any */
> +	if (snet->cb.callback)
> +		return snet->cb.callback(snet->cb.private);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t snet_vq_irq_hndlr(int irq, void *data)
> +{
> +	struct snet_vq *vq = data;
> +	/* Call callback if any */
> +	if (vq->cb.callback)
> +		return vq->cb.callback(vq->cb.private);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void snet_free_irqs(struct snet *snet)
> +{
> +	struct psnet *psnet = snet->psnet;
> +	struct pci_dev *pdev;
> +	u32 i;
> +
> +	/* Which Device allcoated the IRQs? */
> +	if (PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF))
> +		pdev = snet->pdev->physfn;
> +	else
> +		pdev = snet->pdev;
> +
> +	/* Free config's IRQ */
> +	if (snet->cfg_irq != -1) {
> +		devm_free_irq(&pdev->dev, snet->cfg_irq, snet);
> +		snet->cfg_irq = -1;
> +	}
> +	/* Free VQ IRQs */
> +	for (i = 0; i < snet->cfg->vq_num; i++) {
> +		if (snet->vqs[i] && snet->vqs[i]->irq != -1) {
> +			devm_free_irq(&pdev->dev, snet->vqs[i]->irq, snet->vqs[i]);
> +			snet->vqs[i]->irq = -1;
> +		}
> +	}
> +
> +	/* IRQ vectors are freed when the pci remove callback is called */
> +}
> +
> +static int snet_set_vq_address(struct vdpa_device *vdev, u16 idx, u64 desc_area,
> +			       u64 driver_area, u64 device_area)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +	/* save received parameters in vqueue sturct */
> +	snet->vqs[idx]->desc_area = desc_area;
> +	snet->vqs[idx]->driver_area = driver_area;
> +	snet->vqs[idx]->device_area = device_area;
> +
> +	return 0;
> +}
> +
> +static void snet_set_vq_num(struct vdpa_device *vdev, u16 idx, u32 num)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +	/* save num in vqueue */
> +	snet->vqs[idx]->num = num;
> +}
> +
> +static void snet_kick_vq(struct vdpa_device *vdev, u16 idx)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +	/* not ready - ignore */
> +	if (!snet->vqs[idx]->ready)
> +		return;
> +
> +	iowrite32(SNET_KICK_VAL, snet->vqs[idx]->kick_ptr);
> +}
> +
> +static void snet_set_vq_cb(struct vdpa_device *vdev, u16 idx, struct vdpa_callback *cb)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	snet->vqs[idx]->cb.callback = cb->callback;
> +	snet->vqs[idx]->cb.private = cb->private;
> +}
> +
> +static void snet_set_vq_ready(struct vdpa_device *vdev, u16 idx, bool ready)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	snet->vqs[idx]->ready = ready;
> +}
> +
> +static bool snet_get_vq_ready(struct vdpa_device *vdev, u16 idx)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	return snet->vqs[idx]->ready;
> +}
> +
> +static int snet_set_vq_state(struct vdpa_device *vdev, u16 idx, const struct vdpa_vq_state *state)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +	/* Setting the VQ state is not supported.
> +	 * If the asked state is the same as the initial one
> +	 * we can ignore it.
> +	 */
> +	if (SNET_HAS_FEATURE(snet, VIRTIO_F_RING_PACKED)) {
> +		const struct vdpa_vq_state_packed *p = &state->packed;
> +
> +		if (p->last_avail_counter == 1 && p->last_used_counter == 1 &&
> +		    p->last_avail_idx == 0 && p->last_used_idx == 0)
> +			return 0;
> +	} else {
> +		const struct vdpa_vq_state_split *s = &state->split;
> +
> +		if (s->avail_index == 0)
> +			return 0;
> +	}
> +
> +	return -EOPNOTSUPP;
> +}
> +
> +static int snet_get_vq_state(struct vdpa_device *vdev, u16 idx, struct vdpa_vq_state *state)
> +{
> +	/* Not supported */
> +	return -EOPNOTSUPP;
> +}
> +
> +static int snet_get_vq_irq(struct vdpa_device *vdev, u16 idx)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	return snet->vqs[idx]->irq;
> +}
> +
> +static u32 snet_get_vq_align(struct vdpa_device *vdev)
> +{
> +	return (u32)SNET_QUEUE_ALIGNMENT;
> +}
> +
> +static int snet_reset_dev(struct snet *snet)
> +{
> +	struct pci_dev *pdev = snet->pdev;
> +	int ret = 0;
> +	u32 i;
> +
> +	/* If status is 0, nothing to do */
> +	if (!snet->status)
> +		return 0;
> +
> +	/* If DPU started, send a destroy message */
> +	if (snet->status & VIRTIO_CONFIG_S_DRIVER_OK)
> +		ret = snet_send_msg(snet, SNET_MSG_DESTROY, true);
> +
> +	/* Clear VQs */
> +	for (i = 0; i < snet->cfg->vq_num; i++) {
> +		if (!snet->vqs[i])
> +			continue;
> +		snet->vqs[i]->cb.callback = NULL;
> +		snet->vqs[i]->cb.private = NULL;
> +		snet->vqs[i]->desc_area = 0;
> +		snet->vqs[i]->device_area = 0;
> +		snet->vqs[i]->driver_area = 0;
> +		snet->vqs[i]->ready = false;
> +	}
> +
> +	/* Clear config callback */
> +	snet->cb.callback = NULL;
> +	snet->cb.private = NULL;
> +	/* Free IRQs */
> +	snet_free_irqs(snet);
> +	/* Reset status */
> +	snet->status = 0;
> +
> +	if (ret)
> +		SNET_WARN(pdev, "Incomplete reset to SNET[%u] device\n", snet->sid);
> +	else
> +		SNET_DBG(pdev, "Reset SNET[%u] device\n", snet->sid);
> +
> +	return 0;
> +}
> +
> +static int snet_reset(struct vdpa_device *vdev)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	return snet_reset_dev(snet);
> +}
> +
> +static size_t snet_get_config_size(struct vdpa_device *vdev)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	return (size_t)snet->cfg->cfg_size;
> +}
> +
> +static u64 snet_get_features(struct vdpa_device *vdev)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	return snet->cfg->features;
> +}
> +
> +static int snet_set_drv_features(struct vdpa_device *vdev, u64 features)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	snet->negotiated_features = snet->cfg->features & features;
> +	return 0;
> +}
> +
> +static u64 snet_get_drv_features(struct vdpa_device *vdev)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	return snet->negotiated_features;
> +}
> +
> +static u16 snet_get_vq_num_max(struct vdpa_device *vdev)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	return (u16)snet->cfg->vq_size;
> +}
> +
> +static void snet_set_config_cb(struct vdpa_device *vdev, struct vdpa_callback *cb)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	snet->cb.callback = cb->callback;
> +	snet->cb.private = cb->private;
> +}
> +
> +static u32 snet_get_device_id(struct vdpa_device *vdev)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	return snet->cfg->virtio_id;
> +}
> +
> +static u32 snet_get_vendor_id(struct vdpa_device *vdev)
> +{
> +	return (u32)PCI_VENDOR_ID_SOLIDRUN;
> +}
> +
> +static u8 snet_get_status(struct vdpa_device *vdev)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +
> +	return snet->status;
> +}
> +
> +static int snet_write_conf(struct snet *snet)
> +{
> +	u32 off, i, tmp;
> +	int ret;
> +
> +	/* No need to write the config twice */
> +	if (snet->dpu_ready)
> +		return true;
> +
> +	/* Snet data :
> +	 *
> +	 * General data: SNET_GENERAL_CFG_LEN bytes long
> +	 *  0             0x4       0x8        0xC               0x10      0x14        0x1C     0x24
> +	 *  | MAGIC NUMBER | CFG VER | SNET SID | NUMBER OF QUEUES | IRQ IDX | FEATURES |  RSVD  |
> +	 *
> +	 * For every VQ: SNET_GENERAL_CFG_VQ_LEN bytes long
> +	 * 0                          0x4        0x8
> +	 * |  VQ SID  AND  QUEUE SIZE | IRQ Index |
> +	 * |             DESC AREA                |
> +	 * |            DEVICE AREA               |
> +	 * |            DRIVER AREA               |
> +	 * |             RESERVED                 |
> +	 *
> +	 * Magic number should be written last, this is the DPU indication that the data is ready
> +	 */
> +
> +	/* Init offset */
> +	off = snet->psnet->cfg.host_cfg_off;
> +
> +	/* Ignore magic number for now */
> +	off += 4;
> +	snet_write32(snet, off, snet->psnet->negotiated_cfg_ver);
> +	off += 4;
> +	snet_write32(snet, off, snet->sid);
> +	off += 4;
> +	snet_write32(snet, off, snet->cfg->vq_num);
> +	off += 4;
> +	snet_write32(snet, off, snet->cfg_irq_idx);
> +	off += 4;
> +	snet_write64(snet, off, snet->negotiated_features);
> +	off += 8;
> +	/* Ignore reserved */
> +	off += 8;
> +	/* Write VQs */
> +	for (i = 0 ; i < snet->cfg->vq_num ; i++) {
> +		tmp = (i << 16) | (snet->vqs[i]->num & 0xFFFF);
> +		snet_write32(snet, off, tmp);
> +		off += 4;
> +		snet_write32(snet, off, snet->vqs[i]->irq_idx);
> +		off += 4;
> +		snet_write64(snet, off, snet->vqs[i]->desc_area);
> +		off += 8;
> +		snet_write64(snet, off, snet->vqs[i]->device_area);
> +		off += 8;
> +		snet_write64(snet, off, snet->vqs[i]->driver_area);
> +		off += 8;
> +		/* Ignore reserved */
> +		off += 8;
> +	}
> +
> +	/* Clear snet messages address for this device */
> +	snet_write32(snet, snet->psnet->cfg.msg_off, 0);
> +	/* Write magic number - data is ready */
> +	snet_write32(snet, snet->psnet->cfg.host_cfg_off, SNET_SIGNATURE);
> +
> +	/* The DPU will ACK the config by clearing the signature */
> +	ret = readx_poll_timeout(ioread32, snet->bar + snet->psnet->cfg.host_cfg_off,
> +				 tmp, !tmp, 10, SNET_READ_CFG_TIMEOUT);
> +	if (ret) {
> +		SNET_ERR(snet->pdev, "Timeout waiting for the DPU to read the config\n");
> +		return false;
> +	}
> +
> +	/* set DPU flag */
> +	snet->dpu_ready = true;
> +
> +	return true;
> +}
> +
> +static int snet_request_irqs(struct pci_dev *pdev, struct snet *snet)
> +{
> +	int ret, i, irq;
> +
> +	/* Request config IRQ */
> +	irq = pci_irq_vector(pdev, snet->cfg_irq_idx);
> +	ret = devm_request_irq(&pdev->dev, irq, snet_cfg_irq_hndlr, 0,
> +			       snet->cfg_irq_name, snet);
> +	if (ret) {
> +		SNET_ERR(pdev, "Failed to request IRQ\n");
> +		return ret;
> +	}
> +	snet->cfg_irq = irq;
> +
> +	/* Request IRQ for every VQ */
> +	for (i = 0; i < snet->cfg->vq_num; i++) {
> +		irq = pci_irq_vector(pdev, snet->vqs[i]->irq_idx);
> +		ret = devm_request_irq(&pdev->dev, irq, snet_vq_irq_hndlr, 0,
> +				       snet->vqs[i]->irq_name, snet->vqs[i]);
> +		if (ret) {
> +			SNET_ERR(pdev, "Failed to request IRQ\n");
> +			return ret;
> +		}
> +		snet->vqs[i]->irq = irq;
> +	}
> +	return 0;
> +}
> +
> +static void snet_set_status(struct vdpa_device *vdev, u8 status)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +	struct psnet *psnet = snet->psnet;
> +	struct pci_dev *pdev = snet->pdev;
> +	int ret;
> +	bool pf_irqs;
> +
> +	if (status == snet->status)
> +		return;
> +
> +	if ((status & VIRTIO_CONFIG_S_DRIVER_OK) &&
> +	    !(snet->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
> +		/* Request IRQs */
> +		pf_irqs = PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF);
> +		ret = snet_request_irqs(pf_irqs ? pdev->physfn : pdev, snet);
> +		if (ret)
> +			goto set_err;
> +
> +		/* Write config to the DPU */
> +		if (snet_write_conf(snet)) {
> +			SNET_INFO(pdev, "Create SNET[%u] device\n", snet->sid);
> +		} else {
> +			snet_free_irqs(snet);
> +			goto set_err;
> +		}
> +	}
> +
> +	/* Save the new status */
> +	snet->status = status;
> +	return;
> +
> +set_err:
> +	snet->status |= VIRTIO_CONFIG_S_FAILED;
> +}
> +
> +static void snet_get_config(struct vdpa_device *vdev, unsigned int offset,
> +			    void *buf, unsigned int len)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +	void __iomem *cfg_ptr = snet->cfg->virtio_cfg + offset;
> +	u8 *buf_ptr = buf;
> +	u32 i;
> +
> +	/* check for offset error */
> +	if (offset + len > snet->cfg->cfg_size)
> +		return;
> +
> +	/* Write into buffer */
> +	for (i = 0; i < len; i++)
> +		*buf_ptr++ = ioread8(cfg_ptr + i);
> +}
> +
> +static void snet_set_config(struct vdpa_device *vdev, unsigned int offset,
> +			    const void *buf, unsigned int len)
> +{
> +	struct snet *snet = vdpa_to_snet(vdev);
> +	void __iomem *cfg_ptr = snet->cfg->virtio_cfg + offset;
> +	const u8 *buf_ptr = buf;
> +	u32 i;
> +
> +	/* check for offset error */
> +	if (offset + len > snet->cfg->cfg_size)
> +		return;
> +
> +	/* Write into PCI BAR */
> +	for (i = 0; i < len; i++)
> +		iowrite8(*buf_ptr++, cfg_ptr + i);
> +}
> +
> +static const struct vdpa_config_ops snet_config_ops = {
> +	.set_vq_address         = snet_set_vq_address,
> +	.set_vq_num             = snet_set_vq_num,
> +	.kick_vq                = snet_kick_vq,
> +	.set_vq_cb              = snet_set_vq_cb,
> +	.set_vq_ready           = snet_set_vq_ready,
> +	.get_vq_ready           = snet_get_vq_ready,
> +	.set_vq_state           = snet_set_vq_state,
> +	.get_vq_state           = snet_get_vq_state,
> +	.get_vq_irq		= snet_get_vq_irq,
> +	.get_vq_align           = snet_get_vq_align,
> +	.reset                  = snet_reset,
> +	.get_config_size        = snet_get_config_size,
> +	.get_device_features    = snet_get_features,
> +	.set_driver_features    = snet_set_drv_features,
> +	.get_driver_features    = snet_get_drv_features,
> +	.get_vq_num_min         = snet_get_vq_num_max,
> +	.get_vq_num_max         = snet_get_vq_num_max,
> +	.set_config_cb          = snet_set_config_cb,
> +	.get_device_id          = snet_get_device_id,
> +	.get_vendor_id          = snet_get_vendor_id,
> +	.get_status             = snet_get_status,
> +	.set_status             = snet_set_status,
> +	.get_config             = snet_get_config,
> +	.set_config             = snet_set_config,
> +};
> +
> +static int psnet_open_pf_bar(struct pci_dev *pdev, struct psnet *psnet)
> +{
> +	char name[25];
> +	int ret, i, mask = 0;
> +	/* We don't know which BAR will be used to communicate..
> +	 * We will map every bar with len > 0.
> +	 *
> +	 * Later, we will discover the BAR and unmap all other BARs.
> +	 */
> +	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
> +		if (pci_resource_len(pdev, i))
> +			mask |= (1 << i);
> +	}
> +
> +	/* No BAR can be used.. */
> +	if (!mask) {
> +		SNET_ERR(pdev, "Failed to find a PCI BAR\n");
> +		return -ENODEV;
> +	}
> +
> +	snprintf(name, SNET_NAME_SIZE, "psnet[%s]-bars", pci_name(pdev));
> +	ret = pcim_iomap_regions(pdev, mask, name);
> +	if (ret) {
> +		SNET_ERR(pdev, "Failed to request and map PCI BARs\n");
> +		return ret;
> +	}
> +
> +	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
> +		if (mask & (1 << i))
> +			psnet->bars[i] = pcim_iomap_table(pdev)[i];
> +	}
> +
> +	return 0;
> +}
> +
> +static int snet_open_vf_bar(struct pci_dev *pdev, struct snet *snet)
> +{
> +	char name[20];
> +	int ret;
> +
> +	snprintf(name, SNET_NAME_SIZE, "snet[%s]-bar", pci_name(pdev));
> +	/* Request and map BAR */
> +	ret = pcim_iomap_regions(pdev, BIT(snet->psnet->cfg.vf_bar), name);
> +	if (ret) {
> +		SNET_ERR(pdev, "Failed to request and map PCI BAR for a VF\n");
> +		return ret;
> +	}
> +
> +	snet->bar = pcim_iomap_table(pdev)[snet->psnet->cfg.vf_bar];
> +
> +	return 0;
> +}
> +
> +static void snet_free_cfg(struct snet_cfg *cfg)
> +{
> +	u32 i;
> +
> +	if (!cfg->devs)
> +		return;
> +
> +	/* Free devices */
> +	for (i = 0; i < cfg->devices_num; i++) {
> +		if (!cfg->devs[i])
> +			break;
> +
> +		kfree(cfg->devs[i]);
> +	}
> +	/* Free pointers to devices */
> +	kfree(cfg->devs);
> +}
> +
> +/* Detect which BAR is used for communication with the device. */
> +static int psnet_detect_bar(struct psnet *psnet, u32 off)
> +{
> +	unsigned long exit_time;
> +	int i;
> +
> +	exit_time = jiffies + usecs_to_jiffies(SNET_DETECT_TIMEOUT);
> +
> +	/* SNET DPU will write SNET's signature when the config is ready. */
> +	while (time_before(jiffies, exit_time)) {
> +		for (i = 0; i < PCI_STD_NUM_BARS; i++) {
> +			/* Is this BAR mapped? */
> +			if (!psnet->bars[i])
> +				continue;
> +
> +			if (ioread32(psnet->bars[i] + off) == SNET_SIGNATURE)
> +				return i;
> +		}
> +		usleep_range(1000, 10000);
> +	}
> +
> +	return -ENODEV;
> +}
> +
> +static void psnet_unmap_unused_bars(struct pci_dev *pdev, struct psnet *psnet)
> +{
> +	int i, mask = 0;
> +
> +	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
> +		if (psnet->bars[i] && i != psnet->barno)
> +			mask |= (1 << i);
> +	}
> +
> +	if (mask)
> +		pcim_iounmap_regions(pdev, mask);
> +}
> +
> +/* Read SNET config from PCI BAR */
> +static int psnet_read_cfg(struct pci_dev *pdev, struct psnet *psnet)
> +{
> +	struct snet_cfg *cfg = &psnet->cfg;
> +	u32 i, off;
> +	int barno;
> +
> +	/* Move to where the config starts */
> +	off = SNET_CONFIG_OFF;
> +
> +	/* Find BAR used for communication */
> +	barno = psnet_detect_bar(psnet, off);
> +	if (barno < 0) {
> +		SNET_ERR(pdev, "SNET config is not ready.\n");
> +		return barno;
> +	}
> +
> +	/* Save used BAR number and unmap all other BARs */
> +	psnet->barno = barno;
> +	SNET_DBG(pdev, "Using BAR number %d\n", barno);
> +
> +	psnet_unmap_unused_bars(pdev, psnet);
> +
> +	/* load config from BAR */
> +	cfg->key = psnet_read32(psnet, off);
> +	off += 4;
> +	cfg->cfg_size = psnet_read32(psnet, off);
> +	off += 4;
> +	cfg->cfg_ver = psnet_read32(psnet, off);
> +	off += 4;
> +	/* The negotiated config version is the lower one between this driver's config
> +	 * and the DPU's.
> +	 */
> +	psnet->negotiated_cfg_ver = min_t(u32, cfg->cfg_ver, SNET_CFG_VERSION);
> +	SNET_DBG(pdev, "SNET config version %u\n", psnet->negotiated_cfg_ver);
> +
> +	cfg->vf_num = psnet_read32(psnet, off);
> +	off += 4;
> +	cfg->vf_bar = psnet_read32(psnet, off);
> +	off += 4;
> +	cfg->host_cfg_off = psnet_read32(psnet, off);
> +	off += 4;
> +	cfg->max_size_host_cfg = psnet_read32(psnet, off);
> +	off += 4;
> +	cfg->virtio_cfg_off = psnet_read32(psnet, off);
> +	off += 4;
> +	cfg->kick_off = psnet_read32(psnet, off);
> +	off += 4;
> +	cfg->hwmon_off = psnet_read32(psnet, off);
> +	off += 4;
> +	cfg->msg_off = psnet_read32(psnet, off);
> +	off += 4;
> +	cfg->flags = psnet_read32(psnet, off);
> +	off += 4;
> +	/* Ignore Reserved */
> +	off += sizeof(cfg->rsvd);
> +
> +	cfg->devices_num = psnet_read32(psnet, off);
> +	off += 4;
> +	/* Allocate memory to hold pointer to the devices */
> +	cfg->devs = kcalloc(cfg->devices_num, sizeof(void *), GFP_KERNEL);
> +	if (!cfg->devs)
> +		return -ENOMEM;
> +
> +	/* Load device configuration from BAR */
> +	for (i = 0; i < cfg->devices_num; i++) {
> +		cfg->devs[i] = kzalloc(sizeof(*cfg->devs[i]), GFP_KERNEL);
> +		if (!cfg->devs[i]) {
> +			snet_free_cfg(cfg);
> +			return -ENOMEM;
> +		}
> +		/* Read device config */
> +		cfg->devs[i]->virtio_id = psnet_read32(psnet, off);
> +		off += 4;
> +		cfg->devs[i]->vq_num = psnet_read32(psnet, off);
> +		off += 4;
> +		cfg->devs[i]->vq_size = psnet_read32(psnet, off);
> +		off += 4;
> +		cfg->devs[i]->vfid = psnet_read32(psnet, off);
> +		off += 4;
> +		cfg->devs[i]->features = psnet_read64(psnet, off);
> +		off += 8;
> +		/* Ignore Reserved */
> +		off += sizeof(cfg->devs[i]->rsvd);
> +
> +		cfg->devs[i]->cfg_size = psnet_read32(psnet, off);
> +		off += 4;
> +
> +		/* Is the config witten to the DPU going to be too big? */
> +		if (SNET_GENERAL_CFG_LEN + SNET_GENERAL_CFG_VQ_LEN * cfg->devs[i]->vq_num >
> +		    cfg->max_size_host_cfg) {
> +			SNET_ERR(pdev, "Failed to read SNET config, the config is too big..\n");
> +			snet_free_cfg(cfg);
> +			return -EINVAL;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int psnet_alloc_irq_vector(struct pci_dev *pdev, struct psnet *psnet)
> +{
> +	int ret = 0;
> +	u32 i, irq_num = 0;
> +
> +	/* Let's count how many IRQs we need, 1 for every VQ + 1 for config change */
> +	for (i = 0; i < psnet->cfg.devices_num; i++)
> +		irq_num += psnet->cfg.devs[i]->vq_num + 1;
> +
> +	ret = pci_alloc_irq_vectors(pdev, irq_num, irq_num, PCI_IRQ_MSIX);
> +	if (ret != irq_num) {
> +		SNET_ERR(pdev, "Failed to allocate IRQ vectors\n");
> +		return ret;
> +	}
> +	SNET_DBG(pdev, "Allocated %u IRQ vectors from physical function\n", irq_num);
> +
> +	return 0;
> +}
> +
> +static int snet_alloc_irq_vector(struct pci_dev *pdev, struct snet_dev_cfg *snet_cfg)
> +{
> +	int ret = 0;
> +	u32 irq_num;
> +
> +	/* We want 1 IRQ for every VQ + 1 for config change events */
> +	irq_num = snet_cfg->vq_num + 1;
> +
> +	ret = pci_alloc_irq_vectors(pdev, irq_num, irq_num, PCI_IRQ_MSIX);
> +	if (ret <= 0) {
> +		SNET_ERR(pdev, "Failed to allocate IRQ vectors\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void snet_free_vqs(struct snet *snet)
> +{
> +	u32 i;
> +
> +	if (!snet->vqs)
> +		return;
> +
> +	for (i = 0 ; i < snet->cfg->vq_num ; i++) {
> +		if (!snet->vqs[i])
> +			break;
> +
> +		kfree(snet->vqs[i]);
> +	}
> +	kfree(snet->vqs);
> +}
> +
> +static int snet_build_vqs(struct snet *snet)
> +{
> +	u32 i;
> +	/* Allocate the VQ pointers array */
> +	snet->vqs = kcalloc(snet->cfg->vq_num, sizeof(void *), GFP_KERNEL);
> +	if (!snet->vqs)
> +		return -ENOMEM;
> +
> +	/* Allocate the VQs */
> +	for (i = 0; i < snet->cfg->vq_num; i++) {
> +		snet->vqs[i] = kzalloc(sizeof(*snet->vqs[i]), GFP_KERNEL);
> +		if (!snet->vqs[i]) {
> +			snet_free_vqs(snet);
> +			return -ENOMEM;
> +		}
> +		/* Reset IRQ num */
> +		snet->vqs[i]->irq = -1;
> +		/* VQ serial ID */
> +		snet->vqs[i]->sid = i;
> +		/* Kick address - every VQ gets 4B */
> +		snet->vqs[i]->kick_ptr = snet->bar + snet->psnet->cfg.kick_off +
> +					 snet->vqs[i]->sid * 4;
> +		/* Clear kick address for this VQ */
> +		iowrite32(0, snet->vqs[i]->kick_ptr);
> +	}
> +	return 0;
> +}
> +
> +static int psnet_get_next_irq_num(struct psnet *psnet)
> +{
> +	int irq;
> +
> +	spin_lock(&psnet->lock);
> +	irq = psnet->next_irq++;
> +	spin_unlock(&psnet->lock);
> +
> +	return irq;
> +}
> +
> +static void snet_reserve_irq_idx(struct pci_dev *pdev, struct snet *snet)
> +{
> +	struct psnet *psnet = snet->psnet;
> +	int  i;
> +
> +	/* one IRQ for every VQ, and one for config changes */
> +	snet->cfg_irq_idx = psnet_get_next_irq_num(psnet);
> +	snprintf(snet->cfg_irq_name, SNET_NAME_SIZE, "snet[%s]-cfg[%d]",
> +		 pci_name(pdev), snet->cfg_irq_idx);
> +
> +	for (i = 0; i < snet->cfg->vq_num; i++) {
> +		/* Get next free IRQ ID */
> +		snet->vqs[i]->irq_idx = psnet_get_next_irq_num(psnet);
> +		/* Write IRQ name */
> +		snprintf(snet->vqs[i]->irq_name, SNET_NAME_SIZE, "snet[%s]-vq[%d]",
> +			 pci_name(pdev), snet->vqs[i]->irq_idx);
> +	}
> +}
> +
> +/* Find a device config based on virtual function id */
> +static struct snet_dev_cfg *snet_find_dev_cfg(struct snet_cfg *cfg, u32 vfid)
> +{
> +	u32 i;
> +
> +	for (i = 0; i < cfg->devices_num; i++) {
> +		if (cfg->devs[i]->vfid == vfid)
> +			return cfg->devs[i];
> +	}
> +	/* Oppss.. no config found.. */
> +	return NULL;
> +}
> +
> +/* Probe function for a physical PCI function */
> +static int snet_vdpa_probe_pf(struct pci_dev *pdev)
> +{
> +	struct psnet *psnet;
> +	int ret = 0;
> +	bool pf_irqs = false;
> +
> +	ret = pcim_enable_device(pdev);
> +	if (ret) {
> +		SNET_ERR(pdev, "Failed to enable PCI device\n");
> +		return ret;
> +	}
> +
> +	/* Allocate a PCI physical function device */
> +	psnet = kzalloc(sizeof(*psnet), GFP_KERNEL);
> +	if (!psnet)
> +		return -ENOMEM;
> +
> +	/* Init PSNET spinlock */
> +	spin_lock_init(&psnet->lock);
> +
> +	pci_set_master(pdev);
> +	pci_set_drvdata(pdev, psnet);
> +
> +	/* Open SNET MAIN BAR */
> +	ret = psnet_open_pf_bar(pdev, psnet);
> +	if (ret)
> +		goto free_psnet;
> +
> +	/* Try to read SNET's config from PCI BAR */
> +	ret = psnet_read_cfg(pdev, psnet);
> +	if (ret)
> +		goto free_psnet;
> +
> +	/* If SNET_CFG_FLAG_IRQ_PF flag is set, we should use
> +	 * PF MSI-X vectors
> +	 */
> +	pf_irqs = PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF);
> +
> +	if (pf_irqs) {
> +		ret = psnet_alloc_irq_vector(pdev, psnet);
> +		if (ret)
> +			goto free_cfg;
> +	}
> +
> +	SNET_DBG(pdev, "Enable %u virtual functions\n", psnet->cfg.vf_num);
> +	ret = pci_enable_sriov(pdev, psnet->cfg.vf_num);
> +	if (ret) {
> +		SNET_ERR(pdev, "Failed to enable SR-IOV\n");
> +		goto free_irq;
> +	}
> +
> +	/* Create HW monitor device */
> +	if (PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_HWMON)) {
> +#if IS_ENABLED(CONFIG_HWMON)
> +		psnet_create_hwmon(pdev);
> +#else
> +		SNET_WARN(pdev, "Can't start HWMON, CONFIG_HWMON is not enabled\n");
> +#endif
> +	}
> +
> +	return 0;
> +
> +free_irq:
> +	if (pf_irqs)
> +		pci_free_irq_vectors(pdev);
> +free_cfg:
> +	snet_free_cfg(&psnet->cfg);
> +free_psnet:
> +	kfree(psnet);
> +	return ret;
> +}
> +
> +/* Probe function for a virtual PCI function */
> +static int snet_vdpa_probe_vf(struct pci_dev *pdev)
> +{
> +	struct pci_dev *pdev_pf = pdev->physfn;
> +	struct psnet *psnet = pci_get_drvdata(pdev_pf);
> +	struct snet_dev_cfg *dev_cfg;
> +	struct snet *snet;
> +	u32 vfid;
> +	int ret;
> +	bool pf_irqs = false;
> +
> +	/* Get virtual function id.
> +	 * (the DPU counts the VFs from 1)
> +	 */
> +	ret = pci_iov_vf_id(pdev);
> +	if (ret < 0) {
> +		SNET_ERR(pdev, "Failed to find a VF id\n");
> +		return ret;
> +	}
> +	vfid = ret + 1;
> +
> +	/* Find the snet_dev_cfg based on vfid */
> +	dev_cfg = snet_find_dev_cfg(&psnet->cfg, vfid);
> +	if (!dev_cfg) {
> +		SNET_WARN(pdev, "Failed to find a VF config..\n");
> +		return -ENODEV;
> +	}
> +
> +	/* Which PCI device should allocate the IRQs?
> +	 * If the SNET_CFG_FLAG_IRQ_PF flag set, the PF device allocates the IRQs
> +	 */
> +	pf_irqs = PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF);
> +
> +	ret = pcim_enable_device(pdev);
> +	if (ret) {
> +		SNET_ERR(pdev, "Failed to enable PCI VF device\n");
> +		return ret;
> +	}
> +
> +	/* Request for MSI-X IRQs */
> +	if (!pf_irqs) {
> +		ret = snet_alloc_irq_vector(pdev, dev_cfg);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	/* Allocate vdpa device */
> +	snet = vdpa_alloc_device(struct snet, vdpa, &pdev->dev, &snet_config_ops, 1, 1, NULL,
> +				 false);
> +	if (!snet) {
> +		SNET_ERR(pdev, "Failed to allocate a vdpa device\n");
> +		ret = -ENOMEM;
> +		goto free_irqs;
> +	}
> +
> +	/* Save pci device pointer */
> +	snet->pdev = pdev;
> +	snet->psnet = psnet;
> +	snet->cfg = dev_cfg;
> +	snet->dpu_ready = false;
> +	snet->sid = vfid;
> +	/* Reset IRQ value */
> +	snet->cfg_irq = -1;
> +
> +	ret = snet_open_vf_bar(pdev, snet);
> +	if (ret)
> +		goto put_device;
> +
> +	/* Create a VirtIO config pointer */
> +	snet->cfg->virtio_cfg = snet->bar + snet->psnet->cfg.virtio_cfg_off;
> +
> +	pci_set_master(pdev);
> +	pci_set_drvdata(pdev, snet);
> +
> +	ret = snet_build_vqs(snet);
> +	if (ret)
> +		goto put_device;
> +
> +	/* Reserve IRQ indexes,
> +	 * The IRQs may be requested and freed multiple times,
> +	 * but the indexes won't change.
> +	 */
> +	snet_reserve_irq_idx(pf_irqs ? pdev_pf : pdev, snet);
> +
> +	/*set DMA device*/
> +	snet->vdpa.dma_dev = &pdev->dev;
> +
> +	/* Register VDPA device */
> +	ret = vdpa_register_device(&snet->vdpa, snet->cfg->vq_num);
> +	if (ret) {
> +		SNET_ERR(pdev, "Failed to register vdpa device\n");
> +		goto free_vqs;
> +	}
> +
> +	return 0;
> +
> +free_vqs:
> +	snet_free_vqs(snet);
> +put_device:
> +	put_device(&snet->vdpa.dev);
> +free_irqs:
> +	if (!pf_irqs)
> +		pci_free_irq_vectors(pdev);
> +	return ret;
> +}
> +
> +static int snet_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> +{
> +	if (pdev->is_virtfn)
> +		return snet_vdpa_probe_vf(pdev);
> +	else
> +		return snet_vdpa_probe_pf(pdev);
> +}
> +
> +static void snet_vdpa_remove_pf(struct pci_dev *pdev)
> +{
> +	struct psnet *psnet = pci_get_drvdata(pdev);
> +
> +	pci_disable_sriov(pdev);
> +	/* If IRQs are allocated from the PF, we should free the IRQs */
> +	if (PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF))
> +		pci_free_irq_vectors(pdev);
> +
> +	snet_free_cfg(&psnet->cfg);
> +	kfree(psnet);
> +}
> +
> +static void snet_vdpa_remove_vf(struct pci_dev *pdev)
> +{
> +	struct snet *snet = pci_get_drvdata(pdev);
> +	struct psnet *psnet = snet->psnet;
> +
> +	/* If IRQs are allocated from the VF, we should free the IRQs */
> +	if (!PSNET_FLAG_ON(psnet, SNET_CFG_FLAG_IRQ_PF))
> +		pci_free_irq_vectors(pdev);
> +
> +	vdpa_unregister_device(&snet->vdpa);
> +	snet_free_vqs(snet);
> +}
> +
> +static void snet_vdpa_remove(struct pci_dev *pdev)
> +{
> +	if (pdev->is_virtfn)
> +		snet_vdpa_remove_vf(pdev);
> +	else
> +		snet_vdpa_remove_pf(pdev);
> +}
> +
> +static struct pci_device_id snet_driver_pci_ids[] = {
> +	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_SOLIDRUN, SNET_DEVICE_ID,
> +			 PCI_VENDOR_ID_SOLIDRUN, SNET_DEVICE_ID) },
> +	{ 0 },
> +};
> +
> +MODULE_DEVICE_TABLE(pci, snet_driver_pci_ids);
> +
> +static struct pci_driver snet_vdpa_driver = {
> +	.name		= "snet-vdpa-driver",
> +	.id_table	= snet_driver_pci_ids,
> +	.probe		= snet_vdpa_probe,
> +	.remove		= snet_vdpa_remove,
> +};
> +
> +module_pci_driver(snet_vdpa_driver);
> +
> +MODULE_AUTHOR("Alvaro Karsz <alvaro.karsz@solid-run.com>");
> +MODULE_DESCRIPTION("SolidRun vDPA driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/vdpa/solidrun/snet_vdpa.h b/drivers/vdpa/solidrun/snet_vdpa.h
> new file mode 100644
> index 00000000000..3ebfb7deec4
> --- /dev/null
> +++ b/drivers/vdpa/solidrun/snet_vdpa.h
> @@ -0,0 +1,196 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * SolidRun DPU driver for control plane
> + *
> + * Copyright (C) 2022 SolidRun
> + *
> + * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>
> + *
> + */
> +#ifndef _SNET_VDPA_H_
> +#define _SNET_VDPA_H_
> +
> +#include <linux/vdpa.h>
> +#include <linux/pci.h>
> +
> +#define SNET_NAME_SIZE 256
> +
> +#define SNET_ERR(pdev, fmt, ...) dev_err(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
> +#define SNET_WARN(pdev, fmt, ...) dev_warn(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
> +#define SNET_INFO(pdev, fmt, ...) dev_info(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
> +#define SNET_DBG(pdev, fmt, ...) dev_dbg(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
> +#define SNET_HAS_FEATURE(s, f) ((s)->negotiated_features & BIT_ULL(f))
> +/* VQ struct */
> +struct snet_vq {
> +	/* VQ callback */
> +	struct vdpa_callback cb;
> +	/* desc base address */
> +	u64 desc_area;
> +	/* device base address */
> +	u64 device_area;
> +	/* driver base address */
> +	u64 driver_area;
> +	/* Queue size */
> +	u32 num;
> +	/* Serial ID for VQ */
> +	u32 sid;
> +	/* is ready flag */
> +	bool ready;
> +	/* IRQ number */
> +	u32 irq;
> +	/* IRQ index, DPU uses this to parse data from MSI-X table */
> +	u32 irq_idx;
> +	/* IRQ name */
> +	char irq_name[SNET_NAME_SIZE];
> +	/* pointer to mapped PCI BAR register used by this VQ to kick */
> +	void __iomem *kick_ptr;
> +};
> +
> +struct snet {
> +	/* vdpa device */
> +	struct vdpa_device vdpa;
> +	/* Config callback */
> +	struct vdpa_callback cb;
> +	/* array of virqueues */
> +	struct snet_vq **vqs;
> +	/* Used features */
> +	u64 negotiated_features;
> +	/* Device serial ID */
> +	u32 sid;
> +	/* device status */
> +	u8 status;
> +	/* boolean indicating if snet config was passed to the device */
> +	bool dpu_ready;
> +	/* IRQ number */
> +	u32 cfg_irq;
> +	/* IRQ index, DPU uses this to parse data from MSI-X table */
> +	u32 cfg_irq_idx;
> +	/* IRQ name */
> +	char cfg_irq_name[SNET_NAME_SIZE];
> +	/* BAR to access the VF */
> +	void __iomem *bar;
> +	/* PCI device */
> +	struct pci_dev *pdev;
> +	/* Pointer to snet pdev parent device */
> +	struct psnet *psnet;
> +	/* Pointer to snet config device */
> +	struct snet_dev_cfg *cfg;
> +};
> +
> +struct snet_dev_cfg {
> +	/* Device ID following VirtIO spec. */
> +	u32 virtio_id;
> +	/* Number of VQs for this device */
> +	u32 vq_num;
> +	/* Size of every VQ */
> +	u32 vq_size;
> +	/* Virtual Function id */
> +	u32 vfid;
> +	/* Device features, following VirtIO spec */
> +	u64 features;
> +	/* Reserved for future usage */
> +	u32 rsvd[6];
> +	/* VirtIO device specific config size */
> +	u32 cfg_size;
> +	/* VirtIO device specific config address */
> +	void __iomem *virtio_cfg;
> +} __packed;
> +
> +struct snet_cfg {
> +	/* Magic key */
> +	u32 key;
> +	/* Size of total config in bytes */
> +	u32 cfg_size;
> +	/* Config version */
> +	u32 cfg_ver;
> +	/* Number of Virtual Functions to create */
> +	u32 vf_num;
> +	/* BAR to use for the VFs */
> +	u32 vf_bar;
> +	/* Where should we write the SNET's config */
> +	u32 host_cfg_off;
> +	/* Max. allowed size for a SNET's config */
> +	u32 max_size_host_cfg;
> +	/* VirtIO config offset in BAR */
> +	u32 virtio_cfg_off;
> +	/* Offset in PCI BAR for VQ kicks */
> +	u32 kick_off;
> +	/* Offset in PCI BAR for HW monitoring */
> +	u32 hwmon_off;
> +	/* Offset in PCI BAR for SNET messages */
> +	u32 msg_off;
> +	/* Config general flags - enum snet_cfg_flags */
> +	u32 flags;
> +	/* Reserved for future usage */
> +	u32 rsvd[6];
> +	/* Number of snet devices */
> +	u32 devices_num;
> +	/* The actual devices */
> +	struct snet_dev_cfg **devs;
> +} __packed;
> +
> +/* SolidNET PCIe device, one device per PCIe physical function */
> +struct psnet {
> +	/* PCI BARs */
> +	void __iomem *bars[PCI_STD_NUM_BARS];
> +	/* Negotiated config version */
> +	u32 negotiated_cfg_ver;
> +	/* Next IRQ index to use in case when the IRQs are allocated from this device */
> +	u32 next_irq;
> +	/* BAR number used to communicate with the device */
> +	u8 barno;
> +	/* spinlock to protect data that can be changed by SNET devices */
> +	spinlock_t lock;
> +	/* Pointer to the device's config read from BAR */
> +	struct snet_cfg cfg;
> +	/* Name of monitor device */
> +	char hwmon_name[SNET_NAME_SIZE];
> +};
> +
> +enum snet_cfg_flags {
> +	/* Create a HWMON device */
> +	SNET_CFG_FLAG_HWMON = BIT(0),
> +	/* USE IRQs from the physical function */
> +	SNET_CFG_FLAG_IRQ_PF = BIT(1),
> +};
> +
> +#define PSNET_FLAG_ON(p, f)	((p)->cfg.flags & (f))
> +
> +static inline u32 psnet_read32(struct psnet *psnet, u32 off)
> +{
> +	return ioread32(psnet->bars[psnet->barno] + off);
> +}
> +
> +static inline u32 snet_read32(struct snet *snet, u32 off)
> +{
> +	return ioread32(snet->bar + off);
> +}
> +
> +static inline void snet_write32(struct snet *snet, u32 off, u32 val)
> +{
> +	iowrite32(val, snet->bar + off);
> +}
> +
> +static inline u64 psnet_read64(struct psnet *psnet, u32 off)
> +{
> +	u64 val;
> +	/* 64bits are written in 2 halves, low part first */
> +	val = (u64)psnet_read32(psnet, off);
> +	val |= ((u64)psnet_read32(psnet, off + 4) << 32);
> +	return val;
> +}
> +
> +static inline void snet_write64(struct snet *snet, u32 off, u64 val)
> +{
> +	/* The DPU expects a 64bit integer in 2 halves, the low part first */
> +	snet_write32(snet, off, (u32)val);
> +	snet_write32(snet, off + 4, (u32)(val >> 32));
> +}
> +
> +#if IS_ENABLED(CONFIG_HWMON)
> +void psnet_create_hwmon(struct pci_dev *pdev);
> +#else
> +void psnet_create_hwmon(struct pci_dev *pdev) {}
> +#endif
> +
> +#endif //_SNET_VDPA_H_
> -- 
> 2.32.0
> 
> 
> _______________________________________________
> Virtualization mailing list
> Virtualization@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/virtualization
> 
> 


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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-19 10:49   ` Michael S. Tsirkin
@ 2022-12-19 10:55     ` Alvaro Karsz
  2022-12-19 11:03       ` Michael S. Tsirkin
  0 siblings, 1 reply; 26+ messages in thread
From: Alvaro Karsz @ 2022-12-19 10:55 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: virtualization, linux-pci, Jean Delvare, bhelgaas, Guenter Roeck

> could we add a comment explaining this trick please?
> can be patch on top ...

Add a comment where?
Do you mean adding a comment in the change log?

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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-19 10:55     ` Alvaro Karsz
@ 2022-12-19 11:03       ` Michael S. Tsirkin
  2022-12-19 11:32         ` Alvaro Karsz
  0 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2022-12-19 11:03 UTC (permalink / raw)
  To: Alvaro Karsz
  Cc: virtualization, linux-pci, Jean Delvare, bhelgaas, Guenter Roeck

On Mon, Dec 19, 2022 at 12:55:02PM +0200, Alvaro Karsz wrote:
> > could we add a comment explaining this trick please?
> > can be patch on top ...
> 
> Add a comment where?
> Do you mean adding a comment in the change log?

Right here in kconfig file where the trick is.


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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-19 11:03       ` Michael S. Tsirkin
@ 2022-12-19 11:32         ` Alvaro Karsz
  2022-12-19 16:40           ` Michael S. Tsirkin
  0 siblings, 1 reply; 26+ messages in thread
From: Alvaro Karsz @ 2022-12-19 11:32 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: virtualization, linux-pci, Jean Delvare, bhelgaas, Guenter Roeck

Ok,

> can be patch on top ...

Just to be sure,  you mean here to create a new patch adding a comment
to the kconfig file, not a new version for this patch, right?

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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-19 11:32         ` Alvaro Karsz
@ 2022-12-19 16:40           ` Michael S. Tsirkin
  0 siblings, 0 replies; 26+ messages in thread
From: Michael S. Tsirkin @ 2022-12-19 16:40 UTC (permalink / raw)
  To: Alvaro Karsz
  Cc: virtualization, linux-pci, Jean Delvare, bhelgaas, Guenter Roeck

On Mon, Dec 19, 2022 at 01:32:22PM +0200, Alvaro Karsz wrote:
> Ok,
> 
> > can be patch on top ...
> 
> Just to be sure,  you mean here to create a new patch adding a comment
> to the kconfig file, not a new version for this patch, right?

yes


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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-19  8:35 ` [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver Alvaro Karsz
  2022-12-19 10:43   ` Michael S. Tsirkin
  2022-12-19 10:49   ` Michael S. Tsirkin
@ 2022-12-20  6:50   ` Jason Wang
  2022-12-20  7:25     ` Alvaro Karsz
  2022-12-20 16:32   ` Nathan Chancellor
  3 siblings, 1 reply; 26+ messages in thread
From: Jason Wang @ 2022-12-20  6:50 UTC (permalink / raw)
  To: Alvaro Karsz, virtualization, linux-pci
  Cc: bhelgaas, Michael S. Tsirkin, Jean Delvare, Guenter Roeck


在 2022/12/19 16:35, Alvaro Karsz 写道:
> This commit includes:
>   1) The driver to manage the controlplane over vDPA bus.
>   2) A HW monitor device to read health values from the DPU.
>
> Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>
> --
> v2:
> 	- Auto detect the BAR used for communication.
> 	- When waiting for the DPU to write a config, wait for 5secs
> 	  before giving up on the device.
> 	- Return EOPNOTSUPP error code in vDPA set_vq_state callback if
> 	  the vq state is not the same as the initial one.
> 	- Implement a vDPA reset callback.
> 	- Wait for an ACK when sending a message to the DPU.
> 	- Add endianness comments on 64bit read/write functions.
> 	- Remove the get_iova_range and free vDPA callbacks.
> 	- Usage of managed device functions to ioremap a region.
> 	- Call pci_set_drvdata and pci_set_master before
> 	  vdpa_register_device.
> 	- Create DMA isolation between the vDPA devices by using the
> 	  chip SR-IOV feature.
> 	  Every vDPA device gets a PCIe VF with its own DMA device.
>
> v3:
> 	- Validate vDPA config length while receiving the DPU's config,
> 	  not while trying to write the vDPA config to the DPU.
> 	- Request IRQs when vDPA status is set to
> 	  VIRTIO_CONFIG_S_DRIVER_OK.
> 	- Remove snet_reset_dev() from the PCI remove function for a VF.
> v4:
> 	- Get SolidRun vendor ID from pci_ids
> v5:
> 	- Remove "select HWMON" from Kconfig.
> 	  Usage of "depends on HWMON || HWMON=n" instead and usage of
> 	  IS_ENABLED(CONFIG_HWMON) when calling to snet hwmon functions.
> 	  snet_hwmon.c is compiled only if CONFIG_HWMON is defined.
> 	- Remove the  #include <linux/hwmon-sysfs.h> from snet_hwmon.c.
> 	- Remove the unnecessary (long) casting from snet_hwmon_read_reg.
> 	- Remove the "_hwmon" ending from the hwmon name.
> 	- Usage of IS_ERR macro to check if devm_hwmon_device_register_with_info
> 	  failed.
> 	- Replace schedule() with usleep_range() in the "hot loop" in
> 	  psnet_detect_bar.
> 	- Remove the logging of memory allocation failures.
> 	- Add parenthesis to arguments in SNET_* macros.
> 	- Prefer sizeof(*variable) instead of sizeof(struct x) when allocating
> 	  memory.
> v6:
> 	- SNET_WRN -> SNET_WARN.
> ---
>   MAINTAINERS                        |    4 +
>   drivers/vdpa/Kconfig               |   10 +
>   drivers/vdpa/Makefile              |    1 +
>   drivers/vdpa/solidrun/Makefile     |    6 +
>   drivers/vdpa/solidrun/snet_hwmon.c |  188 +++++
>   drivers/vdpa/solidrun/snet_main.c  | 1111 ++++++++++++++++++++++++++++
>   drivers/vdpa/solidrun/snet_vdpa.h  |  196 +++++
>   7 files changed, 1516 insertions(+)
>   create mode 100644 drivers/vdpa/solidrun/Makefile
>   create mode 100644 drivers/vdpa/solidrun/snet_hwmon.c
>   create mode 100644 drivers/vdpa/solidrun/snet_main.c
>   create mode 100644 drivers/vdpa/solidrun/snet_vdpa.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a608f19da3a..7f4d9dcb760 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -21955,6 +21955,10 @@ IFCVF VIRTIO DATA PATH ACCELERATOR
>   R:	Zhu Lingshan <lingshan.zhu@intel.com>
>   F:	drivers/vdpa/ifcvf/
>   
> +SNET DPU VIRTIO DATA PATH ACCELERATOR
> +R:	Alvaro Karsz <alvaro.karsz@solid-run.com>
> +F:	drivers/vdpa/solidrun/
> +
>   VIRTIO BALLOON
>   M:	"Michael S. Tsirkin" <mst@redhat.com>
>   M:	David Hildenbrand <david@redhat.com>
> diff --git a/drivers/vdpa/Kconfig b/drivers/vdpa/Kconfig
> index 50f45d03761..79625c7cc46 100644
> --- a/drivers/vdpa/Kconfig
> +++ b/drivers/vdpa/Kconfig
> @@ -86,4 +86,14 @@ config ALIBABA_ENI_VDPA
>   	  VDPA driver for Alibaba ENI (Elastic Network Interface) which is built upon
>   	  virtio 0.9.5 specification.
>   
> + config SNET_VDPA
> +	tristate "SolidRun's vDPA driver for SolidNET"
> +	depends on PCI_MSI && PCI_IOV && (HWMON || HWMON=n)


So I think we actually don't need to depend on HWMON here?

hwmon.c is only complied when HWMON is enabled and we use IS_ENABLED to 
exclude the hwmon specific does.

Other looks good to me.

Thanks


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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-20  6:50   ` Jason Wang
@ 2022-12-20  7:25     ` Alvaro Karsz
  2022-12-20  8:54       ` Jason Wang
  0 siblings, 1 reply; 26+ messages in thread
From: Alvaro Karsz @ 2022-12-20  7:25 UTC (permalink / raw)
  To: Jason Wang
  Cc: virtualization, linux-pci, bhelgaas, Michael S. Tsirkin,
	Jean Delvare, Guenter Roeck

Hi Jason,

> So I think we actually don't need to depend on HWMON here?
>
> hwmon.c is only complied when HWMON is enabled and we use IS_ENABLED to
> exclude the hwmon specific does.

We are not really depending on HWMON with "(HWMON || HWMON=n)"
If HWMON=n, the driver can be compiled either as a module or built-in.
If HWMON=y, the driver can be compiled either as a module or built-in.
If HWMON=m, the driver will be forced to be compiled as a module.

This technique allows us to use IS_ENABLED instead of IS_REACHABLE

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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-20  7:25     ` Alvaro Karsz
@ 2022-12-20  8:54       ` Jason Wang
  0 siblings, 0 replies; 26+ messages in thread
From: Jason Wang @ 2022-12-20  8:54 UTC (permalink / raw)
  To: Alvaro Karsz
  Cc: virtualization, linux-pci, bhelgaas, Michael S. Tsirkin,
	Jean Delvare, Guenter Roeck

On Tue, Dec 20, 2022 at 3:26 PM Alvaro Karsz <alvaro.karsz@solid-run.com> wrote:
>
> Hi Jason,
>
> > So I think we actually don't need to depend on HWMON here?
> >
> > hwmon.c is only complied when HWMON is enabled and we use IS_ENABLED to
> > exclude the hwmon specific does.
>
> We are not really depending on HWMON with "(HWMON || HWMON=n)"
> If HWMON=n, the driver can be compiled either as a module or built-in.
> If HWMON=y, the driver can be compiled either as a module or built-in.
> If HWMON=m, the driver will be forced to be compiled as a module.
>
> This technique allows us to use IS_ENABLED instead of IS_REACHABLE

Ok, right.

So

Acked-by: Jason Wang <jasowang@redhat.com>

Thanks

>


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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-19  8:35 ` [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver Alvaro Karsz
                     ` (2 preceding siblings ...)
  2022-12-20  6:50   ` Jason Wang
@ 2022-12-20 16:32   ` Nathan Chancellor
  2022-12-20 16:46     ` Alvaro Karsz
  3 siblings, 1 reply; 26+ messages in thread
From: Nathan Chancellor @ 2022-12-20 16:32 UTC (permalink / raw)
  To: Alvaro Karsz
  Cc: virtualization, linux-pci, bhelgaas, Michael S. Tsirkin,
	Jason Wang, Jean Delvare, Guenter Roeck, llvm

Hi Alvaro,

On Mon, Dec 19, 2022 at 10:35:11AM +0200, Alvaro Karsz wrote:
> This commit includes:
>  1) The driver to manage the controlplane over vDPA bus.
>  2) A HW monitor device to read health values from the DPU.
> 
> Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>

<snip>

> +static int psnet_open_pf_bar(struct pci_dev *pdev, struct psnet *psnet)
> +{
> +	char name[25];
> +	int ret, i, mask = 0;
> +	/* We don't know which BAR will be used to communicate..
> +	 * We will map every bar with len > 0.
> +	 *
> +	 * Later, we will discover the BAR and unmap all other BARs.
> +	 */
> +	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
> +		if (pci_resource_len(pdev, i))
> +			mask |= (1 << i);
> +	}
> +
> +	/* No BAR can be used.. */
> +	if (!mask) {
> +		SNET_ERR(pdev, "Failed to find a PCI BAR\n");
> +		return -ENODEV;
> +	}
> +
> +	snprintf(name, SNET_NAME_SIZE, "psnet[%s]-bars", pci_name(pdev));
> +	ret = pcim_iomap_regions(pdev, mask, name);
> +	if (ret) {
> +		SNET_ERR(pdev, "Failed to request and map PCI BARs\n");
> +		return ret;
> +	}
> +
> +	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
> +		if (mask & (1 << i))
> +			psnet->bars[i] = pcim_iomap_table(pdev)[i];
> +	}
> +
> +	return 0;
> +}
> +
> +static int snet_open_vf_bar(struct pci_dev *pdev, struct snet *snet)
> +{
> +	char name[20];
> +	int ret;
> +
> +	snprintf(name, SNET_NAME_SIZE, "snet[%s]-bar", pci_name(pdev));
> +	/* Request and map BAR */
> +	ret = pcim_iomap_regions(pdev, BIT(snet->psnet->cfg.vf_bar), name);
> +	if (ret) {
> +		SNET_ERR(pdev, "Failed to request and map PCI BAR for a VF\n");
> +		return ret;
> +	}
> +
> +	snet->bar = pcim_iomap_table(pdev)[snet->psnet->cfg.vf_bar];
> +
> +	return 0;
> +}

This patch as commit 73a720b16fa1 ("virtio: vdpa: new SolidNET DPU
driver.") in next-20221220 causes the following clang warnings:

  drivers/vdpa/solidrun/snet_main.c:561:2: error: 'snprintf' size argument is too large; destination buffer has size 25, but size argument is 256 [-Werror,-Wfortify-source]
          snprintf(name, SNET_NAME_SIZE, "psnet[%s]-bars", pci_name(pdev));
          ^
  drivers/vdpa/solidrun/snet_main.c:581:2: error: 'snprintf' size argument is too large; destination buffer has size 20, but size argument is 256 [-Werror,-Wfortify-source]
          snprintf(name, SNET_NAME_SIZE, "snet[%s]-bar", pci_name(pdev));
          ^
  2 errors generated.

This does not appear to be a false positive but what was the intent
here? Should the local name variables increase their length or should
the buffer length be reduced?

Cheers,
Nathan

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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-20 16:32   ` Nathan Chancellor
@ 2022-12-20 16:46     ` Alvaro Karsz
  2022-12-20 20:49       ` Nathan Chancellor
                         ` (2 more replies)
  0 siblings, 3 replies; 26+ messages in thread
From: Alvaro Karsz @ 2022-12-20 16:46 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: virtualization, linux-pci, bhelgaas, Michael S. Tsirkin,
	Jason Wang, Jean Delvare, Guenter Roeck, llvm

Hi Nathan,

> This does not appear to be a false positive but what was the intent
> here? Should the local name variables increase their length or should
> the buffer length be reduced?

You're right, the local name variables and snprintf argument don't match.
Thanks for noticing.
I think that we should increase the name variables  to be
SNET_NAME_SIZE bytes long.

How should I proceed from here?
Should I create a new version for this patch, or should I fix it in a
follow up patch?

Thanks,
Alvaro

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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-20 16:46     ` Alvaro Karsz
@ 2022-12-20 20:49       ` Nathan Chancellor
  2022-12-20 23:20         ` Michael S. Tsirkin
  2022-12-20 21:48       ` Arnd Bergmann
  2022-12-21  6:40       ` Michael S. Tsirkin
  2 siblings, 1 reply; 26+ messages in thread
From: Nathan Chancellor @ 2022-12-20 20:49 UTC (permalink / raw)
  To: Alvaro Karsz
  Cc: virtualization, linux-pci, bhelgaas, Michael S. Tsirkin,
	Jason Wang, Jean Delvare, Guenter Roeck, llvm

On Tue, Dec 20, 2022 at 06:46:20PM +0200, Alvaro Karsz wrote:
> Hi Nathan,
> 
> > This does not appear to be a false positive but what was the intent
> > here? Should the local name variables increase their length or should
> > the buffer length be reduced?
> 
> You're right, the local name variables and snprintf argument don't match.
> Thanks for noticing.
> I think that we should increase the name variables  to be
> SNET_NAME_SIZE bytes long.
> 
> How should I proceed from here?
> Should I create a new version for this patch, or should I fix it in a
> follow up patch?

That is up to Michael at the end of the day (each maintainer handles
their tree differently) but I would recommend sending a follow up fix,
as it is easy to fold it in if they want to rebase the tree for it or
just take it as a fix.

Thanks for the quick triage and response!

Cheers,
Nathan

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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-20 16:46     ` Alvaro Karsz
  2022-12-20 20:49       ` Nathan Chancellor
@ 2022-12-20 21:48       ` Arnd Bergmann
  2022-12-21  6:40       ` Michael S. Tsirkin
  2 siblings, 0 replies; 26+ messages in thread
From: Arnd Bergmann @ 2022-12-20 21:48 UTC (permalink / raw)
  To: Alvaro Karsz, Nathan Chancellor
  Cc: virtualization, linux-pci, bhelgaas, Michael S. Tsirkin,
	Jason Wang, Jean Delvare, Guenter Roeck, llvm

On Tue, Dec 20, 2022, at 17:46, Alvaro Karsz wrote:
> Hi Nathan,
>
>> This does not appear to be a false positive but what was the intent
>> here? Should the local name variables increase their length or should
>> the buffer length be reduced?
>
> You're right, the local name variables and snprintf argument don't match.
> Thanks for noticing.
> I think that we should increase the name variables  to be
> SNET_NAME_SIZE bytes long.

If you can show that the string fits into the current length, it
would be better to keep the stack usage low and just adapt the
length to be sizeof(string) instead of SNET_NAME_SIZE.

    Arnd

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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-20 20:49       ` Nathan Chancellor
@ 2022-12-20 23:20         ` Michael S. Tsirkin
  0 siblings, 0 replies; 26+ messages in thread
From: Michael S. Tsirkin @ 2022-12-20 23:20 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: Alvaro Karsz, virtualization, linux-pci, bhelgaas, Jason Wang,
	Jean Delvare, Guenter Roeck, llvm

On Tue, Dec 20, 2022 at 01:49:04PM -0700, Nathan Chancellor wrote:
> On Tue, Dec 20, 2022 at 06:46:20PM +0200, Alvaro Karsz wrote:
> > Hi Nathan,
> > 
> > > This does not appear to be a false positive but what was the intent
> > > here? Should the local name variables increase their length or should
> > > the buffer length be reduced?
> > 
> > You're right, the local name variables and snprintf argument don't match.
> > Thanks for noticing.
> > I think that we should increase the name variables  to be
> > SNET_NAME_SIZE bytes long.
> > 
> > How should I proceed from here?
> > Should I create a new version for this patch, or should I fix it in a
> > follow up patch?
> 
> That is up to Michael at the end of the day (each maintainer handles
> their tree differently) but I would recommend sending a follow up fix,
> as it is easy to fold it in if they want to rebase the tree for it or
> just take it as a fix.
> 
> Thanks for the quick triage and response!
> 
> Cheers,
> Nathan

on top is ok but post soon please as i need to send this to Linus.

-- 
MST


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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-20 16:46     ` Alvaro Karsz
  2022-12-20 20:49       ` Nathan Chancellor
  2022-12-20 21:48       ` Arnd Bergmann
@ 2022-12-21  6:40       ` Michael S. Tsirkin
  2022-12-21  7:05         ` Alvaro Karsz
  2 siblings, 1 reply; 26+ messages in thread
From: Michael S. Tsirkin @ 2022-12-21  6:40 UTC (permalink / raw)
  To: Alvaro Karsz
  Cc: Nathan Chancellor, virtualization, linux-pci, bhelgaas,
	Jason Wang, Jean Delvare, Guenter Roeck, llvm

On Tue, Dec 20, 2022 at 06:46:20PM +0200, Alvaro Karsz wrote:
> Hi Nathan,
> 
> > This does not appear to be a false positive but what was the intent
> > here? Should the local name variables increase their length or should
> > the buffer length be reduced?
> 
> You're right, the local name variables and snprintf argument don't match.
> Thanks for noticing.
> I think that we should increase the name variables  to be
> SNET_NAME_SIZE bytes long.
> 
> How should I proceed from here?
> Should I create a new version for this patch, or should I fix it in a
> follow up patch?
> 
> Thanks,
> Alvaro


Please post a follow-up ASAP. I can squash myself if I rebase.

Thanks!

-- 
MST


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

* Re: [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver.
  2022-12-21  6:40       ` Michael S. Tsirkin
@ 2022-12-21  7:05         ` Alvaro Karsz
  0 siblings, 0 replies; 26+ messages in thread
From: Alvaro Karsz @ 2022-12-21  7:05 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: Nathan Chancellor, virtualization, linux-pci, bhelgaas,
	Jason Wang, Jean Delvare, Guenter Roeck, llvm

> Please post a follow-up ASAP. I can squash myself if I rebase.
>
> Thanks!

Sure, I'll do it now

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

* Re: [RESEND PATCH 2/3] New PCI quirk for SolidRun SNET DPU.
  2022-12-19  8:35 ` [RESEND PATCH 2/3] New PCI quirk for SolidRun SNET DPU Alvaro Karsz
@ 2022-12-29 19:55   ` Bjorn Helgaas
  0 siblings, 0 replies; 26+ messages in thread
From: Bjorn Helgaas @ 2022-12-29 19:55 UTC (permalink / raw)
  To: Alvaro Karsz; +Cc: virtualization, linux-pci, bhelgaas

Hi Alvaro,

Thanks for the patch!

On Mon, Dec 19, 2022 at 10:35:10AM +0200, Alvaro Karsz wrote:
> The DPU advertises FLR, but it may cause the device to hang.
> This only happens with revision 0x1.

Please update the subject line to:

  PCI: Avoid FLR for SolidRun SNET DPU rev 1

This makes the subject meaningful by itself and is similar to previous
quirks:

  5727043c73fd ("PCI: Avoid FLR for AMD Starship USB 3.0")
  0d14f06cd665 ("PCI: Avoid FLR for AMD Matisse HD Audio & USB 3.0")
  f65fd1aa4f98 ("PCI: Avoid FLR for Intel 82579 NICs")

Also, update the commit log so it says what this patch does, instead
of simply describing the current situation.

https://chris.beams.io/posts/git-commit/ is a good reference.

With the above changes,

Acked-by: Bjorn Helgaas <bhelgaas@google.com>

> Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>
> ---
>  drivers/pci/quirks.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
> index 285acc4aacc..809d03272c2 100644
> --- a/drivers/pci/quirks.c
> +++ b/drivers/pci/quirks.c
> @@ -5343,6 +5343,14 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMD, 0x149c, quirk_no_flr);
>  DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_no_flr);
>  DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_no_flr);
>  
> +/* FLR may cause the SolidRun SNET DPU (rev 0x1) to hang */
> +static void quirk_no_flr_snet(struct pci_dev *dev)
> +{
> +	if (dev->revision == 0x1)
> +		quirk_no_flr(dev);
> +}
> +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SOLIDRUN, 0x1000, quirk_no_flr_snet);
> +
>  static void quirk_no_ext_tags(struct pci_dev *pdev)
>  {
>  	struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
> -- 
> 2.32.0
> 
> _______________________________________________
> Virtualization mailing list
> Virtualization@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* Re: [RESEND PATCH 1/3] Add SolidRun vendor id
  2022-12-19  8:35 ` [RESEND PATCH 1/3] Add SolidRun vendor id Alvaro Karsz
@ 2022-12-29 19:55   ` Bjorn Helgaas
  2022-12-29 21:06     ` Alvaro Karsz
  0 siblings, 1 reply; 26+ messages in thread
From: Bjorn Helgaas @ 2022-12-29 19:55 UTC (permalink / raw)
  To: Alvaro Karsz; +Cc: virtualization, linux-pci, bhelgaas

Hi Alvaro,

On Mon, Dec 19, 2022 at 10:35:09AM +0200, Alvaro Karsz wrote:
> The vendor id is used in 2 differrent source files,
> the SNET vdpa driver and pci quirks.

s/id/ID/                   # both in subject and commit log
s/differrent/different/
s/vdpa/vDPA/               # seems to be the conventional style
s/pci/PCI/

Make the commit log say what this patch does.

> Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>

With the above and the sorting fix below:

Acked-by: Bjorn Helgaas <bhelgaas@google.com>

> ---
>  include/linux/pci_ids.h | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> index b362d90eb9b..33bbe3160b4 100644
> --- a/include/linux/pci_ids.h
> +++ b/include/linux/pci_ids.h
> @@ -3115,4 +3115,6 @@
>  
>  #define PCI_VENDOR_ID_NCUBE		0x10ff
>  
> +#define PCI_VENDOR_ID_SOLIDRUN		0xd063

Move this to the right spot so the file is sorted by vendor ID.
PCI_VENDOR_ID_NCUBE, PCI_VENDOR_ID_OCZ, and PCI_VENDOR_ID_XEN got
added in the wrong place.

>  #endif /* _LINUX_PCI_IDS_H */
> -- 
> 2.32.0
> 
> _______________________________________________
> Virtualization mailing list
> Virtualization@lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* Re: [RESEND PATCH 1/3] Add SolidRun vendor id
  2022-12-29 19:55   ` Bjorn Helgaas
@ 2022-12-29 21:06     ` Alvaro Karsz
  2022-12-29 21:29       ` Bjorn Helgaas
  0 siblings, 1 reply; 26+ messages in thread
From: Alvaro Karsz @ 2022-12-29 21:06 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: virtualization, linux-pci, bhelgaas, Michael S. Tsirkin

Hi Bjorn,

> Hi Alvaro,
>
> On Mon, Dec 19, 2022 at 10:35:09AM +0200, Alvaro Karsz wrote:
> > The vendor id is used in 2 differrent source files,
> > the SNET vdpa driver and pci quirks.
>
> s/id/ID/                   # both in subject and commit log
> s/differrent/different/
> s/vdpa/vDPA/               # seems to be the conventional style
> s/pci/PCI/
>
> Make the commit log say what this patch does.
>
> > Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>
>
> With the above and the sorting fix below:
>
> Acked-by: Bjorn Helgaas <bhelgaas@google.com>
>
> > ---
> >  include/linux/pci_ids.h | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> > index b362d90eb9b..33bbe3160b4 100644
> > --- a/include/linux/pci_ids.h
> > +++ b/include/linux/pci_ids.h
> > @@ -3115,4 +3115,6 @@
> >
> >  #define PCI_VENDOR_ID_NCUBE          0x10ff
> >
> > +#define PCI_VENDOR_ID_SOLIDRUN               0xd063
>
> Move this to the right spot so the file is sorted by vendor ID.
> PCI_VENDOR_ID_NCUBE, PCI_VENDOR_ID_OCZ, and PCI_VENDOR_ID_XEN got
> added in the wrong place.
>
> >  #endif /* _LINUX_PCI_IDS_H */
> > --

Thanks for your comments.

The patch was taken by another maintainer (CCed)
https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git/commit/?h=linux-next&id=afc9dcfb846bf35aa7afb160d5370ab5c75e7a70

So, Michael and Bjorn,
Do you want me to create a new version, or fix it in a follow up patch?

BTW, the same is true for the next patch in the series, New PCI quirk
for SolidRun SNET DPU
https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git/commit/?h=linux-next&id=136dd8d8f3a0ac19f75a875e9b27b83d365a5be3

Thanks.

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

* Re: [RESEND PATCH 1/3] Add SolidRun vendor id
  2022-12-29 21:06     ` Alvaro Karsz
@ 2022-12-29 21:29       ` Bjorn Helgaas
  2022-12-29 22:27         ` Michael S. Tsirkin
  0 siblings, 1 reply; 26+ messages in thread
From: Bjorn Helgaas @ 2022-12-29 21:29 UTC (permalink / raw)
  To: Alvaro Karsz; +Cc: bhelgaas, linux-pci, Michael S. Tsirkin, virtualization

On Thu, Dec 29, 2022 at 11:06:02PM +0200, Alvaro Karsz wrote:
> > On Mon, Dec 19, 2022 at 10:35:09AM +0200, Alvaro Karsz wrote:
> > > The vendor id is used in 2 differrent source files,
> > > the SNET vdpa driver and pci quirks.
> >
> > s/id/ID/                   # both in subject and commit log
> > s/differrent/different/
> > s/vdpa/vDPA/               # seems to be the conventional style
> > s/pci/PCI/
> >
> > Make the commit log say what this patch does.
> >
> > > Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>
> >
> > With the above and the sorting fix below:
> >
> > Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> >
> > > ---
> > >  include/linux/pci_ids.h | 2 ++
> > >  1 file changed, 2 insertions(+)
> > >
> > > diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> > > index b362d90eb9b..33bbe3160b4 100644
> > > --- a/include/linux/pci_ids.h
> > > +++ b/include/linux/pci_ids.h
> > > @@ -3115,4 +3115,6 @@
> > >
> > >  #define PCI_VENDOR_ID_NCUBE          0x10ff
> > >
> > > +#define PCI_VENDOR_ID_SOLIDRUN               0xd063
> >
> > Move this to the right spot so the file is sorted by vendor ID.
> > PCI_VENDOR_ID_NCUBE, PCI_VENDOR_ID_OCZ, and PCI_VENDOR_ID_XEN got
> > added in the wrong place.
> >
> > >  #endif /* _LINUX_PCI_IDS_H */
> > > --
> 
> Thanks for your comments.
> 
> The patch was taken by another maintainer (CCed)
> https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git/commit/?h=linux-next&id=afc9dcfb846bf35aa7afb160d5370ab5c75e7a70
> 
> So, Michael and Bjorn,
> Do you want me to create a new version, or fix it in a follow up patch?
> 
> BTW, the same is true for the next patch in the series, New PCI quirk
> for SolidRun SNET DPU
> https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git/commit/?h=linux-next&id=136dd8d8f3a0ac19f75a875e9b27b83d365a5be3

I don't know how Michael runs his tree, so it's up to him, but "New
PCI quirk for SolidRun SNET DPU." is completely different from all the
history and not very informative, so if it were via my tree I would
definitely update both.

Bjorn

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

* Re: [RESEND PATCH 1/3] Add SolidRun vendor id
  2022-12-29 21:29       ` Bjorn Helgaas
@ 2022-12-29 22:27         ` Michael S. Tsirkin
  0 siblings, 0 replies; 26+ messages in thread
From: Michael S. Tsirkin @ 2022-12-29 22:27 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: Alvaro Karsz, bhelgaas, linux-pci, virtualization

On Thu, Dec 29, 2022 at 03:29:06PM -0600, Bjorn Helgaas wrote:
> On Thu, Dec 29, 2022 at 11:06:02PM +0200, Alvaro Karsz wrote:
> > > On Mon, Dec 19, 2022 at 10:35:09AM +0200, Alvaro Karsz wrote:
> > > > The vendor id is used in 2 differrent source files,
> > > > the SNET vdpa driver and pci quirks.
> > >
> > > s/id/ID/                   # both in subject and commit log
> > > s/differrent/different/
> > > s/vdpa/vDPA/               # seems to be the conventional style
> > > s/pci/PCI/
> > >
> > > Make the commit log say what this patch does.
> > >
> > > > Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>
> > >
> > > With the above and the sorting fix below:
> > >
> > > Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> > >
> > > > ---
> > > >  include/linux/pci_ids.h | 2 ++
> > > >  1 file changed, 2 insertions(+)
> > > >
> > > > diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
> > > > index b362d90eb9b..33bbe3160b4 100644
> > > > --- a/include/linux/pci_ids.h
> > > > +++ b/include/linux/pci_ids.h
> > > > @@ -3115,4 +3115,6 @@
> > > >
> > > >  #define PCI_VENDOR_ID_NCUBE          0x10ff
> > > >
> > > > +#define PCI_VENDOR_ID_SOLIDRUN               0xd063
> > >
> > > Move this to the right spot so the file is sorted by vendor ID.
> > > PCI_VENDOR_ID_NCUBE, PCI_VENDOR_ID_OCZ, and PCI_VENDOR_ID_XEN got
> > > added in the wrong place.
> > >
> > > >  #endif /* _LINUX_PCI_IDS_H */
> > > > --
> > 
> > Thanks for your comments.
> > 
> > The patch was taken by another maintainer (CCed)
> > https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git/commit/?h=linux-next&id=afc9dcfb846bf35aa7afb160d5370ab5c75e7a70
> > 
> > So, Michael and Bjorn,
> > Do you want me to create a new version, or fix it in a follow up patch?
> > 
> > BTW, the same is true for the next patch in the series, New PCI quirk
> > for SolidRun SNET DPU
> > https://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost.git/commit/?h=linux-next&id=136dd8d8f3a0ac19f75a875e9b27b83d365a5be3
> 
> I don't know how Michael runs his tree, so it's up to him, but "New
> PCI quirk for SolidRun SNET DPU." is completely different from all the
> history and not very informative, so if it were via my tree I would
> definitely update both.
> 
> Bjorn

New version pls, I rebase so no problem to replace.

-- 
MST


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

end of thread, other threads:[~2022-12-29 22:28 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-19  8:35 [RESEND PATCH 0/3] virtio: vdpa: new SolidNET DPU driver Alvaro Karsz
2022-12-19  8:35 ` [RESEND PATCH 1/3] Add SolidRun vendor id Alvaro Karsz
2022-12-29 19:55   ` Bjorn Helgaas
2022-12-29 21:06     ` Alvaro Karsz
2022-12-29 21:29       ` Bjorn Helgaas
2022-12-29 22:27         ` Michael S. Tsirkin
2022-12-19  8:35 ` [RESEND PATCH 2/3] New PCI quirk for SolidRun SNET DPU Alvaro Karsz
2022-12-29 19:55   ` Bjorn Helgaas
2022-12-19  8:35 ` [PATCH 3/3 v6] virtio: vdpa: new SolidNET DPU driver Alvaro Karsz
2022-12-19 10:43   ` Michael S. Tsirkin
2022-12-19 10:44     ` Michael S. Tsirkin
2022-12-19 10:49   ` Michael S. Tsirkin
2022-12-19 10:55     ` Alvaro Karsz
2022-12-19 11:03       ` Michael S. Tsirkin
2022-12-19 11:32         ` Alvaro Karsz
2022-12-19 16:40           ` Michael S. Tsirkin
2022-12-20  6:50   ` Jason Wang
2022-12-20  7:25     ` Alvaro Karsz
2022-12-20  8:54       ` Jason Wang
2022-12-20 16:32   ` Nathan Chancellor
2022-12-20 16:46     ` Alvaro Karsz
2022-12-20 20:49       ` Nathan Chancellor
2022-12-20 23:20         ` Michael S. Tsirkin
2022-12-20 21:48       ` Arnd Bergmann
2022-12-21  6:40       ` Michael S. Tsirkin
2022-12-21  7:05         ` Alvaro Karsz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).