diff --git a/drivers/net/iavf/iavf.h b/drivers/net/iavf/iavf.h
index 10868f2c30..e1cb1e0bc3 100644
--- a/drivers/net/iavf/iavf.h
+++ b/drivers/net/iavf/iavf.h
@@ -19,6 +19,7 @@
 #define IAVF_AQ_LEN               32
 #define IAVF_AQ_BUF_SZ            4096
 #define IAVF_RESET_WAIT_CNT       500
+#define IAVF_RESET_DETECTED_CNT   100
 #define IAVF_BUF_SIZE_MIN         1024
 #define IAVF_FRAME_SIZE_MAX       9728
 #define IAVF_QUEUE_BASE_ADDR_UNIT 128
@@ -32,6 +33,7 @@
 #define IAVF_NUM_MACADDR_MAX      64
 
 #define IAVF_DEV_WATCHDOG_PERIOD     2000 /* microseconds, set 0 to disable*/
+#define IAVF_MAX_VF_COUNT            256
 
 #define IAVF_DEFAULT_RX_PTHRESH      8
 #define IAVF_DEFAULT_RX_HTHRESH      8
@@ -511,5 +513,5 @@ int iavf_flow_sub_check(struct iavf_adapter *adapter,
 			struct iavf_fsub_conf *filter);
 void iavf_dev_watchdog_enable(struct iavf_adapter *adapter);
 void iavf_dev_watchdog_disable(struct iavf_adapter *adapter);
-int iavf_handle_hw_reset(struct rte_eth_dev *dev);
+int iavf_reset_enqueue(struct rte_eth_dev *dev);
 #endif /* _IAVF_ETHDEV_H_ */
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index d1edb0dd5c..63848f7f6e 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -90,6 +90,23 @@ static struct iavf_proto_xtr_ol iavf_proto_xtr_params[] = {
 			&rte_pmd_ifd_dynflag_proto_xtr_ipsec_crypto_said_mask },
 };
 
+/* struct holding pending PF-to-VF reset */
+struct iavf_reset_info {
+	pthread_mutex_t lock;
+	rte_thread_t reset_tid;
+	uint32_t pending;
+	uint32_t head;
+	uint32_t tail;
+	struct rte_eth_dev *dev[IAVF_MAX_VF_COUNT];
+};
+
+static struct iavf_reset_info reset_info = {
+	.lock = PTHREAD_MUTEX_INITIALIZER,
+	.head = 0,
+	.tail = 0,
+	.pending = 0,
+};
+
 static int iavf_dev_configure(struct rte_eth_dev *dev);
 static int iavf_dev_start(struct rte_eth_dev *dev);
 static int iavf_dev_stop(struct rte_eth_dev *dev);
@@ -310,8 +327,10 @@ iavf_dev_watchdog(void *cb_arg)
 			adapter->vf.vf_reset = true;
 			adapter->vf.link_up = false;
 
-			iavf_dev_event_post(adapter->vf.eth_dev, RTE_ETH_EVENT_INTR_RESET,
-				NULL, 0);
+			adapter->devargs.auto_reset ?
+				iavf_reset_enqueue(adapter->vf.eth_dev) :
+				iavf_dev_event_post(adapter->vf.eth_dev,
+					RTE_ETH_EVENT_INTR_RESET, NULL, 0);
 		}
 	}
 
@@ -1086,9 +1105,6 @@ iavf_dev_stop(struct rte_eth_dev *dev)
 
 	PMD_INIT_FUNC_TRACE();
 
-	if (vf->vf_reset)
-		return 0;
-
 	if (adapter->closed)
 		return -1;
 
@@ -1986,14 +2002,11 @@ iavf_check_vf_reset_done(struct iavf_hw *hw)
 		reset = reset >> IAVF_VFGEN_RSTAT_VFR_STATE_SHIFT;
 		if (reset == VIRTCHNL_VFR_VFACTIVE ||
 		    reset == VIRTCHNL_VFR_COMPLETED)
