diff --git a/drivers/net/atlantic/atl_ethdev.c b/drivers/net/atlantic/atl_ethdev.c
index 31ff50f18..78438174e 100644
--- a/drivers/net/atlantic/atl_ethdev.c
+++ b/drivers/net/atlantic/atl_ethdev.c
@@ -39,6 +39,9 @@
 #include "atl_common.h"
 #include "atl_hw_regs.h"
 #include "atl_logs.h"
+#include "hw_atl/hw_atl_llh.h"
+#include "hw_atl/hw_atl_b0.h"
+#include "hw_atl/hw_atl_b0_internal.h"
 
 static int eth_atl_dev_init(struct rte_eth_dev *eth_dev);
 static int eth_atl_dev_uninit(struct rte_eth_dev *eth_dev);
@@ -126,6 +129,26 @@ static const struct eth_dev_ops atl_eth_dev_ops = {
 	.dev_reset	      = atl_dev_reset,
 };
 
+static inline int32_t
+atl_reset_hw(struct aq_hw_s *hw)
+{
+	return hw_atl_b0_hw_reset(hw);
+}
+
+static inline void
+atl_enable_intr(struct rte_eth_dev *dev)
+{
+	struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	hw_atl_itr_irq_msk_setlsw_set(hw, 0xffffffff);
+}
+
+static void
+atl_disable_intr(struct aq_hw_s *hw)
+{
+	PMD_INIT_FUNC_TRACE();
+	hw_atl_itr_irq_msk_clearlsw_set(hw, 0xffffffff);
+}
 
 static int
 atl_get_bus_info(struct aq_hw_s *hw)
@@ -136,6 +159,16 @@ atl_get_bus_info(struct aq_hw_s *hw)
 	return 0;
 }
 
+static void
+atl_print_adapter_info(struct aq_hw_s *hw __rte_unused)
+{
+	PMD_INIT_LOG(DEBUG, "FW version: %u.%u.%u",
+			hw->fw_ver_actual >> 24,
+			(hw->fw_ver_actual >> 16) & 0xFF,
+			hw->fw_ver_actual & 0xFFFF);
+	PMD_INIT_LOG(DEBUG, "Driver version: %s", ATL_PMD_DRIVER_VERSION);
+}
+
 static int
 eth_atl_dev_init(struct rte_eth_dev *eth_dev)
 {
@@ -157,6 +190,60 @@ eth_atl_dev_init(struct rte_eth_dev *eth_dev)
 		return 0;
 	}
 
+	rte_eth_copy_pci_info(eth_dev, pci_dev);
+
+	/* Vendor and Device ID need to be set before init of shared code */
+	hw->device_id = pci_dev->id.device_id;
+	hw->vendor_id = pci_dev->id.vendor_id;
+	hw->mmio = (void *)pci_dev->mem_resource[0].addr;
+	hw->allow_unsupported_sfp = 1;
+
+	/* Hardware configuration - hardcode */
+	adapter->hw_cfg.is_lro = false;
+	adapter->hw_cfg.is_rss = false;
+	adapter->hw_cfg.num_rss_queues = HW_ATL_B0_RSS_MAX;
+	adapter->hw_cfg.wol = false;
+	adapter->hw_cfg.link_speed_msk = AQ_NIC_RATE_10G|
+			  AQ_NIC_RATE_5G|
+			  AQ_NIC_RATE_2G5|
+			  AQ_NIC_RATE_1G|
+			  AQ_NIC_RATE_100M;
+
+	adapter->hw_cfg.flow_control = (AQ_NIC_FC_RX | AQ_NIC_FC_TX);
+	adapter->hw_cfg.aq_rss.indirection_table_size = HW_ATL_B0_RSS_REDIRECTION_MAX;
+
+        hw->aq_nic_cfg = &adapter->hw_cfg;
+
+	/* pick up the PCI bus settings for reporting later */
+	atl_get_bus_info(hw);
+
+	/* disable interrupt */
+	atl_disable_intr(hw);
+
+	/* Allocate memory for storing MAC addresses */
+	eth_dev->data->mac_addrs = rte_zmalloc("atlantic", ETHER_ADDR_LEN, 0);
+	if (eth_dev->data->mac_addrs == NULL) {
+		PMD_INIT_LOG(ERR, "MAC Malloc failed");
+		return -ENOMEM;
+	}
+
+	err = hw_atl_utils_initfw(hw, &hw->aq_fw_ops); 
+	if (err)
+		return err;
+
+	/* Copy the permanent MAC address */
+	if (hw->aq_fw_ops->get_mac_permanent(hw, (u8*)&eth_dev->data->mac_addrs[0]) != 0)
+		return -EINVAL;
+
+	rte_intr_callback_register(intr_handle,
+				   atl_dev_interrupt_handler, eth_dev);
+
+	/* enable uio/vfio intr/eventfd mapping */
+	rte_intr_enable(intr_handle);
+
+	/* enable support intr */
+	atl_enable_intr(eth_dev);
+
 	return err;
 }
 
