log: register with standardized names
[dpdk.git] / drivers / net / netvsc / hn_vf.c
index d53d27b..75192e6 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <rte_ether.h>
 #include <rte_ethdev.h>
-#include <rte_ethdev_driver.h>
+#include <ethdev_driver.h>
 #include <rte_lcore.h>
 #include <rte_memory.h>
 #include <rte_bus_vmbus.h>
@@ -24,6 +24,7 @@
 #include <rte_bus_pci.h>
 #include <rte_log.h>
 #include <rte_string_fns.h>
+#include <rte_alarm.h>
 
 #include "hn_logs.h"
 #include "hn_var.h"
@@ -52,89 +53,252 @@ static int hn_vf_match(const struct rte_eth_dev *dev)
 /*
  * Attach new PCI VF device and return the port_id
  */
-static int hn_vf_attach(struct hn_data *hv, uint16_t port_id)
+static int hn_vf_attach(struct rte_eth_dev *dev, struct hn_data *hv)
 {
        struct rte_eth_dev_owner owner = { .id = RTE_ETH_DEV_NO_OWNER };
-       int ret;
+       int port, ret;
 
-       if (hn_vf_attached(hv)) {
+       if (hv->vf_ctx.vf_attached) {
                PMD_DRV_LOG(ERR, "VF already attached");
-               return -EEXIST;
+               return 0;
        }
 
-       ret = rte_eth_dev_owner_get(port_id, &owner);
+       port = hn_vf_match(dev);
+       if (port < 0) {
+               PMD_DRV_LOG(NOTICE, "Couldn't find port for VF");
+               return port;
+       }
+
+       PMD_DRV_LOG(NOTICE, "found matching VF port %d", port);
+       ret = rte_eth_dev_owner_get(port, &owner);
        if (ret < 0) {
-               PMD_DRV_LOG(ERR, "Can not find owner for port %d", port_id);
+               PMD_DRV_LOG(ERR, "Can not find owner for port %d", port);
                return ret;
        }
 
        if (owner.id != RTE_ETH_DEV_NO_OWNER) {
                PMD_DRV_LOG(ERR, "Port %u already owned by other device %s",
-                           port_id, owner.name);
+                           port, owner.name);
                return -EBUSY;
        }
 
-       ret = rte_eth_dev_owner_set(port_id, &hv->owner);
+       ret = rte_eth_dev_owner_set(port, &hv->owner);
        if (ret < 0) {
-               PMD_DRV_LOG(ERR, "Can set owner for port %d", port_id);
+               PMD_DRV_LOG(ERR, "Can set owner for port %d", port);
                return ret;
        }
 
-       PMD_DRV_LOG(DEBUG, "Attach VF device %u", port_id);
-       hv->vf_port = port_id;
-       rte_smp_wmb();
+       PMD_DRV_LOG(DEBUG, "Attach VF device %u", port);
+       hv->vf_ctx.vf_attached = true;
+       hv->vf_ctx.vf_port = port;
+       return 0;
+}
+
+static void hn_vf_remove(struct hn_data *hv);
+
+static void hn_remove_delayed(void *args)
+{
+       struct hn_data *hv = args;
+       uint16_t port_id = hv->vf_ctx.vf_port;
+       struct rte_device *dev = rte_eth_devices[port_id].device;
+       int ret;
+
+       /* Tell VSP to switch data path to synthentic */
+       hn_vf_remove(hv);
+
+       PMD_DRV_LOG(NOTICE, "Start to remove port %d", port_id);
+       rte_rwlock_write_lock(&hv->vf_lock);
+
+       /* Give back ownership */
+       ret = rte_eth_dev_owner_unset(port_id, hv->owner.id);
+       if (ret)
+               PMD_DRV_LOG(ERR, "rte_eth_dev_owner_unset failed ret=%d",
+                           ret);
+       hv->vf_ctx.vf_attached = false;
+
+       ret = rte_eth_dev_callback_unregister(port_id, RTE_ETH_EVENT_INTR_RMV,
+                                             hn_eth_rmv_event_callback, hv);
+       if (ret)
+               PMD_DRV_LOG(ERR,
+                           "rte_eth_dev_callback_unregister failed ret=%d",
+                           ret);
+
+       /* Detach and release port_id from system */
+       ret = rte_eth_dev_stop(port_id);
+       if (ret)
+               PMD_DRV_LOG(ERR, "rte_eth_dev_stop failed port_id=%u ret=%d",
+                           port_id, ret);
+
+       ret = rte_eth_dev_close(port_id);
+       if (ret)
+               PMD_DRV_LOG(ERR, "rte_eth_dev_close failed port_id=%u ret=%d",
+                           port_id, ret);
+
+       ret = rte_dev_remove(dev);
+       hv->vf_ctx.vf_state = vf_removed;
+
+       rte_rwlock_write_unlock(&hv->vf_lock);
+}
+
+int hn_eth_rmv_event_callback(uint16_t port_id,
+                             enum rte_eth_event_type event __rte_unused,
+                             void *cb_arg, void *out __rte_unused)
+{
+       struct hn_data *hv = cb_arg;
+
+       PMD_DRV_LOG(NOTICE, "Removing VF portid %d", port_id);
+       rte_eal_alarm_set(1, hn_remove_delayed, hv);
 
        return 0;
 }
 
