[v2] net/iavf: add devargs to enable vf auto-reset

Message ID 20230811094043.200995-1-shiyangx.he@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Qi Zhang
Headers
Series [v2] net/iavf: add devargs to enable vf auto-reset |

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/loongarch-compilation success Compilation OK
ci/loongarch-unit-testing success Unit Testing PASS
ci/Intel-compilation success Compilation OK
ci/intel-Testing success Testing PASS
ci/github-robot: build success github build: passed
ci/intel-Functional success Functional PASS
ci/iol-unit-arm64-testing success Testing PASS
ci/iol-unit-amd64-testing success Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-compile-arm64-testing success Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-sample-apps-testing success Testing PASS
ci/iol-compile-amd64-testing success Testing PASS

Commit Message

Shiyang He Aug. 11, 2023, 9:40 a.m. UTC
  Originally, the iavf PMD does not perform special actions when it
receives a PF-to-VF reset event, resulting in vf being offline and
unavailable.

This patch enables vf auto-reset by setting 'watchdog_period' devargs
to true. The iavf PMD will perform an automatic reset to bring the vf
back online when it receives a PF-to-VF event.

v2: using event handler to handle reset

Signed-off-by: Shiyang He <shiyangx.he@intel.com>
---
 doc/guides/nics/intel_vf.rst           |   3 +
 doc/guides/rel_notes/release_23_11.rst |   3 +
 drivers/net/iavf/iavf.h                |  31 +++++
 drivers/net/iavf/iavf_ethdev.c         | 177 ++++++++++++++++++++++++-
 drivers/net/iavf/iavf_rxtx.c           |  25 ++++
 drivers/net/iavf/iavf_rxtx.h           |   1 +
 drivers/net/iavf/iavf_vchnl.c          |  11 +-
 7 files changed, 248 insertions(+), 3 deletions(-)
  

Patch

diff --git a/doc/guides/nics/intel_vf.rst b/doc/guides/nics/intel_vf.rst
index d365dbc185..c0acd2a7f5 100644
--- a/doc/guides/nics/intel_vf.rst
+++ b/doc/guides/nics/intel_vf.rst
@@ -101,6 +101,9 @@  For more detail on SR-IOV, please refer to the following documents:
     Set ``devargs`` parameter ``watchdog_period`` to adjust the watchdog period in microseconds, or set it to 0 to disable the watchdog,
     for example, ``-a 18:01.0,watchdog_period=5000`` or ``-a 18:01.0,watchdog_period=0``.
 
+    Enable vf auto-reset by setting the ``devargs`` parameter like ``-a 18:01.0,enable_auto_reset=1`` when IAVF is backed
+    by an Intel® E810 device or an Intel® 700 Series Ethernet device.
+
 The PCIE host-interface of Intel Ethernet Switch FM10000 Series VF infrastructure
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/doc/guides/rel_notes/release_23_11.rst b/doc/guides/rel_notes/release_23_11.rst
index 4411bb32c1..80e2d7672f 100644
--- a/doc/guides/rel_notes/release_23_11.rst
+++ b/doc/guides/rel_notes/release_23_11.rst
@@ -72,6 +72,9 @@  New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Updated Intel iavf driver.**
+
+  Added support for iavf auto-reset.
 
 Removed Items
 -------------
diff --git a/drivers/net/iavf/iavf.h b/drivers/net/iavf/iavf.h
index 98861e4242..e78bcda962 100644
--- a/drivers/net/iavf/iavf.h
+++ b/drivers/net/iavf/iavf.h
@@ -95,6 +95,24 @@ 
 
 #define IAVF_L2TPV2_FLAGS_LEN	0x4000
 
+#ifndef DIV_ROUND_UP
+#define DIV_ROUND_UP(n, d) (	\
+{								\
+	const typeof(d) __d = d;	\
+	(((n) + (__d) - 1) / (__d));\
+}								\
+)
+#endif
+#ifndef DELAY
+#define DELAY(x) rte_delay_us(x)
+#endif
+#ifndef msleep
+#define msleep(x) DELAY(1000 * (x))
+#endif
+#ifndef usleep_range
+#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000))
+#endif
+
 struct iavf_adapter;
 struct iavf_rx_queue;
 struct iavf_tx_queue;
