dpdk_vfreset.patch:

diff -urN dpdk-16.07/doc/guides/nics/overview.rst 
dpdk-16.07-new/doc/guides/nics/overview.rst
--- dpdk-16.07/doc/guides/nics/overview.rst     2016-07-28 11:48:41.000000000 
-0700
+++ dpdk-16.07-new/doc/guides/nics/overview.rst 2016-12-15 17:32:27.436425563 
-0800
@@ -89,6 +89,7 @@
    Speed capabilities
    Link status            Y Y Y   Y Y   Y Y Y     Y   Y Y Y Y         Y Y      
   Y Y   Y Y Y Y Y
    Link status event      Y Y       Y     Y Y     Y   Y Y             Y Y      
   Y Y     Y Y
+   Link reset                               Y Y   Y     Y Y
    Queue status event                                                          
             Y
    Rx interrupt                     Y     Y Y Y Y Y Y Y Y Y Y Y Y Y Y
    Queue start/stop           Y   Y   Y Y Y Y Y Y     Y Y     Y Y Y Y Y Y      
         Y Y   Y Y
diff -urN dpdk-16.07/doc/guides/rel_notes/release_16_07.rst 
dpdk-16.07-new/doc/guides/rel_notes/release_16_07.rst
--- dpdk-16.07/doc/guides/rel_notes/release_16_07.rst   2016-07-28 
11:48:41.000000000 -0700
+++ dpdk-16.07-new/doc/guides/rel_notes/release_16_07.rst       2016-12-15 
17:32:27.436425563 -0800
@@ -15,6 +15,15 @@
 
       firefox build/doc/html/guides/rel_notes/release_16_07.html
 
+* **Added device reset support for ixgbe VF.**
+
+  Added the device reset API. APP can call this API to reset the VF port
+  when it's not working.
+  Based on the mailbox interruption support, when VF reseives the control
+  message from PF, it means the PF link state changes, VF uses the reset
+  callback in the message handler to notice the APP. APP need call the device
+  reset API to reset the VF port.
+
 
 New Features
 ------------
diff -urN dpdk-16.07/drivers/net/ixgbe/ixgbe_ethdev.c 
dpdk-16.07-new/drivers/net/ixgbe/ixgbe_ethdev.c
--- dpdk-16.07/drivers/net/ixgbe/ixgbe_ethdev.c 2016-07-28 11:48:41.000000000 
-0700
+++ dpdk-16.07-new/drivers/net/ixgbe/ixgbe_ethdev.c     2016-12-15 
17:47:51.212425563 -0800
@@ -388,6 +388,10 @@
 static int ixgbe_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
                                         struct rte_eth_udp_tunnel *udp_tunnel);
 
+static int ixgbevf_dev_reset(struct rte_eth_dev *dev,
+                            struct rte_eth_reset_state *state,
+                            uint32_t nonce);
+
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
  */
@@ -593,6 +597,7 @@
        .reta_query           = ixgbe_dev_rss_reta_query,
        .rss_hash_update      = ixgbe_dev_rss_hash_update,
        .rss_hash_conf_get    = ixgbe_dev_rss_hash_conf_get,
+       .dev_reset            = ixgbevf_dev_reset,
 };
 
 /* store statistics names and its offset in stats structure */
@@ -4157,7 +4162,9 @@
                ETH_VLAN_EXTEND_MASK;
        ixgbevf_vlan_offload_set(dev, mask);
 
-       ixgbevf_dev_rxtx_start(dev);
+       err = ixgbevf_dev_rxtx_start(dev);
+       if (err)
+               return err;
 
        /* check and configure queue intr-vector mapping */
        if (dev->data->dev_conf.intr_conf.rxq != 0) {
@@ -7305,6 +7312,75 @@
 }
 
 static int
+ixgbevf_dev_reset(struct rte_eth_dev *dev, struct rte_eth_reset_state *state, 
uint32_t nonce)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       int diag = 0;
+       uint32_t vteiam;
+       struct timespec ts;
+
+       /* STATES: [0] initial, [2] stopped, and [1] started (reset complete). 
*/
+       if (state->state <= 1)
+       {
+               /* Nothing needs to be done if reset is complete and the nonce 
is the same. */
+               if (state->state == 1 && state->nonce == nonce)
+                       return 0;
+
+               state->nonce = nonce;
+               state->state = 2;
+               /* Performance VF reset. */
+               dev->data->dev_started = 0;
+               ixgbevf_dev_stop(dev);
+               if (dev->data->dev_conf.intr_conf.lsc == 0)
+                       diag = ixgbe_dev_link_update(dev, 0);
+               if (diag) {
+                       PMD_INIT_LOG(INFO, "Ixgbe VF reset: "
+                                    "Failed to update link.");
+               }
+               clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
+               state->time = ts.tv_sec;
+               return 1;
+       }
+
+       /* Delay of 1s */
+       clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
+       if (ts.tv_sec - state->time < 1) {
+               return 1;
+       }
+
+       state->state = 0;
+       diag = ixgbevf_dev_start(dev);
+       /* If fail to start the device, need to stop/start it again. */
+       if (diag) {
+               PMD_INIT_LOG(ERR, "Ixgbe VF reset: "
+                            "Failed to start device.");
+               return 1;
+       }
+       dev->data->dev_started = 1;
+       ixgbevf_dev_stats_reset(dev);
+       if (dev->data->dev_conf.intr_conf.lsc == 0)
+               diag = ixgbe_dev_link_update(dev, 0);
+       if (diag) {
+               PMD_INIT_LOG(INFO, "Ixgbe VF reset: "
+                            "Failed to update link.");
+       }
+
+       /**
+        * When the PF link is down, there has chance
+        * that VF cannot operate its registers. Will
+        * check if the registers is written
+        * successfully. If not, repeat stop/start until
+        * the PF link is up, in other words, until the
+        * registers can be written.
+        */
+       vteiam = IXGBE_READ_REG(hw, IXGBE_VTEIAM);
+       /* Reference ixgbevf_intr_enable when checking. */
+       state->state = (vteiam == IXGBE_VF_IRQ_ENABLE_MASK && state->nonce == 
nonce);
+       /* The state is going to be 1 if successful and 0 -- otherwise. */
+       return !state->state;
+}
+
+static int
 ixgbevf_dev_interrupt_get_status(struct rte_eth_dev *dev)
 {
        uint32_t eicr;
diff -urN dpdk-16.07/drivers/net/ixgbe/ixgbe_ethdev.h 
dpdk-16.07-new/drivers/net/ixgbe/ixgbe_ethdev.h
--- dpdk-16.07/drivers/net/ixgbe/ixgbe_ethdev.h 2016-07-28 11:48:41.000000000 
-0700
+++ dpdk-16.07-new/drivers/net/ixgbe/ixgbe_ethdev.h     2016-12-15 
17:32:27.436425563 -0800
@@ -377,7 +377,7 @@
 
 void ixgbevf_dev_tx_init(struct rte_eth_dev *dev);
 
-void ixgbevf_dev_rxtx_start(struct rte_eth_dev *dev);
+int ixgbevf_dev_rxtx_start(struct rte_eth_dev *dev);
 
 uint16_t ixgbe_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
                uint16_t nb_pkts);
diff -urN dpdk-16.07/drivers/net/ixgbe/ixgbe_rxtx.c 
dpdk-16.07-new/drivers/net/ixgbe/ixgbe_rxtx.c
--- dpdk-16.07/drivers/net/ixgbe/ixgbe_rxtx.c   2016-07-28 11:48:41.000000000 
-0700
+++ dpdk-16.07-new/drivers/net/ixgbe/ixgbe_rxtx.c       2016-12-15 
17:32:27.440425563 -0800
@@ -5247,7 +5247,7 @@
 /*
  * [VF] Start Transmit and Receive Units.
  */
-void __attribute__((cold))
+int __attribute__((cold))
 ixgbevf_dev_rxtx_start(struct rte_eth_dev *dev)
 {
        struct ixgbe_hw     *hw;
@@ -5283,8 +5283,10 @@
                        rte_delay_ms(1);
                        txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i));
                } while (--poll_ms && !(txdctl & IXGBE_TXDCTL_ENABLE));
-               if (!poll_ms)
+               if (!poll_ms) {
                        PMD_INIT_LOG(ERR, "Could not enable Tx Queue %d", i);
+                       return -1;
+               }
        }
        for (i = 0; i < dev->data->nb_rx_queues; i++) {
 
@@ -5300,12 +5302,16 @@
                        rte_delay_ms(1);
                        rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i));
                } while (--poll_ms && !(rxdctl & IXGBE_RXDCTL_ENABLE));
-               if (!poll_ms)
+               if (!poll_ms) {
                        PMD_INIT_LOG(ERR, "Could not enable Rx Queue %d", i);
+                       return -1;
+               }
                rte_wmb();
                IXGBE_WRITE_REG(hw, IXGBE_VFRDT(i), rxq->nb_rx_desc - 1);
 
        }
+
+       return 0;
 }
 
 /* Stubs needed for linkage when CONFIG_RTE_IXGBE_INC_VECTOR is set to 'n' */
diff -urN dpdk-16.07/lib/librte_ether/rte_ethdev.c 
dpdk-16.07-new/lib/librte_ether/rte_ethdev.c
--- dpdk-16.07/lib/librte_ether/rte_ethdev.c    2016-07-28 11:48:41.000000000 
-0700
+++ dpdk-16.07-new/lib/librte_ether/rte_ethdev.c        2016-12-15 
17:32:27.440425563 -0800
@@ -3446,3 +3446,20 @@
                                -ENOTSUP);
        return (*dev->dev_ops->l2_tunnel_offload_set)(dev, l2_tunnel, mask, en);
 }
+
+int
+rte_eth_dev_reset(uint8_t port_id, struct rte_eth_reset_state *state, uint32_t 
nonce)
+{
+       struct rte_eth_dev *dev;
+       int diag;
+
+       RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+       dev = &rte_eth_devices[port_id];
+
+       RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_reset, -ENOTSUP);
+
+       diag = (*dev->dev_ops->dev_reset)(dev, state, nonce);
+
+       return diag;
+}
diff -urN dpdk-16.07/lib/librte_ether/rte_ethdev.h 
dpdk-16.07-new/lib/librte_ether/rte_ethdev.h
--- dpdk-16.07/lib/librte_ether/rte_ethdev.h    2016-07-28 11:48:41.000000000 
-0700
+++ dpdk-16.07-new/lib/librte_ether/rte_ethdev.h        2016-12-15 
17:40:44.936425563 -0800
@@ -980,6 +980,15 @@
 };
 
 /**
+ * A structure to maintain reset state.
+ */
+struct rte_eth_reset_state {
+       time_t time;
+       uint32_t nonce;
+       uint8_t state;
+};
+
+/**
  * RX/TX queue states
  */
 #define RTE_ETH_QUEUE_STATE_STOPPED 0
@@ -1347,6 +1356,11 @@
         uint8_t en);
 /**< @internal enable/disable the l2 tunnel offload functions */
 
+typedef int  (*eth_dev_reset_t)(struct rte_eth_dev *dev,
+                               struct rte_eth_reset_state *state,
+                               uint32_t nonce);
+/**< @internal Function used to reset a configured Ethernet device. */
+
 #ifdef RTE_NIC_BYPASS
 
 enum {
@@ -1537,6 +1551,8 @@
        eth_l2_tunnel_eth_type_conf_t l2_tunnel_eth_type_conf;
        /** Enable/disable l2 tunnel offload functions */
        eth_l2_tunnel_offload_set_t l2_tunnel_offload_set;
+       /** Reset device. */
+       eth_dev_reset_t dev_reset;
 };
 
 /**
@@ -4368,6 +4384,30 @@
 int
 rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
 
+/**
+ * Reset an ethernet device when it's not working. One scenario is, after PF
+ * port is down and up, the related VF port should be reset.
+ * The API will stop the port, clear the rx/tx queues, re-setup the rx/tx
+ * queues, restart the port.
+ * Before calling this API, APP should stop the rx/tx. When tx is being 
stopped,
+ * APP can drop the packets and release the buffer instead of sending them.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param state
+ *   The reset state (must be initialized to 0 initially).
+ * @param nonce
+ *   A 32-bit number indicating the current reset attempt.
+ *
+ * @return
+ *   - (0) if successful.
+ *   - (1) needs to be called again.
+ *   - (-ENODEV) if port identifier is invalid.
+ *   - (-ENOTSUP) if hardware doesn't support this function.
+ */
+int
+rte_eth_dev_reset(uint8_t port_id, struct rte_eth_reset_state *state, uint32_t 
nonce);
+
 #ifdef __cplusplus
 }
 #endif
diff -urN dpdk-16.07/lib/librte_ether/rte_ether_version.map 
dpdk-16.07-new/lib/librte_ether/rte_ether_version.map
--- dpdk-16.07/lib/librte_ether/rte_ether_version.map   2016-07-28 
11:48:41.000000000 -0700
+++ dpdk-16.07-new/lib/librte_ether/rte_ether_version.map       2016-12-15 
17:32:27.440425563 -0800
@@ -138,4 +138,5 @@
        rte_eth_dev_get_name_by_port;
        rte_eth_dev_get_port_by_name;
        rte_eth_xstats_get_names;
+       rte_eth_dev_reset;
 } DPDK_16.04;

Reply via email to