-			break;
+			return 0;
 		rte_delay_ms(20);
 	}
 
-	if (i >= IAVF_RESET_WAIT_CNT)
-		return -1;
-
-	return 0;
+	return -1;
 }
 
 static int
@@ -2928,15 +2941,12 @@ iavf_dev_close(struct rte_eth_dev *dev)
 static int
 iavf_dev_uninit(struct rte_eth_dev *dev)
 {
-	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
-
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
 		return -EPERM;
 
 	iavf_dev_close(dev);
 
-	if (!vf->in_reset_recovery)
-		iavf_dev_event_handler_fini();
+	iavf_dev_event_handler_fini();
 
 	return 0;
 }
@@ -2949,7 +2959,6 @@ iavf_dev_reset(struct rte_eth_dev *dev)
 {
 	int ret;
 	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
 
 	/*
 	 * Check whether the VF reset has been done and inform application,
@@ -2961,7 +2970,6 @@ iavf_dev_reset(struct rte_eth_dev *dev)
 		PMD_DRV_LOG(ERR, "Wait too long for reset done!\n");
 		return ret;
 	}
-	vf->vf_reset = false;
 
 	PMD_DRV_LOG(DEBUG, "Start dev_reset ...\n");
 	ret = iavf_dev_uninit(dev);
@@ -2971,41 +2979,127 @@ iavf_dev_reset(struct rte_eth_dev *dev)
 	return iavf_dev_init(dev);
 }
 
+static struct rte_eth_dev *
+iavf_reset_dequeue(void)
+{
+	struct rte_eth_dev *dev;
+
+	pthread_mutex_lock(&reset_info.lock);
+	if (reset_info.head == reset_info.tail) {
+		pthread_mutex_unlock(&reset_info.lock);
+		return NULL;
+	}
+	dev = reset_info.dev[reset_info.head];
+	reset_info.head = (reset_info.head + 1) % IAVF_MAX_VF_COUNT;
+	reset_info.pending--;
+	pthread_mutex_unlock(&reset_info.lock);
+
+	return dev;
+}
+
+static inline bool
+iavf_is_reset(struct iavf_hw *hw)
+{
+	return !(IAVF_READ_REG(hw, IAVF_VF_ARQLEN1) &
+		 IAVF_VF_ARQLEN1_ARQENABLE_MASK);
+}
+
+static bool
+iavf_is_reset_detected(struct iavf_adapter *adapter)
+{
+	struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(adapter);
+	int i;
+
+	/* poll until we see the reset actually happen */
+	for (i = 0; i < IAVF_RESET_DETECTED_CNT; i++) {
+		if (iavf_is_reset(hw))
+			return true;
+		rte_delay_ms(20);
+	}
+
+	return false;
+}
+
 /*
  * Handle hardware reset
  */
-int
-iavf_handle_hw_reset(struct rte_eth_dev *dev)
+static uint32_t
+iavf_hw_reset_handler(void *arg __rte_unused)
 {
-	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
-	int ret;
+	struct rte_eth_dev *dev;
+	int ret, i;
 
-	vf->in_reset_recovery = true;
+	for (dev = iavf_reset_dequeue(); dev != NULL; dev = iavf_reset_dequeue()) {
+		struct iavf_adapter *adapter = dev->data->dev_private;
+		struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
 
-	ret = iavf_dev_reset(dev);
-	if (ret)
-		goto error;
+		if (!iavf_is_reset_detected(adapter))
+			return 0;
 
-	/* VF states restore */
-	ret = iavf_dev_configure(dev);
-	if (ret)
-		goto error;
+		vf->in_reset_recovery = true;
 
-	iavf_dev_xstats_reset(dev);
+		ret = iavf_dev_reset(dev);
+		if (ret)
+			goto error;
 
-	/* start the device */
-	ret = iavf_dev_start(dev);
-	if (ret)
-		goto error;
-	dev->data->dev_started = 1;
+		/* VF states restore */
+		ret = iavf_dev_configure(dev);
+		if (ret)
+			goto error;
 
-	vf->in_reset_recovery = false;
-	return 0;
+		iavf_dev_xstats_reset(dev);
+
+		/* start the device */
+		ret = iavf_dev_start(dev);
+		if (ret)
+			goto error;
+
+		/* Restore queue parameters */
+		for (i = 0; i < dev->data->nb_rx_queues; i++) {
+			struct iavf_rx_queue *rxq = dev->data->rx_queues[i];
+			rxq->vsi = &vf->vsi;
+		}
+
+		for (i = 0; i < dev->data->nb_tx_queues; i++) {
+			struct iavf_tx_queue *txq = dev->data->tx_queues[i];
+			txq->vsi = &vf->vsi;
+		}
+		dev->data->dev_started = 1;
 
 error:
-	PMD_DRV_LOG(DEBUG, "RESET recover with error code=%d\n", ret);
-	vf->in_reset_recovery = false;
-	return ret;
+		vf->in_reset_recovery = false;
+	}
+
+	return -1;
+}
+
+int
+iavf_reset_enqueue(struct rte_eth_dev *dev)
+{
+	int first_entry;
+
+	pthread_mutex_lock(&reset_info.lock);
+	if ((reset_info.tail + 1) % IAVF_MAX_VF_COUNT == reset_info.head) {
+		pthread_mutex_unlock(&reset_info.lock);
+		return -1;
+	}
+	first_entry = reset_info.pending == 0;
+	reset_info.dev[reset_info.tail] = dev;
+	reset_info.tail = (reset_info.tail + 1) % IAVF_MAX_VF_COUNT;
+	reset_info.pending++;
+	if (first_entry) {
+		PMD_DRV_LOG(DEBUG, "Create reset thread !!!\n");
+		if (rte_thread_create_internal_control(&reset_info.reset_tid,
+			"iavf-reset-thread", iavf_hw_reset_handler, NULL)) {
+			pthread_mutex_unlock(&reset_info.lock);
+			PMD_DRV_LOG(ERR, "Fail to kick off iavf-reset-thread\n");
+			return -1;
+		}
+		rte_thread_detach(reset_info.reset_tid);
+	}
+	pthread_mutex_unlock(&reset_info.lock);
+
+	return 0;
 }
 
 static int
diff --git a/drivers/net/iavf/iavf_vchnl.c b/drivers/net/iavf/iavf_vchnl.c
index 0a3e1d082c..cccc9a57e3 100644
--- a/drivers/net/iavf/iavf_vchnl.c
+++ b/drivers/net/iavf/iavf_vchnl.c
@@ -80,14 +80,6 @@ iavf_dev_event_handle(void *param __rte_unused)
 		TAILQ_FOREACH_SAFE(pos, &pending, next, save_next) {
 			TAILQ_REMOVE(&pending, pos, next);
 
-			struct iavf_adapter *adapter = pos->dev->data->dev_private;
-			if (pos->event == RTE_ETH_EVENT_INTR_RESET &&
-			    adapter->devargs.auto_reset) {
-				iavf_handle_hw_reset(pos->dev);
-				rte_free(pos);
-				continue;
-			}
-
 			rte_eth_dev_callback_process(pos->dev, pos->event, pos->param);
 			rte_free(pos);
 		}
@@ -462,8 +454,9 @@ iavf_handle_pf_event_msg(struct rte_eth_dev *dev, uint8_t *msg,
 		vf->link_up = false;
 		if (!vf->vf_reset) {
 			vf->vf_reset = true;
-			iavf_dev_event_post(dev, RTE_ETH_EVENT_INTR_RESET,
-				NULL, 0);
+			adapter->devargs.auto_reset ?
+				iavf_reset_enqueue(dev) :
+				iavf_dev_event_post(dev, RTE_ETH_EVENT_INTR_RESET, NULL, 0);
 		}
 		break;
 	case VIRTCHNL_EVENT_LINK_CHANGE:
