[RFC net-next 2/3] nfp: initialize NFP VF device according to enable_vnet configuration

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Kyle Xu <zhenbing.xu@xxxxxxxxxxxx>

Users can determine how to instantiate the NFP VF devices through
configure the devlink parameter 'enable_vnet' with the PF device
before enable the SRIOV.

If 'enable_vnet' is enabled, the VF devices are configured to working
as vDPA VFs. Here we still need the PCI resources allocation but can
not just complete the vDPA device registration in NFP driver, since
it should be registered as vDPA driver according to the kernel vDPA
framework. Therefore, we need to complete the driver registration
with the help of the auxiliary bus, the vDPA VF will be initialized
as auxiliary device and registered to the auxiliary bus. Otherwise
the VF device will be initialized as PCI VF device as usual.

Signed-off-by: Kyle Xu <zhenbing.xu@xxxxxxxxxxxx>
Signed-off-by: Louis Peens <louis.peens@xxxxxxxxxxxx>
---
 drivers/net/ethernet/netronome/Kconfig        |   1 +
 drivers/net/ethernet/netronome/nfp/nfp_net.h  |  16 ++
 .../ethernet/netronome/nfp/nfp_net_common.c   |   3 +
 .../ethernet/netronome/nfp/nfp_netvf_main.c   | 264 ++++++++++++++----
 4 files changed, 224 insertions(+), 60 deletions(-)

diff --git a/drivers/net/ethernet/netronome/Kconfig b/drivers/net/ethernet/netronome/Kconfig
index d03d6e96f730..022303eab1a3 100644
--- a/drivers/net/ethernet/netronome/Kconfig
+++ b/drivers/net/ethernet/netronome/Kconfig
@@ -24,6 +24,7 @@ config NFP
 	select NET_DEVLINK
 	select CRC32
 	select DIMLIB
+	select AUXILIARY_BUS
 	help
 	  This driver supports the Netronome(R) NFP4000/NFP6000 based
 	  cards working as a advanced Ethernet NIC.  It works with both
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h
index 46764aeccb37..538dc194add8 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h
@@ -13,6 +13,7 @@
 #define _NFP_NET_H_
 
 #include <linux/atomic.h>
+#include <linux/auxiliary_bus.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/netdevice.h>
@@ -98,6 +99,9 @@
 #define NFP_NET_RX_BUF_NON_DATA	(NFP_NET_RX_BUF_HEADROOM +		\
 				 SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
 
+/* VF auxiliary device driver match name */
+#define NFP_NET_VF_ADEV_DRV_MATCH_NAME "nfp_vf_vdpa"
+
 /* Forward declarations */
 struct nfp_cpp;
 struct nfp_dev_info;
@@ -136,6 +140,18 @@ struct nfp_nfdk_tx_buf;
 		__d->dma_addr_lo = cpu_to_le32(lower_32_bits(__addr));	\
 	} while (0)
 
+/**
+ * struct nfp_net_vf_aux_dev - NFP VF auxiliary device structure
+ * @aux_dev: Auxiliary device structure of this device
+ * @pdev: Backpointer to PCI device
+ * @dev_info: NFP ASIC params
+ */
+struct nfp_net_vf_aux_dev {
+	struct auxiliary_device aux_dev;
+	struct pci_dev *pdev;
+	const struct nfp_dev_info *dev_info;
+};
+
 /**
  * struct nfp_net_tx_ring - TX ring structure
  * @r_vec:      Back pointer to ring vector structure
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index 182ba0a8b095..469b4c794f88 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -74,6 +74,7 @@ u32 nfp_qcp_queue_offset(const struct nfp_dev_info *dev_info, u16 queue)
 	queue &= dev_info->qc_idx_mask;
 	return dev_info->qc_addr_offset + NFP_QCP_QUEUE_ADDR_SZ * queue;
 }
+EXPORT_SYMBOL_GPL(nfp_qcp_queue_offset);
 
 /* Firmware reconfig
  *
@@ -390,6 +391,7 @@ nfp_net_irqs_alloc(struct pci_dev *pdev, struct msix_entry *irq_entries,
 
 	return got_irqs;
 }
+EXPORT_SYMBOL_GPL(nfp_net_irqs_alloc);
 
 /**
  * nfp_net_irqs_assign() - Assign interrupts allocated externally to netdev
@@ -432,6 +434,7 @@ void nfp_net_irqs_disable(struct pci_dev *pdev)
 {
 	pci_disable_msix(pdev);
 }
+EXPORT_SYMBOL_GPL(nfp_net_irqs_disable);
 
 /**
  * nfp_net_irq_rxtx() - Interrupt service routine for RX/TX rings.
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c
index e19bb0150cb5..71d3abf7e191 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_netvf_main.c
@@ -35,8 +35,25 @@ struct nfp_net_vf {
 	struct dentry *ddir;
 };
 
+/**
+ * struct nfp_net_vf_dev - NFP VF device structure
+ * @v_dev: Pointer of PCI VF device
+ * @a_dev: Pointer of VF auxiliary device
+ * @enable_vnet: VDPA networking device flag
+ */
+struct nfp_net_vf_dev {
+	union {
+		struct nfp_net_vf *v_dev;
+		struct nfp_net_vf_aux_dev *a_dev;
+	};
+	bool enable_vnet;
+};
+
 static const char nfp_net_driver_name[] = "nfp_netvf";
 