@@ -305,6 +323,7 @@  struct iavf_devargs {
 	uint8_t proto_xtr[IAVF_MAX_QUEUE_NUM];
 	uint16_t quanta_size;
 	uint32_t watchdog_period;
+	uint8_t  enable_auto_reset;
 };
 
 struct iavf_security_ctx;
@@ -424,8 +443,19 @@  _atomic_set_async_response_cmd(struct iavf_info *vf, enum virtchnl_ops ops)
 
 	return !ret;
 }
+
+static inline bool
+iavf_is_reset(struct iavf_hw *hw)
+{
+	return !(IAVF_READ_REG(hw, IAVF_VF_ARQLEN1) &
+		 IAVF_VF_ARQLEN1_ARQENABLE_MASK);
+}
+
 int iavf_check_api_version(struct iavf_adapter *adapter);
 int iavf_get_vf_resource(struct iavf_adapter *adapter);
+void iavf_dev_event_post(struct rte_eth_dev *dev,
+			enum rte_eth_event_type event,
+			void *param, size_t param_alloc_size);
 void iavf_dev_event_handler_fini(void);
 int iavf_dev_event_handler_init(void);
 void iavf_handle_virtchnl_msg(struct rte_eth_dev *dev);
@@ -501,4 +531,5 @@  int iavf_flow_sub_check(struct iavf_adapter *adapter,
 			struct iavf_fsub_conf *filter);
 void iavf_dev_watchdog_enable(struct iavf_adapter *adapter);
 void iavf_dev_watchdog_disable(struct iavf_adapter *adapter);
+int iavf_handle_hw_reset(struct rte_eth_dev *dev);
 #endif /* _IAVF_ETHDEV_H_ */
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index f2fc5a5621..9ac612e12b 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -37,6 +37,7 @@ 
 #define IAVF_PROTO_XTR_ARG         "proto_xtr"
 #define IAVF_QUANTA_SIZE_ARG       "quanta_size"
 #define IAVF_RESET_WATCHDOG_ARG    "watchdog_period"
+#define IAVF_ENABLE_AUTO_RESET_ARG "enable_auto_reset"
 
 uint64_t iavf_timestamp_dynflag;
 int iavf_timestamp_dynfield_offset = -1;
@@ -45,6 +46,7 @@  static const char * const iavf_valid_args[] = {
 	IAVF_PROTO_XTR_ARG,
 	IAVF_QUANTA_SIZE_ARG,
 	IAVF_RESET_WATCHDOG_ARG,
+	IAVF_ENABLE_AUTO_RESET_ARG,
 	NULL
 };
 
@@ -305,8 +307,8 @@  iavf_dev_watchdog(void *cb_arg)
 			adapter->vf.vf_reset = true;
 			adapter->vf.link_up = false;
 
-			rte_eth_dev_callback_process(adapter->vf.eth_dev,
-				RTE_ETH_EVENT_INTR_RESET, NULL);
+			iavf_dev_event_post(adapter->vf.eth_dev, RTE_ETH_EVENT_INTR_RESET,
+				 NULL, 0);
 		}
 	}
 
@@ -2210,6 +2212,26 @@  parse_u16(__rte_unused const char *key, const char *value, void *args)
 	return 0;
 }
 
+static int
+parse_bool(const char *key, const char *value, void *args)
+{
+	int *i = (int *)args;
+	char *end;
+	int num;
+
+	num = strtoul(value, &end, 10);
+
+	if (num != 0 && num != 1) {
+		PMD_DRV_LOG(WARNING, "invalid value:\"%s\" for key:\"%s\", "
+			"value must be 0 or 1",
+			value, key);
+		return -1;
+	}
+
+	*i = num;
+	return 0;
+}
+
 static int
 iavf_parse_watchdog_period(__rte_unused const char *key, const char *value, void *args)
 {
@@ -2278,6 +2300,11 @@  static int iavf_parse_devargs(struct rte_eth_dev *dev)
 		goto bail;
 	}
 
