[1/5] net/enic: extend vnic dev API for VF representors
diff mbox series

Message ID 20200909135656.18892-2-hyonkim@cisco.com
State Accepted
Delegated to: Ferruh Yigit
Headers show
Series
  • net/enic: add SR-IOV VF representor
Related show

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Hyong Youb Kim (hyonkim) Sept. 9, 2020, 1:56 p.m. UTC
VF representors need to proxy devcmd through the PF vnic_dev
instance. Extend vnic_dev to accommodate them as follows.

1. Add vnic_vf_rep_register()
A VF representor creates its own vnic_dev instance via this function
and saves VF ID. When performing devcmd, vnic_dev uses the saved VF ID
to proxy devcmd through the PF vnic_dev instance.

2. Add vnic_register_lock()
As PF and VF representors appear as independent ports to the
application, its threads may invoke APIs on them simultaneously,
leading to race conditions on the PF vnic_dev. For example, thread A
can query stats on PF port, while thread B queries stats on a VF
representor.

The PF port invokes this function to provide a lock to vnic_dev. This
lock is used to serialize devcmd calls from PF and VF representors.

3. Add utility functions to assist VF representor settings
vnic_dev_mtu() and vnic_dev_uif() retrieve vnic MTU and UIF number
(uplink index), respectively.

Signed-off-by: Hyong Youb Kim <hyonkim@cisco.com>
Reviewed-by: John Daley <johndale@cisco.com>
---
 drivers/net/enic/base/vnic_dev.c | 112 ++++++++++++++++++++++++++++++-
 drivers/net/enic/base/vnic_dev.h |   4 ++
 2 files changed, 113 insertions(+), 3 deletions(-)

Patch
diff mbox series

diff --git a/drivers/net/enic/base/vnic_dev.c b/drivers/net/enic/base/vnic_dev.c
index ac03817f4..aaca07ca6 100644
--- a/drivers/net/enic/base/vnic_dev.c
+++ b/drivers/net/enic/base/vnic_dev.c
@@ -61,6 +61,16 @@  struct vnic_dev {
 	void (*free_consistent)(void *priv,
 		size_t size, void *vaddr,
 		dma_addr_t dma_handle);
+	/*
+	 * Used to serialize devcmd access, currently from PF and its
+	 * VF representors. When there are no representors, lock is
+	 * not used.
+	 */
+	int locked;
+	void (*lock)(void *priv);
+	void (*unlock)(void *priv);
+	struct vnic_dev *pf_vdev;
+	int vf_id;
 };
 
 #define VNIC_MAX_RES_HDR_SIZE \
@@ -84,6 +94,14 @@  void vnic_register_cbacks(struct vnic_dev *vdev,
 	vdev->free_consistent = free_consistent;
 }
 
+void vnic_register_lock(struct vnic_dev *vdev, void (*lock)(void *priv),
+	void (*unlock)(void *priv))
+{
+	vdev->lock = lock;
+	vdev->unlock = unlock;
+	vdev->locked = 0;
+}
+
 static int vnic_dev_discover_res(struct vnic_dev *vdev,
 	struct vnic_dev_bar *bar, unsigned int num_bars)
 {
@@ -410,12 +428,39 @@  static int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev,
 	return err;
 }
 
+void vnic_dev_cmd_proxy_by_index_start(struct vnic_dev *vdev, uint16_t index)
+{
+	vdev->proxy = PROXY_BY_INDEX;
+	vdev->proxy_index = index;
+}
+
+void vnic_dev_cmd_proxy_end(struct vnic_dev *vdev)
+{
+	vdev->proxy = PROXY_NONE;
+	vdev->proxy_index = 0;
+}
+
 int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
 	uint64_t *a0, uint64_t *a1, int wait)
 {
 	uint64_t args[2];
+	bool vf_rep;
+	int vf_idx;
 	int err;
 
+	vf_rep = false;
+	if (vdev->pf_vdev) {
+		vf_rep = true;
+		vf_idx = vdev->vf_id;
+		/* Everything below assumes PF vdev */
+		vdev = vdev->pf_vdev;
+	}
+	if (vdev->lock)
+		vdev->lock(vdev->priv);
+	/* For VF representor, proxy devcmd to VF index */
+	if (vf_rep)
+		vnic_dev_cmd_proxy_by_index_start(vdev, vf_idx);
+
 	args[0] = *a0;
 	args[1] = *a1;
 	memset(vdev->args, 0, sizeof(vdev->args));
@@ -435,6 +480,10 @@  int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
 		break;
 	}
 