+/* NFP vf auxiliary device ID allocator definition */
+static DEFINE_IDA(nfp_vf_adev_ida);
+
 static const struct pci_device_id nfp_netvf_pci_device_ids[] = {
 	{ PCI_VENDOR_ID_NETRONOME, PCI_DEVICE_ID_NFP3800_VF,
 	  PCI_VENDOR_ID_NETRONOME, PCI_ANY_ID,
@@ -74,10 +91,20 @@ static void nfp_netvf_get_mac_addr(struct nfp_net *nn)
 	ether_addr_copy(nn->dp.netdev->perm_addr, mac_addr);
 }
 
-static int nfp_netvf_pci_probe(struct pci_dev *pdev,
-			       const struct pci_device_id *pci_id)
+static bool nfp_net_get_enable_vnet(void __iomem *ctrl_bar)
+{
+	u32 enable_vnet;
+
+	enable_vnet = readl(ctrl_bar + NFP_NET_CFG_CTRL_WORD1);
+	return !!(enable_vnet & NFP_NET_CFG_CTRL_ENABLE_VNET);
+}
+
+static int nfp_netvf_pci_probe_vf_dev(struct pci_dev *pdev,
+				      const struct pci_device_id *pci_id,
+				      u8 __iomem *ctrl_bar,
+				      struct nfp_net_vf_dev *vf_dev,
+				      const struct nfp_dev_info *dev_info)
 {
-	const struct nfp_dev_info *dev_info;
 	struct nfp_net_fw_version fw_ver;
 	int max_tx_rings, max_rx_rings;
 	u32 tx_bar_off, rx_bar_off;
@@ -85,49 +112,17 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
 	int tx_bar_no, rx_bar_no;
 	struct nfp_net_vf *vf;
 	unsigned int num_irqs;
-	u8 __iomem *ctrl_bar;
 	struct nfp_net *nn;
 	u32 startq;
 	int stride;
 	int err;
 
-	dev_info = &nfp_dev_info[pci_id->driver_data];
-
 	vf = kzalloc(sizeof(*vf), GFP_KERNEL);
 	if (!vf)
 		return -ENOMEM;
-	pci_set_drvdata(pdev, vf);
-
-	err = pci_enable_device_mem(pdev);
-	if (err)
-		goto err_free_vf;
-
-	err = pci_request_regions(pdev, nfp_net_driver_name);
-	if (err) {
-		dev_err(&pdev->dev, "Unable to allocate device memory.\n");
-		goto err_pci_disable;
-	}
-
-	pci_set_master(pdev);
-
-	err = dma_set_mask_and_coherent(&pdev->dev, dev_info->dma_mask);
-	if (err)
-		goto err_pci_regions;
 
-	/* Map the Control BAR.
-	 *
-	 * Irrespective of the advertised BAR size we only map the
-	 * first NFP_NET_CFG_BAR_SZ of the BAR.  This keeps the code
-	 * the identical for PF and VF drivers.
-	 */
-	ctrl_bar = ioremap(pci_resource_start(pdev, NFP_NET_CTRL_BAR),
-				   NFP_NET_CFG_BAR_SZ);
-	if (!ctrl_bar) {
-		dev_err(&pdev->dev,
-			"Failed to map resource %d\n", NFP_NET_CTRL_BAR);
-		err = -EIO;
-		goto err_pci_regions;
-	}
+	vf_dev->v_dev = vf;
+	vf->q_bar = NULL;
 
 	nfp_net_get_fw_version(&fw_ver, ctrl_bar);
 	if (fw_ver.extend & NFP_NET_CFG_VERSION_RESERVED_MASK ||
@@ -136,7 +131,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
 			fw_ver.extend, fw_ver.class,
 			fw_ver.major, fw_ver.minor);
 		err = -EINVAL;
-		goto err_ctrl_unmap;
+		goto err_vf_free;
 	}
 
 	/* Determine stride */
@@ -157,7 +152,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
 				fw_ver.extend, fw_ver.class,
 				fw_ver.major, fw_ver.minor);
 			err = -EINVAL;
