This is an automated email from the ASF dual-hosted git repository.

jerpelea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 880c8e5d266 drivers/net: add IGB network card support
880c8e5d266 is described below

commit 880c8e5d26662f690432645327e3b76ebd2980b0
Author: p-szafonimateusz <p-szafonimate...@xiaomi.com>
AuthorDate: Mon Jun 9 13:04:38 2025 +0200

    drivers/net: add IGB network card support
    
    Add support for Intel IGB type of network cards.
    
    Signed-off-by: p-szafonimateusz <p-szafonimate...@xiaomi.com>
---
 .../components/drivers/special/pci/index.rst       |   10 +
 drivers/net/CMakeLists.txt                         |    4 +
 drivers/net/Kconfig                                |   30 +
 drivers/net/Make.defs                              |    8 +-
 drivers/net/igb.c                                  | 1492 ++++++++++++++++++++
 drivers/net/igb.h                                  |  544 +++++++
 drivers/pci/pci_drivers.c                          |   11 +
 include/nuttx/net/igb.h                            |   59 +
 8 files changed, 2156 insertions(+), 2 deletions(-)

diff --git a/Documentation/components/drivers/special/pci/index.rst 
b/Documentation/components/drivers/special/pci/index.rst
index 99160423b4e..ddd5dca7e58 100644
--- a/Documentation/components/drivers/special/pci/index.rst
+++ b/Documentation/components/drivers/special/pci/index.rst
@@ -50,6 +50,16 @@ Supported devices:
 - Intel 82574L
 - Intel 82574L
 
+Intel igb
+---------
+
+Intel igb compatible NIC support can be found in ``drivers/net/igb.c``.
+
+Supported devices:
+
+- Intel 82576
+- Intel I211
+
 Intel igc
 ---------
 
diff --git a/drivers/net/CMakeLists.txt b/drivers/net/CMakeLists.txt
index 3d0937f7f5f..1e9613871e8 100644
--- a/drivers/net/CMakeLists.txt
+++ b/drivers/net/CMakeLists.txt
@@ -89,6 +89,10 @@ if(CONFIG_NET)
     list(APPEND SRCS e1000.c)
   endif()
 
+  if(CONFIG_NET_IGB)
+    list(APPEND SRCS igb.c)
+  endif()
+
   if(CONFIG_NET_IGC)
     list(APPEND SRCS igc.c)
   endif()
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 77e6604877c..ffb561a3e47 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -815,6 +815,36 @@ config NET_E1000_RXSPARE
 
 endif # NET_E1000
 
+menuconfig NET_IGB
+       bool "Intel IGB support"
+       default n
+       depends on PCI && PCI_MSIX
+       ---help---
+               Enable IGB PCI Ethernet driver.
+
+if NET_IGB
+
+config NET_IGB_TXDESC
+       int "Intel IGB TX descriptors"
+       default 256
+
+config NET_IGB_RXDESC
+       int "Intel IGB RX descriptors"
+       default 256
+
+config NET_IGB_RXSPARE
+       int "Intel IGB spare RX buffers"
+       default 8
+
+config NET_IGB_INT_INTERVAL
+       int "Intel IGB interrupt interval"
+       default 100
+       range 1 8191
+       ---help---
+               Minimum Inter-interrupt Interval in 1 us increments.
+
+endif # NET_IGB
+
 menuconfig NET_IGC
        bool "Intel IGC support"
        default n
diff --git a/drivers/net/Make.defs b/drivers/net/Make.defs
index f341749752b..b1e781b7e00 100644
--- a/drivers/net/Make.defs
+++ b/drivers/net/Make.defs
@@ -103,14 +103,18 @@ ifeq ($(CONFIG_NET_E1000),y)
   CSRCS += e1000.c
 endif
 
-ifeq ($(CONFIG_DRIVERS_WIFI_SIM),y)
-  CSRCS += wifi_sim.c
+ifeq ($(CONFIG_NET_IGB),y)
+  CSRCS += igb.c
 endif
 
 ifeq ($(CONFIG_NET_IGC),y)
   CSRCS += igc.c
 endif
 
+ifeq ($(CONFIG_DRIVERS_WIFI_SIM),y)
+  CSRCS += wifi_sim.c
+endif
+
 # Include network build support
 
 DEPPATH += --dep-path net