+	ret = rte_kvargs_process(kvlist, IAVF_ENABLE_AUTO_RESET_ARG,
+				 &parse_bool, &ad->devargs.enable_auto_reset);
+	if (ret)
+		goto bail;
+
 bail:
 	rte_kvargs_free(kvlist);
 	return ret;
@@ -2879,6 +2906,152 @@  iavf_dev_reset(struct rte_eth_dev *dev)
 	return iavf_dev_init(dev);
 }
 
+static bool
+iavf_is_reset_detected(struct iavf_adapter *adapter)
+{
+	struct iavf_hw *hw = &adapter->hw;
+	int i;
+
+	/* poll until we see the reset actually happen */
+	for (i = 0; i < IAVF_RESET_WAIT_CNT; i++) {
+		if (iavf_is_reset(hw))
+			return true;
+		usleep_range(5000, 10000);
+	}
+
+	return false;
+}
+
+static int
+iavf_uninit_hw(struct rte_eth_dev *dev, struct iavf_hw *hw)
+{
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = dev->intr_handle;
+	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	struct iavf_adapter *adapter = dev->data->dev_private;
+
+	iavf_reset_queues(dev);
+
+	/* Disable the interrupt for Rx */
+	rte_intr_efd_disable(intr_handle);
+	/* Rx interrupt vector mapping free */
+	rte_intr_vec_list_free(intr_handle);
+
+	adapter->stopped = 1;
+	dev->data->dev_started = 0;
+
+	adapter->closed = true;
+
+	/* free iAVF security device context all related resources */
+	iavf_security_ctx_destroy(adapter);
+
+	iavf_flow_flush(dev, NULL);
+	iavf_flow_uninit(adapter);
+
+	if (vf->promisc_unicast_enabled || vf->promisc_multicast_enabled)
+		iavf_config_promisc(adapter, false, false);
+
+	iavf_shutdown_adminq(hw);
+	if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) {
+		/* disable uio intr before callback unregister */
+		rte_intr_disable(intr_handle);
+
+		/* unregister callback func from eal lib */
+		rte_intr_callback_unregister(intr_handle,
+					     iavf_dev_interrupt_handler, dev);
+	}
+	iavf_disable_irq0(hw);
+
+	if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_QOS)
+		iavf_tm_conf_uninit(dev);
+
+	if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
+		if (vf->rss_lut) {
+			rte_free(vf->rss_lut);
+			vf->rss_lut = NULL;
+		}
+		if (vf->rss_key) {
+			rte_free(vf->rss_key);
+			vf->rss_key = NULL;
+		}
+	}
+
+	rte_free(vf->vf_res);
+	vf->vsi_res = NULL;
+	vf->vf_res = NULL;
+
+	rte_free(vf->aq_resp);
+	vf->aq_resp = NULL;
+
+	if (vf->vf_reset && !rte_pci_set_bus_master(pci_dev, true))
+		vf->vf_reset = false;
+
+	/* disable watchdog */
+	iavf_dev_watchdog_disable(adapter);
+
+	return 0;
+}
+
+static int
+iavf_reset_hw(struct rte_eth_dev *dev, struct iavf_hw *hw)
+{
+	iavf_uninit_hw(dev, hw);
+
+	return iavf_dev_init(dev);
+}
+
+/*
+ * Handle hardware reset
+ */
+int
+iavf_handle_hw_reset(struct rte_eth_dev *dev)
+{
+	struct iavf_adapter *adapter = dev->data->dev_private;
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	int ret;
+
+	ret = iavf_is_reset_detected(adapter);
+	if (!ret) {
+		PMD_DRV_LOG(ERR, "Did not detect vf reset!\n");
+		return ret;
+	}
+
+	ret = iavf_check_vf_reset_done(hw);
+	if (ret) {
+		PMD_DRV_LOG(ERR, "Wait too long for reset done!\n");
+		return ret;
+	}
+
+	ret = iavf_reset_hw(dev, hw);
+	if (ret) {
+		PMD_DRV_LOG(ERR, "Failed to reset vf!\n");
+		return ret;
+	}
+
+	/*
+	 * This may return a failure due to the vf may not able to get
+	 * a response from the pf.
+	 */
+	ret = iavf_dev_configure(dev);
+	if (ret)
+		PMD_DRV_LOG(ERR, "Failed to configure dev!");
+
+	iavf_dev_xstats_reset(dev);
+
+	/* start the device */
+	ret = iavf_dev_start(dev);
+	if (ret) {
+		PMD_DRV_LOG(ERR, "Failed to start dev!");
+		return ret;
+	}
+
+	dev->data->dev_started = 1;
+	vf->vf_reset = false;
+
+	return 0;
+}
+
 static int
 iavf_dcf_cap_check_handler(__rte_unused const char *key,
 			   const char *value, __rte_unused void *opaque)