+static int hn_setup_vf_queues(int port, struct rte_eth_dev *dev)
+{
+       struct hn_rx_queue *rx_queue;
+       struct rte_eth_txq_info txinfo;
+       struct rte_eth_rxq_info rxinfo;
+       int i, ret = 0;
+
+       for (i = 0; i < dev->data->nb_tx_queues; i++) {
+               ret = rte_eth_tx_queue_info_get(dev->data->port_id, i, &txinfo);
+               if (ret) {
+                       PMD_DRV_LOG(ERR,
+                                   "rte_eth_tx_queue_info_get failed ret=%d",
+                                   ret);
+                       return ret;
+               }
+
+               ret = rte_eth_tx_queue_setup(port, i, txinfo.nb_desc, 0,
+                                            &txinfo.conf);
+               if (ret) {
+                       PMD_DRV_LOG(ERR,
+                                   "rte_eth_tx_queue_setup failed ret=%d",
+                                   ret);
+                       return ret;
+               }
+       }
+
+       for (i = 0; i < dev->data->nb_rx_queues; i++) {
+               ret = rte_eth_rx_queue_info_get(dev->data->port_id, i, &rxinfo);
+               if (ret) {
+                       PMD_DRV_LOG(ERR,
+                                   "rte_eth_rx_queue_info_get failed ret=%d",
+                                   ret);
+                       return ret;
+               }
+
+               rx_queue = dev->data->rx_queues[i];
+
+               ret = rte_eth_rx_queue_setup(port, i, rxinfo.nb_desc, 0,
+                                            &rxinfo.conf, rx_queue->mb_pool);
+               if (ret) {
+                       PMD_DRV_LOG(ERR,
+                                   "rte_eth_rx_queue_setup failed ret=%d",
+                                   ret);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+int hn_vf_add(struct rte_eth_dev *dev, struct hn_data *hv);
+
+static void hn_vf_add_retry(void *args)
+{
+       struct rte_eth_dev *dev = args;
+       struct hn_data *hv = dev->data->dev_private;
+
+       hn_vf_add(dev, hv);
+}
+
+int hn_vf_configure(struct rte_eth_dev *dev,
+                   const struct rte_eth_conf *dev_conf);
+
 /* Add new VF device to synthetic device */
 int hn_vf_add(struct rte_eth_dev *dev, struct hn_data *hv)
 {
-       int port, err;
+       int ret, port;
 
-       port = hn_vf_match(dev);
-       if (port < 0) {
-               PMD_DRV_LOG(NOTICE, "No matching MAC found");
-               return port;
+       if (!hv->vf_ctx.vf_vsp_reported || hv->vf_ctx.vf_vsc_switched)
+               return 0;
+
+       rte_rwlock_write_lock(&hv->vf_lock);
+
+       ret = hn_vf_attach(dev, hv);
+       if (ret) {
+               PMD_DRV_LOG(NOTICE,
+                           "RNDIS reports VF but device not found, retrying");
+               rte_eal_alarm_set(1000000, hn_vf_add_retry, dev);
+               goto exit;
        }
 
-       rte_spinlock_lock(&hv->vf_lock);
-       err = hn_vf_attach(hv, port);
-
-       if (err == 0) {
-               dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
-               hv->vf_intr = (struct rte_intr_handle) {
-                       .fd = -1,
-                       .type = RTE_INTR_HANDLE_EXT,
-               };
-               dev->intr_handle = &hv->vf_intr;
-               hn_nvs_set_datapath(hv, NVS_DATAPATH_VF);
+       port = hv->vf_ctx.vf_port;
+
+       /* If the primary device has started, this is a VF host add.
+        * Configure and start VF device.
+        */
+       if (dev->data->dev_started) {
+               if (rte_eth_devices[port].data->dev_started) {
+                       PMD_DRV_LOG(ERR, "VF already started on hot add");
+                       goto exit;
+               }
+
+               PMD_DRV_LOG(NOTICE, "configuring VF port %d", port);
+               ret = hn_vf_configure(dev, &dev->data->dev_conf);
+               if (ret) {
+                       PMD_DRV_LOG(ERR, "Failed to configure VF port %d",
+                                   port);
+                       goto exit;
+               }
+
+               ret = hn_setup_vf_queues(port, dev);
+               if (ret) {
+                       PMD_DRV_LOG(ERR,
+                                   "Failed to configure VF queues port %d",
+                                   port);
+                       goto exit;
+               }
+
+               PMD_DRV_LOG(NOTICE, "Starting VF port %d", port);
+               ret = rte_eth_dev_start(port);
+               if (ret) {
+                       PMD_DRV_LOG(ERR, "rte_eth_dev_start failed ret=%d",
+                                   ret);
+                       goto exit;
+               }
+               hv->vf_ctx.vf_state = vf_started;
        }
-       rte_spinlock_unlock(&hv->vf_lock);
 
-       return err;
+       ret = hn_nvs_set_datapath(hv, NVS_DATAPATH_VF);
+       if (ret == 0)
+               hv->vf_ctx.vf_vsc_switched = true;
+
+exit:
+       rte_rwlock_write_unlock(&hv->vf_lock);
+       return ret;
 }
 
-/* Remove new VF device */
+/* Switch data path to VF device */
 static void hn_vf_remove(struct hn_data *hv)
 {
+       int ret;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       if (!hv->vf_ctx.vf_vsc_switched) {
+               PMD_DRV_LOG(ERR, "VF path not active");
+               return;
+       }
 
-       if (!hn_vf_attached(hv)) {
+       rte_rwlock_write_lock(&hv->vf_lock);
+       if (!hv->vf_ctx.vf_vsc_switched) {
                PMD_DRV_LOG(ERR, "VF path not active");
        } else {
                /* Stop incoming packets from arriving on VF */
-               hn_nvs_set_datapath(hv, NVS_DATAPATH_SYNTHETIC);
-
-               /* Stop transmission over VF */
-               hv->vf_port = HN_INVALID_PORT;
-               rte_smp_wmb();
-
-               /* Give back ownership */
-               rte_eth_dev_owner_unset(hv->vf_port, hv->owner.id);
+               ret = hn_nvs_set_datapath(hv, NVS_DATAPATH_SYNTHETIC);
+               if (ret == 0)
+                       hv->vf_ctx.vf_vsc_switched = false;
        }
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_write_unlock(&hv->vf_lock);
 }
 
 /* Handle VF association message from host */
@@ -156,15 +320,25 @@ hn_nvs_handle_vfassoc(struct rte_eth_dev *dev,
                    vf_assoc->allocated ? "add to" : "remove from",
                    dev->data->port_id);
 
-       hv->vf_present = vf_assoc->allocated;
+       hv->vf_ctx.vf_vsp_reported = vf_assoc->allocated;
 
-       if (dev->state != RTE_ETH_DEV_ATTACHED)
-               return;
+       if (dev->state == RTE_ETH_DEV_ATTACHED) {
+               if (vf_assoc->allocated)
+                       hn_vf_add(dev, hv);
+               else
+                       hn_vf_remove(hv);
+       }
+}
 
-       if (vf_assoc->allocated)
-               hn_vf_add(dev, hv);
-       else
-               hn_vf_remove(hv);
+static void
+hn_vf_merge_desc_lim(struct rte_eth_desc_lim *lim,
+                    const struct rte_eth_desc_lim *vf_lim)
+{
+       lim->nb_max = RTE_MIN(vf_lim->nb_max, lim->nb_max);
+       lim->nb_min = RTE_MAX(vf_lim->nb_min, lim->nb_min);
+       lim->nb_align = RTE_MAX(vf_lim->nb_align, lim->nb_align);
+       lim->nb_seg_max = RTE_MIN(vf_lim->nb_seg_max, lim->nb_seg_max);
+       lim->nb_mtu_seg_max = RTE_MIN(vf_lim->nb_seg_max, lim->nb_seg_max);
 }
 
 /*
@@ -196,11 +370,13 @@ static int hn_vf_info_merge(struct rte_eth_dev *vf_dev,
                                      info->max_tx_queues);
        info->tx_offload_capa &= vf_info.tx_offload_capa;
        info->tx_queue_offload_capa &= vf_info.tx_queue_offload_capa;
+       hn_vf_merge_desc_lim(&info->tx_desc_lim, &vf_info.tx_desc_lim);
 
        info->min_rx_bufsize = RTE_MAX(vf_info.min_rx_bufsize,
                                       info->min_rx_bufsize);
        info->max_rx_pktlen  = RTE_MAX(vf_info.max_rx_pktlen,
                                       info->max_rx_pktlen);
+       hn_vf_merge_desc_lim(&info->rx_desc_lim, &vf_info.rx_desc_lim);
 
        return 0;
 }
@@ -210,102 +386,73 @@ int hn_vf_info_get(struct hn_data *hv, struct rte_eth_dev_info *info)
        struct rte_eth_dev *vf_dev;
        int ret = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev)
                ret = hn_vf_info_merge(vf_dev, info);
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
        return ret;
 }
 
-int hn_vf_link_update(struct rte_eth_dev *dev,
-                     int wait_to_complete)
+int hn_vf_configure(struct rte_eth_dev *dev,
+                   const struct rte_eth_conf *dev_conf)
 {
        struct hn_data *hv = dev->data->dev_private;
-       struct rte_eth_dev *vf_dev;
+       struct rte_eth_conf vf_conf = *dev_conf;
        int ret = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
-       vf_dev = hn_get_vf_dev(hv);
-       if (vf_dev && vf_dev->dev_ops->link_update)
-               ret = (*vf_dev->dev_ops->link_update)(vf_dev, wait_to_complete);
-       rte_spinlock_unlock(&hv->vf_lock);
-
-       return ret;
-}
+       /* link state interrupt does not matter here. */
+       vf_conf.intr_conf.lsc = 0;
 
-/* called when VF has link state interrupts enabled */
-static int hn_vf_lsc_event(uint16_t port_id __rte_unused,
-                          enum rte_eth_event_type event,
-                          void *cb_arg, void *out __rte_unused)
-{
-       struct rte_eth_dev *dev = cb_arg;
+       /* need to monitor removal event */
+       vf_conf.intr_conf.rmv = 1;
 
-       if (event != RTE_ETH_EVENT_INTR_LSC)
-               return 0;
+       if (hv->vf_ctx.vf_attached) {
+               ret = rte_eth_dev_callback_register(hv->vf_ctx.vf_port,
+                                                   RTE_ETH_EVENT_INTR_RMV,
+                                                   hn_eth_rmv_event_callback,
+                                                   hv);
+               if (ret) {
+                       PMD_DRV_LOG(ERR,
+                                   "Registering callback failed for vf port %d ret %d",
+                                   hv->vf_ctx.vf_port, ret);
+                       return ret;
+               }
 
-       /* if link state has changed pass on */
-       if (hn_dev_link_update(dev, 0) == 0)
-               return 0; /* no change */
+               ret = rte_eth_dev_configure(hv->vf_ctx.vf_port,
+                                           dev->data->nb_rx_queues,
+                                           dev->data->nb_tx_queues,
+                                           &vf_conf);
+               if (ret) {
+                       PMD_DRV_LOG(ERR, "VF configuration failed: %d", ret);
 
-       return _rte_eth_dev_callback_process(dev,
-                                            RTE_ETH_EVENT_INTR_LSC,
-                                            NULL);
-}
+                       rte_eth_dev_callback_unregister(hv->vf_ctx.vf_port,
+                                                       RTE_ETH_EVENT_INTR_RMV,
+                                                       hn_eth_rmv_event_callback,
+                                                       hv);
 
-static int _hn_vf_configure(struct rte_eth_dev *dev,
-                           uint16_t vf_port,
-                           const struct rte_eth_conf *dev_conf)
-{
-       struct rte_eth_conf vf_conf = *dev_conf;
-       struct rte_eth_dev *vf_dev;
-       int ret;
+                       return ret;
+               }
 
-       vf_dev = &rte_eth_devices[vf_port];
-       if (dev_conf->intr_conf.lsc &&
-           (vf_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC)) {
-               PMD_DRV_LOG(DEBUG, "enabling LSC for VF %u",
-                           vf_port);
-               vf_conf.intr_conf.lsc = 1;
-       } else {
-               PMD_DRV_LOG(DEBUG, "disabling LSC for VF %u",
-                           vf_port);
-               vf_conf.intr_conf.lsc = 0;
+               hv->vf_ctx.vf_state = vf_configured;
        }
 
-       ret = rte_eth_dev_configure(vf_port,
-                                   dev->data->nb_rx_queues,
-                                   dev->data->nb_tx_queues,
-                                   &vf_conf);
-       if (ret) {
-               PMD_DRV_LOG(ERR,
-                           "VF configuration failed: %d", ret);
-       } else if (vf_conf.intr_conf.lsc) {
-               ret = rte_eth_dev_callback_register(vf_port,
-                                                   RTE_ETH_DEV_INTR_LSC,
-                                                   hn_vf_lsc_event, dev);
-               if (ret)
-                       PMD_DRV_LOG(ERR,
-                                   "Failed to register LSC callback for VF %u",
-                                   vf_port);
-       }
        return ret;
 }
 
-/*
- * Configure VF if present.
- * Force VF to have same number of queues as synthetic device
+/* Configure VF if present.
+ * VF device will have the same number of queues as the synthetic device
  */
-int hn_vf_configure(struct rte_eth_dev *dev,
-                   const struct rte_eth_conf *dev_conf)
+int hn_vf_configure_locked(struct rte_eth_dev *dev,
+                          const struct rte_eth_conf *dev_conf)
 {
        struct hn_data *hv = dev->data->dev_private;
        int ret = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
-       if (hv->vf_port != HN_INVALID_PORT)
-               ret = _hn_vf_configure(dev, hv->vf_port, dev_conf);
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_write_lock(&hv->vf_lock);
+       ret = hn_vf_configure(dev, dev_conf);
+       rte_rwlock_write_unlock(&hv->vf_lock);
+
        return ret;
 }
 
@@ -315,11 +462,11 @@ const uint32_t *hn_vf_supported_ptypes(struct rte_eth_dev *dev)
        struct rte_eth_dev *vf_dev;
        const uint32_t *ptypes = NULL;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev && vf_dev->dev_ops->dev_supported_ptypes_get)
                ptypes = (*vf_dev->dev_ops->dev_supported_ptypes_get)(vf_dev);
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
 
        return ptypes;
 }
@@ -330,24 +477,31 @@ int hn_vf_start(struct rte_eth_dev *dev)
        struct rte_eth_dev *vf_dev;
        int ret = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev)
                ret = rte_eth_dev_start(vf_dev->data->port_id);
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
        return ret;
 }
 
-void hn_vf_stop(struct rte_eth_dev *dev)
+int hn_vf_stop(struct rte_eth_dev *dev)
 {
        struct hn_data *hv = dev->data->dev_private;
        struct rte_eth_dev *vf_dev;
+       int ret = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
-       if (vf_dev)
-               rte_eth_dev_stop(vf_dev->data->port_id);
-       rte_spinlock_unlock(&hv->vf_lock);
+       if (vf_dev) {
+               ret = rte_eth_dev_stop(vf_dev->data->port_id);
+               if (ret != 0)
+                       PMD_DRV_LOG(ERR, "Failed to stop device on port %u",
+                                   vf_dev->data->port_id);
+       }
+       rte_rwlock_read_unlock(&hv->vf_lock);
+
+       return ret;
 }
 
 /* If VF is present, then cascade configuration down */
@@ -355,11 +509,25 @@ void hn_vf_stop(struct rte_eth_dev *dev)
        {                                                       \
                struct hn_data *hv = (dev)->data->dev_private;  \
                struct rte_eth_dev *vf_dev;                     \
-               rte_spinlock_lock(&hv->vf_lock);                \
+               rte_rwlock_read_lock(&hv->vf_lock);             \
                vf_dev = hn_get_vf_dev(hv);                     \
                if (vf_dev)                                     \
                        func(vf_dev->data->port_id);            \
-               rte_spinlock_unlock(&hv->vf_lock);              \
+               rte_rwlock_read_unlock(&hv->vf_lock);           \
+       }
+
+/* If VF is present, then cascade configuration down */
+#define VF_ETHDEV_FUNC_RET_STATUS(dev, func)                   \
+       {                                                       \
+               struct hn_data *hv = (dev)->data->dev_private;  \
+               struct rte_eth_dev *vf_dev;                     \
+               int ret = 0;                                    \
+               rte_rwlock_read_lock(&hv->vf_lock);             \
+               vf_dev = hn_get_vf_dev(hv);                     \
+               if (vf_dev)                                     \
+                       ret = func(vf_dev->data->port_id);      \
+               rte_rwlock_read_unlock(&hv->vf_lock);           \
+               return ret;                                     \
        }
 
 void hn_vf_reset(struct rte_eth_dev *dev)
@@ -367,43 +535,51 @@ void hn_vf_reset(struct rte_eth_dev *dev)
        VF_ETHDEV_FUNC(dev, rte_eth_dev_reset);
 }
 
-void hn_vf_close(struct rte_eth_dev *dev)
+int hn_vf_close(struct rte_eth_dev *dev)
 {
+       int ret = 0;
        struct hn_data *hv = dev->data->dev_private;
-       uint16_t vf_port;
 
-       rte_spinlock_lock(&hv->vf_lock);
-       vf_port = hv->vf_port;
-       if (vf_port != HN_INVALID_PORT)
-               rte_eth_dev_close(vf_port);
+       rte_eal_alarm_cancel(hn_vf_add_retry, dev);
+
+       rte_rwlock_read_lock(&hv->vf_lock);
+       if (hv->vf_ctx.vf_attached) {
+               rte_eth_dev_callback_unregister(hv->vf_ctx.vf_port,
+                                               RTE_ETH_EVENT_INTR_RMV,
+                                               hn_eth_rmv_event_callback,
+                                               hv);
+               rte_eal_alarm_cancel(hn_remove_delayed, hv);
+               ret = rte_eth_dev_close(hv->vf_ctx.vf_port);
+               hv->vf_ctx.vf_attached = false;
+       }
+       rte_rwlock_read_unlock(&hv->vf_lock);
 
-       hv->vf_port = HN_INVALID_PORT;
-       rte_spinlock_unlock(&hv->vf_lock);
+       return ret;
 }
 
-void hn_vf_stats_reset(struct rte_eth_dev *dev)
+int hn_vf_stats_reset(struct rte_eth_dev *dev)
 {
-       VF_ETHDEV_FUNC(dev, rte_eth_stats_reset);
+       VF_ETHDEV_FUNC_RET_STATUS(dev, rte_eth_stats_reset);
 }
 
-void hn_vf_allmulticast_enable(struct rte_eth_dev *dev)
+int hn_vf_allmulticast_enable(struct rte_eth_dev *dev)
 {
-       VF_ETHDEV_FUNC(dev, rte_eth_allmulticast_enable);
+       VF_ETHDEV_FUNC_RET_STATUS(dev, rte_eth_allmulticast_enable);
 }
 
-void hn_vf_allmulticast_disable(struct rte_eth_dev *dev)
+int hn_vf_allmulticast_disable(struct rte_eth_dev *dev)
 {
-       VF_ETHDEV_FUNC(dev, rte_eth_allmulticast_disable);
+       VF_ETHDEV_FUNC_RET_STATUS(dev, rte_eth_allmulticast_disable);
 }
 
-void hn_vf_promiscuous_enable(struct rte_eth_dev *dev)
+int hn_vf_promiscuous_enable(struct rte_eth_dev *dev)
 {
-       VF_ETHDEV_FUNC(dev, rte_eth_promiscuous_enable);
+       VF_ETHDEV_FUNC_RET_STATUS(dev, rte_eth_promiscuous_enable);
 }
 
-void hn_vf_promiscuous_disable(struct rte_eth_dev *dev)
+int hn_vf_promiscuous_disable(struct rte_eth_dev *dev)
 {
-       VF_ETHDEV_FUNC(dev, rte_eth_promiscuous_disable);
+       VF_ETHDEV_FUNC_RET_STATUS(dev, rte_eth_promiscuous_disable);
 }
 
 int hn_vf_mc_addr_list(struct rte_eth_dev *dev,
@@ -414,12 +590,12 @@ int hn_vf_mc_addr_list(struct rte_eth_dev *dev,
        struct rte_eth_dev *vf_dev;
        int ret = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev)
                ret = rte_eth_dev_set_mc_addr_list(vf_dev->data->port_id,
                                                   mc_addr_set, nb_mc_addr);
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
        return ret;
 }
 
@@ -432,13 +608,13 @@ int hn_vf_tx_queue_setup(struct rte_eth_dev *dev,
        struct rte_eth_dev *vf_dev;
        int ret = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev)
                ret = rte_eth_tx_queue_setup(vf_dev->data->port_id,
                                             queue_idx, nb_desc,
                                             socket_id, tx_conf);
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
        return ret;
 }
 
@@ -446,7 +622,7 @@ void hn_vf_tx_queue_release(struct hn_data *hv, uint16_t queue_id)
 {
        struct rte_eth_dev *vf_dev;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev && vf_dev->dev_ops->tx_queue_release) {
                void *subq = vf_dev->data->tx_queues[queue_id];
@@ -454,7 +630,7 @@ void hn_vf_tx_queue_release(struct hn_data *hv, uint16_t queue_id)
                (*vf_dev->dev_ops->tx_queue_release)(subq);
        }
 
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
 }
 
 int hn_vf_rx_queue_setup(struct rte_eth_dev *dev,
@@ -467,13 +643,13 @@ int hn_vf_rx_queue_setup(struct rte_eth_dev *dev,
        struct rte_eth_dev *vf_dev;
        int ret = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev)
                ret = rte_eth_rx_queue_setup(vf_dev->data->port_id,
                                             queue_idx, nb_desc,
                                             socket_id, rx_conf, mp);
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
        return ret;
 }
 
@@ -481,14 +657,14 @@ void hn_vf_rx_queue_release(struct hn_data *hv, uint16_t queue_id)
 {
        struct rte_eth_dev *vf_dev;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev && vf_dev->dev_ops->rx_queue_release) {
                void *subq = vf_dev->data->rx_queues[queue_id];
 
                (*vf_dev->dev_ops->rx_queue_release)(subq);
        }
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
 }
 
 int hn_vf_stats_get(struct rte_eth_dev *dev,
@@ -498,11 +674,11 @@ int hn_vf_stats_get(struct rte_eth_dev *dev,
        struct rte_eth_dev *vf_dev;
        int ret = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev)
                ret = rte_eth_stats_get(vf_dev->data->port_id, stats);
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
        return ret;
 }
 
@@ -514,12 +690,12 @@ int hn_vf_xstats_get_names(struct rte_eth_dev *dev,
        struct rte_eth_dev *vf_dev;
        int i, count = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev)
                count = rte_eth_xstats_get_names(vf_dev->data->port_id,
                                                 names, n);
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
 
        /* add vf_ prefix to xstat names */
        if (names) {
@@ -543,12 +719,12 @@ int hn_vf_xstats_get(struct rte_eth_dev *dev,
        struct rte_eth_dev *vf_dev;
        int i, count = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev)
                count = rte_eth_xstats_get(vf_dev->data->port_id,
                                           xstats + offset, n - offset);
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
 
        /* Offset id's for VF stats */
        if (count > 0) {
@@ -559,16 +735,21 @@ int hn_vf_xstats_get(struct rte_eth_dev *dev,
        return count;
 }
 
-void hn_vf_xstats_reset(struct rte_eth_dev *dev)
+int hn_vf_xstats_reset(struct rte_eth_dev *dev)
 {
        struct hn_data *hv = dev->data->dev_private;
        struct rte_eth_dev *vf_dev;
+       int ret;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev)
-               rte_eth_xstats_reset(vf_dev->data->port_id);
-       rte_spinlock_unlock(&hv->vf_lock);
+               ret = rte_eth_xstats_reset(vf_dev->data->port_id);
+       else
+               ret = -EINVAL;
+       rte_rwlock_read_unlock(&hv->vf_lock);
+
+       return ret;
 }
 
 int hn_vf_rss_hash_update(struct rte_eth_dev *dev,
@@ -578,11 +759,11 @@ int hn_vf_rss_hash_update(struct rte_eth_dev *dev,
        struct rte_eth_dev *vf_dev;
        int ret = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev && vf_dev->dev_ops->rss_hash_update)
                ret = vf_dev->dev_ops->rss_hash_update(vf_dev, rss_conf);
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
 
        return ret;
 }
@@ -595,12 +776,12 @@ int hn_vf_reta_hash_update(struct rte_eth_dev *dev,
        struct rte_eth_dev *vf_dev;
        int ret = 0;
 
-       rte_spinlock_lock(&hv->vf_lock);
+       rte_rwlock_read_lock(&hv->vf_lock);
        vf_dev = hn_get_vf_dev(hv);
        if (vf_dev && vf_dev->dev_ops->reta_update)
                ret = vf_dev->dev_ops->reta_update(vf_dev,
                                                   reta_conf, reta_size);
-       rte_spinlock_unlock(&hv->vf_lock);
+       rte_rwlock_read_unlock(&hv->vf_lock);
 
        return ret;
 }