[dpdk-dev] [PATCH] i40e: support user unaware VF reset

Zhe Tao zhe.tao at intel.com
Fri May 6 10:46:11 CEST 2016


Problem:
Now the i40e VF PMD driver does not support reset event from PF.
Customer want the user unaware VF reset feature in VF PMD driver,
with this feature, the application doesn't need to concern about
the VF reset procedure and all the application can work correctly
when VF is doing the reset.

Solution:
The following step need to be done
--capture the VF reset event
--reconfigure the VF device
--restore all the configuration parameters.
With this patch, the first two steps can be meet,
part of the configuration parameters can be restored.
This patch mainly focus on the reconfiguration of the VF device when
receive the VF reset event from PF.

Known issues:
This feature cannot work on the primary secondary mixed scenario.

Signed-off-by: zhe.tao <zhe.tao at intel.com>
---
 doc/guides/rel_notes/release_16_07.rst |   5 ++
 drivers/net/i40e/i40e_ethdev.h         |   7 ++
 drivers/net/i40e/i40e_ethdev_vf.c      | 148 ++++++++++++++++++++++++++++++++-
 drivers/net/i40e/i40e_rxtx.c           |  10 +++
 drivers/net/i40e/i40e_rxtx.h           |   4 +
 5 files changed, 171 insertions(+), 3 deletions(-)

diff --git a/doc/guides/rel_notes/release_16_07.rst b/doc/guides/rel_notes/release_16_07.rst
index 83c841b..6c7e051 100644
--- a/doc/guides/rel_notes/release_16_07.rst
+++ b/doc/guides/rel_notes/release_16_07.rst
@@ -34,6 +34,11 @@ This section should contain new features added in this release. Sample format:
 
   Refer to the previous release notes for examples.
 
+* **Added user unaware VF reset in i40e VF driver.**
+
+  A new feature has been added to allow i40e VF driver to handle the VF reset
+  event from PF, and all the operation for VF reset should not be noticed by the
+  application.
 
 Resolved Issues
 ---------------
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index cfd2399..fa52996 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -540,6 +540,11 @@ struct i40e_adapter {
 	struct rte_timecounter systime_tc;
 	struct rte_timecounter rx_tstamp_tc;
 	struct rte_timecounter tx_tstamp_tc;
+
+	/* VF reset variable must put at the end of the structure */
+	rte_spinlock_t vf_reset_lock;
+	rte_spinlock_t reset_trigger_lock;
+	uint8_t reset_number;
 };
 
 int i40e_dev_switch_queues(struct i40e_pf *pf, bool on);
@@ -593,6 +598,8 @@ void i40e_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
 void i40e_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,
 	struct rte_eth_txq_info *qinfo);
 
+void i40evf_emulate_vf_reset(uint8_t port_id);
+
 /* I40E_DEV_PRIVATE_TO */
 #define I40E_DEV_PRIVATE_TO_PF(adapter) \
 	(&((struct i40e_adapter *)adapter)->pf)
diff --git a/drivers/net/i40e/i40e_ethdev_vf.c b/drivers/net/i40e/i40e_ethdev_vf.c
index 2bce69b..e71a34f 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -157,6 +157,11 @@ i40evf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id);
 static void i40evf_handle_pf_event(__rte_unused struct rte_eth_dev *dev,
 				   uint8_t *msg,
 				   uint16_t msglen);
+static int i40evf_dev_uninit(struct rte_eth_dev *eth_dev);
+static int i40evf_dev_init(struct rte_eth_dev *eth_dev);
+static void i40evf_dev_close(struct rte_eth_dev *dev);
+static int i40evf_dev_start(struct rte_eth_dev *dev);
+static int i40evf_dev_configure(struct rte_eth_dev *dev);
 
 /* Default hash key buffer for RSS */
 static uint32_t rss_key_default[I40E_VFQF_HKEY_MAX_INDEX + 1];
@@ -1306,18 +1311,155 @@ i40evf_uninit_vf(struct rte_eth_dev *dev)
 }
 
 static void
-i40evf_handle_pf_event(__rte_unused struct rte_eth_dev *dev,
-			   uint8_t *msg,
-			   __rte_unused uint16_t msglen)
+i40e_vf_queue_reset(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		struct i40e_rx_queue *rxq = dev->data->rx_queues[i];
+
+		if (rxq->q_set) {
+			i40e_dev_rx_queue_setup(dev,
+						rxq->queue_id,
+						rxq->nb_rx_desc,
+						rxq->socket_id,
+						&rxq->rxconf,
+						rxq->mp);
+		}
+	}
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		struct i40e_tx_queue *txq = dev->data->tx_queues[i];
+
+		if (txq->q_set) {
+			i40e_dev_tx_queue_setup(dev,
+						txq->queue_id,
+						txq->nb_tx_desc,
+						txq->socket_id,
+						&txq->txconf);
+		}
+	}
+}
+
+static void
+i40e_vf_reset_dev(struct rte_eth_dev *dev)
+{
+	struct i40e_adapter *adapter =
+		I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+
+	i40evf_dev_close(dev);
+	PMD_DRV_LOG(DEBUG, "i40evf dev close complete");
+	i40evf_dev_uninit(dev);
+	PMD_DRV_LOG(DEBUG, "i40evf dev detached");
+	memset(dev->data->dev_private, 0,
+	       (uint64_t)&adapter->vf_reset_lock - (uint64_t)adapter);
+
+	i40evf_dev_configure(dev);
+	i40evf_dev_init(dev);
+	PMD_DRV_LOG(DEBUG, "i40evf dev attached");
+	i40e_vf_queue_reset(dev);
+	PMD_DRV_LOG(DEBUG, "i40evf queue reset");
+	i40evf_dev_start(dev);
+	PMD_DRV_LOG(DEBUG, "i40evf dev restart");
+}
+
+static void
+i40e_vf_reset_handler(struct rte_eth_dev *dev)
+{
+	struct i40e_adapter *adapter =
+		I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+
+	if (rte_spinlock_trylock(&adapter->vf_reset_lock)) {
+		while (1) {
+			i40e_vf_reset_dev(dev);
+			rte_spinlock_lock(&adapter->reset_trigger_lock);
+			if (2 != adapter->reset_number) {
+				adapter->reset_number = 0;
+				rte_delay_us(100);
+				rte_spinlock_unlock(&adapter->vf_reset_lock);
+				break;
+			} else {
+				adapter->reset_number = 1;
+			}
+			rte_spinlock_unlock(&adapter->reset_trigger_lock);
+		};
+	}
+}
+
+static uint16_t
+i40evf_recv_pkts_detach(void *rx_queue,
+			struct rte_mbuf __rte_unused **rx_pkts,
+			uint16_t __rte_unused nb_pkts)
+{
+	struct i40e_rx_queue *rxq = (struct i40e_rx_queue *)rx_queue;
+	uint8_t port_id = rxq->port_id;
+
+	i40e_vf_reset_handler(&rte_eth_devices[port_id]);
+
+	return 0;
+}
+
+static uint16_t
+i40evf_xmit_pkts_detach(void *tx_queue,
+			struct rte_mbuf __rte_unused **tx_pkts,
+			uint16_t __rte_unused nb_pkts)
+{
+	struct i40e_tx_queue *txq = (struct i40e_tx_queue *)tx_queue;
+	uint8_t port_id = txq->port_id;
+
+	i40e_vf_reset_handler(&rte_eth_devices[port_id]);
+	return 0;
+}
+
+static void
+i40evf_handle_vf_reset(struct rte_eth_dev *dev)
+{
+	dev->rx_pkt_burst = i40evf_recv_pkts_detach;
+	dev->tx_pkt_burst = i40evf_xmit_pkts_detach;
+
+	rte_delay_us(10);
+}
+
+void
+i40evf_emulate_vf_reset(uint8_t port_id)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	struct i40e_adapter *adapter =
+		I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+
+	rte_spinlock_lock(&adapter->reset_trigger_lock);
+	if (0 == adapter->reset_number) {
+		i40evf_handle_vf_reset(dev);
+		adapter->reset_number = 1;
+	} else {
+		adapter->reset_number = 2;
+	}
+	rte_spinlock_unlock(&adapter->reset_trigger_lock);
+}
+
+static void
+i40evf_handle_pf_event(struct rte_eth_dev *dev,
+		       uint8_t *msg,
+		       __rte_unused uint16_t msglen)
 {
 	struct i40e_virtchnl_pf_event *pf_msg =
 			(struct i40e_virtchnl_pf_event *)msg;
 	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	struct i40e_adapter *adapter =
+		I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 
 	switch (pf_msg->event) {
 	case I40E_VIRTCHNL_EVENT_RESET_IMPENDING:
 		PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_RESET_IMPENDING event\n");
 		_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RESET);
+
+		rte_spinlock_lock(&adapter->reset_trigger_lock);
+		if (0 == adapter->reset_number) {
+			i40evf_handle_vf_reset(dev);
+			adapter->reset_number = 1;
+		} else {
+			adapter->reset_number = 2;
+		}
+		rte_spinlock_unlock(&adapter->vf_reset_lock);
 		break;
 	case I40E_VIRTCHNL_EVENT_LINK_CHANGE:
 		PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event\n");
diff --git a/drivers/net/i40e/i40e_rxtx.c b/drivers/net/i40e/i40e_rxtx.c
index 4d35d83..e556583 100644
--- a/drivers/net/i40e/i40e_rxtx.c
+++ b/drivers/net/i40e/i40e_rxtx.c
@@ -2159,6 +2159,7 @@ i40e_dev_rx_queue_setup(struct rte_eth_dev *dev,
 	uint16_t len, i;
 	uint16_t base, bsf, tc_mapping;
 	int use_def_burst_func = 1;
+	struct rte_eth_rxconf conf = *rx_conf;
 
 	if (hw->mac.type == I40E_MAC_VF || hw->mac.type == I40E_MAC_X722_VF) {
 		struct i40e_vf *vf =
@@ -2197,6 +2198,8 @@ i40e_dev_rx_queue_setup(struct rte_eth_dev *dev,
 		return -ENOMEM;
 	}
 	rxq->mp = mp;
+	rxq->socket_id = socket_id;
+	rxq->rxconf = conf;
 	rxq->nb_rx_desc = nb_desc;
 	rxq->rx_free_thresh = rx_conf->rx_free_thresh;
 	rxq->queue_id = queue_idx;
@@ -2376,6 +2379,7 @@ i40e_dev_tx_queue_setup(struct rte_eth_dev *dev,
 	uint32_t ring_size;
 	uint16_t tx_rs_thresh, tx_free_thresh;
 	uint16_t i, base, bsf, tc_mapping;
+	struct rte_eth_txconf conf = *tx_conf;
 
 	if (hw->mac.type == I40E_MAC_VF || hw->mac.type == I40E_MAC_X722_VF) {
 		struct i40e_vf *vf =
@@ -2499,6 +2503,8 @@ i40e_dev_tx_queue_setup(struct rte_eth_dev *dev,
 	}
 
 	txq->nb_tx_desc = nb_desc;
+	txq->socket_id = socket_id;
+	txq->txconf = conf;
 	txq->tx_rs_thresh = tx_rs_thresh;
 	txq->tx_free_thresh = tx_free_thresh;
 	txq->pthresh = tx_conf->tx_thresh.pthresh;
@@ -2956,8 +2962,12 @@ void
 i40e_dev_free_queues(struct rte_eth_dev *dev)
 {
 	uint16_t i;
+	struct i40e_adapter *adapter =
+		I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
 
 	PMD_INIT_FUNC_TRACE();
+	if (adapter->reset_number)
+		return;
 
 	for (i = 0; i < dev->data->nb_rx_queues; i++) {
 		i40e_dev_rx_queue_release(dev->data->rx_queues[i]);
diff --git a/drivers/net/i40e/i40e_rxtx.h b/drivers/net/i40e/i40e_rxtx.h
index 98179f0..9e1b05a 100644
--- a/drivers/net/i40e/i40e_rxtx.h
+++ b/drivers/net/i40e/i40e_rxtx.h
@@ -140,6 +140,8 @@ struct i40e_rx_queue {
 	bool rx_deferred_start; /**< don't start this queue in dev start */
 	uint16_t rx_using_sse; /**<flag indicate the usage of vPMD for rx */
 	uint8_t dcb_tc;         /**< Traffic class of rx queue */
+	uint8_t socket_id;
+	struct rte_eth_rxconf rxconf;
 };
 
 struct i40e_tx_entry {
@@ -181,6 +183,8 @@ struct i40e_tx_queue {
 	bool q_set; /**< indicate if tx queue has been configured */
 	bool tx_deferred_start; /**< don't start this queue in dev start */
 	uint8_t dcb_tc;         /**< Traffic class of tx queue */
+	uint8_t socket_id;
+	struct rte_eth_txconf txconf;
 };
 
 /** Offload features */
-- 
2.1.4



More information about the dev mailing list