diff --git a/drivers/net/igb.c b/drivers/net/igb.c
new file mode 100644
index 00000000000..8585dd83b3e
--- /dev/null
+++ b/drivers/net/igb.c
@@ -0,0 +1,1492 @@
+/*****************************************************************************
+ * drivers/net/igb.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Included Files
+ *****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/addrenv.h>
+#include <nuttx/spinlock.h>
+
+#include <nuttx/net/netdev_lowerhalf.h>
+#include <nuttx/pci/pci.h>
+#include <nuttx/net/igb.h>
+
+#include <arch/barriers.h>
+
+#include "igb.h"
+
+/*****************************************************************************
+ * Pre-processor Definitions
+ *****************************************************************************/
+
+#if CONFIG_NET_IGB_TXDESC % 8 != 0
+#  error CONFIG_NET_IGB_TXDESC must be multiple of 8
+#endif
+
+#if CONFIG_NET_IGB_RXDESC % 8 != 0
+#  error CONFIG_NET_IGB_RXDESC must be multiple of 8
+#endif
+
+/* Packet buffer size */
+
+#define IGB_PKTBUF_SIZE        2048
+#define IGB_RCTL_BSIZE         IGB_RCTL_BSIZE_2048
+
+/* TX and RX descriptors */
+
+#define IGB_TX_DESC            CONFIG_NET_IGB_TXDESC
+#define IGB_RX_DESC            CONFIG_NET_IGB_RXDESC
+
+/* After RX packet is done, we provide free netpkt to the RX descriptor ring.
+ * The upper-half network logic is responsible for freeing the RX packets
+ * so we need some additional spare netpkt buffers to assure that it's
+ * always possible to allocate the new RX packet in the receiver logic.
+ * It's hard to tell how many spare buffers is needed, for now it's set to 8.
+ */
+
+#define IGB_TX_QUOTA           IGB_TX_DESC
+#define IGB_RX_QUOTA           (IGB_RX_DESC + CONFIG_NET_IGB_RXSPARE)
+
+/* NOTE: CONFIG_IOB_ALIGNMENT must match system D-CACHE line size */
+
+#if CONFIG_IOB_NBUFFERS < IGB_RX_QUOTA + IGB_TX_QUOTA
+#  error CONFIG_IOB_NBUFFERS must be > (IGB_RX_QUOTA + IGB_TX_QUOTA)
+#endif
+
+#if CONFIG_IOB_BUFSIZE < IGB_PKTBUF_SIZE
+#  error CONFIG_IOB_BUFSIZE must be > IGB_PKTBUF_SIZE
+#endif
+
+/* PCI BARs */
+
+#define IGB_MMIO_BAR           0
+#define IGB_FLASH_BAR          1
+#define IGB_IO_BAR             2
+#define IGB_MSIX_BAR           3
+
+/* For MSI-X we allocate all interrupts to MSI-X vector 0 */
+
+#define IGB_GPIE_MSIX_SINGLE   (IGB_GPIE_NSICR | IGB_GPIE_EIAME | \
+                                IGB_GPIE_PBASUPPORT)
+#define IGB_MSIX_IMS           (IGB_IC_TXDW | IGB_IC_LSC | \
+                                IGB_IC_RXMISS | IGB_IC_RXDW)
+#define IGB_MSIX_EIMS          (IGB_EIMS_NOMSIX_OTHER | \
+                                IGB_EIMS_NOMSIX_RXTX0)
+#define IGB_MSIX_IVAR0         (IGB_IVAR0_RXQ0_VAL | IGB_IVAR0_TXQ0_VAL)
+#define IGB_MSIX_IVARMSC       (IGB_IVARMSC_OTHER_VAL)
+
+/*****************************************************************************
+ * Private Types
+ *****************************************************************************/
+
+/* Extend default PCI devie type */
+
+struct igb_type_s
+{
+  uint32_t desc_align;          /* Descriptor alignment */
+  uint32_t mta_regs;            /* MTA registers */
+};
+
+/* IGB private data */
+
+struct igb_driver_s
+{
+  /* This holds the information visible to the NuttX network */
+
+  struct netdev_lowerhalf_s dev;
+  struct work_s work;
+
+  /* Packets list */
+
+  FAR netpkt_t **tx_pkt;
+  FAR netpkt_t **rx_pkt;
+
+  /* Descriptors */
+
+  FAR struct igb_tx_leg_s *tx;
+  FAR struct igb_rx_leg_s *rx;
+
+  size_t tx_now;
+  size_t tx_done;
+  size_t rx_now;
+
+  /* PCI data */
+
+  FAR struct pci_device_s     *pcidev;
+  FAR const struct igb_type_s *type;
+  int                          irq;
+  uint64_t                     base;
+
+#ifdef CONFIG_NET_MCASTGROUP
+  /* MTA shadow */
+
+  FAR uint32_t *mta;
+#endif
+};
+
+/*****************************************************************************
+ * Private Functions Definitions
+ *****************************************************************************/
+
+/* Helpers */
+
+static uint32_t igb_getreg_mem(FAR struct igb_driver_s *priv,
+                               unsigned int offset);
+static void igb_putreg_mem(FAR struct igb_driver_s *priv,
+                           unsigned int offset,
+                           uint32_t value);
+#ifdef CONFIG_DEBUG_NET_INFO
+static void igb_dump_reg(FAR struct igb_driver_s *priv,
+                         FAR const char *msg, unsigned int offset);
+static void igb_dump_mem(FAR struct igb_driver_s *priv, FAR const char *msg);
+#endif
+
+/* Rings management */
+
+static void igb_txclean(FAR struct igb_driver_s *priv);
+static void igb_rxclean(FAR struct igb_driver_s *priv);
+
+/* Common TX logic */
+
+static int igb_transmit(FAR struct netdev_lowerhalf_s *dev,
+                        FAR netpkt_t *pkt);
+
+/* Interrupt handling */
+
+static FAR netpkt_t *igb_receive(FAR struct netdev_lowerhalf_s *dev);
+static void igb_txdone(FAR struct netdev_lowerhalf_s *dev);
+
+static void igb_msix_interrupt(FAR struct igb_driver_s *priv);
+static int igb_interrupt(int irq, FAR void *context, FAR void *arg);
+
+/* NuttX callback functions */
+
+static int igb_ifup(FAR struct netdev_lowerhalf_s *dev);
+static int igb_ifdown(FAR struct netdev_lowerhalf_s *dev);
+
+#ifdef CONFIG_NET_MCASTGROUP
+static uint32_t igb_hashmta(FAR struct igb_driver_s *priv,
+                            FAR const uint8_t *mac);
+static int igb_addmac(FAR struct netdev_lowerhalf_s *dev,
+                      FAR const uint8_t *mac);
+static int igb_rmmac(FAR struct netdev_lowerhalf_s *dev,
+                     FAR const uint8_t *mac);
+#endif
+
+/* Initialization */
+
+static void igb_disable(FAR struct igb_driver_s *priv);
+static void igb_enable(FAR struct igb_driver_s *priv);
+static int igb_initialize(FAR struct igb_driver_s *priv);
+static int igb_probe(FAR struct pci_device_s *dev);
+
+/*****************************************************************************
+ * Private Data
+ *****************************************************************************/
+
+/* Intel 82576 (QEMU -device igb) */
+
+static const struct igb_type_s g_igb_82576 =
+{
+  .desc_align = 128,
+  .mta_regs   = 128
+};
+
+/* Intel I211 */
+
+static const struct igb_type_s g_igb_i211 =
+{
+  .desc_align = 128,
+  .mta_regs   = 128
+};
+
+static const struct pci_device_id_s g_igb_id_table[] =
+{
+  {
+    PCI_DEVICE(0x8086, 0x10c9),
+    .driver_data = (uintptr_t)&g_igb_82576
+  },
+
+  {
+    PCI_DEVICE(0x8086, 0x1539),
+    .driver_data = (uintptr_t)&g_igb_i211
+  },
+
+  {
+    PCI_DEVICE(0x8086, 0x1533),
+    .driver_data = (uintptr_t)&g_igb_i211
+  },
+  { }
+};
+
+static struct pci_driver_s g_pci_igb_drv =
+{
+  .id_table = g_igb_id_table,
+  .probe    = igb_probe,
+};
+
+static const struct netdev_ops_s g_igb_ops =
+{
+  .ifup     = igb_ifup,
+  .ifdown   = igb_ifdown,
+  .transmit = igb_transmit,
+  .receive  = igb_receive,
+#ifdef CONFIG_NET_MCASTGROUP
+  .addmac   = igb_addmac,
+  .rmmac    = igb_rmmac,
+#endif
+};
+
+/*****************************************************************************
+ * Private Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Name: igb_getreg_mem
+ *****************************************************************************/
+
+static uint32_t igb_getreg_mem(FAR struct igb_driver_s *priv,
+                               unsigned int offset)
+{
+  uintptr_t addr = priv->base + offset;
+  return *((FAR volatile uint32_t *)addr);
+}
+
+/*****************************************************************************
+ * Name: igb_putreg_mem
+ *****************************************************************************/
+
+static void igb_putreg_mem(FAR struct igb_driver_s *priv,
+                           unsigned int offset,
+                           uint32_t value)
+{
+  uintptr_t addr = priv->base + offset;
+  *((FAR volatile uint32_t *)addr) = value;
+}
+
+#ifdef CONFIG_DEBUG_NET_INFO
+/*****************************************************************************
+ * Name: igb_dump_reg
+ *****************************************************************************/
+
+static void igb_dump_reg(FAR struct igb_driver_s *priv,
+                         FAR const char *msg, unsigned int offset)
+{
+  ninfo("\t%s:\t\t0x%" PRIx32 "\n", msg, igb_getreg_mem(priv, offset));
+}
+
+/*****************************************************************************
+ * Name: igb_dump_mem
+ *****************************************************************************/
+
+static void igb_dump_mem(FAR struct igb_driver_s *priv, FAR const char *msg)
+{
+  ninfo("\nDump: %s\n", msg);
+
+  ninfo("General registers:\n");
+  igb_dump_reg(priv, "CTRL", IGB_CTRL);
+  igb_dump_reg(priv, "STATUS", IGB_STATUS);
+  igb_dump_reg(priv, "CTRLEXT", IGB_CTRLEXT);
+  igb_dump_reg(priv, "MDIC", IGB_MDIC);
+  igb_dump_reg(priv, "SERDESCTL", IGB_SERDESCTL);
+  igb_dump_reg(priv, "FCAL", IGB_FCAL);
+  igb_dump_reg(priv, "FCAH", IGB_FCAH);
+  igb_dump_reg(priv, "FCT", IGB_FCT);
+  igb_dump_reg(priv, "CONNSW", IGB_CONNSW);
+  igb_dump_reg(priv, "VET", IGB_VET);
+  igb_dump_reg(priv, "FCTTV", IGB_FCTTV);
+
+  ninfo("Interrupt registers:\n");
+  igb_dump_reg(priv, "ICS", IGB_ICS);
+  igb_dump_reg(priv, "IMS", IGB_IMS);
+  igb_dump_reg(priv, "IAM", IGB_IAM);
+  igb_dump_reg(priv, "EICS", IGB_EICS);
+  igb_dump_reg(priv, "EIMS", IGB_EIMS);
+  igb_dump_reg(priv, "EIAM", IGB_EIAM);
+  igb_dump_reg(priv, "EIAC", IGB_EIAC);
+  igb_dump_reg(priv, "IVAR0", IGB_IVAR0);
+  igb_dump_reg(priv, "IVARMSC", IGB_IVARMSC);
+  igb_dump_reg(priv, "EITR0", IGB_EITR0);
+  igb_dump_reg(priv, "GPIE", IGB_GPIE);
+  igb_dump_reg(priv, "PBACL", IGB_PBACL);
+
+  ninfo("Receive registers:\n");
+  igb_dump_reg(priv, "RCTL", IGB_RCTL);
+  igb_dump_reg(priv, "PSRCTL", IGB_PSRCTL);
+  igb_dump_reg(priv, "FCRTL0", IGB_FCRTL0);
+  igb_dump_reg(priv, "FCRTH0", IGB_FCRTH0);
+  igb_dump_reg(priv, "RXPBSIZE", IGB_RXPBSIZE);
+  igb_dump_reg(priv, "FCRTV", IGB_FCRTV);
+  igb_dump_reg(priv, "RDBAL0", IGB_RDBAL0);
+  igb_dump_reg(priv, "RDBAH0", IGB_RDBAH0);
+  igb_dump_reg(priv, "RDLEN0", IGB_RDLEN0);
+  igb_dump_reg(priv, "SRRCTL0", IGB_SRRCTL0);
+  igb_dump_reg(priv, "RDH0", IGB_RDH0);
+  igb_dump_reg(priv, "RDT0", IGB_RDT0);
+  igb_dump_reg(priv, "RXDCTL0", IGB_RXDCTL0);
+  igb_dump_reg(priv, "RXCTL0", IGB_RXCTL0);
+  igb_dump_reg(priv, "RXCSUM", IGB_RXCSUM);
+  igb_dump_reg(priv, "RLPML", IGB_RLPML);
+  igb_dump_reg(priv, "RFCTL", IGB_RFCTL);
+  igb_dump_reg(priv, "MTA", IGB_MTA);
+  igb_dump_reg(priv, "RAL", IGB_RAL);
+  igb_dump_reg(priv, "RAH", IGB_RAH);
+
+  ninfo("Transmit registers:\n");
+  igb_dump_reg(priv, "TXPBSIZE", IGB_TXPBSIZE);
+  igb_dump_reg(priv, "PBTWAC", IGB_PBTWAC);
+  igb_dump_reg(priv, "TCTL", IGB_TCTL);
+  igb_dump_reg(priv, "TCTLEXT", IGB_TCTLEXT);
+  igb_dump_reg(priv, "TIPG", IGB_TIPG);
+  igb_dump_reg(priv, "RETXCTL", IGB_RETXCTL);
+  igb_dump_reg(priv, "DTXCTL", IGB_DTXCTL);
+  igb_dump_reg(priv, "TDBAL0", IGB_TDBAL0);
+  igb_dump_reg(priv, "TDBAH0", IGB_TDBAH0);
+  igb_dump_reg(priv, "TDLEN0", IGB_TDLEN0);
+  igb_dump_reg(priv, "TDH0", IGB_TDH0);
+  igb_dump_reg(priv, "TDT0", IGB_TDT0);
+  igb_dump_reg(priv, "TXDCTL0", IGB_TXDCTL0);
+  igb_dump_reg(priv, "TXCTL0", IGB_TXCTL0);
+  igb_dump_reg(priv, "TDWBAL0", IGB_TDWBAL0);
+  igb_dump_reg(priv, "TDWBAH0", IGB_TDWBAH0);
+
+  ninfo("Statistic registers:\n");
+  igb_dump_reg(priv, "CRCERRS", IGB_CRCERRS);
+  igb_dump_reg(priv, "ALGNERRC", IGB_ALGNERRC);
+  igb_dump_reg(priv, "RXERRC", IGB_RXERRC);
+  igb_dump_reg(priv, "MPC", IGB_MPC);
+  igb_dump_reg(priv, "SCC", IGB_SCC);
+  igb_dump_reg(priv, "ECOL", IGB_ECOL);
+  igb_dump_reg(priv, "MCC", IGB_MCC);
+  igb_dump_reg(priv, "LATECOL", IGB_LATECOL);
+  igb_dump_reg(priv, "COLC", IGB_COLC);
+  igb_dump_reg(priv, "DC", IGB_DC);
+  igb_dump_reg(priv, "TNCRS", IGB_TNCRS);
+  igb_dump_reg(priv, "RLEC", IGB_RLEC);
+  igb_dump_reg(priv, "XONRXC", IGB_XONRXC);
+  igb_dump_reg(priv, "XONTXC", IGB_XONTXC);
+  igb_dump_reg(priv, "XOFFRXC", IGB_XOFFRXC);
+  igb_dump_reg(priv, "XOFFTXC", IGB_XOFFTXC);
+  igb_dump_reg(priv, "FCRUC", IGB_FCRUC);
+  igb_dump_reg(priv, "PRC64", IGB_PRC64);
+  igb_dump_reg(priv, "PRC127", IGB_PRC127);
+  igb_dump_reg(priv, "PRC255", IGB_PRC255);
+  igb_dump_reg(priv, "PRC511", IGB_PRC511);
+  igb_dump_reg(priv, "PRC1023", IGB_PRC1023);
+  igb_dump_reg(priv, "PRC1522", IGB_PRC1522);
+  igb_dump_reg(priv, "GPRC", IGB_GPRC);
+  igb_dump_reg(priv, "BPRC", IGB_BPRC);
+  igb_dump_reg(priv, "MPRC", IGB_MPRC);
+  igb_dump_reg(priv, "GPTC", IGB_GPTC);
+  igb_dump_reg(priv, "GORCL", IGB_GORCL);
+  igb_dump_reg(priv, "GORCH", IGB_GORCH);
+  igb_dump_reg(priv, "GOTCL", IGB_GOTCL);
+  igb_dump_reg(priv, "GOTCH", IGB_GOTCH);
+  igb_dump_reg(priv, "RNBC", IGB_RNBC);
+  igb_dump_reg(priv, "RUC", IGB_RUC);
+  igb_dump_reg(priv, "RFC", IGB_RFC);
+  igb_dump_reg(priv, "ROC", IGB_ROC);
+  igb_dump_reg(priv, "RJC", IGB_RJC);
+  igb_dump_reg(priv, "MNGPRC", IGB_MNGPRC);
+  igb_dump_reg(priv, "MPDC", IGB_MPDC);
+  igb_dump_reg(priv, "TORL", IGB_TORL);
+  igb_dump_reg(priv, "TORH", IGB_TORH);
+  igb_dump_reg(priv, "TPR", IGB_TPR);
+  igb_dump_reg(priv, "TPT", IGB_TPT);
+  igb_dump_reg(priv, "PTC64", IGB_PTC64);
+  igb_dump_reg(priv, "PTC127", IGB_PTC127);
+  igb_dump_reg(priv, "PTC255", IGB_PTC255);
+  igb_dump_reg(priv, "PTC511", IGB_PTC511);
+  igb_dump_reg(priv, "PTC1023", IGB_PTC1023);
+  igb_dump_reg(priv, "PTC1522", IGB_PTC1522);
+  igb_dump_reg(priv, "BPTC", IGB_BPTC);
+  ninfo("Diagnostic registers:\n");
+  igb_dump_reg(priv, "RDFT", IGB_RDFT);
+  igb_dump_reg(priv, "RDFHS", IGB_RDFHS);
+  igb_dump_reg(priv, "RDFTS", IGB_RDFTS);
+  igb_dump_reg(priv, "RDFPC", IGB_RDFPC);
+  igb_dump_reg(priv, "RPBECCSTS", IGB_RPBECCSTS);
+  igb_dump_reg(priv, "TPBECCSTS", IGB_TPBECCSTS);
+  igb_dump_reg(priv, "FCSTS0", IGB_FCSTS0);
+  igb_dump_reg(priv, "RDHESTS", IGB_RDHESTS);
+  igb_dump_reg(priv, "TDHESTS", IGB_TDHESTS);
+  igb_dump_reg(priv, "TDFH", IGB_TDFH);
+  igb_dump_reg(priv, "TDFT", IGB_TDFT);
+  igb_dump_reg(priv, "TDFHS", IGB_TDFHS);
+  igb_dump_reg(priv, "TDFTS", IGB_TDFTS);
+  igb_dump_reg(priv, "TDFPC", IGB_TDFPC);
+  igb_dump_reg(priv, "TDHMP", IGB_TDHMP);
+  igb_dump_reg(priv, "CIRC", IGB_CIRC);
+  igb_dump_reg(priv, "TXBDC", IGB_TXBDC);
+  igb_dump_reg(priv, "TXIDLE", IGB_TXIDLE);
+  igb_dump_reg(priv, "RXBDC", IGB_RXBDC);
+  igb_dump_reg(priv, "RXIDLE", IGB_RXIDLE);
+}
+#endif
+
+/*****************************************************************************
+ * Name: igb_txclean
+ *
+ * Description:
+ *   Clean transmission ring
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumption:
+ *   This function can be called only after card reset and when TX is disabled
+ *
+ *****************************************************************************/
+
+static void igb_txclean(FAR struct igb_driver_s *priv)
+{
+  FAR struct netdev_lowerhalf_s *netdev = &priv->dev;
+
+  /* Reset ring */
+
+  igb_putreg_mem(priv, IGB_TDH0, 0);
+  igb_putreg_mem(priv, IGB_TDT0, 0);
+
+  /* Free any pending TX */
+
+  while (priv->tx_now != priv->tx_done)
+    {
+      /* Free net packet */
+
+      netpkt_free(netdev, priv->tx_pkt[priv->tx_done], NETPKT_TX);
+
+      /* Next descriptor */
+
+      priv->tx_done = (priv->tx_done + 1) % IGB_TX_DESC;
+    }
+
+  priv->tx_now  = 0;
+  priv->tx_done = 0;
+}
+
+/*****************************************************************************
+ * Name: igb_rxclean
+ *
+ * Description:
+ *   Clean receive ring
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumption:
+ *   This function can be called only after card reset and when RX is disabled
+ *
+ *****************************************************************************/
+
+static void igb_rxclean(FAR struct igb_driver_s *priv)
+{
+  priv->rx_now = 0;
+
+  igb_putreg_mem(priv, IGB_RDH0, 0);
+  igb_putreg_mem(priv, IGB_RDT0, IGB_RX_DESC - 1);
+}
+
+/*****************************************************************************
+ * Name: igb_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ *****************************************************************************/
+
+static int igb_transmit(FAR struct netdev_lowerhalf_s *dev,
+                          FAR netpkt_t *pkt)
+{
+  FAR struct igb_driver_s *priv    = (FAR struct igb_driver_s *)dev;
+  uint64_t                 pa      = 0;
+  int                      desc    = priv->tx_now;
+  size_t                   len     = netpkt_getdatalen(dev, pkt);
+  size_t                   tx_next = (priv->tx_now + 1) % IGB_TX_DESC;
+
+  ninfo("transmit\n");
+
+  /* Check the send length */
+
+  if (len > IGB_PKTBUF_SIZE)
+    {
+      nerr("net transmit buffer too large\n");
+      return -EINVAL;
+    }
+
+  if (!IFF_IS_RUNNING(dev->netdev.d_flags))
+    {
+      return -ENETDOWN;
+    }
+
+  /* Drop packet if ring full */
+
+  if (tx_next == priv->tx_done)
+    {
+      return -ENOMEM;
+    }
+
+  /* Store TX packet reference */
+
+  priv->tx_pkt[priv->tx_now] = pkt;
+
+  /* Prepare next TX descriptor */
+
+  priv->tx_now = tx_next;
+
+  /* Setup TX descriptor */
+
+  pa = up_addrenv_va_to_pa(netpkt_getdata(dev, pkt));
+
+  priv->tx[desc].addr   = pa;
+  priv->tx[desc].len    = len;
+  priv->tx[desc].cmd    = (IGB_TDESC_CMD_EOP | IGB_TDESC_CMD_IFCS |
+                           IGB_TDESC_CMD_RS);
+  priv->tx[desc].cso    = 0;
+  priv->tx[desc].status = 0;
+
+  UP_DSB();
+
+  /* Update TX tail */
+
+  igb_putreg_mem(priv, IGB_TDT0, priv->tx_now);
+
+  ninfodumpbuffer("Transmitted:", netpkt_getdata(dev, pkt), len);
+
+  return OK;
+}
+
+/*****************************************************************************
+ * Name: igb_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ *****************************************************************************/
+
+static FAR netpkt_t *igb_receive(FAR struct netdev_lowerhalf_s *dev)
+{
+  FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev;
+  FAR netpkt_t            *pkt  = NULL;
+  FAR struct igb_rx_leg_s *rx   = NULL;
+  int                      desc = 0;
+
+  desc = priv->rx_now;
+
+  /* Get RX descriptor and RX packet */
+
+  rx = &priv->rx[desc];
+  pkt = priv->rx_pkt[desc];
+
+  /* Check if descriptor done */
+
+  if (!(rx->status & IGB_RDESC_STATUS_DD))
+    {
+      return NULL;
+    }
+
+  /* Next descriptor */
+
+  priv->rx_now = (priv->rx_now + 1) % IGB_RX_DESC;
+
+  /* Allocate new rx packet */
+
+  priv->rx_pkt[desc] = netpkt_alloc(dev, NETPKT_RX);
+  if (priv->rx_pkt[desc] == NULL)
+    {
+      nerr("alloc pkt_new failed\n");
+      PANIC();
+    }
+
+  /* Set packet length */
+
+  netpkt_setdatalen(dev, pkt, rx->len);
+
+  /* Store new packet in RX descriptor ring */
+
+  rx->addr   = up_addrenv_va_to_pa(
+               netpkt_getdata(dev, priv->rx_pkt[desc]));
+  rx->len    = 0;
+  rx->status = 0;
+
+  /* Update RX tail */
+
+  igb_putreg_mem(priv, IGB_RDT0, desc);
+
+  /* Handle errors */
+
+  if (rx->errors)
+    {
+      nerr("RX error reported (%"PRIu8")\n", rx->errors);
+      NETDEV_RXERRORS(&priv->dev.netdev);
+      netpkt_free(dev, pkt, NETPKT_RX);
+      return NULL;
+    }
+
+  return pkt;
+}
+
+/*****************************************************************************
+ * Name: igb_txdone
+ *
+ * Description:
+ *   An interrupt was received indicating that the last TX packet(s) is done
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ *****************************************************************************/
+
+static void igb_txdone(FAR struct netdev_lowerhalf_s *dev)
+{
+  FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev;
+
+  while (priv->tx_now != priv->tx_done)
+    {
+      if (priv->tx[priv->tx_done].status == 0)
+        {
+          break;
+        }
+
+      if (!(priv->tx[priv->tx_done].status & IGB_TDESC_STATUS_DD))
+        {
+          nerr("tx failed: 0x%" PRIx32 "\n", priv->tx[priv->tx_done].status);
+          NETDEV_TXERRORS(&priv->dev.netdev);
+        }
+
+      /* Free net packet */
+
+      netpkt_free(dev, priv->tx_pkt[priv->tx_done], NETPKT_TX);
+
+      /* Next descriptor */
+
+      priv->tx_done = (priv->tx_done + 1) % IGB_TX_DESC;
+    }
+
+  netdev_lower_txdone(dev);
+}
+
+/*****************************************************************************
+ * Name: igb_link_work
+ *
+ * Description:
+ *   Handle link status change.
+ *
+ * Input Parameters:
+ *   arg - Reference to the lover half driver structure (cast to void *)
+ *
+ * Returned Value:
+ *   None
+ *
+ *****************************************************************************/
+
+static void igb_link_work(FAR void *arg)
+{
+  FAR struct igb_driver_s *priv = arg;
+  uint32_t tmp;
+
+  tmp = igb_getreg_mem(priv, IGB_STATUS);
+  if (tmp & IGB_STATUS_LU)
+    {
+      ninfo("Link up, status = 0x%x\n", tmp);
+
+      netdev_lower_carrier_on(&priv->dev);
+    }
+  else
+    {
+      ninfo("Link down\n");
+
+      netdev_lower_carrier_off(&priv->dev);
+    }
+}
+
+/*****************************************************************************
+ * Name: igb_misx_interrupt
+ *
+ * Description:
+ *   Perform MSI-X interrupt work
+ *
+ * Input Parameters:
+ *   arg - The argument passed when work_queue() was called.
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   Runs on a worker thread.
+ *
+ *****************************************************************************/
+
+static void igb_msix_interrupt(FAR struct igb_driver_s *priv)
+{
+  uint32_t icr  = 0;
+  uint32_t eicr = 0;
+
+  /* Get interrupts */
+
+  icr  = igb_getreg_mem(priv, IGB_ICR);
+  eicr = igb_getreg_mem(priv, IGB_EICR);
+
+  ninfo("eicr = 0x%" PRIx32 " icr = 0x%" PRIx32 "\n", eicr, icr);
+
+  if (icr == 0)
+    {
+      /* Ignore spurious interrupts */
+
+      return;
+    }
+
+  /* Receiver Descriptor Write Back */
+
+  if (icr & IGB_IC_RXDW)
+    {
+      netdev_lower_rxready(&priv->dev);
+    }
+
+  /* Link Status Change */
+
+  if (icr & IGB_IC_LSC)
+    {
+      if (work_available(&priv->work))
+        {
+          /* Schedule to work queue because netdev_lower_carrier_xxx API
+           * can't be used in interrupt context
+           */
+
+          work_queue(LPWORK, &priv->work, igb_link_work, priv, 0);
+        }
+    }
+
+  /* Receiver Miss */
+
+  if (icr & IGB_IC_RXMISS)
+    {
+      nerr("Receiver Miss\n");
+      netdev_lower_rxready(&priv->dev);
+    }
+
+  /* Transmit Descriptor Written Back */
+
+  if (icr & IGB_IC_TXDW)
+    {
+      igb_txdone(&priv->dev);
+    }
+}
+
+/*****************************************************************************
+ * Name: igb_interrupt
+ *
+ * Description:
+ *   Hardware interrupt handler
+ *
+ * Input Parameters:
+ *   irq     - Number of the IRQ that generated the interrupt
+ *   context - Interrupt register state save info (architecture-specific)
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   Runs in the context of a the Ethernet interrupt handler.  Local
+ *   interrupts are disabled by the interrupt logic.
+ *
+ *****************************************************************************/
+
+static int igb_interrupt(int irq, FAR void *context, FAR void *arg)
+{
+  FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)arg;
+
+  DEBUGASSERT(priv != NULL);
+
+  ninfo("interrupt!\n");
+
+  /* Schedule to perform the interrupt processing on the worker thread. */
+
+  igb_msix_interrupt(priv);
+
+  return OK;
+}
+
+/*****************************************************************************
+ * Name: igb_ifup
+ *
+ * Description:
+ *   NuttX Callback: Bring up the Ethernet interface when an IP address is
+ *   provided
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ *****************************************************************************/
+
+static int igb_ifup(FAR struct netdev_lowerhalf_s *dev)
+{
+  FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev;
+  irqstate_t flags;
+
+#ifdef CONFIG_NET_IPv4
+  ninfo("Bringing up: %u.%u.%u.%u\n",
+        ip4_addr1(dev->netdev.d_ipaddr), ip4_addr2(dev->netdev.d_ipaddr),
+        ip4_addr3(dev->netdev.d_ipaddr), ip4_addr4(dev->netdev.d_ipaddr));
+#endif
+
+#ifdef CONFIG_NET_IPv6
+  ninfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+        dev->netdev.d_ipv6addr[0], dev->netdev.d_ipv6addr[1],
+        dev->netdev.d_ipv6addr[2], dev->netdev.d_ipv6addr[3],
+        dev->netdev.d_ipv6addr[4], dev->netdev.d_ipv6addr[5],
+        dev->netdev.d_ipv6addr[6], dev->netdev.d_ipv6addr[7]);
+#endif
+
+  flags = enter_critical_section();
+
+  /* Enable the Ethernet */
+
+  igb_enable(priv);
+  leave_critical_section(flags);
+
+  /* Update link status in case link status interrupt is missing */
+
+  igb_link_work(priv);
+
+  return OK;
+}
+
+/*****************************************************************************
+ * Name: igb_ifdown
+ *
+ * Description:
+ *   NuttX Callback: Stop the interface.
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ *****************************************************************************/
+
+static int igb_ifdown(FAR struct netdev_lowerhalf_s *dev)
+{
+  FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev;
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  /* Put the EMAC in its reset, non-operational state.  This should be
+   * a known configuration that will guarantee the igb_ifup() always
+   * successfully brings the interface back up.
+   */
+
+  igb_disable(priv);
+  leave_critical_section(flags);
+  return OK;
+}
+
+#ifdef CONFIG_NET_MCASTGROUP
+/*****************************************************************************
+ * Name: igb_hashmta
+ *
+ * Note: This logic is based on freeBSD igb implementation
+ *
+ *****************************************************************************/
+
+static uint32_t igb_hashmta(FAR struct igb_driver_s *priv,
+                              FAR const uint8_t *mac)
+{
+  uint32_t hash_mask = 0;
+  uint8_t  bit_shift = 0;
+
+  /* Register count multiplied by bits per register */
+
+  hash_mask = (priv->type->mta_regs * 32) - 1;
+
+/* For a mc_filter_type of 0, bit_shift is the number of left-shifts
+ * where 0xFF would still fall within the hash mask.
+ */
+
+  while (hash_mask >> bit_shift != 0xff)
+    {
+      bit_shift++;
+    }
+
+  /* bit_shift += 0 because we have MO set to 0 */
+
+  return hash_mask & ((mac[4] >> (8 - bit_shift)) | (mac[5] << bit_shift));
+}
+
+/*****************************************************************************
+ * Name: igb_addmac
+ *
+ * Description:
+ *   NuttX Callback: Add the specified MAC address to the hardware multicast
+ *   address filtering
+ *
+ * Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *   mac  - The MAC address to be added
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ *****************************************************************************/
+
+static int igb_addmac(FAR struct netdev_lowerhalf_s *dev,
+                        FAR const uint8_t *mac)
+{
+  FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev;
+  uint16_t                 hash = 0;
+  uint8_t                  row  = 0;
+  uint8_t                  bit  = 0;
+  int                      i    = 0;
+
+  hash = igb_hashmta(priv, mac);
+  bit = hash & 31;
+  row = (hash >> 5) & (priv->type->mta_regs - 1);
+
+  /* Bits 4:0 indicate bit in row word */
+
+  priv->mta[row] |= (1 << bit);
+
+  /* Replace the entire MTA */
+
+  for (i = priv->type->mta_regs - 1; i >= 0; i--)
+    {
+      igb_putreg_mem(priv, IGB_MTA + (i << 2), priv->mta[i]);
+    }
+
+  return OK;
+}
+
+/*****************************************************************************
+ * Name: igb_rmmac
+ *
+ * Description:
+ *   NuttX Callback: Remove the specified MAC address from the hardware
+ *   multicast address filtering
+ *
+ * Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *   mac  - The MAC address to be removed
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ *****************************************************************************/
+
+static int igb_rmmac(FAR struct netdev_lowerhalf_s *dev,
+                       FAR const uint8_t *mac)
+{
+  FAR struct igb_driver_s *priv = (FAR struct igb_driver_s *)dev;
+  uint16_t                 hash = 0;
+  uint8_t                  row  = 0;
+  uint8_t                  bit  = 0;
+  int                      i    = 0;
+
+  hash = igb_hashmta(priv, mac);
+  bit = hash & 31;
+  row = (hash >> 5) & (priv->type->mta_regs - 1);
+
+  /* Bits 4:0 indicate bit in row word */
+
+  priv->mta[row] &= ~(1 << bit);
+
+  /* Replace the entire MTA */
+
+  for (i = priv->type->mta_regs - 1; i >= 0; i--)
+    {
+      igb_putreg_mem(priv, IGB_MTA + (i << 2), priv->mta[i]);
+    }
+
+  return OK;
+}
+#endif  /* CONFIG_NET_MCASTGROUP */
+
+/*****************************************************************************
+ * Name: igb_disable
+ *
+ * Description:
+ *   Reset device to known state.
+ *
+ *****************************************************************************/
+
+static void igb_disable(FAR struct igb_driver_s *priv)
+{
+  uint32_t regval;
+  int      i = 0;
+
+  /* Disable interrupts */
+
+  igb_putreg_mem(priv, IGB_EIMC, IGB_MSIX_EIMS);
+  igb_putreg_mem(priv, IGB_IMC, IGB_MSIX_IMS);
+  up_disable_irq(priv->irq);
+
+  /* Disable Transmitter */
+
+  regval = igb_getreg_mem(priv, IGB_TCTL);
+  regval &= ~IGB_TCTL_EN;
+  igb_putreg_mem(priv, IGB_TCTL, regval);
+
+  /* Disable Receiver */
+
+  igb_putreg_mem(priv, IGB_RCTL, 0);
+
+  /* We have to reset device, otherwise writing to RDH and THD corrupts
+   * the device state.
+   */
+
+  igb_putreg_mem(priv, IGB_CTRL, IGB_CTRL_RST);
+
+  /* Reset Tx tail */
+
+  igb_txclean(priv);
+
+  /* Reset Rx tail */
+
+  igb_rxclean(priv);
+
+  /* Free RX packets */
+
+  for (i = 0; i < IGB_RX_DESC; i += 1)
+    {
+      netpkt_free(&priv->dev, priv->rx_pkt[i], NETPKT_RX);
+    }
+}
+
+/*****************************************************************************
+ * Name: igb_phy_reset
+ *
+ * Description:
+ *   Reset PHY
+ *
+ *****************************************************************************/
+
+static void igb_phy_reset(FAR struct igb_driver_s *priv)
+{
+  uint32_t regval = 0;
+
+  regval = igb_getreg_mem(priv, IGB_CTRL);
+  igb_putreg_mem(priv, IGB_CTRL, regval | IGB_CTRL_PHYRST);
+  up_udelay(100);
+  igb_putreg_mem(priv, IGB_CTRL, regval);
+  up_udelay(100);
+}
+
+/*****************************************************************************
+ * Name: igb_enable
+ *
+ * Description:
+ *   Enable device.
+ *
+ *****************************************************************************/
+
+static void igb_enable(FAR struct igb_driver_s *priv)
+{
+  FAR struct netdev_lowerhalf_s *dev = (FAR struct netdev_lowerhalf_s *)priv;
+  uint64_t pa     = 0;
+  uint32_t regval = 0;
+  int      i      = 0;
+
+  /* Reset PHY */
+
+  igb_phy_reset(priv);
+
+  /* Reset Multicast Table Array */
+
+  for (i = 0; i < priv->type->mta_regs; i++)
+    {
+      igb_putreg_mem(priv, IGB_MTA + (i << 2), 0);
+    }
+
+  /* Allocate RX packets */
+
+  for (i = 0; i < IGB_RX_DESC; i += 1)
+    {
+      priv->rx_pkt[i] = netpkt_alloc(dev, NETPKT_RX);
+      if (priv->rx_pkt[i] == NULL)
+        {
+          nerr("alloc rx_pkt failed\n");
+          PANIC();
+        }
+
+      /* Configure RX descriptor */
+
+      priv->rx[i].addr   = up_addrenv_va_to_pa(
+                           netpkt_getdata(dev, priv->rx_pkt[i]));
+      priv->rx[i].len    = 0;
+      priv->rx[i].status = 0;
+    }
+
+  /* Setup TX descriptor */
+
+  /* The address passed to the NIC must be physical */
+
+  pa = up_addrenv_va_to_pa(priv->tx);
+
+  regval = (uint32_t)pa;
+  igb_putreg_mem(priv, IGB_TDBAL0, regval);
+  regval = (uint32_t)(pa >> 32);
+  igb_putreg_mem(priv, IGB_TDBAH0, regval);
+
+  regval = IGB_TX_DESC * sizeof(struct igb_tx_leg_s);
+  igb_putreg_mem(priv, IGB_TDLEN0, regval);
+
+  /* Reset TX tail */
+
+  igb_txclean(priv);
+
+  /* Setup RX descriptor */
+
+  /* The address passed to the NIC must be physical */
+
+  pa = up_addrenv_va_to_pa(priv->rx);
+
+  regval = (uint32_t)pa;
+  igb_putreg_mem(priv, IGB_RDBAL0, regval);
+  regval = (uint32_t)(pa >> 32);
+  igb_putreg_mem(priv, IGB_RDBAH0, regval);
+
+  regval = IGB_RX_DESC * sizeof(struct igb_rx_leg_s);
+  igb_putreg_mem(priv, IGB_RDLEN0, regval);
+
+  /* Enable interrupts */
+
+  igb_putreg_mem(priv, IGB_EIMS, IGB_MSIX_EIMS);
+  igb_putreg_mem(priv, IGB_IMS, IGB_MSIX_IMS);
+  up_enable_irq(priv->irq);
+
+  /* Set link up */
+
+  igb_putreg_mem(priv, IGB_CTRL, IGB_CTRL_SLU);
+
+  /* Setup and enable Transmitter */
+
+  regval = igb_getreg_mem(priv, IGB_TCTL);
+  regval |= IGB_TCTL_EN | IGB_TCTL_PSP;
+  igb_putreg_mem(priv, IGB_TCTL, regval);
+
+  /* Setup and enable Receiver */
+
+  regval = (IGB_RCTL_EN | IGB_RCTL_MPE |
+            (IGB_RCTL_BSIZE << IGB_RCTL_BSIZE_SHIFT));
+#ifdef CONFIG_NET_PROMISCUOUS
+  regval |= IGB_RCTL_UPE | IGB_RCTL_MPE;
+#endif
+  igb_putreg_mem(priv, IGB_RCTL, regval);
+
+  /* Enable TX queeu */
+
+  regval = igb_getreg_mem(priv, IGB_TXDCTL0);
+  regval |= IGB_TXDCTL_ENABLE;
+  igb_putreg_mem(priv, IGB_TXDCTL0, regval);
+
+  /* Enable RX queue */
+
+  regval = igb_getreg_mem(priv, IGB_RXDCTL0);
+  regval |= IGB_RXDCTL_ENABLE;
+  igb_putreg_mem(priv, IGB_RXDCTL0, regval);
+
+  /* Reset RX tail - after queue is enabled */
+
+  igb_rxclean(priv);
+
+#ifdef CONFIG_DEBUG_NET_INFO
+  /* Dump memory */
+
+  igb_dump_mem(priv, "enabled");
+#endif
+}
+
+/*****************************************************************************
+ * Name: igb_initialize
+ *
+ * Description:
+ *   Initialize device
+ *
+ *****************************************************************************/
+
+static int igb_initialize(FAR struct igb_driver_s *priv)
+{
+  uint32_t regval = 0;
+  uint64_t mac    = 0;
+  int      ret    = OK;
+
+  /* Allocate MSI */
+
+  ret = pci_alloc_irq(priv->pcidev, &priv->irq, 1);
+  if (ret != 1)
+    {
+      nerr("Failed to allocate MSI %d\n", ret);
+      return ret;
+    }
+
+  /* Attach IRQ */
+
+  irq_attach(priv->irq, igb_interrupt, priv);
+
+  /* Connect MSI */
+
+  ret = pci_connect_irq(priv->pcidev, &priv->irq, 1);
+  if (ret != OK)
+    {
+      nerr("Failed to connect MSI %d\n", ret);
+      pci_release_irq(priv->pcidev, &priv->irq, 1);
+
+      return -ENOTSUP;
+    }
+
+  /* Clear previous Extended Interrupt Mask */
+
+  igb_putreg_mem(priv, IGB_EIMC, 0xffffffff);
+  igb_putreg_mem(priv, IGB_IMC, 0xffffffff);
+
+  /* Configure MSI-X */
+
+  igb_putreg_mem(priv, IGB_IVAR0, IGB_MSIX_IVAR0);
+  igb_putreg_mem(priv, IGB_IVARMSC, IGB_MSIX_IVARMSC);
+
+  /* Enable MSI-X Single Vector */
+
+  igb_putreg_mem(priv, IGB_GPIE, IGB_GPIE_MSIX_SINGLE);
+  igb_putreg_mem(priv, IGB_EIMS, IGB_MSIX_EIMS);
+
+  /* Configure Other causes */
+
+  igb_putreg_mem(priv, IGB_IMS, IGB_MSIX_IMS);
+
+  /* Configure Interrupt Throttle */
+
+  igb_putreg_mem(priv, IGB_EITR0, (CONFIG_NET_IGB_INT_INTERVAL << 2));
+
+  /* Get MAC if valid */
+
+  regval = igb_getreg_mem(priv, IGB_RAH);
+  if (regval & IGB_RAH_AV)
+    {
+      mac = ((uint64_t)regval & IGB_RAH_RAH_MASK) << 32;
+      mac |= igb_getreg_mem(priv, IGB_RAL);
+      memcpy(&priv->dev.netdev.d_mac.ether, &mac, sizeof(struct ether_addr));
+    }
+  else
+    {
+      nwarn("Receive Address not valid!\n");
+    }
+
+  return OK;
+}
+
+/*****************************************************************************
+ * Name: igb_probe
+ *
+ * Description:
+ *   Initialize device
+ *
+ *****************************************************************************/
+
+static int igb_probe(FAR struct pci_device_s *dev)
+{
+  FAR const struct igb_type_s   *type   = NULL;
+  FAR struct igb_driver_s       *priv   = NULL;
+  FAR struct netdev_lowerhalf_s *netdev = NULL;
+  int                            ret    = -ENOMEM;
+
+  /* Get type data associated with this PCI device card */
+
+  type = (FAR const struct igb_type_s *)dev->id->driver_data;
+
+  /* Not found private data */
+
+  if (type == NULL)
+    {
+      return -ENODEV;
+    }
+
+  /* Allocate the interface structure */
+
+  priv = kmm_zalloc(sizeof(*priv));
+  if (priv == NULL)
+    {
+      return ret;
+    }
+
+  priv->pcidev = dev;
+
+  /* Allocate TX descriptors */
+
+  priv->tx = kmm_memalign(type->desc_align,
+                          IGB_TX_DESC * sizeof(struct igb_tx_leg_s));
+  if (priv->tx == NULL)
+    {
+      nerr("alloc tx failed %d\n", errno);
+      goto errout;
+    }
+
+  /* Allocate RX descriptors */
+
+  priv->rx = kmm_memalign(type->desc_align,
+                          IGB_RX_DESC * sizeof(struct igb_rx_leg_s));
+  if (priv->rx == NULL)
+    {
+      nerr("alloc rx failed %d\n", errno);
+      goto errout;
+    }
+
+  /* Allocate TX packet pointer array */
+
+  priv->tx_pkt = kmm_zalloc(IGB_TX_DESC * sizeof(netpkt_t *));
+  if (priv->tx_pkt == NULL)
+    {
+      nerr("alloc tx_pkt failed\n");
+      goto errout;
+    }
+
+  /* Allocate RX packet pointer array */
+
+  priv->rx_pkt = kmm_zalloc(IGB_RX_DESC * sizeof(netpkt_t *));
+  if (priv->rx_pkt == NULL)
+    {
+      nerr("alloc rx_pkt failed\n");
+      goto errout;
+    }
+
+#ifdef CONFIG_NET_MCASTGROUP
+  /* Allocate MTA shadow */
+
+  priv->mta = kmm_zalloc(type->mta_regs);
+  if (priv->mta == NULL)
+    {
+      nerr("alloc mta failed\n");
+      goto errout;
+    }
+#endif
+
+  /* Get devices */
+
+  netdev     = &priv->dev;
+  priv->type = type;
+
+  pci_set_master(dev);
+  pciinfo("Enabled bus mastering\n");
+  pci_enable_device(dev);
+  pciinfo("Enabled memory resources\n");
+
+  /* If the BAR is MMIO then it must be mapped */
+
+  priv->base = (uintptr_t)pci_map_bar(dev, IGB_MMIO_BAR);
+  if (!priv->base)
+    {
+      pcierr("Not found MMIO control bar\n");
+      goto errout;
+    }
+
+  /* Initialize PHYs, Ethernet interface, and setup up Ethernet interrupts */
+
+  ret = igb_initialize(priv);
+  if (ret != OK)
+    {
+      nerr("igb_initialize failed %d\n", ret);
+      return ret;
+    }
+
+  /* Register the network device */
+
+  netdev->quota[NETPKT_TX] = IGB_TX_QUOTA;
+  netdev->quota[NETPKT_RX] = IGB_RX_QUOTA;
+  netdev->ops = &g_igb_ops;
+
+  return netdev_lower_register(netdev, NET_LL_ETHERNET);
+
+errout:
+  kmm_free(priv->tx);
+  kmm_free(priv->rx);
+#ifdef CONFIG_NET_MCASTGROUP
+  kmm_free(priv->mta);
+#endif
+  kmm_free(priv);
+  return ret;
+}
+
+/*****************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Name: pci_igb_init
+ *
+ * Description:
+ *   Register a pci driver
+ *
+ *****************************************************************************/
+
+int pci_igb_init(void)
+{
+  return pci_register_driver(&g_pci_igb_drv);
+}
diff --git a/drivers/net/igb.h b/drivers/net/igb.h
new file mode 100644
index 00000000000..e281fd5ad3c
--- /dev/null
+++ b/drivers/net/igb.h
@@ -0,0 +1,544 @@
+/*****************************************************************************
+ * drivers/net/igb.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ *****************************************************************************/
+
+#ifndef __DRIVERS_NET_IGB_H
+#define __DRIVERS_NET_IGB_H
+
+/*****************************************************************************
+ * Included Files
+ *****************************************************************************/
+
+#include <stdint.h>
+
+/*****************************************************************************
+ * Pre-processor Definitions
+ *****************************************************************************/
+
+/* General registers */
+
+#define IGB_CTRL                  (0x0000)   /* Device Control Register */
+#define IGB_STATUS                (0x0008)   /* Device Status Register  */
+#define IGB_CTRLEXT               (0x0018)   /* Extended Device Control 
Register */
+#define IGB_MDIC                  (0x0020)   /* MDI Control Register */
+#define IGB_SERDESCTL             (0x0024)   /* Serdes_ana */
+#define IGB_FCAL                  (0x0028)   /* Flow Control Address Low */
+#define IGB_FCAH                  (0x002c)   /* Flow Control Address High */
+#define IGB_FCT                   (0x0030)   /* Flow Control Type */
+#define IGB_CONNSW                (0x0034)   /* Copper/Fiber Switch Control */
+#define IGB_VET                   (0x0038)   /* VLAN Ether Type */
+#define IGB_FCTTV                 (0x0170)   /* Flow Control Transmit Timer 
Value */
+#define IGB_LEDCTL                (0x0e00)   /* LED Control */
+#define IGB_I2CCM                 (0x1028)   /* SFP I2C Command */
+#define IGB_I2CPARAMS             (0x102c)   /* SFP I2C Parameter */
+#define IGB_WDSTP                 (0x1040)   /* Watchdog Setup Register */
+#define IGB_WDSWSTS               (0x1044)   /* Watchdog Software */
+#define IGB_FRTIMER               (0x1048)   /* Free Running Timer */
+#define IGB_TCPTIMER              (0x104c)   /* TCP Timer */
+#define IGB_DCAID                 (0x5b70)   /* DCA Requester ID Information 
Register */
+#define IGB_SWSM                  (0x5b50)   /* Software Semaphore Register */
+#define IGB_FWSM                  (0x5b54)   /* Firmware Semaphore Register */
+#define IGB_SWFWSYNC              (0x5b5c)   /* Software-Firmware 
Synchronization */
+
+/* Flash/EEPROM Registers */
+
+#define IGB_EEC                   (0x00010)  /* EEPROM/FLASH Control Register 
*/
+#define IGB_EERD                  (0x00014)  /* EEPROM Read Register */
+#define IGB_FLA                   (0x0001c)  /* Flash Access Register */
+#define IGB_EEMNGCTL              (0x01010)  /* MNG EEPROM Control Register */
+#define IGB_EEMNGDATA             (0x01014)  /* MNG EEPROM Read/Write data */
+#define IGB_FLMNGCTL              (0x01018)  /* MNG Flash Control Register */
+#define IGB_FLMNGDATA             (0x0101c)  /* MNG Flash Read data */
+#define IGB_FLMNGCNT              (0x01020)  /* MNG Flash Read Counter */
+#define IGB_EEARBC                (0x01024)  /* EEPROM Auto Read Bus Control */
+#define IGB_FLASHOP               (0x0103c)  /* Flash Opcode Register */
+#define IGB_EEDIAG                (0x01038)  /* EEPROM Diagnostic */
+#define IGB_VPDDIAG               (0x01060)  /* VPD Diagnostic */
+
+/* Interrupt registers */
+
+#define IGB_ICR                   (0x1500)   /* Interrupt Cause Read */
+#define IGB_ICS                   (0x1504)   /* Interrupt Cause Set */
+#define IGB_IMS                   (0x1508)   /* Interrupt Mask Set */
+#define IGB_IMC                   (0x150c)   /* Interrupt Mask Clear */
+#define IGB_IAM                   (0x1510)   /* Interrupt Acknowledge 
Auto–Mask */
+#define IGB_EICS                  (0x1520)   /* Extended Interrupt Cause Set */
+#define IGB_EIMS                  (0x1524)   /* Extended Interrupt Mask 
Set/Read */
+#define IGB_EIMC                  (0x1528)   /* Extended Interrupt Mask Clear 
*/
+#define IGB_EIAC                  (0x152c)   /* Extended Interrupt Auto Clear 
*/
+#define IGB_EIAM                  (0x1530)   /* Extended Interrupt Auto Mask */
+#define IGB_EICR                  (0x1580)   /* Extended Interrupt Cause Read 
*/
+#define IGB_IVAR0                 (0x1700)   /* Interrupt Vector Allocation 
Registers  */
+#define IGB_IVARMSC               (0x1740)   /* Interrupt Vector Allocation 
Registers - MISC */
+#define IGB_EITR0                 (0x1680)   /* Extended Interrupt Throttling 
Rate 0 - 24 */
+#define IGB_GPIE                  (0x1514)   /* General Purpose Interrupt 
Enable */
+#define IGB_PBACL                 (0x5b68)   /* MSI-X PBA Clear */
+
+/* Receive registers */
+
+#define IGB_RCTL                  (0x0100)   /* Receive Control */
+#define IGB_FCRTL0                (0x2160)   /* Flow Control Receive Threshold 
Low */
+#define IGB_PSRCTL                (0x2170)   /* Packet Split Receive Control 
Register */
+#define IGB_FCRTH0                (0x2168)   /* Flow Control Receive Threshold 
High */
+#define IGB_RXPBSIZE              (0x2404)   /* Rx Packet Buffer Size */
+#define IGB_PBRWAC                (0x24e8)   /* Rx Packet Buffer wrap around 
counter */
+#define IGB_FCRTV                 (0x2460)   /* Flow Control Refresh Threshold 
Value */
+#define IGB_DRXMXOD               (0x2540)   /* DMA RX Max Total Allow Size 
Requests */
+#define IGB_RDBAL0                (0xc000)   /* Tx Descriptor Base Address Low 
*/
+#define IGB_RDBAH0                (0xc004)   /* Rx Descriptor Base Address 
High */
+#define IGB_RDLEN0                (0xc008)   /* Rx Descriptor Length */
+#define IGB_SRRCTL0               (0xc00c)   /* Split and Replication Receive 
Control Register Queue */
+#define IGB_RDH0                  (0xc010)   /* Rx Descriptor Head */
+#define IGB_RDT0                  (0xc018)   /* Rx Descriptor Tail */
+#define IGB_RXDCTL0               (0xc028)   /* Receive Descriptor Control 
Queue */
+#define IGB_RXCTL0                (0xc014)   /* Receive Queue DCA CTRL 
Register */
+#define IGB_RXCSUM                (0x5000)   /* Receive Checksum Control */
+#define IGB_RLPML                 (0x5004)   /* Receive Long packet maximal 
length */
+#define IGB_RFCTL                 (0x5008)   /* Receive Filter Control 
Register */
+#define IGB_MTA                   (0x5200)   /* Multicast Table Array (n) */
+#define IGB_RAL                   (0x5400)   /* Receive Address Low */
+#define IGB_RAH                   (0x5404)   /* Receive Address Low */
+#define IGB_PSRTYPE0              (0x5480)   /* Packet Split Receive type (n) 
*/
+#define IGB_RPLPSRTYPE            (0x54c0)   /* Replicated Packet Split 
Receive type */
+#define IGB_VTCTL                 (0x5818)   /* Next Generation VMDq Control 
register */
+#define IGB_VFTA0                 (0x5600)   /* VLAN Filter Table Array (n) */
+#define IGB_MRQC                  (0x5818)   /* Multiple Receive Queues 
Command */
+#define IGB_RETA                  (0x5c00)   /* Redirection Table */
+#define IGB_RSSRK                 (0x5c80)   /* RSS Random Key Register */
+
+/* Transmit registers */
+
+#define IGB_TXPBSIZE              (0x3404)   /* Transmit Packet Buffer Size */
+#define IGB_PBTWAC                (0x34e8)   /* Tx Packet Buffer wrap around 
counter */
+#define IGB_TCTL                  (0x0400)   /* Transmit Control */
+#define IGB_TCTLEXT               (0x0404)   /* Transmit Control Extended */
+#define IGB_TIPG                  (0x0410)   /* Transmit IPG Register */
+#define IGB_RETXCTL               (0x041c)   /* Retry Buffer Control */
+#define IGB_DTXCTL                (0x3590)   /* DMA Tx Control */
+#define IGB_DTXTCPFLGL            (0x359c)   /* DMA Tx TCP Flags Control Low */
+#define IGB_DTXTCPFLGH            (0x35a0)   /* DMA Tx TCP Flags Control High 
*/
+#define IGB_DTXMXSZRQ             (0x3540)   /* DMA Tx Max Total Allow Size 
Requests */
+#define IGB_DTXMXPKTSZ            (0x355c)   /* DMA Tx Max Allowable Packet 
Size */
+#define IGB_TDBAL0                (0xe000)   /* Tx Descriptor Base Low */
+#define IGB_TDBAH0                (0xe004)   /* Tx Descriptor Base High*/
+#define IGB_TDLEN0                (0xe008)   /* Tx Descriptor Ring Length */
+#define IGB_TDH0                  (0xe010)   /* Tx Descriptor Head */
+#define IGB_TDT0                  (0xe018)   /* Tx Descriptor Tail */
+#define IGB_TXDCTL0               (0xe028)   /* Transmit Descriptor Control 
Queue */
+#define IGB_TXCTL0                (0xe014)   /* Tx DCA CTRL Register Queue */
+#define IGB_TDWBAL0               (0xe038)   /* Transmit Descriptor WB Address 
Low Queue */
+#define IGB_TDWBAH0               (0xe03c)   /* Transmit Descriptor WB Address 
High Queue */
+
+/* TODO: Filters */
+
+#define IGB_ETQF0                 (0x5cb0)   /* EType Queue Filter */
+#define IGB_IMIR0                 (0x5a80)   /* Immediate Interrupt Rx */
+#define IGB_IMIREXT0              (0x5aa9)   /* Immediate Interrupt Rx 
Extended */
+#define IGB_IMIRVP                (0x5ac0)   /* Immediate Interrupt Rx VLAN 
Priority */
+#define IGB_SAQF0                 (0x5980)   /* Source Address Queue Filter */
+#define IGB_DAQF0                 (0x59a0)   /* Destination Address Queue 
Filter */
+#define IGB_SPQF0                 (0x59c0)   /* Source Port Queue Filter */
+#define IGB_FTQF0                 (0x59e0)   /* Five-Tuple Queue Filter */
+#define IGB_SYNQF                 (0x55fc)   /* SYN Packet Queue Filter */
+
+/* TODO: Virtualization */
+
+/* Statistic registers */
+
+#define IGB_CRCERRS               (0x04000)  /* CRC Error Count */
+#define IGB_ALGNERRC              (0x04004)  /* Alignment Error Count */
+#define IGB_SYMERRS               (0x04008)  /* Symbol Error Count */
+#define IGB_RXERRC                (0x0400c)  /* RX Error Count */
+#define IGB_MPC                   (0x04010)  /* Missed Packets Count */
+#define IGB_SCC                   (0x04014)  /* Single Collision Count */
+#define IGB_ECOL                  (0x04018)  /* Excessive Collisions Count */
+#define IGB_MCC                   (0x0401c)  /* Multiple Collision Count */
+#define IGB_LATECOL               (0x04020)  /* Late Collisions Count */
+#define IGB_COLC                  (0x04028)  /* Collision Count */
+#define IGB_DC                    (0x04030)  /* Defer Count */
+#define IGB_TNCRS                 (0x04034)  /* Transmit with No CRS */
+#define IGB_HTDPMC                (0x0403c)  /* Host Transmit Discarded 
Packets by MAC Count */
+#define IGB_RLEC                  (0x04040)  /* Receive Length Error Count */
+#define IGB_CBRDPC                (0x04044)  /* Circuit Breaker Rx dropped 
packet */
+#define IGB_XONRXC                (0x04048)  /* XON Received Count */
+#define IGB_XONTXC                (0x0404c)  /* XON Transmitted Count */
+#define IGB_XOFFRXC               (0x04050)  /* XOFF Received Count */
+#define IGB_XOFFTXC               (0x04054)  /* XOFF Transmitted Count */
+#define IGB_FCRUC                 (0x04058)  /* FC Received Unsupported Count 
*/
+#define IGB_PRC64                 (0x0405c)  /* Packets Received [64 Bytes] 
Count */
+#define IGB_PRC127                (0x04060)  /* Packets Received [65–127 
Bytes] Count */
+#define IGB_PRC255                (0x04064)  /* Packets Received [128–255 
Bytes] */
+#define IGB_PRC511                (0x04068)  /* Packets Received [256–511 
Bytes] */
+#define IGB_PRC1023               (0x0406c)  /* Packets Received [512–1023 
Bytes] */
+#define IGB_PRC1522               (0x04070)  /* Packets Received [1024 to Max 
Bytes] */
+#define IGB_GPRC                  (0x04074)  /* Good Packets Received Count */
+#define IGB_BPRC                  (0x04078)  /* Broadcast Packets Received 
Count */
+#define IGB_MPRC                  (0x0407c)  /* Multicast Packets Received 
Count */
+#define IGB_GPTC                  (0x04080)  /* Good Packets Transmitted Count 
*/
+#define IGB_GORCL                 (0x04088)  /* Good Octets Received Count Low 
*/
+#define IGB_GORCH                 (0x0408c)  /* Good Octets Received Count 
High */
+#define IGB_GOTCL                 (0x04090)  /* Good Octets Transmitted Count 
Low */
+#define IGB_GOTCH                 (0x04094)  /* Good Octets Transmitted Count 
High */
+#define IGB_RNBC                  (0x040a0)  /* Receive No Buffers Count */
+#define IGB_RUC                   (0x040a4)  /* Receive Undersize Count */
+#define IGB_RFC                   (0x040a8)  /* Receive Fragment Count */
+#define IGB_ROC                   (0x040ac)  /* Receive Oversize Count */
+#define IGB_RJC                   (0x040b0)  /* Receive Jabber Count */
+#define IGB_MNGPRC                (0x040b4)  /* Management Packets Received 
Count */
+#define IGB_MPDC                  (0x040b8)  /* Management Packets Dropped 
Count */
+#define IGB_MNGPTC                (0x040bc)  /* Management Packets Transmitted 
Count */
+#define IGB_BMNGPRC               (0x0414c)  /* BMC Management Packets Receive 
Count */
+#define IGB_BMPDC                 (0x04140)  /* BMC Management Packets Dropped 
Count */
+#define IGB_BMNGPTC               (0x04144)  /* BMC Management Packets 
Transmitted Count */
+#define IGB_TORL                  (0x040c0)  /* Total Octets Received */
+#define IGB_TORH                  (0x040c4)  /* Total Octets Received */
+#define IGB_TOTL                  (0x040c8)  /* Total Octets Transmitted */
+#define IGB_TOTH                  (0x040cc)  /* Total Octets Transmitted */
+#define IGB_TPR                   (0x040d0)  /* Total Packets Received */
+#define IGB_TPT                   (0x040d4)  /* Total Packets Transmitted */
+#define IGB_PTC64                 (0x040d8)  /* Packets Transmitted [64 Bytes] 
Count */
+#define IGB_PTC127                (0x040dc)  /* Packets Transmitted [65–127 
Bytes] Count */
+#define IGB_PTC255                (0x040e0)  /* Packets Transmitted [128–255 
Bytes] Count */
+#define IGB_PTC511                (0x040e4)  /* Packets Transmitted [256–511 
Bytes] Count */
+#define IGB_PTC1023               (0x040e8)  /* Packets Transmitted [512–1023 
Bytes] Count */
+#define IGB_PTC1522               (0x040ec)  /* Packets Transmitted [Greater 
than 1024 Bytes] Count */
+#define IGB_MCPTC                 (0x040f0)  /* Multicast Packets Transmitted 
Count */
+#define IGB_BPTC                  (0x040f4)  /* Broadcast Packets Transmitted 
Count */
+                                             /* ... missing registers */
+
+/* Wake Up and Proxying */
+
+#define IGB_WUC                   (0x5800)   /* Wake Up Control Register */
+#define IGB_WUFC                  (0x5808)   /* Wake Up Filter Control 
Register */
+#define IGB_WUS                   (0x5810)   /* Wake Up Status Register */
+#define IGB_WUPL                  (0x5900)   /* Wake Up Packet Length */
+#define IGB_WUPM                  (0x5a00)   /* Wake Up Packet Memory */
+#define IGB_FHFT                  (0x9000)   /* Flexible Host Filter Table 
registers */
+#define IGB_FHFTEXT               (0x9a00)   /* Flexible Host Filter Table 
registers extended */
+
+/* TODO: Management Register */
+
+/* TODO: PCIe */
+
+/* Diagnostic */
+
+#define IGB_RDFH                  (0x2410)   /* RX Data FIFO Head */
+#define IGB_RDFT                  (0x2418)   /* RX Data FIFO Tail */
+#define IGB_RDFHS                 (0x2420)   /* RX Data FIFO Head Saved */
+#define IGB_RDFTS                 (0x2428)   /* RX Data FIFO Tail Saved */
+#define IGB_RDFPC                 (0x2430)   /*  Receive Data FIFO Packet 
Count */
+#define IGB_RPBECCSTS             (0x245c)   /* Receive Packet buffer ECC 
control */
+#define IGB_TPBECCSTS             (0x345C)   /* Transmit Packet buffer ECC 
control */
+#define IGB_FCSTS0                (0x2464)   /* Flow Control Status */
+#define IGB_RDHESTS               (0x25c0)   /* Rx Descriptor Handler ECC 
status */
+#define IGB_TDHESTS               (0x35c0)   /* Tx Descriptor Handler ECC 
status */
+#define IGB_TDFH                  (0x3410)   /* TX Data FIFO Head */
+#define IGB_TDFT                  (0x3418)   /* TX Data FIFO Tail */
+#define IGB_TDFHS                 (0x3420)   /* TX Data FIFO Head Saved */
+#define IGB_TDFTS                 (0x3428)   /* TX Data FIFO Tail Saved */
+#define IGB_TDFPC                 (0x3430)   /* Transmit Data FIFO Packet 
Count */
+#define IGB_TDHMP                 (0x35fc)   /* Tx Descriptor Handler Memory 
Page Number */
+#define IGB_CIRC                  (0x0f00)   /* Circuits Control */
+#define IGB_TXBDC                 (0x35e0)   /* Tx DMA Performance Burst and 
Descriptor Count */
+#define IGB_TXIDLE                (0x35e4)   /* Tx DMA Performance Idle Count 
*/
+#define IGB_RXBDC                 (0x25e0)   /* Tx DMA Performance Burst and 
Descriptor Count */
+#define IGB_RXIDLE                (0x25E4)   /* Tx DMA Performance Idle Count 
*/
+
+/* TODO: PCS */
+
+/* TODO: Time Sync */
+
+/* TODO: MACSec */
+
+/* TODO: IPSec */
+
+/* Device Control Register */
+
+#define IGB_CTRL_FD               (1 << 0)   /* Bit 0: Full-Duplex */
+                                             /* Bit 1: Reserved */
+#define IGB_CTRL_GIOMDIS          (1 << 2)   /* Bit 2: GIO Master Enable 
Status */
+#define IGB_CTRL_LRST             (1 << 3)   /* Bit 3: Link Reset */
+                                             /* Bits 4-5: Reserved */
+#define IGB_CTRL_SLU              (1 << 6)   /* Bit 6: Set Link Up */
+#define IGB_CTRL_ILOS             (1 << 7)   /* Bit 7: Invert Loss-of-Signal */
+#define IGB_CTRL_SPEED_SHIFT      (8)        /* Bits 8-9: Speed selection */
+#define IGB_CTRL_SPEED_MASK       (3 << IGB_CTRL_SPEED_SHIFT)
+#  define IGB_CTRL_SPEED_10MBS    (0 << IGB_CTRL_SPEED_SHIFT)
+#  define IGB_CTRL_SPEED_100MBS   (1 << IGB_CTRL_SPEED_SHIFT)
+#  define IGB_CTRL_SPEED_1000MBS  (2 << IGB_CTRL_SPEED_SHIFT)
+
+                                             /* Bit 10: Reserved */
+#define IGB_CTRL_FRCSPD           (1 << 11)  /* Bit 11: Force Speed */
+#define IGB_CTRL_FRCDPLX          (1 << 12)  /* Bit 12: Force Duplex */
+                                             /* Bits 13-15: Reserved */
+#define IGB_CTRL_SDP0_GPIEN       (1 << 16)  /* Bit 16: GPI Detection Enable 
for SDP0 */
+#define IGB_CTRL_SDP1_GPIEN       (1 << 17)  /* Bit 17: GPI Detection Enable 
for SDP1 */
+#define IGB_CTRL_SDP0_DATA        (1 << 18)  /* Bit 18: SDP0 Data Value */
+#define IGB_CTRL_SDP1_DATA        (1 << 19)  /* Bit 19: SDP1 Data Value */
+#define IGB_CTRL_ADVD3WUC         (1 << 20)  /* Bit 20: D3Cold Wakeup 
Capability Advertisement Enable */
+#define IGB_CTRL_SDP0_WDE         (1 << 21)  /* Bit 21: SDP0 Used for Watchdog 
Indication */
+#define IGB_CTRL_SDP0_IODIR       (1 << 22)  /* Bit 22: SDP0 Pin 
Directionality */
+#define IGB_CTRL_SDP1_IODIR       (1 << 23)  /* Bit 23: SDP1 Pin 
Directionality */
+                                             /* Bits 24-25: Reserved */
+#define IGB_CTRL_RST              (1 << 26)  /* Bit 26: Device Reset */
+#define IGB_CTRL_RFCE             (1 << 27)  /* Bit 27: Receive Flow Control 
Enable */
+#define IGB_CTRL_TFCE             (1 << 28)  /* Bit 28: Transmit Flow Control 
Enable */
+                                             /* Bit 29: Reserved */
+#define IGB_CTRL_VME              (1 << 30)  /* Bit 30: VLAN Mode Enable */
+#define IGB_CTRL_PHYRST           (1 << 31)  /* Bit 31: PHY Reset */
+
+/* Device Status Regiuster */
+
+#define IGB_STATUS_FD             (1 << 0)   /* Bit 0: Full Duplex */
+#define IGB_STATUS_LU             (1 << 1)   /* Bit 1: Link Up */
+#define IGB_STATUS_LANID_SHIFT    (2)        /* Bit 2-3: LAN ID*/
+#define IGB_STATUS_TXOFF          (1 << 4)   /* Bit 4: Transmission Paused */
+                                             /* Bit 5: Reserved */
+#define IGB_STATUS_SPEED_SHFIT    (6)        /* Bits 6-7: Link speed setting */
+#define IGB_STATUS_ASDV_SHFIT     (8)        /* Bits 8-9: Auto-Speed Detection 
Value. */
+#define IGB_STATUS_PHYRA          (10)       /* Bit 10: PHY Reset Asserted */
+                                             /* Bits 11-13: Reserved */
+#define IGB_STATUS_NVFS_SHFIT     (14)       /* Bits 14-17: Num VFs in the IOV 
capability */
+#define IGB_STATUS_IOVMODE        (18)       /* Bit 18: VF enable (VFE) bit in 
the IOV */
+#define IGB_STATUS_GIOM           (19)       /* Bit 19: GIO Master Disable bit 
state */
+                                             /* Bits 20-30: Reserved */
+#define IGB_STATUS_DMACGE         (31)       /* Bit 31: DMA clock gating 
Enable bit */
+
+/* Receive Address High */
+
+#define IGB_RAH_RAH_MASK          (0xffff)   /* Bits 0-15: Receive address 
High */
+#define IGB_RAH_ASEL              (16)       /* Bits 16-17 Address Select */
+#define IGB_RAH_POOLSEL           (18)       /* Bits 18-25 Pool Select */
+                                             /* Bits 26-30: Reserved */
+#define IGB_RAH_AV                (1 << 31)  /* Bit 31: Address Valid */
+
+/* Transmit Control */
+
+                                             /* Bit 0: Reserved */
+#define IGB_TCTL_EN               (1 << 1)   /* Bit 1: Transmit Enable */
+                                             /* Bit 2: Reserved */
+#define IGB_TCTL_PSP              (1 << 3)   /* Bit 3: Pad Short Packets */
+#define IGB_TCTL_CT_SHIFT         (4)        /* Bits 4-11: Collision Threshold 
*/
+#define IGB_TCTL_COLD_SHIFT       (12)       /* Bits 12-21: Collision Distance 
(BST) */
+#define IGB_TCTL_SWXOFF           (1 << 22)  /* Bit 22: Software XOFF 
Transmission */
+                                             /* Bit 23: Reserved */
+#define IGB_TCTL_RTLC             (1 << 24)  /* Bit 24: Re-transmit on Late 
Collision */
+                                             /* Bits 25-32: Reserved */
+
+/* Transmit Descriptor Control */
+
+#define IGB_TXDCTL_PTHRESH_SHIFT  (0)       /* Bits 0-4: Prefetch Threshold */
+                                            /* Bits 5-7: Reserved */
+#define IGB_TXDCTL_HTHRESH_SHIFT  (8)       /* Bits 8-12: Host Threshold */
+                                            /* Bits 13-15: Reserved */
+#define IGB_TXDCTL_WTHRESH_SHIFT  (16)      /* Bits 16-20: Write-Back 
Threshold */
+                                            /* Bits 21-24: Reserved */
+#define IGB_TXDCTL_ENABLE         (1 << 25) /* Bit 25: Transmit Queue Enable */
+                                            /* Bits 27-31: Reserved */
+
+/* Tx Descriptor Ring Length */
+
+/* Receive Control */
+
+                                             /* Bit 0: Reserved */
+#define IGB_RCTL_EN               (1 << 1)   /* Bit 1: Receiver Enable */
+#define IGB_RCTL_SBP              (1 << 2)   /* Bit 2: Store Bad Packets */
+#define IGB_RCTL_UPE              (1 << 3)   /* Bit 3: Unicast Promiscuous 
Enabled */
+#define IGB_RCTL_MPE              (1 << 4)   /* Bit 4: Multicast Promiscuous 
Enabled */
+#define IGB_RCTL_LPE              (1 << 5)   /* Bit 5: Long Packet Reception 
Enable */
+#define IGB_RCTL_LBM_SHIFT        (6)        /* Bits 6-7: Loopback mode */
+                                             /* Bits 8-11: Reserved */
+#define IGB_RCTL_MO_SHIFT         (12)       /* Bits 12-13: Multicast Offset */
+                                             /* Bit 14: Reserved */
+#define IGB_RCTL_BAM              (1 << 15)  /* Bit 15: Broadcast Accept Mode 
*/
+#define IGB_RCTL_BSIZE_SHIFT      (16)       /* Bits 16-17: Receive Buffer 
Size */
+#  define IGB_RCTL_BSIZE_2048     (0 << 16)  /* 00b: 2048 bytes */
+#  define IGB_RCTL_BSIZE_1024     (1 << 16)  /* 01b: 1024 bytes */
+#  define IGB_RCTL_BSIZE_512      (2 << 16)  /* 10b: 512 bytes */
+#  define IGB_RCTL_BSIZE_256      (3 << 16)  /* 11b: 256 bytes */
+#define IGB_RCTL_VFE              (1 << 18)  /* Bit 18: VLAN Filter Enable */
+#define IGB_RCTL_CFIEN            (1 << 18)  /* Bit 19: Canonical Form 
Indicator Enable */
+#define IGB_RCTL_CFI              (1 << 20)  /* Bit 20: Canonical Form 
Indicator bit value */
+#define IGB_RCTL_PSP              (1 << 21)  /* Bit 21: Pad Small Receive 
Packets */
+#define IGB_RCTL_DPF              (1 << 22)  /* Bit 22: Discard Pause Frames */
+#define IGB_RCTL_PMCF             (1 << 23)  /* Bit 23: Pass MAC Control 
Frames */
+                                             /* Bits 24-25: Reserved */
+#define IGB_RCTL_SECRC            (1 << 26)  /* Bit 26: Strip Ethernet CRC 
from incoming packet */
+                                             /* Bits 27-31: Reserved */
+
+/* Receive Descriptor Control */
+
+#define IGB_RXDCTL_PTHRESH_SHIFT  (0)       /* Bits 0-4: Prefetch Threshold */
+                                            /* Bits 5-7: Reserved */
+#define IGB_RXDCTL_HTHRESH_SHIFT  (8)       /* Bits 8-12: Host Threshold */
+                                            /* Bits 13-15: Reserved */
+#define IGB_RXDCTL_WTHRESH_SHIFT  (16)      /* Bits 16-20: Write-Back 
Threshold */
+                                            /* Bits 21-24: Reserved */
+#define IGB_RXDCTL_ENABLE         (1 << 25) /* Bit 25: Receive Queue Enable */
+#define IGB_RXDCTL_SWFLUSH        (1 << 26) /* Bit 26: Receive Software Flush 
*/
+                                            /* Bits 27-31: Reserved */
+
+/* Interrupt Cause */
+
+#define IGB_IC_TXDW               (1 << 0)   /* Bit 0: Transmit Descriptor 
Written Back */
+                                             /* Bit 1: Reserved */
+#define IGB_IC_LSC                (1 << 2)   /* Bit 2: Link Status Change */
+                                             /* Bit 3: Reserved */
+#define IGB_IC_RXDMT0             (1 << 4)   /* Bit 4: Receive Descriptor 
Minimum Threshold Reached */
+#define IGB_IC_MACSEC             (1 << 5)   /* Bit 5: Sets the MACSec 
interrupt */
+#define IGB_IC_RXMISS             (1 << 6)   /* Bit 6: Receiver Miss Interrupt 
*/
+#define IGB_IC_RXDW               (1 << 7)   /* Bit 7: Receiver Descriptor 
Write Back interrupt */
+#define IGB_IC_VMMB               (1 << 8)   /* Bit 8: Sets the VM mailbox 
interrupt. */
+                                             /* Bits 9-10: Reserved */
+                                             /* Bits 11-14: General Purpose 
Interrupts */
+#define IGB_IC_PTRAP              (1 << 15)  /* Bit 15: Probe trap interrupt */
+                                             /* Bits 16-17: Reserved */
+#define IGB_IC_MNG                (1 << 18)  /* Bit 18: Management Event 
interrupt */
+                                             /* Bit 19: Reserved */
+#define IGB_IC_OMED               (1 << 20)  /* Bit 20: Sets the Other Media 
Energy Detected Interrupt */
+                                             /* Bit 21: Reserved */
+#define IGB_IC_FER                (1 << 22)  /* Bit 22: Fatal Error interrupt 
*/
+#define IGB_IC_NFER               (1 << 23)  /* Bit 23: Sets the Non Fatal 
Error Interrupt */
+#define IGB_IC_CSRTO              (1 << 24)  /* Bit 24: Sets the CSR access 
time out indication interrupt */
+#define IGB_IC_SCE                (1 << 25)  /* Bit 25: Set the Storm Control 
Event Interrupt */
+#define IGB_IC_SWD                (1 << 26)  /* Bit 26: Software Watchdog 
interrupt */
+                                             /* Bit 27: Reserved */
+#define IGB_IC_DOUTSYNC           (1 << 28)  /* Bit 28: Sets the DMA Tx Out of 
Sync Interrupt. */
+                                             /* Bit 29: Reserved */
+#define IGB_IC_TCPTIM             (1 << 30)  /* Bit 30: Sets the TCP timer 
interrupt */
+                                             /* Bit 31: Reserved */
+
+/* Extended Interrupt Mask for Non-MSI-X Mode */
+
+#define IGB_EIMS_NOMSIX_RXTX0     (1 << 0)
+#define IGB_EIMS_NOMSIX_RXTX1     (1 << 1)
+#define IGB_EIMS_NOMSIX_RXTX2     (1 << 2)
+#define IGB_EIMS_NOMSIX_RXTX3     (1 << 3)
+#define IGB_EIMS_NOMSIX_TCPTIM    (1 << 30)
+#define IGB_EIMS_NOMSIX_OTHER     (1 << 31)
+
+/* Extended Interrupt Mask for MSI-X Mode */
+
+#define IGB_EIMS_MSIX_0           (1 << 0)
+#define IGB_EIMS_MSIX_1           (1 << 1)
+#define IGB_EIMS_MSIX_2           (1 << 2)
+#define IGB_EIMS_MSIX_3           (1 << 3)
+#define IGB_EIMS_MSIX_4           (1 << 4)
+
+/* Interrupt Vector Allocation Registers */
+
+#define IGB_IVAR0_RXQ0_SHIFT      (0)        /* Bits 0-4: MSI-X vector 
assigned to RxQ0 */
+#define IGB_IVAR0_RXQ0_VAL        (1 << 7)   /* Bit 7: Valid bit for RxQ0 */
+#define IGB_IVAR0_TXQ0_SHIFT      (8)        /* Bits 8-12: MSI-X vector 
assigned to TxQ0 */
+#define IGB_IVAR0_TXQ0_VAL        (1 << 7)   /* Bit 7: Valid bit for TxQ0 */
+
+/* Interrupt Vector Allocation Registers - Misc */
+
+#define IGB_IVARMSC_TCPTIM        (0)        /* Bits 0-5: MSI-X vectorassigned 
to TCP timer interrupt */
+                                             /* Bits 5-6: Reserved */
+#define IGB_IVARMSC_TCPTIM_VAL    (1 << 7)   /* Bit 7: Enable bit for TCP 
timer interrupt */
+#define IGB_IVARMSC_OTHER_SHIFT   (8)        /* Bits 8-12: MSI-X vector 
assigned to Other Cause */
+                                             /* Bits 13-14: Reserved */
+#define IGB_IVARMSC_OTHER_VAL     (1 << 15)  /* Bit 15: Enable bit for Other 
Cause */
+                                             /* Bits 20-30: Reserved */
+
+/* General Purpose Interrupt Enable */
+
+#define IGB_GPIE_NSICR            (1 << 0)   /* Bit 0: Non Selective Interrupt 
Clear on Read */
+                                             /* Bits 1-3: Reserved */
+#define IGB_GPIE_MSIX             (1 << 4)   /* Bit 4: MSI-X mode */
+                                             /* Bits 5-6: Reserved */
+#define IGB_GPIE_LLINTERVAL_SHIFT (7)        /* Bits 7-11: Low Latency Credits 
Increment Rate */
+                                             /* Bits 12-29: Reserved */
+#define IGB_GPIE_EIAME            (1 << 30)  /* Bit 30: Extended Interrupt 
Auto Mask Enable */
+#define IGB_GPIE_PBASUPPORT       (1 << 31)  /* Bit 31: PBA Support */
+
+/* Transmit Descriptor Command Field */
+
+#define IGB_TDESC_CMD_EOP         (1 << 0)   /* Bit 0: End Of Packet */
+#define IGB_TDESC_CMD_IFCS        (1 << 1)   /* Bit 1: Insert FCS */
+#define IGB_TDESC_CMD_IC          (1 << 2)   /* Bit 2: Insert Checksum */
+#define IGB_TDESC_CMD_RS          (1 << 3)   /* Bit 3: Report Status */
+#define IGB_TDESC_CMD_DEXT        (1 << 5)   /* Bit 5: Extension (0b for 
legacy mode) */
+#define IGB_TDESC_CMD_VLE         (1 << 6)   /* Bit 6: VLAN Packet Enable */
+
+/* Transmit Descriptor Status Field */
+
+#define IGB_TDESC_STATUS_DD       (1 << 0)   /* Bit 0: Descriptor Done */
+
+/* Transmit Descriptor Special Field */
+
+#define IGB_TDESC_SPEC_VLAN_SHIFT (0)        /* Bits 0-11: VLAN Identifier */
+#define IGB_TDESC_SPEC_CFI        (1 << 12)  /* Bit 12: Canonical Form 
Indicator */
+#define IGB_TDESC_SPEC_PRI_SHIFT  (13)       /* Bits 13-15: User Priority */
+
+/* Receive Descriptor Status Field */
+
+#define IGB_RDESC_STATUS_DD       (1 << 0)   /* Bit 0: Descriptor Done */
+#define IGB_RDESC_STATUS_EOP      (1 << 1)   /* Bit 1: End of Packet */
+#define IGB_RDESC_STATUS_VP       (1 << 3)   /* Bit 3: Packet is 802.1Q 
(matched VET) */
+#define IGB_RDESC_STATUS_UDPCS    (1 << 4)   /* Bit 4: UDP checksum or IP 
payload checksum calculated on packet */
+#define IGB_RDESC_STATUS_L4CS     (1 << 5)   /* Bit 5: L4 (UDP or TCP) 
checksum calculated on packet */
+#define IGB_RDESC_STATUS_IPCS     (1 << 6)   /* Bit 6: IP Checksum Calculated 
on Packet */
+#define IGB_RDESC_STATUS_PIF      (1 << 7)   /* Bit 7: Passed in-exact filter 
*/
+
+/* Receive Descriptor Errors Field */
+
+#define IGB_RDESC_ERRORS_L4E      (1 << 5)   /* Bit 5: TCP/UDP Checksum Error 
*/
+#define IGB_RDESC_ERRORS_IPE      (1 << 6)   /* Bit 6: IP Checksum Error */
+#define IGB_RDESC_ERRORS_RXE      (1 << 7)   /* Bit 7: RX Data Error */
+
+/* Receive Descriptor Special Field */
+
+#define IGB_RDESC_SPEC_VLAN_SHIFT (0)        /* Bits 0-11: VLAN Identifier */
+#define IGB_RDESC_SPEC_CFI        (1 << 12)  /* Bit 12: Canonical Form 
Indicator */
+#define IGB_RDESC_SPEC_PRI_SHIFT  (13)       /* Bits 13-15: User Priority */
+
+/*****************************************************************************
+ * Public Types
+ *****************************************************************************/
+
+/* Legacy TX descriptor */
+
+begin_packed_struct struct igb_tx_leg_s
+{
+  uint64_t addr;
+  uint16_t len;
+  uint8_t  cso;
+  uint8_t  cmd;
+  uint8_t  status;
+  uint8_t  css;
+  uint16_t special;
+} end_packed_struct;
+
+/* Legacy RX descriptor */
+
+begin_packed_struct struct igb_rx_leg_s
+{
+  uint64_t addr;
+  uint16_t len;
+  uint16_t checksum;
+  uint8_t  status;
+  uint8_t  errors;
+  uint16_t special;
+} end_packed_struct;
+
+#endif  /* __DRIVERS_NET_IGB!_H */
diff --git a/drivers/pci/pci_drivers.c b/drivers/pci/pci_drivers.c
index 5a0301c8dfd..c2204bd1239 100644
--- a/drivers/pci/pci_drivers.c
+++ b/drivers/pci/pci_drivers.c
@@ -32,6 +32,7 @@
 #include <nuttx/virtio/virtio-pci.h>
 #include <nuttx/net/e1000.h>
 #include <nuttx/net/igc.h>
+#include <nuttx/net/igb.h>
 #include <nuttx/can/kvaser_pci.h>
 #include <nuttx/can/ctucanfd_pci.h>
 #include <nuttx/usb/xhci_pci.h>
@@ -163,6 +164,16 @@ int pci_register_drivers(void)
     }
 #endif
 
+  /* Initialization igb driver */
+
+#ifdef CONFIG_NET_IGB
+  ret = pci_igb_init();
+  if (ret < 0)
+    {
+      pcierr("pci_igb_init failed, ret=%d\n", ret);
+    }
+#endif
+
   /* Initialzie Kvaser pci driver */
 
 #ifdef CONFIG_CAN_KVASER
diff --git a/include/nuttx/net/igb.h b/include/nuttx/net/igb.h
new file mode 100644
index 00000000000..1377959a984
--- /dev/null
+++ b/include/nuttx/net/igb.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+ * include/nuttx/net/igb.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_NET_IGB_H
+#define __INCLUDE_NUTTX_NET_IGB_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pci_igb_init
+ *
+ * Description:
+ *   Register a pci driver
+ *
+ ****************************************************************************/
+
+int pci_igb_init(void);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_NET_IGB_H */

Reply via email to