+	if (vf_rep)
+		vnic_dev_cmd_proxy_end(vdev);
+	if (vdev->unlock)
+		vdev->unlock(vdev->priv);
 	if (err == 0) {
 		*a0 = args[0];
 		*a1 = args[1];
@@ -446,17 +495,41 @@  int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
 int vnic_dev_cmd_args(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
 		      uint64_t *args, int nargs, int wait)
 {
+	bool vf_rep;
+	int vf_idx;
+	int err;
+
+	vf_rep = false;
+	if (vdev->pf_vdev) {
+		vf_rep = true;
+		vf_idx = vdev->vf_id;
+		vdev = vdev->pf_vdev;
+	}
+	if (vdev->lock)
+		vdev->lock(vdev->priv);
+	if (vf_rep)
+		vnic_dev_cmd_proxy_by_index_start(vdev, vf_idx);
+
 	switch (vdev->proxy) {
 	case PROXY_BY_INDEX:
-		return vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_INDEX, cmd,
+		err = vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_INDEX, cmd,
 				args, nargs, wait);
+		break;
 	case PROXY_BY_BDF:
-		return vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_BDF, cmd,
+		err = vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_BDF, cmd,
 				args, nargs, wait);
+		break;
 	case PROXY_NONE:
 	default:
-		return vnic_dev_cmd_no_proxy(vdev, cmd, args, nargs, wait);
+		err = vnic_dev_cmd_no_proxy(vdev, cmd, args, nargs, wait);
+		break;
 	}
+
+	if (vf_rep)
+		vnic_dev_cmd_proxy_end(vdev);
+	if (vdev->unlock)
+		vdev->unlock(vdev->priv);
+	return err;
 }
 
 int vnic_dev_fw_info(struct vnic_dev *vdev,
@@ -1012,6 +1085,22 @@  uint32_t vnic_dev_port_speed(struct vnic_dev *vdev)
 	return vdev->notify_copy.port_speed;
 }
 
+uint32_t vnic_dev_mtu(struct vnic_dev *vdev)
+{
+	if (!vnic_dev_notify_ready(vdev))
+		return 0;
+
+	return vdev->notify_copy.mtu;
+}
+
+uint32_t vnic_dev_uif(struct vnic_dev *vdev)
+{
+	if (!vnic_dev_notify_ready(vdev))
+		return 0;
+
+	return vdev->notify_copy.uif;
+}
+
 uint32_t vnic_dev_intr_coal_timer_usec_to_hw(struct vnic_dev *vdev,
 					     uint32_t usec)
 {
@@ -1100,6 +1189,23 @@  struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
 	return NULL;
 }
 
+struct vnic_dev *vnic_vf_rep_register(void *priv, struct vnic_dev *pf_vdev,
+	int vf_id)
+{
+	struct vnic_dev *vdev;
+
+	vdev = (struct vnic_dev *)rte_zmalloc("enic-vf-rep-vdev",
+				sizeof(struct vnic_dev), RTE_CACHE_LINE_SIZE);
+	if (!vdev)
+		return NULL;
+	vdev->priv = priv;
+	vdev->pf_vdev = pf_vdev;
+	vdev->vf_id = vf_id;
+	vdev->alloc_consistent = pf_vdev->alloc_consistent;
+	vdev->free_consistent = pf_vdev->free_consistent;
+	return vdev;
+}
+
 /*
  *  vnic_dev_classifier: Add/Delete classifier entries
  *  @vdev: vdev of the device
diff --git a/drivers/net/enic/base/vnic_dev.h b/drivers/net/enic/base/vnic_dev.h
index 02e19c0b8..30ba57bfc 100644
--- a/drivers/net/enic/base/vnic_dev.h
+++ b/drivers/net/enic/base/vnic_dev.h
@@ -80,6 +80,8 @@  void vnic_register_cbacks(struct vnic_dev *vdev,
 	void (*free_consistent)(void *priv,
 		size_t size, void *vaddr,
 		dma_addr_t dma_handle));
+void vnic_register_lock(struct vnic_dev *vdev, void (*lock)(void *priv),
+	void (*unlock)(void *priv));
 void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
 	unsigned int index);
 dma_addr_t vnic_dev_get_res_bus_addr(struct vnic_dev *vdev,
@@ -172,6 +174,8 @@  struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
 	void *priv, struct rte_pci_device *pdev, struct vnic_dev_bar *bar,
 	unsigned int num_bars);
 struct rte_pci_device *vnic_dev_get_pdev(struct vnic_dev *vdev);
+struct vnic_dev *vnic_vf_rep_register(void *priv, struct vnic_dev *pf_vdev,
+	int vf_id);
 int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev);
 int vnic_dev_cmd_init(struct vnic_dev *vdev, int fallback);
 int vnic_dev_get_size(void);