-			goto err_ctrl_unmap;
+			goto err_vf_free;
 		}
 	}
 
@@ -192,7 +187,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
 			   max_tx_rings, max_rx_rings);
 	if (IS_ERR(nn)) {
 		err = PTR_ERR(nn);
-		goto err_ctrl_unmap;
+		goto err_vf_free;
 	}
 	vf->nn = nn;
 
@@ -245,7 +240,8 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
 		if (!nn->rx_bar) {
 			nn_err(nn, "Failed to map resource %d\n", rx_bar_no);
 			err = -EIO;
-			goto err_unmap_tx;
+			iounmap(nn->tx_bar);
+			goto err_netdev_free;
 		}
 	}
 
@@ -258,7 +254,7 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
 	if (!num_irqs) {
 		nn_warn(nn, "Unable to allocate MSI-X Vectors. Exiting\n");
 		err = -EIO;
-		goto err_unmap_rx;
+		goto err_unmap_txrx;
 	}
 	nfp_net_irqs_assign(nn, vf->irq_entries, num_irqs);
 
@@ -274,34 +270,25 @@ static int nfp_netvf_pci_probe(struct pci_dev *pdev,
 
 err_irqs_disable:
 	nfp_net_irqs_disable(pdev);
-err_unmap_rx:
-	if (!vf->q_bar)
-		iounmap(nn->rx_bar);
-err_unmap_tx:
-	if (!vf->q_bar)
+err_unmap_txrx:
+	if (!vf->q_bar) {
 		iounmap(nn->tx_bar);
-	else
+		iounmap(nn->rx_bar);
+	} else {
 		iounmap(vf->q_bar);
+	}
 err_netdev_free:
 	nfp_net_free(nn);
-err_ctrl_unmap:
-	iounmap(ctrl_bar);
-err_pci_regions:
-	pci_release_regions(pdev);
-err_pci_disable:
-	pci_disable_device(pdev);
-err_free_vf:
-	pci_set_drvdata(pdev, NULL);
+err_vf_free:
 	kfree(vf);
+	vf_dev->v_dev = NULL;
 	return err;
 }
 
