diff --git a/drivers/net/virtio/virtio_ethdev.c b/drivers/net/virtio/virtio_ethdev.c
index b98d195..c477b05 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -1037,7 +1037,7 @@ eth_virtio_dev_init(struct rte_eth_dev *eth_dev)
 
 	pci_dev = eth_dev->pci_dev;
 
-	if (vtpci_init(pci_dev, hw) < 0)
+	if (vtpci_init(eth_dev, hw) < 0)
 		return -1;
 
 	/* Reset the device although not necessary at startup */
@@ -1177,7 +1177,7 @@ eth_virtio_dev_uninit(struct rte_eth_dev *eth_dev)
 		rte_intr_callback_unregister(&pci_dev->intr_handle,
 						virtio_interrupt_handler,
 						eth_dev);
-	vtpci_uninit(dev, hw)
+	vtpci_uninit(eth_dev, hw);
 
 	PMD_INIT_LOG(DEBUG, "dev_uninit completed");
 
diff --git a/drivers/net/virtio/virtio_pci.c b/drivers/net/virtio/virtio_pci.c
index ffcd2fa..20b64eb 100644
--- a/drivers/net/virtio/virtio_pci.c
+++ b/drivers/net/virtio/virtio_pci.c
@@ -68,6 +68,190 @@
 #define VIRTIO_WRITE_REG_4(hw, reg, value) \
 	outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
 
+static uint8_t
+phys_legacy_read8(struct virtio_hw *hw, uint8_t *addr)
+{
+	return VIRTIO_READ_REG_1(hw, (uint64_t)addr);
+}
+
+static uint16_t
+phys_legacy_read16(struct virtio_hw *hw, uint16_t *addr)
+{
+	return VIRTIO_READ_REG_2(hw, (uint64_t)addr);
+}
+
+static uint32_t
+phys_legacy_read32(struct virtio_hw *hw, uint32_t *addr)
+{
+	return VIRTIO_READ_REG_4(hw, (uint64_t)addr);
+}
+
+static void
+phys_legacy_write8(struct virtio_hw *hw, uint8_t *addr, uint8_t val)
+{
+	return VIRTIO_WRITE_REG_1(hw, (uint64_t)addr, val);
+}
+
+static void
+phys_legacy_write16(struct virtio_hw *hw, uint16_t *addr, uint16_t val)
+{
+	return VIRTIO_WRITE_REG_2(hw, (uint64_t)addr, val);
+}
+
+static void
+phys_legacy_write32(struct virtio_hw *hw, uint32_t *addr, uint32_t val)
+{
+	return VIRTIO_WRITE_REG_4(hw, (uint64_t)addr, val);
+}
+
+#define MODERN_READ_DEF(nr_bits, type) 		\
+static inline type				\
+io_read##nr_bits(type *addr)			\
+{						\
+	return *(volatile type *)addr;		\
+}
+
+#define MODERN_WRITE_DEF(nr_bits, type) 	\
+static inline void				\
+io_write##nr_bits(type *addr, type val)		\
+{						\
+	*(volatile type *)addr = val;		\
+}
+
+MODERN_READ_DEF (8, uint8_t)
+MODERN_WRITE_DEF(8, uint8_t)
+
+MODERN_READ_DEF (16, uint16_t)
+MODERN_WRITE_DEF(16, uint16_t)
+
+MODERN_READ_DEF (32, uint32_t)
+MODERN_WRITE_DEF(32, uint32_t)
+
+static uint8_t
+phys_modern_read8(struct virtio_hw *hw __rte_unused, uint8_t *addr)
+{
+	return io_read8((uint8_t *)addr);
+}
+
+static uint16_t
+phys_modern_read16(struct virtio_hw *hw __rte_unused, uint16_t *addr)
+{
+	return io_read16((uint16_t *)addr);
+}
+
+static uint32_t
+phys_modern_read32(struct virtio_hw *hw __rte_unused, uint32_t *addr)
+{
+	return io_read32((uint32_t *)addr);
+}
+
+static void
+phys_modern_write8(struct virtio_hw *hw __rte_unused,
+		uint8_t *addr, uint8_t val)
+{
+	return io_write8((uint8_t *)addr, val);
+}
+
+static void
+phys_modern_write16(struct virtio_hw *hw __rte_unused,
+		uint16_t *addr, uint16_t val)
+{
+	return io_write16((uint16_t *)addr, val);
+}
+
+static void
+phys_modern_write32(struct virtio_hw *hw __rte_unused,
+		uint32_t *addr, uint32_t val)
+{
+	return io_write32((uint32_t *)addr, val);
+}
+
+static int
+phys_map_pci_cfg(struct virtio_hw *hw)
+{
+	return rte_eal_pci_map_device(hw->dev);
+}
+
+static void
+phys_unmap_pci_cfg(struct virtio_hw *hw)
+{
+	rte_eal_pci_unmap_device(hw->dev);
+}
+
+static int
+phys_read_pci_cfg(struct virtio_hw *hw, void *buf, size_t len, off_t offset)
+{
+	return rte_eal_pci_read_config(hw->dev, buf, len, offset);
+}
+
+static void *
+phys_get_cfg_addr(struct virtio_hw *hw, struct virtio_pci_cap *cap)
+{
+	uint8_t  bar    = cap->bar;
+	uint32_t length = cap->length;
+	uint32_t offset = cap->offset;
+	uint8_t *base;
+
+	if (bar > 5) {
+		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
+		return NULL;
+	}
+
+	if (offset + length > hw->dev->mem_resource[bar].len) {
+		PMD_INIT_LOG(ERR,
+			"invalid cap: overflows bar space: %u > %"PRIu64,
+			offset + length, hw->dev->mem_resource[bar].len);
+		return NULL;
+	}
+
+	base = hw->dev->mem_resource[bar].addr;
+	if (base == NULL) {
+		PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar);
+		return NULL;
+	}
+
+	return base + offset;
+}
+
+static const struct virtio_pci_access_ops phys_access_ops = {
+	.legacy_read8		= phys_legacy_read8,
+	.legacy_read16		= phys_legacy_read16,
+	.legacy_read32		= phys_legacy_read32,
+	.legacy_write8		= phys_legacy_write8,
+	.legacy_write16		= phys_legacy_write16,
+	.legacy_write32		= phys_legacy_write32,
+
+	.modern_read8		= phys_modern_read8,
+	.modern_read16		= phys_modern_read16,
+	.modern_read32		= phys_modern_read32,
+	.modern_write8		= phys_modern_write8,
+	.modern_write16		= phys_modern_write16,
+	.modern_write32		= phys_modern_write32,
+
+	.map_pci_cfg		= phys_map_pci_cfg,
+	.unmap_pci_cfg		= phys_unmap_pci_cfg,
+	.read_pci_cfg		= phys_read_pci_cfg,
+	.get_cfg_addr		= phys_get_cfg_addr,
+};
+
+static int
+vtpci_access_init(struct rte_eth_dev *dev, struct virtio_hw *hw)
+{
+	if (dev->dev_type == RTE_ETH_DEV_PCI) {
+		hw->vtpci_access_ops = &phys_access_ops;
+		return 0;
+	}
+
+	PMD_DRV_LOG(ERR, "Unkown virtio-net device.");
+	return -1;
+}
+
+static void
+vtpci_access_uninit(struct rte_eth_dev *dev __rte_unused, struct virtio_hw *hw)
+{
+	hw->vtpci_access_ops = NULL;
+}
+
 static void
 legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 		       void *dst, int length)
@@ -80,13 +264,16 @@ legacy_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 	for (d = dst; length > 0; d += size, off += size, length -= size) {
 		if (length >= 4) {
 			size = 4;
-			*(uint32_t *)d = VIRTIO_READ_REG_4(hw, off);
+			*(uint32_t *)d = hw->vtpci_access_ops->legacy_read32(
+						hw, (uint32_t *)off);
 		} else if (length >= 2) {
 			size = 2;
-			*(uint16_t *)d = VIRTIO_READ_REG_2(hw, off);
+			*(uint16_t *)d = hw->vtpci_access_ops->legacy_read16(
+						hw, (uint16_t *)off);
 		} else {
 			size = 1;
-			*d = VIRTIO_READ_REG_1(hw, off);
+			*d = hw->vtpci_access_ops->legacy_read8(
+						hw, (uint8_t *)off);
 		}
 	}
 }
@@ -103,13 +290,16 @@ legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	for (s = src; length > 0; s += size, off += size, length -= size) {
 		if (length >= 4) {
 			size = 4;
-			VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s);
+			hw->vtpci_access_ops->legacy_write32(hw,
+					(uint32_t *)off, *(const uint32_t *)s);
 		} else if (length >= 2) {
 			size = 2;
-			VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s);
+			hw->vtpci_access_ops->legacy_write16(hw,
+					(uint16_t *)off, *(const uint16_t *)s);
 		} else {
 			size = 1;
-			VIRTIO_WRITE_REG_1(hw, off, *s);
+			hw->vtpci_access_ops->legacy_write8(hw,
+					(uint8_t *)off, *s);
 		}
 	}
 }
@@ -117,7 +307,8 @@ legacy_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 static uint64_t
 legacy_get_features(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
+	return hw->vtpci_access_ops->legacy_read32(hw,
+			(uint32_t *)VIRTIO_PCI_HOST_FEATURES);
 }
 
 static void
@@ -128,19 +319,22 @@ legacy_set_features(struct virtio_hw *hw, uint64_t features)
 			"only 32 bit features are allowed for legacy virtio!");
 		return;
 	}
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
+	hw->vtpci_access_ops->legacy_write32(hw,
+			(uint32_t *)VIRTIO_PCI_GUEST_FEATURES, features);
 }
 
 static uint8_t
 legacy_get_status(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
+	return hw->vtpci_access_ops->legacy_read8(hw,
+			(uint8_t *)VIRTIO_PCI_STATUS);
 }
 
 static void
 legacy_set_status(struct virtio_hw *hw, uint8_t status)
 {
-	VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
+	hw->vtpci_access_ops->legacy_write8(hw,
+			(uint8_t *)VIRTIO_PCI_STATUS, status);
 }
 
 static void
@@ -152,45 +346,56 @@ legacy_reset(struct virtio_hw *hw)
 static uint8_t
 legacy_get_isr(struct virtio_hw *hw)
 {
-	return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
+	return hw->vtpci_access_ops->legacy_read8(hw,
+			(uint8_t *)VIRTIO_PCI_ISR);
 }
 
 /* Enable one vector (0) for Link State Intrerrupt */
 static uint16_t
 legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR, vec);
-	return VIRTIO_READ_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR);
+	hw->vtpci_access_ops->legacy_write16(hw,
+			(uint16_t *)VIRTIO_MSI_CONFIG_VECTOR, vec);
+	return hw->vtpci_access_ops->legacy_read16(hw,
+			(uint16_t *)VIRTIO_MSI_CONFIG_VECTOR);
 }
 
 static uint16_t
 legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, queue_id);
-	return VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
+	hw->vtpci_access_ops->legacy_write16(hw,
+			(uint16_t *)VIRTIO_PCI_QUEUE_SEL, queue_id);
+	return hw->vtpci_access_ops->legacy_read16(hw,
+			(uint16_t *)VIRTIO_PCI_QUEUE_NUM);
 }
 
 static void
 legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
+	hw->vtpci_access_ops->legacy_write16(hw,
+			(uint16_t *)VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
-		vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+	hw->vtpci_access_ops->legacy_write32(hw,
+			(uint32_t *)VIRTIO_PCI_QUEUE_PFN,
+			vq->vq_ring_mem >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
 }
 
 static void
 legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
+	hw->vtpci_access_ops->legacy_write16(hw,
+			(uint16_t *)VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
 
-	VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
+	hw->vtpci_access_ops->legacy_write32(hw,
+			(uint32_t *)VIRTIO_PCI_QUEUE_PFN, 0);
 }
 
 static void
 legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
+	hw->vtpci_access_ops->legacy_write16(hw,
+			(uint16_t *)VIRTIO_PCI_QUEUE_NOTIFY,
+			vq->vq_queue_index);
 }
 
 #ifdef RTE_EXEC_ENV_LINUXAPP
@@ -468,35 +673,12 @@ static const struct virtio_pci_ops legacy_ops = {
 	.notify_queue	= legacy_notify_queue,
 };
 
-
-#define MODERN_READ_DEF(nr_bits, type)		\
-static inline type				\
-io_read##nr_bits(type *addr)			\
-{						\
-	return *(volatile type *)addr;		\
-}
-
-#define MODERN_WRITE_DEF(nr_bits, type)		\
-static inline void				\
-io_write##nr_bits(type *addr, type val)		\
-{						\
-	*(volatile type *)addr = val;		\
-}
-
-MODERN_READ_DEF (8, uint8_t)
-MODERN_WRITE_DEF(8, uint8_t)
-
-MODERN_READ_DEF (16, uint16_t)
-MODERN_WRITE_DEF(16, uint16_t)
-
-MODERN_READ_DEF (32, uint32_t)
-MODERN_WRITE_DEF(32, uint32_t)
-
 static inline void
-io_write64_twopart(uint32_t *lo, uint32_t *hi, uint64_t val)
+io_write64_twopart(struct virtio_hw *hw,
+		   uint32_t *lo, uint32_t *hi, uint64_t val)
 {
-	io_write32(lo, (uint32_t)val);
-	io_write32(hi, val >> 32);
+	hw->vtpci_access_ops->modern_write32(hw, lo, (uint32_t)val);
+	hw->vtpci_access_ops->modern_write32(hw, hi, val >> 32);
 }
 
 static void
@@ -508,13 +690,16 @@ modern_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 	uint8_t old_gen, new_gen;
 
 	do {
-		old_gen = io_read8(&hw->common_cfg->config_generation);
+		old_gen = hw->vtpci_access_ops->modern_read8(hw,
+				&hw->common_cfg->config_generation);
 
 		p = dst;
 		for (i = 0;  i < length; i++)
-			*p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i);
+			*p++ = hw->vtpci_access_ops->modern_read8(hw,
+					(uint8_t *)hw->dev_cfg + offset + i);
 
-		new_gen = io_read8(&hw->common_cfg->config_generation);
+		new_gen = hw->vtpci_access_ops->modern_read8(hw,
+				&hw->common_cfg->config_generation);
 	} while (old_gen != new_gen);
 }
 
@@ -526,7 +711,8 @@ modern_write_dev_config(struct virtio_hw *hw, uint64_t offset,
 	const uint8_t *p = src;
 
 	for (i = 0;  i < length; i++)
-		io_write8((uint8_t *)hw->dev_cfg + offset + i, *p++);
+		hw->vtpci_access_ops->modern_write8(hw,
+				(uint8_t *)hw->dev_cfg + offset + i, *p++);
 }
 
 static uint64_t
@@ -534,11 +720,15 @@ modern_get_features(struct virtio_hw *hw)
 {
 	uint32_t features_lo, features_hi;
 
-	io_write32(&hw->common_cfg->device_feature_select, 0);
-	features_lo = io_read32(&hw->common_cfg->device_feature);
+	hw->vtpci_access_ops->modern_write32(hw,
+			&hw->common_cfg->device_feature_select, 0);
+	features_lo = hw->vtpci_access_ops->modern_read32(hw,
+			&hw->common_cfg->device_feature);
 
-	io_write32(&hw->common_cfg->device_feature_select, 1);
-	features_hi = io_read32(&hw->common_cfg->device_feature);
+	hw->vtpci_access_ops->modern_write32(hw,
+			&hw->common_cfg->device_feature_select, 1);
+	features_hi = hw->vtpci_access_ops->modern_read32(hw,
+			&hw->common_cfg->device_feature);
 
 	return ((uint64_t)(features_hi) << 32) | features_lo;
 }
@@ -546,25 +736,30 @@ modern_get_features(struct virtio_hw *hw)
 static void
 modern_set_features(struct virtio_hw *hw, uint64_t features)
 {
-	io_write32(&hw->common_cfg->guest_feature_select, 0);
-	io_write32(&hw->common_cfg->guest_feature,
-		   features & ((1ULL << 32) - 1));
+	hw->vtpci_access_ops->modern_write32(hw,
+			&hw->common_cfg->guest_feature_select, 0);
+	hw->vtpci_access_ops->modern_write32(hw,
+			&hw->common_cfg->guest_feature,
+			features & ((1ULL << 32) - 1));
 
-	io_write32(&hw->common_cfg->guest_feature_select, 1);
-	io_write32(&hw->common_cfg->guest_feature,
-		   features >> 32);
+	hw->vtpci_access_ops->modern_write32(hw,
+			&hw->common_cfg->guest_feature_select, 1);
+	hw->vtpci_access_ops->modern_write32(hw,
+			&hw->common_cfg->guest_feature, features >> 32);
 }
 
 static uint8_t
 modern_get_status(struct virtio_hw *hw)
 {
-	return io_read8(&hw->common_cfg->device_status);
+	return hw->vtpci_access_ops->modern_read8(hw,
+			&hw->common_cfg->device_status);
 }
 
 static void
 modern_set_status(struct virtio_hw *hw, uint8_t status)
 {
-	io_write8(&hw->common_cfg->device_status, status);
+	hw->vtpci_access_ops->modern_write8(hw,
+			&hw->common_cfg->device_status, status);
 }
 
 static void
@@ -577,21 +772,25 @@ modern_reset(struct virtio_hw *hw)
 static uint8_t
 modern_get_isr(struct virtio_hw *hw)
 {
-	return io_read8(hw->isr);
+	return hw->vtpci_access_ops->modern_read8(hw, hw->isr);
 }
 
 static uint16_t
 modern_set_config_irq(struct virtio_hw *hw, uint16_t vec)
 {
-	io_write16(&hw->common_cfg->msix_config, vec);
-	return io_read16(&hw->common_cfg->msix_config);
+	hw->vtpci_access_ops->modern_write16(hw,
+			&hw->common_cfg->msix_config, vec);
+	return hw->vtpci_access_ops->modern_read16(hw,
+			&hw->common_cfg->msix_config);
 }
 
 static uint16_t
 modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
 {
-	io_write16(&hw->common_cfg->queue_select, queue_id);
-	return io_read16(&hw->common_cfg->queue_size);
+	hw->vtpci_access_ops->modern_write16(hw,
+			&hw->common_cfg->queue_select, queue_id);
+	return hw->vtpci_access_ops->modern_read16(hw,
+			&hw->common_cfg->queue_size);
 }
 
 static void
@@ -606,20 +805,23 @@ modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
 							 ring[vq->vq_nentries]),
 				   VIRTIO_PCI_VRING_ALIGN);
 
-	io_write16(&hw->common_cfg->queue_select, vq->vq_queue_index);
+	hw->vtpci_access_ops->modern_write16(hw,
+			&hw->common_cfg->queue_select, vq->vq_queue_index);
 
-	io_write64_twopart(&hw->common_cfg->queue_desc_lo,
+	io_write64_twopart(hw, &hw->common_cfg->queue_desc_lo,
 			   &hw->common_cfg->queue_desc_hi, desc_addr);
-	io_write64_twopart(&hw->common_cfg->queue_avail_lo,
+	io_write64_twopart(hw, &hw->common_cfg->queue_avail_lo,
 			   &hw->common_cfg->queue_avail_hi, avail_addr);
-	io_write64_twopart(&hw->common_cfg->queue_used_lo,
+	io_write64_twopart(hw, &hw->common_cfg->queue_used_lo,
 			   &hw->common_cfg->queue_used_hi, used_addr);
 
-	notify_off = io_read16(&hw->common_cfg->queue_notify_off);
+	notify_off = hw->vtpci_access_ops->modern_read16(hw,
+				&hw->common_cfg->queue_notify_off);
 	vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
 				notify_off * hw->notify_off_multiplier);
 
-	io_write16(&hw->common_cfg->queue_enable, 1);
+	hw->vtpci_access_ops->modern_write16(hw,
+			&hw->common_cfg->queue_enable, 1);
 
 	PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index);
 	PMD_INIT_LOG(DEBUG, "\t desc_addr: %"PRIx64, desc_addr);
@@ -632,22 +834,24 @@ modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
 static void
 modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
 {
-	io_write16(&hw->common_cfg->queue_select, vq->vq_queue_index);
+	hw->vtpci_access_ops->modern_write16(hw,
+			&hw->common_cfg->queue_select, vq->vq_queue_index);
 
-	io_write64_twopart(&hw->common_cfg->queue_desc_lo,
+	io_write64_twopart(hw, &hw->common_cfg->queue_desc_lo,
 			   &hw->common_cfg->queue_desc_hi, 0);
-	io_write64_twopart(&hw->common_cfg->queue_avail_lo,
+	io_write64_twopart(hw, &hw->common_cfg->queue_avail_lo,
 			   &hw->common_cfg->queue_avail_hi, 0);
-	io_write64_twopart(&hw->common_cfg->queue_used_lo,
+	io_write64_twopart(hw, &hw->common_cfg->queue_used_lo,
 			   &hw->common_cfg->queue_used_hi, 0);
 
-	io_write16(&hw->common_cfg->queue_enable, 0);
+	hw->vtpci_access_ops->modern_write16(hw,
+			&hw->common_cfg->queue_enable, 0);
 }
 
 static void
 modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
 {
-	io_write16(vq->notify_addr, 1);
+	hw->vtpci_access_ops->modern_write16(hw, vq->notify_addr, 1);
 }
 
 static const struct virtio_pci_ops modern_ops = {
@@ -666,7 +870,6 @@ static const struct virtio_pci_ops modern_ops = {
 	.notify_queue	= modern_notify_queue,
 };
 
-
 void
 vtpci_read_dev_config(struct virtio_hw *hw, uint64_t offset,
 		      void *dst, int length)
@@ -739,55 +942,28 @@ vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
 	return hw->vtpci_ops->set_config_irq(hw, vec);
 }
 
-static void *
-get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
-{
-	uint8_t  bar    = cap->bar;
-	uint32_t length = cap->length;
-	uint32_t offset = cap->offset;
-	uint8_t *base;
-
-	if (bar > 5) {
-		PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
-		return NULL;
-	}
-
-	if (offset + length > dev->mem_resource[bar].len) {
-		PMD_INIT_LOG(ERR,
-			"invalid cap: overflows bar space: %u > %"PRIu64,
-			offset + length, dev->mem_resource[bar].len);
-		return NULL;
-	}
-
-	base = dev->mem_resource[bar].addr;
-	if (base == NULL) {
-		PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar);
-		return NULL;
-	}
-
-	return base + offset;
-}
-
 static int
-virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
+virtio_read_caps(struct virtio_hw *hw)
 {
 	uint8_t pos;
 	struct virtio_pci_cap cap;
 	int ret;
 
-	if (rte_eal_pci_map_device(dev) < 0) {
+	if (hw->vtpci_access_ops->map_pci_cfg(hw) < 0) {
 		PMD_INIT_LOG(DEBUG, "failed to map pci device!");
 		return -1;
 	}
 
-	ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST);
+	ret = hw->vtpci_access_ops->read_pci_cfg(
+			hw, &pos, 1, PCI_CAPABILITY_LIST);
 	if (ret < 0) {
 		PMD_INIT_LOG(DEBUG, "failed to read pci capability list");
 		return -1;
 	}
 
 	while (pos) {
-		ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos);
+		ret = hw->vtpci_access_ops->read_pci_cfg(
+				hw, &cap, sizeof(cap), pos);
 		if (ret < 0) {
 			PMD_INIT_LOG(ERR,
 				"failed to read pci cap at pos: %x", pos);
@@ -807,18 +983,22 @@ virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
 
 		switch (cap.cfg_type) {
 		case VIRTIO_PCI_CAP_COMMON_CFG:
-			hw->common_cfg = get_cfg_addr(dev, &cap);
+			hw->common_cfg =
+				hw->vtpci_access_ops->get_cfg_addr(hw, &cap);
 			break;
 		case VIRTIO_PCI_CAP_NOTIFY_CFG:
-			rte_eal_pci_read_config(dev, &hw->notify_off_multiplier,
+			hw->vtpci_access_ops->read_pci_cfg(hw,
+						&hw->notify_off_multiplier,
 						4, pos + sizeof(cap));
-			hw->notify_base = get_cfg_addr(dev, &cap);
+			hw->notify_base =
+				hw->vtpci_access_ops->get_cfg_addr(hw, &cap);
 			break;
 		case VIRTIO_PCI_CAP_DEVICE_CFG:
-			hw->dev_cfg = get_cfg_addr(dev, &cap);
+			hw->dev_cfg =
+				hw->vtpci_access_ops->get_cfg_addr(hw, &cap);
 			break;
 		case VIRTIO_PCI_CAP_ISR_CFG:
-			hw->isr = get_cfg_addr(dev, &cap);
+			hw->isr = hw->vtpci_access_ops->get_cfg_addr(hw, &cap);
 			break;
 		}
 
@@ -844,42 +1024,53 @@ virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
 }
 
 int
-vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
+vtpci_init(struct rte_eth_dev *eth_dev, struct virtio_hw *hw)
 {
-	hw->dev = dev;
+	struct rte_pci_device *pci_dev = eth_dev->pci_dev;
+
+	hw->dev = pci_dev;
+
+	if (pci_dev == NULL) {
+		PMD_INIT_LOG(INFO, "No pci device specified.");
+		return -1;
+	}
+
+	if (vtpci_access_init(eth_dev, hw) < 0)
+		return -1;
 
 	/*
 	 * Try if we can succeed reading virtio pci caps, which exists
 	 * only on modern pci device. If failed, we fallback to legacy
 	 * virtio handling.
 	 */
-	if (virtio_read_caps(dev, hw) == 0) {
+	if (virtio_read_caps(hw) == 0) {
 		PMD_INIT_LOG(INFO, "modern virtio pci detected.");
 		hw->vtpci_ops = &modern_ops;
 		hw->modern    = 1;
-		dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
+		pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
 		return 0;
 	}
 
 	PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
-	if (legacy_virtio_resource_init(dev) < 0)
+	if (legacy_virtio_resource_init(pci_dev) < 0)
 		return -1;
 
 	hw->vtpci_ops = &legacy_ops;
-	hw->use_msix = legacy_virtio_has_msix(&dev->addr);
-	hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
+	hw->use_msix = legacy_virtio_has_msix(&pci_dev->addr);
+	hw->io_base  = (uint32_t)(uintptr_t)pci_dev->mem_resource[0].addr;
 	hw->modern   = 0;
 
 	return 0;
 }
 
 void
-vtpci_uninit(struct rte_pci_device *dev, struct virtio_hw *hw)
+vtpci_uninit(struct rte_eth_dev *eth_dev, struct virtio_hw *hw)
 {
 	hw->dev  = NULL;
 	hw->vtpci_ops = NULL;
 	hw->use_msix = 0;
 	hw->io_base  = 0;
 	hw->modern   = 0;
-	rte_eal_pci_unmap_device(dev);
+	hw->vtpci_access_ops->unmap_pci_cfg(hw);
+	vtpci_access_uninit(eth_dev, hw);
 }
diff --git a/drivers/net/virtio/virtio_pci.h b/drivers/net/virtio/virtio_pci.h
index ec1d46b..b102679 100644
--- a/drivers/net/virtio/virtio_pci.h
+++ b/drivers/net/virtio/virtio_pci.h
@@ -222,6 +222,35 @@ struct virtio_pci_common_cfg {
 
 struct virtio_hw;
 
+struct virtio_pci_access_ops {
+	uint8_t (*legacy_read8)(struct virtio_hw *hw, uint8_t *addr);
+	uint16_t (*legacy_read16)(struct virtio_hw *hw, uint16_t *addr);
+	uint32_t (*legacy_read32)(struct virtio_hw *hw, uint32_t *addr);
+	void (*legacy_write8)(struct virtio_hw *hw,
+				uint8_t *addr, uint8_t val);
+	void (*legacy_write16)(struct virtio_hw *hw,
+				uint16_t *addr, uint16_t val);
+	void (*legacy_write32)(struct virtio_hw *hw,
+				uint32_t *addr, uint32_t val);
+
+	uint8_t (*modern_read8)(struct virtio_hw *hw, uint8_t *addr);
+	uint16_t (*modern_read16)(struct virtio_hw *hw, uint16_t *addr);
+	uint32_t (*modern_read32)(struct virtio_hw *hw, uint32_t *addr);
+	void (*modern_write8)(struct virtio_hw *hw,
+				uint8_t *addr, uint8_t val);
+	void (*modern_write16)(struct virtio_hw *hw,
+				uint16_t *addr, uint16_t val);
+	void (*modern_write32)(struct virtio_hw *hw,
+				uint32_t *addr, uint32_t val);
+
+	int (*map_pci_cfg)(struct virtio_hw *hw);
+	void (*unmap_pci_cfg)(struct virtio_hw *hw);
+	void *(*get_cfg_addr)(struct virtio_hw *hw,
+				struct virtio_pci_cap *cap);
+	int (*read_pci_cfg)(struct virtio_hw *hw,
+				void *buf, size_t len, off_t offset);
+};
+
 struct virtio_pci_ops {
 	void (*read_dev_cfg)(struct virtio_hw *hw, uint64_t offset,
 			     void *dst, int len);
@@ -266,6 +295,7 @@ struct virtio_hw {
 	struct virtio_pci_common_cfg *common_cfg;
 	struct virtio_net_config *dev_cfg;
 	const struct virtio_pci_ops *vtpci_ops;
+	const struct virtio_pci_access_ops *vtpci_access_ops;
 };
 
 /*
@@ -327,8 +357,8 @@ vtpci_with_feature(struct virtio_hw *hw, uint64_t bit)
 /*
  * Function declaration from virtio_pci.c
  */
-int vtpci_init(struct rte_pci_device *, struct virtio_hw *);
-void vtpci_uninit(struct rte_pci_device *dev, struct virtio_hw *);
+int vtpci_init(struct rte_eth_dev *, struct virtio_hw *);
+void vtpci_uninit(struct rte_eth_dev *, struct virtio_hw *);
 void vtpci_reset(struct virtio_hw *);
 
 void vtpci_reinit_complete(struct virtio_hw *);
