+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\n", 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\n",
+ 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\n",
+ 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\n",
+ 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\n",
+ 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\n", 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\n",
+ 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\n",
+ 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\n",
+ 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\n",
+ 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);
+