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