-static void nfp_netvf_pci_remove(struct pci_dev *pdev)
+static void nfp_netvf_pci_remove_vf_dev(struct nfp_net_vf *vf, struct pci_dev *pdev)
 {
-	struct nfp_net_vf *vf;
 	struct nfp_net *nn;
 
-	vf = pci_get_drvdata(pdev);
 	if (!vf)
 		return;
 
@@ -326,12 +313,169 @@ static void nfp_netvf_pci_remove(struct pci_dev *pdev)
 	iounmap(nn->dp.ctrl_bar);
 
 	nfp_net_free(nn);
+	kfree(vf);
+}
+
+static int nfp_vf_adev_idx_alloc(void)
+{
+	return ida_alloc(&nfp_vf_adev_ida, GFP_KERNEL);
+}
+
+static void nfp_vf_adev_idx_free(int idx)
+{
+	ida_free(&nfp_vf_adev_ida, idx);
+}
+
+static void nfp_vf_adev_release(struct device *dev)
+{
+	struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+
+	nfp_vf_adev_idx_free(auxdev->id);
+}
+
+static int nfp_netvf_pci_probe_vf_aux_dev(struct pci_dev *pdev,
+					  struct nfp_net_vf_dev *vf_dev,
+					  const struct nfp_dev_info *dev_info)
+{
+	int id, err;
+
+	id = nfp_vf_adev_idx_alloc();
+	if (id < 0)
+		return id;
+
+	vf_dev->a_dev = kzalloc(sizeof(*vf_dev->a_dev), GFP_KERNEL);
+	if (!vf_dev->a_dev) {
+		err = -ENOMEM;
+		goto dev_alloc_err;
+	}
+
+	vf_dev->a_dev->aux_dev.id = id;
+	vf_dev->a_dev->aux_dev.name = NFP_NET_VF_ADEV_DRV_MATCH_NAME;
+	vf_dev->a_dev->aux_dev.dev.parent = &pdev->dev;
+	vf_dev->a_dev->aux_dev.dev.release = nfp_vf_adev_release;
+	vf_dev->a_dev->pdev = pdev;
+	vf_dev->a_dev->dev_info = dev_info;
+
+	err = auxiliary_device_init(&vf_dev->a_dev->aux_dev);
+	if (err)
+		goto adev_init_err;
+
+	err = auxiliary_device_add(&vf_dev->a_dev->aux_dev);
+	if (err)
+		goto adev_add_err;
+
+	return 0;
+
+adev_add_err:
+	auxiliary_device_uninit(&vf_dev->a_dev->aux_dev);
+adev_init_err:
+	kfree(vf_dev->a_dev);
+	vf_dev->a_dev = NULL;
+dev_alloc_err:
+	nfp_vf_adev_idx_free(id);
+	return err;
+}
+
+static void nfp_netvf_pci_remove_vf_aux_dev(struct nfp_net_vf_aux_dev *a_dev, struct pci_dev *pdev)
+{
+	if (!a_dev)
+		return;
+
+	auxiliary_device_delete(&a_dev->aux_dev);
+	auxiliary_device_uninit(&a_dev->aux_dev);
+
+	kfree(a_dev);
+}
+
+static int nfp_netvf_pci_probe(struct pci_dev *pdev,
+			       const struct pci_device_id *pci_id)
+{
+	const struct nfp_dev_info *dev_info;
+	struct nfp_net_vf_dev *vf_dev;
+	u8 __iomem *ctrl_bar;
+	int err;
+
+	dev_info = &nfp_dev_info[pci_id->driver_data];
+
+	vf_dev = kzalloc(sizeof(*vf_dev), GFP_KERNEL);
+	if (!vf_dev)
+		return -ENOMEM;
+	pci_set_drvdata(pdev, vf_dev);
+
+	err = pci_enable_device_mem(pdev);
+	if (err)
+		goto err_free_vf;
+
+	err = pci_request_regions(pdev, nfp_net_driver_name);
+	if (err) {
+		dev_err(&pdev->dev, "Unable to allocate device memory.\n");
+		goto err_pci_disable;
+	}
+
+	pci_set_master(pdev);
+
+	err = dma_set_mask_and_coherent(&pdev->dev, dev_info->dma_mask);
+	if (err)
+		goto err_pci_regions;
+
+	/* Map the Control BAR.
+	 *
+	 * Irrespective of the advertised BAR size we only map the
+	 * first NFP_NET_CFG_BAR_SZ of the BAR.  This keeps the code
+	 * the identical for PF and VF drivers.
+	 */
+	ctrl_bar = ioremap(pci_resource_start(pdev, NFP_NET_CTRL_BAR), NFP_NET_CFG_BAR_SZ);
+	if (!ctrl_bar) {
+		dev_err(&pdev->dev, "Failed to map resource %d\n", NFP_NET_CTRL_BAR);
+		err = -EIO;
+		goto err_pci_regions;
+	}
+
+	/* Read the enable_vnet config, determine how to initialize the VF driver.
+	 * ENABLE:  VF instantiated as vDPA networking auxiliary device.
+	 * DISABLE: VF instantiated as NFP VF, initialize NFP PCI VF device.
+	 */
+	vf_dev->enable_vnet = nfp_net_get_enable_vnet(ctrl_bar);
+	if (!vf_dev->enable_vnet)
+		err = nfp_netvf_pci_probe_vf_dev(pdev, pci_id, ctrl_bar, vf_dev, dev_info);
+	else
+		err = nfp_netvf_pci_probe_vf_aux_dev(pdev, vf_dev, dev_info);
+
+	if (err)
+		goto err_ctrl_unmap;
+
+	return 0;
+
+err_ctrl_unmap:
+	iounmap(ctrl_bar);
+err_pci_regions:
+	pci_release_regions(pdev);
+err_pci_disable:
+	pci_disable_device(pdev);
+err_free_vf:
+	pci_set_drvdata(pdev, NULL);
+	kfree(vf_dev);
+	return err;
+}
+
+static void nfp_netvf_pci_remove(struct pci_dev *pdev)
+{
+	struct nfp_net_vf_dev *vf_dev;
+
+	vf_dev = pci_get_drvdata(pdev);
+	if (!vf_dev)
+		return;
+
+	if (vf_dev->enable_vnet)
+		nfp_netvf_pci_remove_vf_aux_dev(vf_dev->a_dev, pdev);
+	else
+		nfp_netvf_pci_remove_vf_dev(vf_dev->v_dev, pdev);
 
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
 
 	pci_set_drvdata(pdev, NULL);
-	kfree(vf);
+	kfree(vf_dev);
 }
 
 struct pci_driver nfp_netvf_pci_driver = {
-- 
2.34.1





[Index of Archives]     [KVM Development]     [Libvirt Development]     [Libvirt Users]     [CentOS Virtualization]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux