diff --git a/drivers/net/igc/Makefile b/drivers/net/igc/Makefile
index 7b51daf..7c8d00d 100644
--- a/drivers/net/igc/Makefile
+++ b/drivers/net/igc/Makefile
@@ -13,12 +13,58 @@ CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_eal
 LDLIBS += -lrte_ethdev
 LDLIBS += -lrte_bus_pci
+LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mempool
 
 EXPORT_MAP := rte_pmd_igc_version.map
 
 #
+# Add extra flags for base driver files (also known as shared code)
+# to disable warnings
+#
+ifeq ($(CONFIG_RTE_TOOLCHAIN_ICC),y)
+#
+# CFLAGS for icc
+#
+CFLAGS_BASE_DRIVER  = -diag-disable 177 -diag-disable 181
+CFLAGS_BASE_DRIVER += -diag-disable 869 -diag-disable 2259
+else
+#
+# CFLAGS for gcc/clang
+#
+CFLAGS_BASE_DRIVER = -Wno-unused-parameter
+CFLAGS_BASE_DRIVER += -Wno-unused-variable
+CFLAGS_BASE_DRIVER += -Wno-uninitialized
+ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
+ifeq ($(shell test $(GCC_VERSION) -ge 60 && echo 1), 1)
+CFLAGS_BASE_DRIVER += -Wno-misleading-indentation
+ifeq ($(shell test $(GCC_VERSION) -ge 70 && echo 1), 1)
+CFLAGS_BASE_DRIVER += -Wno-implicit-fallthrough
+endif
+endif
+endif
+endif
+
+#
+# Add extra flags for base driver files (also known as shared code)
+# to disable warnings in them
+#
+BASE_DRIVER_OBJS=$(sort $(patsubst %.c,%.o,$(notdir $(wildcard $(SRCDIR)/base/*.c))))
+$(foreach obj, $(BASE_DRIVER_OBJS), $(eval CFLAGS_$(obj)+=$(CFLAGS_BASE_DRIVER)))
+
+VPATH += $(SRCDIR)/base
+
+#
 # all source are stored in SRCS-y
 #
+SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += e1000_api.c
+SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += e1000_base.c
+SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += e1000_i225.c
+SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += e1000_mac.c
+SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += e1000_manage.c
+SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += e1000_nvm.c
+SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += e1000_osdep.c
+SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += e1000_phy.c
 SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += igc_logs.c
 SRCS-$(CONFIG_RTE_LIBRTE_IGC_PMD) += igc_ethdev.c
 
diff --git a/drivers/net/igc/base/README b/drivers/net/igc/base/README
new file mode 100644
index 0000000..31e2f26
--- /dev/null
+++ b/drivers/net/igc/base/README
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+Intel® IGC driver
+==================
+
+This directory contains source code of FreeBSD igc driver of version
+2019.10.18 released by the team which develops basic drivers for any
+i225 NIC.
+The directory of base/ contains the original source package.
+This driver is valid for the product(s) listed below
+
+* Intel® Ethernet Network Adapters I225
+
+Updating the driver
+===================
+
+NOTE: The source code in this directory should not be modified apart from
+the following file(s):
+
+    e1000_osdep.h
+    e1000_osdep.c
diff --git a/drivers/net/igc/base/e1000_osdep.c b/drivers/net/igc/base/e1000_osdep.c
new file mode 100644
index 0000000..56703cb
--- /dev/null
+++ b/drivers/net/igc/base/e1000_osdep.c
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2001-2020
+ */
+
+#include "e1000_api.h"
+
+/*
+ * NOTE: the following routines using the igc
+ * naming style are provided to the shared
+ * code but are OS specific
+ */
+
+void
+igc_write_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value)
+{
+	(void)hw;
+	(void)reg;
+	(void)value;
+}
+
+void
+igc_read_pci_cfg(struct igc_hw *hw, u32 reg, u16 *value)
+{
+	(void)hw;
+	(void)reg;
+	*value = 0;
+}
+
+void
+igc_pci_set_mwi(struct igc_hw *hw)
+{
+	(void)hw;
+}
+
+void
+igc_pci_clear_mwi(struct igc_hw *hw)
+{
+	(void)hw;
+}
+
+/*
+ * Read the PCI Express capabilities
+ */
+int32_t
+igc_read_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value)
+{
+	(void)hw;
+	(void)reg;
+	(void)value;
+	return IGC_NOT_IMPLEMENTED;
+}
+
+/*
+ * Write the PCI Express capabilities
+ */
+int32_t
+igc_write_pcie_cap_reg(struct igc_hw *hw, u32 reg, u16 *value)
+{
+	(void)hw;
+	(void)reg;
+	(void)value;
+
+	return IGC_NOT_IMPLEMENTED;
+}
diff --git a/drivers/net/igc/base/e1000_osdep.h b/drivers/net/igc/base/e1000_osdep.h
new file mode 100644
index 0000000..57d646e
--- /dev/null
+++ b/drivers/net/igc/base/e1000_osdep.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2001-2020
+ */
+
+
+#ifndef _IGC_OSDEP_H_
+#define _IGC_OSDEP_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_byteorder.h>
+#include <rte_io.h>
+
+#include "../igc_logs.h"
+
+#define DELAY(x) rte_delay_us(x)
+#define usec_delay(x) DELAY(x)
+#define usec_delay_irq(x) DELAY(x)
+#define msec_delay(x) DELAY(1000 * (x))
+#define msec_delay_irq(x) DELAY(1000 * (x))
+
+#define DEBUGFUNC(F)            DEBUGOUT(F "\n")
+#define DEBUGOUT(S, args...)    PMD_DRV_LOG_RAW(DEBUG, S, ##args)
+#define DEBUGOUT1(S, args...)   DEBUGOUT(S, ##args)
+#define DEBUGOUT2(S, args...)   DEBUGOUT(S, ##args)
+#define DEBUGOUT3(S, args...)   DEBUGOUT(S, ##args)
+#define DEBUGOUT6(S, args...)   DEBUGOUT(S, ##args)
+#define DEBUGOUT7(S, args...)   DEBUGOUT(S, ##args)
+
+#define UNREFERENCED_PARAMETER(_p)
+#define UNREFERENCED_1PARAMETER(_p)
+#define UNREFERENCED_2PARAMETER(_p, _q)
+#define UNREFERENCED_3PARAMETER(_p, _q, _r)
+#define UNREFERENCED_4PARAMETER(_p, _q, _r, _s)
+
+#define FALSE			0
+#define TRUE			1
+
+#define	CMD_MEM_WRT_INVALIDATE	0x0010  /* BIT_4 */
+
+/* Mutex used in the shared code */
+#define IGC_MUTEX                     uintptr_t
+#define IGC_MUTEX_INIT(mutex)         (*(mutex) = 0)
+#define IGC_MUTEX_LOCK(mutex)         (*(mutex) = 1)
+#define IGC_MUTEX_UNLOCK(mutex)       (*(mutex) = 0)
+
+typedef uint64_t	u64;
+typedef uint32_t	u32;
+typedef uint16_t	u16;
+typedef uint8_t		u8;
+typedef int64_t		s64;
+typedef int32_t		s32;
+typedef int16_t		s16;
+typedef int8_t		s8;
+typedef int		bool;
+
+#define STATIC          static
+#define false           FALSE
+#define true            TRUE
+
+#define __le16		u16
+#define __le32		u32
+#define __le64		u64
+
+#define IGC_WRITE_FLUSH(a) IGC_READ_REG(a, IGC_STATUS)
+
+#define IGC_PCI_REG(reg)	rte_read32(reg)
+
+#define IGC_PCI_REG16(reg)	rte_read16(reg)
+
+#define IGC_PCI_REG_WRITE(reg, value)			\
+	rte_write32((rte_cpu_to_le_32(value)), reg)
+
+#define IGC_PCI_REG_WRITE_RELAXED(reg, value)		\
+	rte_write32_relaxed((rte_cpu_to_le_32(value)), reg)
+
+#define IGC_PCI_REG_WRITE16(reg, value)		\
+	rte_write16((rte_cpu_to_le_16(value)), reg)
+
+#define IGC_PCI_REG_ADDR(hw, reg) \
+	((volatile uint32_t *)((char *)(hw)->hw_addr + (reg)))
+
+#define IGC_PCI_REG_ARRAY_ADDR(hw, reg, index) \
+	IGC_PCI_REG_ADDR((hw), (reg) + ((index) << 2))
+
+#define IGC_PCI_REG_FLASH_ADDR(hw, reg) \
+	((volatile uint32_t *)((char *)(hw)->flash_address + (reg)))
+
+static inline uint32_t igc_read_addr(volatile void *addr)
+{
+	return rte_le_to_cpu_32(IGC_PCI_REG(addr));
+}
+
+static inline uint16_t igc_read_addr16(volatile void *addr)
+{
+	return rte_le_to_cpu_16(IGC_PCI_REG16(addr));
+}
+
+/* Register READ/WRITE macros */
+
+#define IGC_READ_REG(hw, reg) \
+	igc_read_addr(IGC_PCI_REG_ADDR((hw), (reg)))
+
+#define IGC_READ_REG_LE_VALUE(hw, reg) \
+	rte_read32(IGC_PCI_REG_ADDR((hw), (reg)))
+
+#define IGC_WRITE_REG(hw, reg, value) \
+	IGC_PCI_REG_WRITE(IGC_PCI_REG_ADDR((hw), (reg)), (value))
+
+#define IGC_WRITE_REG_LE_VALUE(hw, reg, value) \
+	rte_write32(value, IGC_PCI_REG_ADDR((hw), (reg)))
+
+#define IGC_READ_REG_ARRAY(hw, reg, index) \
+	IGC_PCI_REG(IGC_PCI_REG_ARRAY_ADDR((hw), (reg), (index)))
+
+#define IGC_WRITE_REG_ARRAY(hw, reg, index, value) \
+	IGC_PCI_REG_WRITE(IGC_PCI_REG_ARRAY_ADDR((hw), (reg), (index)), \
+			(value))
+
+#define IGC_READ_REG_ARRAY_DWORD IGC_READ_REG_ARRAY
+#define IGC_WRITE_REG_ARRAY_DWORD IGC_WRITE_REG_ARRAY
+
+/*
+ * To be able to do IO write, we need to map IO BAR
+ * (bar 2/4 depending on device).
+ * Right now mapping multiple BARs is not supported by DPDK.
+ * Fortunatelly we need it only for legacy hw support.
+ */
+
+#define IGC_WRITE_REG_IO(hw, reg, value) \
+	IGC_WRITE_REG(hw, reg, value)
+
+/*
+ * Tested on I217/I218 chipset.
+ */
+
+#define IGC_READ_FLASH_REG(hw, reg) \
+	igc_read_addr(IGC_PCI_REG_FLASH_ADDR((hw), (reg)))
+
+#define IGC_READ_FLASH_REG16(hw, reg)  \
+	igc_read_addr16(IGC_PCI_REG_FLASH_ADDR((hw), (reg)))
+
+#define IGC_WRITE_FLASH_REG(hw, reg, value)  \
+	IGC_PCI_REG_WRITE(IGC_PCI_REG_FLASH_ADDR((hw), (reg)), (value))
+
+#define IGC_WRITE_FLASH_REG16(hw, reg, value) \
+	IGC_PCI_REG_WRITE16(IGC_PCI_REG_FLASH_ADDR((hw), (reg)), (value))
+
+#endif /* _IGC_OSDEP_H_ */
diff --git a/drivers/net/igc/base/meson.build b/drivers/net/igc/base/meson.build
new file mode 100644
index 0000000..f51026e
--- /dev/null
+++ b/drivers/net/igc/base/meson.build
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2020 Intel Corporation
+
+sources = [
+	'e1000_api.c',
+	'e1000_base.c',
+	'e1000_i225.c',
+	'e1000_mac.c',
+	'e1000_manage.c',
+	'e1000_nvm.c',
+	'e1000_osdep.c',
+	'e1000_phy.c',
+]
+
+error_cflags = ['-Wno-unused-parameter', '-Wno-unused-variable']
+c_args = cflags
+
+foreach flag: error_cflags
+	if cc.has_argument(flag)
+		c_args += flag
+	endif
+endforeach
+
+base_lib = static_library('igc_base', sources,
+	dependencies: static_rte_eal,
+	c_args: c_args)
+
+base_objs = base_lib.extract_all_objects()
diff --git a/drivers/net/igc/igc_ethdev.c b/drivers/net/igc/igc_ethdev.c
index 2baba69..4d78f0e 100644
--- a/drivers/net/igc/igc_ethdev.c
+++ b/drivers/net/igc/igc_ethdev.c
@@ -11,11 +11,8 @@
 #include "igc_ethdev.h"
 
 #define IGC_INTEL_VENDOR_ID		0x8086
-#define IGC_DEV_ID_I225_LM		0x15F2
-#define IGC_DEV_ID_I225_V		0x15F3
-#define IGC_DEV_ID_I225_K		0x3100
-#define IGC_DEV_ID_I225_I		0x15F8
-#define IGC_DEV_ID_I220_V		0x15F7
+
+#define IGC_FC_PAUSE_TIME		0x0680
 
 static const struct rte_pci_id pci_id_igc_map[] = {
 	{ RTE_PCI_DEVICE(IGC_INTEL_VENDOR_ID, IGC_DEV_ID_I225_LM) },
@@ -84,6 +81,90 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 	RTE_SET_USED(dev);
 }
 
+/*
+ *  Get hardware rx-buffer size.
+ */
+static inline int
+igc_get_rx_buffer_size(struct igc_hw *hw)
+{
+	return (IGC_READ_REG(hw, IGC_RXPBS) & 0x3f) << 10;
+}
+
+/*
+ * igc_hw_control_acquire sets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means
+ * that the driver is loaded.
+ */
+static void
+igc_hw_control_acquire(struct igc_hw *hw)
+{
+	uint32_t ctrl_ext;
+
+	/* Let firmware know the driver has taken over */
+	ctrl_ext = IGC_READ_REG(hw, IGC_CTRL_EXT);
+	IGC_WRITE_REG(hw, IGC_CTRL_EXT, ctrl_ext | IGC_CTRL_EXT_DRV_LOAD);
+}
+
+/*
+ * igc_hw_control_release resets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that the
+ * driver is no longer loaded.
+ */
+static void
+igc_hw_control_release(struct igc_hw *hw)
+{
+	uint32_t ctrl_ext;
+
+	/* Let firmware taken over control of h/w */
+	ctrl_ext = IGC_READ_REG(hw, IGC_CTRL_EXT);
+	IGC_WRITE_REG(hw, IGC_CTRL_EXT,
+			ctrl_ext & ~IGC_CTRL_EXT_DRV_LOAD);
+}
+
+static int
+igc_hardware_init(struct igc_hw *hw)
+{
+	uint32_t rx_buf_size;
+	int diag;
+
+	/* Let the firmware know the OS is in control */
+	igc_hw_control_acquire(hw);
+
+	/* Issue a global reset */
+	igc_reset_hw(hw);
+
+	/* disable all wake up */
+	IGC_WRITE_REG(hw, IGC_WUC, 0);
+
+	/*
+	 * Hardware flow control
+	 * - High water mark should allow for at least two standard size (1518)
+	 *   frames to be received after sending an XOFF.
+	 * - Low water mark works best when it is very near the high water mark.
+	 *   This allows the receiver to restart by sending XON when it has
+	 *   drained a bit. Here we use an arbitrary value of 1500 which will
+	 *   restart after one full frame is pulled from the buffer. There
+	 *   could be several smaller frames in the buffer and if so they will
+	 *   not trigger the XON until their total number reduces the buffer
+	 *   by 1500.
+	 */
+	rx_buf_size = igc_get_rx_buffer_size(hw);
+	hw->fc.high_water = rx_buf_size - (RTE_ETHER_MAX_LEN * 2);
+	hw->fc.low_water = hw->fc.high_water - 1500;
+	hw->fc.pause_time = IGC_FC_PAUSE_TIME;
+	hw->fc.send_xon = 1;
+	hw->fc.requested_mode = igc_fc_full;
+
+	diag = igc_init_hw(hw);
+	if (diag < 0)
+		return diag;
+
+	igc_get_phy_info(hw);
+	igc_check_for_link(hw);
+
+	return 0;
+}
+
 static int
 eth_igc_start(struct rte_eth_dev *dev)
 {
@@ -92,17 +173,92 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static int
+igc_reset_swfw_lock(struct igc_hw *hw)
+{
+	int ret_val;
+
+	/*
+	 * Do mac ops initialization manually here, since we will need
+	 * some function pointers set by this call.
+	 */
+	ret_val = igc_init_mac_params(hw);
+	if (ret_val)
+		return ret_val;
+
+	/*
+	 * SMBI lock should not fail in this early stage. If this is the case,
+	 * it is due to an improper exit of the application.
+	 * So force the release of the faulty lock.
+	 */
+	if (igc_get_hw_semaphore_generic(hw) < 0)
+		PMD_DRV_LOG(DEBUG, "SMBI lock released");
+
+	igc_put_hw_semaphore_generic(hw);
+
+	if (hw->mac.ops.acquire_swfw_sync != NULL) {
+		uint16_t mask;
+
+		/*
+		 * Phy lock should not fail in this early stage.
+		 * If this is the case, it is due to an improper exit of the
+		 * application. So force the release of the faulty lock.
+		 */
+		mask = IGC_SWFW_PHY0_SM;
+		if (hw->mac.ops.acquire_swfw_sync(hw, mask) < 0) {
+			PMD_DRV_LOG(DEBUG, "SWFW phy%d lock released",
+				    hw->bus.func);
+		}
+		hw->mac.ops.release_swfw_sync(hw, mask);
+
+		/*
+		 * This one is more tricky since it is common to all ports; but
+		 * swfw_sync retries last long enough (1s) to be almost sure
+		 * that if lock can not be taken it is due to an improper lock
+		 * of the semaphore.
+		 */
+		mask = IGC_SWFW_EEP_SM;
+		if (hw->mac.ops.acquire_swfw_sync(hw, mask) < 0)
+			PMD_DRV_LOG(DEBUG, "SWFW common locks released");
+
+		hw->mac.ops.release_swfw_sync(hw, mask);
+	}
+
+	return IGC_SUCCESS;
+}
+
 static void
 eth_igc_close(struct rte_eth_dev *dev)
 {
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+
 	PMD_INIT_FUNC_TRACE();
-	 RTE_SET_USED(dev);
+
+	igc_phy_hw_reset(hw);
+	igc_hw_control_release(hw);
+
+	/* Reset any pending lock */
+	igc_reset_swfw_lock(hw);
+}
+
+static void
+igc_identify_hardware(struct rte_eth_dev *dev, struct rte_pci_device *pci_dev)
+{
+	struct igc_hw *hw =
+		IGC_DEV_PRIVATE_HW(dev);
+
+	hw->vendor_id = pci_dev->id.vendor_id;
+	hw->device_id = pci_dev->id.device_id;
+	hw->subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+	hw->subsystem_device_id = pci_dev->id.subsystem_device_id;
 }
 
 static int
 eth_igc_dev_init(struct rte_eth_dev *dev)
 {
 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+	int error = 0;
 
 	PMD_INIT_FUNC_TRACE();
 	dev->dev_ops = &eth_igc_ops;
@@ -117,12 +273,89 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 
 	rte_eth_copy_pci_info(dev, pci_dev);
 
+	hw->back = pci_dev;
+	hw->hw_addr = (void *)pci_dev->mem_resource[0].addr;
+
+	igc_identify_hardware(dev, pci_dev);
+	if (igc_setup_init_funcs(hw, FALSE) != IGC_SUCCESS) {
+		error = -EIO;
+		goto err_late;
+	}
+
+	igc_get_bus_info(hw);
+
+	/* Reset any pending lock */
+	if (igc_reset_swfw_lock(hw) != IGC_SUCCESS) {
+		error = -EIO;
+		goto err_late;
+	}
+
+	/* Finish initialization */
+	if (igc_setup_init_funcs(hw, TRUE) != IGC_SUCCESS) {
+		error = -EIO;
+		goto err_late;
+	}
+
+	hw->mac.autoneg = 1;
+	hw->phy.autoneg_wait_to_complete = 0;
+	hw->phy.autoneg_advertised = IGC_ALL_SPEED_DUPLEX_2500;
+
+	/* Copper options */
+	if (hw->phy.media_type == igc_media_type_copper) {
+		hw->phy.mdix = 0; /* AUTO_ALL_MODES */
+		hw->phy.disable_polarity_correction = 0;
+		hw->phy.ms_type = igc_ms_hw_default;
+	}
+
+	/*
+	 * Start from a known state, this is important in reading the nvm
+	 * and mac from that.
+	 */
+	igc_reset_hw(hw);
+
+	/* Make sure we have a good EEPROM before we read from it */
+	if (igc_validate_nvm_checksum(hw) < 0) {
+		/*
+		 * Some PCI-E parts fail the first check due to
+		 * the link being in sleep state, call it again,
+		 * if it fails a second time its a real issue.
+		 */
+		if (igc_validate_nvm_checksum(hw) < 0) {
+			PMD_INIT_LOG(ERR, "EEPROM checksum invalid");
+			error = -EIO;
+			goto err_late;
+		}
+	}
+
+	/* Read the permanent MAC address out of the EEPROM */
+	if (igc_read_mac_addr(hw) != 0) {
+		PMD_INIT_LOG(ERR, "EEPROM error while reading MAC address");
+		error = -EIO;
+		goto err_late;
+	}
+
+	/* Allocate memory for storing MAC addresses */
 	dev->data->mac_addrs = rte_zmalloc("igc",
-		RTE_ETHER_ADDR_LEN, 0);
+		RTE_ETHER_ADDR_LEN * hw->mac.rar_entry_count, 0);
 	if (dev->data->mac_addrs == NULL) {
 		PMD_INIT_LOG(ERR, "Failed to allocate %d bytes needed to "
-				"store MAC addresses", RTE_ETHER_ADDR_LEN);
-		return -ENODEV;
+						"store MAC addresses",
+				RTE_ETHER_ADDR_LEN * hw->mac.rar_entry_count);
+		error = -ENOMEM;
+		goto err_late;
+	}
+
+	/* Copy the permanent MAC address */
+	rte_ether_addr_copy((struct rte_ether_addr *)hw->mac.addr,
+			&dev->data->mac_addrs[0]);
+
+	/* Now initialize the hardware */
+	if (igc_hardware_init(hw) != 0) {
+		PMD_INIT_LOG(ERR, "Hardware initialization failed");
+		rte_free(dev->data->mac_addrs);
+		dev->data->mac_addrs = NULL;
+		error = -ENODEV;
+		goto err_late;
 	}
 
 	/* Pass the information to the rte_eth_dev_close() that it should also
@@ -130,11 +363,22 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 	 */
 	dev->data->dev_flags |= RTE_ETH_DEV_CLOSE_REMOVE;
 
+	hw->mac.get_link_status = 1;
+
+	/* Indicate SOL/IDER usage */
+	if (igc_check_reset_block(hw) < 0)
+		PMD_INIT_LOG(ERR, "PHY reset is blocked due to"
+				" SOL/IDER session.");
+
 	PMD_INIT_LOG(DEBUG, "port_id %d vendorID=0x%x deviceID=0x%x",
 			dev->data->port_id, pci_dev->id.vendor_id,
 			pci_dev->id.device_id);
 
 	return 0;
+
+err_late:
+	igc_hw_control_release(hw);
+	return error;
 }
 
 static int
@@ -227,7 +471,8 @@ static int eth_igc_infos_get(struct rte_eth_dev *dev,
 	struct rte_pci_device *pci_dev)
 {
 	PMD_INIT_FUNC_TRACE();
-	return rte_eth_dev_pci_generic_probe(pci_dev, 0, eth_igc_dev_init);
+	return rte_eth_dev_pci_generic_probe(pci_dev,
+		sizeof(struct igc_adapter), eth_igc_dev_init);
 }
 
 static int
diff --git a/drivers/net/igc/igc_ethdev.h b/drivers/net/igc/igc_ethdev.h
index a774413..c5d51f6 100644
--- a/drivers/net/igc/igc_ethdev.h
+++ b/drivers/net/igc/igc_ethdev.h
@@ -5,12 +5,31 @@
 #ifndef _IGC_ETHDEV_H_
 #define _IGC_ETHDEV_H_
 
+#include <rte_ethdev.h>
+
+#include "base/e1000_osdep.h"
+#include "base/e1000_hw.h"
+#include "base/e1000_i225.h"
+#include "base/e1000_api.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 #define IGC_QUEUE_PAIRS_NUM		4
 
+/*
+ * Structure to store private data for each driver instance (for each port).
+ */
+struct igc_adapter {
+	struct igc_hw         hw;
+};
+
+#define IGC_DEV_PRIVATE(_dev)	((_dev)->data->dev_private)
+
+#define IGC_DEV_PRIVATE_HW(_dev) \
+	(&((struct igc_adapter *)(_dev)->data->dev_private)->hw)
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/drivers/net/igc/meson.build b/drivers/net/igc/meson.build
index 927938f..ffa62f1 100644
--- a/drivers/net/igc/meson.build
+++ b/drivers/net/igc/meson.build
@@ -1,7 +1,12 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2020 Intel Corporation
 
+subdir('base')
+objs = [base_objs]
+
 sources = files(
 	'igc_logs.c',
 	'igc_ethdev.c'
 )
+
+includes += include_directories('base')