diff --git a/drivers/net/iavf/iavf_rxtx.c b/drivers/net/iavf/iavf_rxtx.c
index f7df4665d1..a1f556d1ce 100644
--- a/drivers/net/iavf/iavf_rxtx.c
+++ b/drivers/net/iavf/iavf_rxtx.c
@@ -1094,6 +1094,31 @@  iavf_dev_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
 	rte_free(q);
 }
 
+void
+iavf_reset_queues(struct rte_eth_dev *dev)
+{
+	struct iavf_rx_queue *rxq;
+	struct iavf_tx_queue *txq;
+	int i;
+
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		txq = dev->data->tx_queues[i];
+		if (!txq)
+			continue;
+		iavf_txq_release_mbufs_ops[txq->rel_mbufs_type].release_mbufs(txq);
+		reset_tx_queue(txq);
+		dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
+	}
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		rxq = dev->data->rx_queues[i];
+		if (!rxq)
+			continue;
+		iavf_rxq_release_mbufs_ops[rxq->rel_mbufs_type].release_mbufs(rxq);
+		reset_rx_queue(rxq);
+		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
+	}
+}
+
 void
 iavf_stop_queues(struct rte_eth_dev *dev)
 {
diff --git a/drivers/net/iavf/iavf_rxtx.h b/drivers/net/iavf/iavf_rxtx.h
index 605ea3f824..237022338e 100644
--- a/drivers/net/iavf/iavf_rxtx.h
+++ b/drivers/net/iavf/iavf_rxtx.h
@@ -650,6 +650,7 @@  int iavf_dev_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id);
 int iavf_dev_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id);
 int iavf_dev_tx_done_cleanup(void *txq, uint32_t free_cnt);
 void iavf_dev_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid);
+void iavf_reset_queues(struct rte_eth_dev *dev);
 void iavf_stop_queues(struct rte_eth_dev *dev);
 uint16_t iavf_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
 		       uint16_t nb_pkts);
diff --git a/drivers/net/iavf/iavf_vchnl.c b/drivers/net/iavf/iavf_vchnl.c
index 524732f67d..dffe91f8c9 100644
--- a/drivers/net/iavf/iavf_vchnl.c
+++ b/drivers/net/iavf/iavf_vchnl.c
@@ -79,6 +79,15 @@  iavf_dev_event_handle(void *param __rte_unused)
 		struct iavf_event_element *pos, *save_next;
 		TAILQ_FOREACH_SAFE(pos, &pending, next, save_next) {
 			TAILQ_REMOVE(&pending, pos, next);
+
+			struct iavf_adapter *adapter = pos->dev->data->dev_private;
+			if (pos->event == RTE_ETH_EVENT_INTR_RESET &&
+			    adapter->devargs.enable_auto_reset) {
+				iavf_handle_hw_reset(pos->dev);
+				rte_free(pos);
+				continue;
+			}
+
 			rte_eth_dev_callback_process(pos->dev, pos->event, pos->param);
 			rte_free(pos);
 		}
@@ -87,7 +96,7 @@  iavf_dev_event_handle(void *param __rte_unused)
 	return 0;
 }
 
-static void
+void
 iavf_dev_event_post(struct rte_eth_dev *dev,
 		enum rte_eth_event_type event,
 		void *param, size_t param_alloc_size)