@@ -172,10 +259,30 @@ eth_atl_dev_uninit(struct rte_eth_dev *eth_dev)
 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
 		return -EPERM;
 
+	hw = ATL_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
+
+	if (hw->adapter_stopped == 0)
+		atl_dev_close(eth_dev);
+
 	eth_dev->dev_ops = NULL;
 	eth_dev->rx_pkt_burst = NULL;
 	eth_dev->tx_pkt_burst = NULL;
 
+	/* disable uio intr before callback unregister */
+	rte_intr_disable(intr_handle);
+	rte_intr_callback_unregister(intr_handle,
+				     atl_dev_interrupt_handler, eth_dev);
+
+	rte_free(eth_dev->data->mac_addrs);
+	eth_dev->data->mac_addrs = NULL;
+
+	rte_free(eth_dev->data->hash_mac_addrs);
+	eth_dev->data->hash_mac_addrs = NULL;
+
+#ifdef RTE_LIBRTE_SECURITY
+	rte_free(eth_dev->security_ctx);
+#endif
+
 	return 0;
 }
 
@@ -198,6 +305,11 @@ atl_dev_configure(struct rte_eth_dev *dev)
 {
 	struct atl_interrupt *intr = ATL_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
 
+	PMD_INIT_FUNC_TRACE();
+
+	/* set flag to update link status after init */
+	intr->flags |= ATL_FLAG_NEED_LINK_UPDATE;
+
 	return 0;
 }
 
@@ -218,6 +330,33 @@ atl_dev_start(struct rte_eth_dev *dev)
 	int status;
 	int err;
 
+	PMD_INIT_FUNC_TRACE();
+
+	if (dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED) {
+		PMD_INIT_LOG(ERR,
+		"Invalid link_speeds for port %u, fix speed not supported",
+				dev->data->port_id);
+		return -EINVAL;
+	}
+
+	/* disable uio/vfio intr/eventfd mapping */
+	rte_intr_disable(intr_handle);
+
+	/* stop adapter */
+	hw->adapter_stopped = 0;
+
+	/* reinitialize adapter
+	 * this calls reset and start
+	 */
+	status = atl_reset_hw(hw);
+	if (status != 0) {
+		return -1;
+	}
+
+	err = hw_atl_b0_hw_init(hw, (uint8_t*)dev->data->mac_addrs);
+
+	hw_atl_b0_hw_start(hw);
+
 	/* check and configure queue intr-vector mapping */
 	if ((rte_intr_cap_multiple(intr_handle) ||
 	    !RTE_ETH_DEV_SRIOV(dev).active) &&
@@ -244,6 +383,33 @@ atl_dev_start(struct rte_eth_dev *dev)
 		}
 	}
 
+	if (rte_intr_allow_others(intr_handle)) {
+		/* check if lsc interrupt is enabled */
+		if (dev->data->dev_conf.intr_conf.lsc != 0)
+			atl_dev_lsc_interrupt_setup(dev, TRUE);
+		else
+			atl_dev_lsc_interrupt_setup(dev, FALSE);
+	} else {
+		rte_intr_callback_unregister(intr_handle,
+					     atl_dev_interrupt_handler, dev);
+		if (dev->data->dev_conf.intr_conf.lsc != 0)
+			PMD_INIT_LOG(INFO, "lsc won't enable because of"
+				     " no intr multiplex");
+	}
+
+	/* check if rxq interrupt is enabled */
+	if (dev->data->dev_conf.intr_conf.rxq != 0 &&
+	    rte_intr_dp_is_en(intr_handle))
+		atl_dev_rxq_interrupt_setup(dev);
+
+	/* enable uio/vfio intr/eventfd mapping */
+	rte_intr_enable(intr_handle);
+
+	/* resume enabled intr since hw reset */
+	atl_enable_intr(dev);
+
+	atl_print_adapter_info(hw);
+
 	return 0;
 
 error:
@@ -257,7 +423,40 @@ atl_dev_start(struct rte_eth_dev *dev)
 static void
 atl_dev_stop(struct rte_eth_dev *dev)
 {
+	struct rte_eth_link link;
+	struct aq_hw_s *hw =
+		ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+	struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
+	PMD_INIT_FUNC_TRACE();
+
+	/* disable interrupts */
+	atl_disable_intr(hw);
+
+	/* reset the NIC */
+	atl_reset_hw(hw);
+	hw->adapter_stopped = 0;
+	/* Clear stored conf */
+	dev->data->scattered_rx = 0;
+	dev->data->lro = 0;
+
+	/* Clear recorded link status */
+	memset(&link, 0, sizeof(link));
+	rte_atl_dev_atomic_write_link_status(dev, &link);
+
+	if (!rte_intr_allow_others(intr_handle))
+		/* resume to the default handler */
+		rte_intr_callback_register(intr_handle,
+					   atl_dev_interrupt_handler,
+					   (void *)dev);
+
+	/* Clean datapath event and queue/vec mapping */
+	rte_intr_efd_disable(intr_handle);
+	if (intr_handle->intr_vec != NULL) {
+		rte_free(intr_handle->intr_vec);
+		intr_handle->intr_vec = NULL;
+	}
 }
 
 /*
@@ -270,6 +469,8 @@ atl_dev_close(struct rte_eth_dev *dev)
 
 	PMD_INIT_FUNC_TRACE();
 
+	atl_reset_hw(hw);
+
 	atl_dev_stop(dev);
 	hw->adapter_stopped = 1;
 }
@@ -288,6 +489,58 @@ atl_dev_reset(struct rte_eth_dev *dev)
 	return ret;
 }
 
+
+/*
+ * It executes link_update after knowing an interrupt occurred.
+ *
+ * @param dev
+ *  Pointer to struct rte_eth_dev.
+ *
+ * @return
+ *  - On success, zero.
+ *  - On failure, a negative value.
+ */
+static int
+atl_dev_interrupt_action(struct rte_eth_dev *dev,
+			   struct rte_intr_handle *intr_handle)
+{
+	struct atl_interrupt *intr =
+		ATL_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
+
+	if (intr->flags & ATL_FLAG_NEED_LINK_UPDATE) {
+                atl_dev_link_update(dev, 0);
+                intr->flags &= ~ATL_FLAG_NEED_LINK_UPDATE;
+                atl_dev_link_status_print(dev);
+                _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
+	}
+
+	atl_enable_intr(dev);
+	rte_intr_enable(intr_handle);
+
+	return 0;
+}
+
+/**
+ * Interrupt handler triggered by NIC  for handling
+ * specific interrupt.
+ *
+ * @param handle
+ *  Pointer to interrupt handle.
+ * @param param
+ *  The address of parameter (struct rte_eth_dev *) regsitered before.
+ *
+ * @return
+ *  void
+ */
+static void
+atl_dev_interrupt_handler(void *param)
+{
+	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+
+	atl_dev_interrupt_get_status(dev);
+	atl_dev_interrupt_action(dev, dev->intr_handle);
+}
+
 RTE_PMD_REGISTER_PCI(net_atlantic, rte_atl_pmd);
 RTE_PMD_REGISTER_PCI_TABLE(net_atlantic, pci_id_atl_map);
 RTE_PMD_REGISTER_KMOD_DEP(net_atlantic, "* igb_uio | uio_pci_generic");
diff --git a/drivers/net/atlantic/atl_ethdev.h b/drivers/net/atlantic/atl_ethdev.h
index 18a814a32..0018fa898 100644
--- a/drivers/net/atlantic/atl_ethdev.h
+++ b/drivers/net/atlantic/atl_ethdev.h
@@ -20,6 +20,8 @@
  * Structure to store private data for each driver instance (for each port).
  */
 struct atl_adapter {
+	struct aq_hw_s             hw;
+	struct aq_hw_cfg_s         hw_cfg;
 };
 
 #define ATL_DEV_TO_ADAPTER(dev) \
