All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/13] Introduce igb
@ 2023-01-14  4:09 Akihiko Odaki
  2023-01-14  4:09 ` [PATCH v2 01/13] hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr Akihiko Odaki
                   ` (14 more replies)
  0 siblings, 15 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:09 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich

Based-on: <20230114035919.35251-1-akihiko.odaki@daynix.com>
([PATCH 00/19] e1000x cleanups (preliminary for IGB))

igb is a family of Intel's gigabit ethernet controllers. This series implements
82576 emulation in particular. You can see the last patch for the documentation.

Note that there is another effort to bring 82576 emulation. This series was
developed independently by Sriram Yagnaraman.
https://lists.gnu.org/archive/html/qemu-devel/2022-12/msg04670.html

It is possible to merge the work from Sriram Yagnaraman and to cherry-pick
useful changes from this series later.

I think there are several different ways to get the changes into the mainline.
I'm open to any options.

V1 -> V2:
- Spun off e1000e general improvements to a distinct series.
- Restored vnet_hdr offload as there seems nothing preventing from that.

Akihiko Odaki (13):
  hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr
  pcie: Introduce pcie_sriov_num_vfs
  e1000: Split header files
  igb: Copy e1000e code
  igb: Rename identifiers
  igb: Build igb
  igb: Transform to 82576 implementation
  tests/qtest/e1000e-test: Fabricate ethernet header
  tests/qtest/libqos/e1000e: Export macreg functions
  tests/qtest/libqos/igb: Copy e1000e code
  tests/qtest/libqos/igb: Transform to igb tests
  tests/avocado: Add igb test
  docs/system/devices/igb: Add igb documentation

 MAINTAINERS                                   |    9 +
 docs/system/device-emulation.rst              |    1 +
 docs/system/devices/igb.rst                   |   70 +
 hw/net/Kconfig                                |    5 +
 hw/net/e1000.c                                |    1 +
 hw/net/e1000_common.h                         |  102 +
 hw/net/e1000_regs.h                           |  927 +---
 hw/net/e1000e.c                               |    3 +-
 hw/net/e1000e_core.c                          |    1 +
 hw/net/e1000x_common.c                        |    1 +
 hw/net/e1000x_common.h                        |   74 -
 hw/net/e1000x_regs.h                          |  940 ++++
 hw/net/igb.c                                  |  615 +++
 hw/net/igb_common.h                           |  144 +
 hw/net/igb_core.c                             | 3946 +++++++++++++++++
 hw/net/igb_core.h                             |  147 +
 hw/net/igb_regs.h                             |  624 +++
 hw/net/igbvf.c                                |  327 ++
 hw/net/meson.build                            |    2 +
 hw/net/net_tx_pkt.c                           |    6 +
 hw/net/net_tx_pkt.h                           |    8 +
 hw/net/trace-events                           |   32 +
 hw/pci/pcie_sriov.c                           |    5 +
 include/hw/pci/pcie_sriov.h                   |    3 +
 .../org.centos/stream/8/x86_64/test-avocado   |    1 +
 tests/avocado/igb.py                          |   38 +
 tests/qtest/e1000e-test.c                     |   17 +-
 tests/qtest/fuzz/generic_fuzz_configs.h       |    5 +
 tests/qtest/igb-test.c                        |  243 +
 tests/qtest/libqos/e1000e.c                   |   12 -
 tests/qtest/libqos/e1000e.h                   |   14 +
 tests/qtest/libqos/igb.c                      |  185 +
 tests/qtest/libqos/meson.build                |    1 +
 tests/qtest/meson.build                       |    1 +
 34 files changed, 7492 insertions(+), 1018 deletions(-)
 create mode 100644 docs/system/devices/igb.rst
 create mode 100644 hw/net/e1000_common.h
 create mode 100644 hw/net/e1000x_regs.h
 create mode 100644 hw/net/igb.c
 create mode 100644 hw/net/igb_common.h
 create mode 100644 hw/net/igb_core.c
 create mode 100644 hw/net/igb_core.h
 create mode 100644 hw/net/igb_regs.h
 create mode 100644 hw/net/igbvf.c
 create mode 100644 tests/avocado/igb.py
 create mode 100644 tests/qtest/igb-test.c
 create mode 100644 tests/qtest/libqos/igb.c

-- 
2.39.0



^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 01/13] hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
@ 2023-01-14  4:09 ` Akihiko Odaki
  2023-01-14  4:09 ` [PATCH v2 02/13] pcie: Introduce pcie_sriov_num_vfs Akihiko Odaki
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:09 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich, Gal Hammer

Expose the ethernet header so that igb can utilize it to perform the
internal routing among its SR-IOV functions.

Signed-off-by: Gal Hammer <gal.hammer@sap.com>
Signed-off-by: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/net/net_tx_pkt.c | 6 ++++++
 hw/net/net_tx_pkt.h | 8 ++++++++
 2 files changed, 14 insertions(+)

diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c
index 2533ea2700..2c57c8d642 100644
--- a/hw/net/net_tx_pkt.c
+++ b/hw/net/net_tx_pkt.c
@@ -278,6 +278,12 @@ bool net_tx_pkt_parse(struct NetTxPkt *pkt)
     }
 }
 
+struct eth_header *net_tx_pkt_get_eth_hdr(struct NetTxPkt *pkt)
+{
+    assert(pkt);
+    return (struct eth_header *)&pkt->l2_hdr;
+}
+
 struct virtio_net_hdr *net_tx_pkt_get_vhdr(struct NetTxPkt *pkt)
 {
     assert(pkt);
diff --git a/hw/net/net_tx_pkt.h b/hw/net/net_tx_pkt.h
index 4ec8bbe9bd..4e70453c12 100644
--- a/hw/net/net_tx_pkt.h
+++ b/hw/net/net_tx_pkt.h
@@ -44,6 +44,14 @@ void net_tx_pkt_init(struct NetTxPkt **pkt, PCIDevice *pci_dev,
  */
 void net_tx_pkt_uninit(struct NetTxPkt *pkt);
 
+/**
+ * get ethernet header
+ *
+ * @pkt:            packet
+ * @ret:            ethernet header
+ */
+struct eth_header *net_tx_pkt_get_eth_hdr(struct NetTxPkt *pkt);
+
 /**
  * get virtio header
  *
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 02/13] pcie: Introduce pcie_sriov_num_vfs
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
  2023-01-14  4:09 ` [PATCH v2 01/13] hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr Akihiko Odaki
@ 2023-01-14  4:09 ` Akihiko Odaki
  2023-01-14  4:09 ` [PATCH v2 03/13] e1000: Split header files Akihiko Odaki
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:09 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich, Gal Hammer

igb can use this function to change its behavior depending on the
number of virtual functions currently enabled.

Signed-off-by: Gal Hammer <gal.hammer@sap.com>
Signed-off-by: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/pci/pcie_sriov.c         | 5 +++++
 include/hw/pci/pcie_sriov.h | 3 +++
 2 files changed, 8 insertions(+)

diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c
index f0bd72e069..aa5a757b11 100644
--- a/hw/pci/pcie_sriov.c
+++ b/hw/pci/pcie_sriov.c
@@ -300,3 +300,8 @@ PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n)
     }
     return NULL;
 }
+
+uint16_t pcie_sriov_num_vfs(PCIDevice *dev)
+{
+    return dev->exp.sriov_pf.num_vfs;
+}
diff --git a/include/hw/pci/pcie_sriov.h b/include/hw/pci/pcie_sriov.h
index 96cc743309..095fb0c9ed 100644
--- a/include/hw/pci/pcie_sriov.h
+++ b/include/hw/pci/pcie_sriov.h
@@ -76,4 +76,7 @@ PCIDevice *pcie_sriov_get_pf(PCIDevice *dev);
  */
 PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n);
 
+/* Returns the current number of virtual functions. */
+uint16_t pcie_sriov_num_vfs(PCIDevice *dev);
+
 #endif /* QEMU_PCIE_SRIOV_H */
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 03/13] e1000: Split header files
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
  2023-01-14  4:09 ` [PATCH v2 01/13] hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr Akihiko Odaki
  2023-01-14  4:09 ` [PATCH v2 02/13] pcie: Introduce pcie_sriov_num_vfs Akihiko Odaki
@ 2023-01-14  4:09 ` Akihiko Odaki
  2023-01-14  4:09 ` [PATCH v2 04/13] igb: Copy e1000e code Akihiko Odaki
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:09 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich, Gal Hammer

Some definitions in the header files are invalid for igb so extract
them to new header files to keep igb from referring to them.

Signed-off-by: Gal Hammer <gal.hammer@sap.com>
Signed-off-by: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 hw/net/e1000.c         |   1 +
 hw/net/e1000_common.h  | 102 +++++
 hw/net/e1000_regs.h    | 927 +---------------------------------------
 hw/net/e1000e.c        |   3 +-
 hw/net/e1000e_core.c   |   1 +
 hw/net/e1000x_common.c |   1 +
 hw/net/e1000x_common.h |  74 ----
 hw/net/e1000x_regs.h   | 940 +++++++++++++++++++++++++++++++++++++++++
 8 files changed, 1049 insertions(+), 1000 deletions(-)
 create mode 100644 hw/net/e1000_common.h
 create mode 100644 hw/net/e1000x_regs.h

diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index c81d914a02..23d3d32403 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -39,6 +39,7 @@
 #include "qemu/module.h"
 #include "qemu/range.h"
 
+#include "e1000_common.h"
 #include "e1000x_common.h"
 #include "trace.h"
 #include "qom/object.h"
diff --git a/hw/net/e1000_common.h b/hw/net/e1000_common.h
new file mode 100644
index 0000000000..48feda7404
--- /dev/null
+++ b/hw/net/e1000_common.h
@@ -0,0 +1,102 @@
+/*
+ * QEMU e1000(e) emulation - shared definitions
+ *
+ * Copyright (c) 2008 Qumranet
+ *
+ * Based on work done by:
+ * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
+ * Copyright (c) 2007 Dan Aloni
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_NET_E1000_COMMON_H
+#define HW_NET_E1000_COMMON_H
+
+#include "e1000_regs.h"
+
+#define defreg(x)   x = (E1000_##x >> 2)
+enum {
+    defreg(CTRL),    defreg(EECD),    defreg(EERD),    defreg(GPRC),
+    defreg(GPTC),    defreg(ICR),     defreg(ICS),     defreg(IMC),
+    defreg(IMS),     defreg(LEDCTL),  defreg(MANC),    defreg(MDIC),
+    defreg(MPC),     defreg(PBA),     defreg(RCTL),    defreg(RDBAH0),
+    defreg(RDBAL0),  defreg(RDH0),    defreg(RDLEN0),  defreg(RDT0),
+    defreg(STATUS),  defreg(SWSM),    defreg(TCTL),    defreg(TDBAH),
+    defreg(TDBAL),   defreg(TDH),     defreg(TDLEN),   defreg(TDT),
+    defreg(TDLEN1),  defreg(TDBAL1),  defreg(TDBAH1),  defreg(TDH1),
+    defreg(TDT1),    defreg(TORH),    defreg(TORL),    defreg(TOTH),
+    defreg(TOTL),    defreg(TPR),     defreg(TPT),     defreg(TXDCTL),
+    defreg(WUFC),    defreg(RA),      defreg(MTA),     defreg(CRCERRS),
+    defreg(VFTA),    defreg(VET),     defreg(RDTR),    defreg(RADV),
+    defreg(TADV),    defreg(ITR),     defreg(SCC),     defreg(ECOL),
+    defreg(MCC),     defreg(LATECOL), defreg(COLC),    defreg(DC),
+    defreg(TNCRS),   defreg(SEQEC),   defreg(CEXTERR), defreg(RLEC),
+    defreg(XONRXC),  defreg(XONTXC),  defreg(XOFFRXC), defreg(XOFFTXC),
+    defreg(FCRUC),   defreg(AIT),     defreg(TDFH),    defreg(TDFT),
+    defreg(TDFHS),   defreg(TDFTS),   defreg(TDFPC),   defreg(WUC),
+    defreg(WUS),     defreg(POEMB),   defreg(PBS),     defreg(RDFH),
+    defreg(RDFT),    defreg(RDFHS),   defreg(RDFTS),   defreg(RDFPC),
+    defreg(PBM),     defreg(IPAV),    defreg(IP4AT),   defreg(IP6AT),
+    defreg(WUPM),    defreg(FFLT),    defreg(FFMT),    defreg(FFVT),
+    defreg(TARC0),   defreg(TARC1),   defreg(IAM),     defreg(EXTCNF_CTRL),
+    defreg(GCR),     defreg(TIMINCA), defreg(EIAC),    defreg(CTRL_EXT),
+    defreg(IVAR),    defreg(MFUTP01), defreg(MFUTP23), defreg(MANC2H),
+    defreg(MFVAL),   defreg(MDEF),    defreg(FACTPS),  defreg(FTFT),
+    defreg(RUC),     defreg(ROC),     defreg(RFC),     defreg(RJC),
+    defreg(PRC64),   defreg(PRC127),  defreg(PRC255),  defreg(PRC511),
+    defreg(PRC1023), defreg(PRC1522), defreg(PTC64),   defreg(PTC127),
+    defreg(PTC255),  defreg(PTC511),  defreg(PTC1023), defreg(PTC1522),
+    defreg(GORCL),   defreg(GORCH),   defreg(GOTCL),   defreg(GOTCH),
+    defreg(RNBC),    defreg(BPRC),    defreg(MPRC),    defreg(RFCTL),
+    defreg(PSRCTL),  defreg(MPTC),    defreg(BPTC),    defreg(TSCTFC),
+    defreg(IAC),     defreg(MGTPRC),  defreg(MGTPDC),  defreg(MGTPTC),
+    defreg(TSCTC),   defreg(RXCSUM),  defreg(FUNCTAG), defreg(GSCL_1),
+    defreg(GSCL_2),  defreg(GSCL_3),  defreg(GSCL_4),  defreg(GSCN_0),
+    defreg(GSCN_1),  defreg(GSCN_2),  defreg(GSCN_3),  defreg(GCR2),
+    defreg(RAID),    defreg(RSRPD),   defreg(TIDV),    defreg(EITR),
+    defreg(MRQC),    defreg(RETA),    defreg(RSSRK),   defreg(RDBAH1),
+    defreg(RDBAL1),  defreg(RDLEN1),  defreg(RDH1),    defreg(RDT1),
+    defreg(PBACLR),  defreg(FCAL),    defreg(FCAH),    defreg(FCT),
+    defreg(FCRTH),   defreg(FCRTL),   defreg(FCTTV),   defreg(FCRTV),
+    defreg(FLA),     defreg(EEWR),    defreg(FLOP),    defreg(FLOL),
+    defreg(FLSWCTL), defreg(FLSWCNT), defreg(RXDCTL),  defreg(RXDCTL1),
+    defreg(MAVTV0),  defreg(MAVTV1),  defreg(MAVTV2),  defreg(MAVTV3),
+    defreg(TXSTMPL), defreg(TXSTMPH), defreg(SYSTIML), defreg(SYSTIMH),
+    defreg(RXCFGL),  defreg(RXUDP),   defreg(TIMADJL), defreg(TIMADJH),
+    defreg(RXSTMPH), defreg(RXSTMPL), defreg(RXSATRL), defreg(RXSATRH),
+    defreg(FLASHT),  defreg(TIPG),    defreg(RDH),     defreg(RDT),
+    defreg(RDLEN),   defreg(RDBAH),   defreg(RDBAL),
+    defreg(TXDCTL1),
+    defreg(FLSWDATA),
+    defreg(CTRL_DUP),
+    defreg(EXTCNF_SIZE),
+    defreg(EEMNGCTL),
+    defreg(EEMNGDATA),
+    defreg(FLMNGCTL),
+    defreg(FLMNGDATA),
+    defreg(FLMNGCNT),
+    defreg(TSYNCRXCTL),
+    defreg(TSYNCTXCTL),
+
+    /* Aliases */
+    defreg(RDH0_A),  defreg(RDT0_A),  defreg(RDTR_A),  defreg(RDFH_A),
+    defreg(RDFT_A),  defreg(TDH_A),   defreg(TDT_A),   defreg(TIDV_A),
+    defreg(TDFH_A),  defreg(TDFT_A),  defreg(RA_A),    defreg(RDBAL0_A),
+    defreg(TDBAL_A), defreg(TDLEN_A), defreg(VFTA_A),  defreg(RDLEN0_A),
+    defreg(FCRTL_A), defreg(FCRTH_A)
+};
+
+#endif
diff --git a/hw/net/e1000_regs.h b/hw/net/e1000_regs.h
index 4545fe25a6..8a4ce82034 100644
--- a/hw/net/e1000_regs.h
+++ b/hw/net/e1000_regs.h
@@ -32,157 +32,35 @@
 #ifndef HW_E1000_REGS_H
 #define HW_E1000_REGS_H
 
-/* PCI Device IDs */
-#define E1000_DEV_ID_82542               0x1000
-#define E1000_DEV_ID_82543GC_FIBER       0x1001
-#define E1000_DEV_ID_82543GC_COPPER      0x1004
-#define E1000_DEV_ID_82544EI_COPPER      0x1008
-#define E1000_DEV_ID_82544EI_FIBER       0x1009
-#define E1000_DEV_ID_82544GC_COPPER      0x100C
-#define E1000_DEV_ID_82544GC_LOM         0x100D
-#define E1000_DEV_ID_82540EM             0x100E
-#define E1000_DEV_ID_82540EM_LOM         0x1015
-#define E1000_DEV_ID_82540EP_LOM         0x1016
-#define E1000_DEV_ID_82540EP             0x1017
-#define E1000_DEV_ID_82540EP_LP          0x101E
-#define E1000_DEV_ID_82545EM_COPPER      0x100F
-#define E1000_DEV_ID_82545EM_FIBER       0x1011
-#define E1000_DEV_ID_82545GM_COPPER      0x1026
-#define E1000_DEV_ID_82545GM_FIBER       0x1027
-#define E1000_DEV_ID_82545GM_SERDES      0x1028
-#define E1000_DEV_ID_82546EB_COPPER      0x1010
-#define E1000_DEV_ID_82546EB_FIBER       0x1012
-#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
-#define E1000_DEV_ID_82541EI             0x1013
-#define E1000_DEV_ID_82541EI_MOBILE      0x1018
-#define E1000_DEV_ID_82541ER_LOM         0x1014
-#define E1000_DEV_ID_82541ER             0x1078
-#define E1000_DEV_ID_82547GI             0x1075
-#define E1000_DEV_ID_82541GI             0x1076
-#define E1000_DEV_ID_82541GI_MOBILE      0x1077
-#define E1000_DEV_ID_82541GI_LF          0x107C
-#define E1000_DEV_ID_82546GB_COPPER      0x1079
-#define E1000_DEV_ID_82546GB_FIBER       0x107A
-#define E1000_DEV_ID_82546GB_SERDES      0x107B
-#define E1000_DEV_ID_82546GB_PCIE        0x108A
-#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
-#define E1000_DEV_ID_82547EI             0x1019
-#define E1000_DEV_ID_82547EI_MOBILE      0x101A
-#define E1000_DEV_ID_82571EB_COPPER      0x105E
-#define E1000_DEV_ID_82571EB_FIBER       0x105F
-#define E1000_DEV_ID_82571EB_SERDES      0x1060
-#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
-#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
-#define E1000_DEV_ID_82571EB_QUAD_FIBER  0x10A5
-#define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE  0x10BC
-#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
-#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA
-#define E1000_DEV_ID_82572EI_COPPER      0x107D
-#define E1000_DEV_ID_82572EI_FIBER       0x107E
-#define E1000_DEV_ID_82572EI_SERDES      0x107F
-#define E1000_DEV_ID_82572EI             0x10B9
-#define E1000_DEV_ID_82573E              0x108B
-#define E1000_DEV_ID_82573E_IAMT         0x108C
-#define E1000_DEV_ID_82573L              0x109A
-#define E1000_DEV_ID_82574L              0x10D3
-#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
-#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT     0x1096
-#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT     0x1098
-#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT     0x10BA
-#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT     0x10BB
+#include "e1000x_regs.h"
 
-#define E1000_DEV_ID_ICH8_IGP_M_AMT      0x1049
-#define E1000_DEV_ID_ICH8_IGP_AMT        0x104A
-#define E1000_DEV_ID_ICH8_IGP_C          0x104B
-#define E1000_DEV_ID_ICH8_IFE            0x104C
-#define E1000_DEV_ID_ICH8_IFE_GT         0x10C4
-#define E1000_DEV_ID_ICH8_IFE_G          0x10C5
-#define E1000_DEV_ID_ICH8_IGP_M          0x104D
-
-/* Device Specific Register Defaults */
-#define E1000_PHY_ID2_82541x 0x380
-#define E1000_PHY_ID2_82544x 0xC30
-#define E1000_PHY_ID2_8254xx_DEFAULT 0xC20 /* 82540x, 82545x, and 82546x */
-#define E1000_PHY_ID2_82573x 0xCC0
-#define E1000_PHY_ID2_82574x 0xCB1
-
-/* Register Set. (82543, 82544)
- *
- * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
- * These registers are physically located on the NIC, but are mapped into the
- * host memory address space.
- *
- * RW - register is both readable and writable
- * RO - register is read only
- * WO - register is write only
- * R/clr - register is read only and is cleared when read
- * A - register array
- */
-#define E1000_CTRL     0x00000  /* Device Control - RW */
-#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
-#define E1000_STATUS   0x00008  /* Device Status - RO */
-#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
-#define E1000_EERD     0x00014  /* EEPROM Read - RW */
-#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
-#define E1000_FLA      0x0001C  /* Flash Access - RW */
-#define E1000_MDIC     0x00020  /* MDI Control - RW */
-#define E1000_SCTL     0x00024  /* SerDes Control - RW */
-#define E1000_FEXTNVM  0x00028  /* Future Extended NVM register */
-#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
-#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
-#define E1000_FCT      0x00030  /* Flow Control Type - RW */
-#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
-#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
 #define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
-#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
-#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
 #define E1000_EIAC     0x000DC  /* Ext. Interrupt Auto Clear - RW */
-#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
-#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
 #define E1000_IVAR     0x000E4  /* Interrupt Vector Allocation Register - RW */
 #define E1000_EITR     0x000E8  /* Extended Interrupt Throttling Rate - RW */
-#define E1000_RCTL     0x00100  /* RX Control - RW */
-#define E1000_RDTR1    0x02820  /* RX Delay Timer (1) - RW */
 #define E1000_RDBAL1   0x02900  /* RX Descriptor Base Address Low (1) - RW */
 #define E1000_RDBAH1   0x02904  /* RX Descriptor Base Address High (1) - RW */
 #define E1000_RDLEN1   0x02908  /* RX Descriptor Length (1) - RW */
 #define E1000_RDH1     0x02910  /* RX Descriptor Head (1) - RW */
 #define E1000_RDT1     0x02918  /* RX Descriptor Tail (1) - RW */
-#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
 #define E1000_FCRTV    0x05F40  /* Flow Control Refresh Timer Value - RW */
 #define E1000_TXCW     0x00178  /* TX Configuration Word - RW */
 #define E1000_RXCW     0x00180  /* RX Configuration Word - RO */
-#define E1000_TCTL     0x00400  /* TX Control - RW */
-#define E1000_TCTL_EXT 0x00404  /* Extended TX Control - RW */
-#define E1000_TIPG     0x00410  /* TX Inter-packet gap -RW */
 #define E1000_TBT      0x00448  /* TX Burst Timer - RW */
 #define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
-#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
 #define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
 #define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
 #define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
-#define FEXTNVM_SW_CONFIG  0x0001
 #define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
 #define E1000_PBM      0x10000  /* Packet Buffer Memory - RW */
 #define E1000_PBS      0x01008  /* Packet Buffer Size - RW */
-#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
-#define E1000_EEMNGDATA    0x01014 /* MNG EEPROM Read/Write data */
-#define E1000_FLMNGCTL     0x01018 /* MNG Flash Control */
-#define E1000_FLMNGDATA    0x0101C /* MNG FLASH Read data */
-#define E1000_FLMNGCNT     0x01020 /* MNG FLASH Read Counter */
-#define E1000_FLASH_UPDATES 1000
-#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
 #define E1000_FLASHT   0x01028  /* FLASH Timer Register */
 #define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
 #define E1000_FLSWCTL  0x01030  /* FLASH control register */
 #define E1000_FLSWDATA 0x01034  /* FLASH data register */
 #define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
-#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
 #define E1000_FLOL     0x01050  /* FEEP Auto Load */
 #define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
-#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
-#define E1000_FCRTL_A  0x00168  /* Alias to FCRTL */
-#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
 #define E1000_FCRTH_A  0x00160  /* Alias to FCRTH */
 #define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
 #define E1000_RDBAL    0x02800  /* RX Descriptor Base Address Low - RW */
@@ -208,23 +86,7 @@
 #define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
 #define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
 #define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
-#define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
-#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
 #define E1000_POEMB    0x00F10  /* PHY OEM Bits Register - RW */
-#define E1000_RDFH     0x02410  /* Receive Data FIFO Head Register - RW */
-#define E1000_RDFH_A   0x08000  /* Alias to RDFH */
-#define E1000_RDFT     0x02418  /* Receive Data FIFO Tail Register - RW */
-#define E1000_RDFT_A   0x08008  /* Alias to RDFT */
-#define E1000_RDFHS    0x02420  /* Receive Data FIFO Head Saved Register - RW */
-#define E1000_RDFTS    0x02428  /* Receive Data FIFO Tail Saved Register - RW */
-#define E1000_RDFPC    0x02430  /* Receive Data FIFO Packet Count - RW */
-#define E1000_TDFH     0x03410  /* TX Data FIFO Head - RW */
-#define E1000_TDFH_A   0x08010  /* Alias to TDFH */
-#define E1000_TDFT     0x03418  /* TX Data FIFO Tail - RW */
-#define E1000_TDFT_A   0x08018  /* Alias to TDFT */
-#define E1000_TDFHS    0x03420  /* TX Data FIFO Head Saved - RW */
-#define E1000_TDFTS    0x03428  /* TX Data FIFO Tail Saved - RW */
-#define E1000_TDFPC    0x03430  /* TX Data FIFO Packet Count - RW */
 #define E1000_TDBAL    0x03800  /* TX Descriptor Base Address Low - RW */
 #define E1000_TDBAL_A  0x00420  /* Alias to TDBAL */
 #define E1000_TDBAH    0x03804  /* TX Descriptor Base Address High - RW */
@@ -248,174 +110,40 @@
 #define E1000_TDT1     0x03918  /* TX Desc Tail (1) - RW */
 #define E1000_TXDCTL1  0x03928  /* TX Descriptor Control (1) - RW */
 #define E1000_TARC1    0x03940  /* TX Arbitration Count (1) */
-#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
-#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
-#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
-#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
-#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
-#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
-#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
-#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
-#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
-#define E1000_COLC     0x04028  /* Collision Count - R/clr */
-#define E1000_DC       0x04030  /* Defer Count - R/clr */
-#define E1000_TNCRS    0x04034  /* TX-No CRS - R/clr */
 #define E1000_SEQEC    0x04038  /* Sequence Error Count - R/clr */
 #define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
-#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
-#define E1000_XONRXC   0x04048  /* XON RX Count - R/clr */
-#define E1000_XONTXC   0x0404C  /* XON TX Count - R/clr */
-#define E1000_XOFFRXC  0x04050  /* XOFF RX Count - R/clr */
-#define E1000_XOFFTXC  0x04054  /* XOFF TX Count - R/clr */
-#define E1000_FCRUC    0x04058  /* Flow Control RX Unsupported Count- R/clr */
-#define E1000_PRC64    0x0405C  /* Packets RX (64 bytes) - R/clr */
-#define E1000_PRC127   0x04060  /* Packets RX (65-127 bytes) - R/clr */
-#define E1000_PRC255   0x04064  /* Packets RX (128-255 bytes) - R/clr */
-#define E1000_PRC511   0x04068  /* Packets RX (255-511 bytes) - R/clr */
-#define E1000_PRC1023  0x0406C  /* Packets RX (512-1023 bytes) - R/clr */
-#define E1000_PRC1522  0x04070  /* Packets RX (1024-1522 bytes) - R/clr */
-#define E1000_GPRC     0x04074  /* Good Packets RX Count - R/clr */
-#define E1000_BPRC     0x04078  /* Broadcast Packets RX Count - R/clr */
-#define E1000_MPRC     0x0407C  /* Multicast Packets RX Count - R/clr */
-#define E1000_GPTC     0x04080  /* Good Packets TX Count - R/clr */
-#define E1000_GORCL    0x04088  /* Good Octets RX Count Low - R/clr */
-#define E1000_GORCH    0x0408C  /* Good Octets RX Count High - R/clr */
-#define E1000_GOTCL    0x04090  /* Good Octets TX Count Low - R/clr */
-#define E1000_GOTCH    0x04094  /* Good Octets TX Count High - R/clr */
-#define E1000_RNBC     0x040A0  /* RX No Buffers Count - R/clr */
-#define E1000_RUC      0x040A4  /* RX Undersize Count - R/clr */
-#define E1000_RFC      0x040A8  /* RX Fragment Count - R/clr */
-#define E1000_ROC      0x040AC  /* RX Oversize Count - R/clr */
-#define E1000_RJC      0x040B0  /* RX Jabber Count - R/clr */
-#define E1000_MGTPRC   0x040B4  /* Management Packets RX Count - R/clr */
-#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
-#define E1000_MGTPTC   0x040BC  /* Management Packets TX Count - R/clr */
-#define E1000_TORL     0x040C0  /* Total Octets RX Low - R/clr */
-#define E1000_TORH     0x040C4  /* Total Octets RX High - R/clr */
-#define E1000_TOTL     0x040C8  /* Total Octets TX Low - R/clr */
-#define E1000_TOTH     0x040CC  /* Total Octets TX High - R/clr */
-#define E1000_TPR      0x040D0  /* Total Packets RX - R/clr */
-#define E1000_TPT      0x040D4  /* Total Packets TX - R/clr */
-#define E1000_PTC64    0x040D8  /* Packets TX (64 bytes) - R/clr */
-#define E1000_PTC127   0x040DC  /* Packets TX (65-127 bytes) - R/clr */
-#define E1000_PTC255   0x040E0  /* Packets TX (128-255 bytes) - R/clr */
-#define E1000_PTC511   0x040E4  /* Packets TX (256-511 bytes) - R/clr */
-#define E1000_PTC1023  0x040E8  /* Packets TX (512-1023 bytes) - R/clr */
-#define E1000_PTC1522  0x040EC  /* Packets TX (1024-1522 Bytes) - R/clr */
-#define E1000_MPTC     0x040F0  /* Multicast Packets TX Count - R/clr */
-#define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
-#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
 #define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context TX Fail - R/clr */
-#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
-#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Packet Timer Expire Count */
 #define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Absolute Timer Expire Count */
 #define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Packet Timer Expire Count */
 #define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Absolute Timer Expire Count */
 #define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
 #define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Minimum Threshold Count */
-#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
 #define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
-#define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
-#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
-#define E1000_MAVTV0   0x05010  /* Management VLAN TAG Value 0 */
-#define E1000_MAVTV1   0x05014  /* Management VLAN TAG Value 1 */
-#define E1000_MAVTV2   0x05018  /* Management VLAN TAG Value 2 */
-#define E1000_MAVTV3   0x0501c  /* Management VLAN TAG Value 3 */
-#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
-#define E1000_RA       0x05400  /* Receive Address - RW Array */
-#define E1000_RA_A     0x00040  /* Alias to RA */
-#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
-#define E1000_VFTA_A   0x00600  /* Alias to VFTA */
-#define E1000_WUC      0x05800  /* Wakeup Control - RW */
-#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
-#define E1000_WUS      0x05810  /* Wakeup Status - RO */
-#define E1000_MANC     0x05820  /* Management Control - RW */
-#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
-#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
-#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
-#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
-#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
 #define E1000_MFUTP01  0x05828  /* Management Flex UDP/TCP Ports 0/1 - RW */
 #define E1000_MFUTP23  0x05830  /* Management Flex UDP/TCP Ports 2/3 - RW */
-#define E1000_MFVAL    0x05824  /* Manageability Filters Valid - RW */
-#define E1000_MDEF     0x05890  /* Manageability Decision Filters - RW Array */
 #define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
 #define E1000_HOST_IF  0x08800  /* Host Interface */
-#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
-#define E1000_FTFT     0x09400  /* Flexible TCO Filter Table - RW Array */
 #define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
 
 #define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */
 #define E1000_MDPHYA     0x0003C /* PHY address - RW */
-#define E1000_MANC2H     0x05860 /* Management Control To Host - RW */
-#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
 
-#define E1000_GCR       0x05B00 /* PCI-Ex Control */
-#define E1000_FUNCTAG   0x05B08 /* Function-Tag Register */
-#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
-#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
-#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
-#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
-#define E1000_GSCN_0    0x05B20 /* 3GIO Statistic Counter Register #0 */
-#define E1000_GSCN_1    0x05B24 /* 3GIO Statistic Counter Register #1 */
-#define E1000_GSCN_2    0x05B28 /* 3GIO Statistic Counter Register #2 */
-#define E1000_GSCN_3    0x05B2C /* 3GIO Statistic Counter Register #3 */
-#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
-#define E1000_SWSM      0x05B50 /* SW Semaphore */
 #define E1000_GCR2      0x05B64 /* 3GIO Control Register 2 */
-#define E1000_FWSM      0x05B54 /* FW Semaphore */
-#define E1000_PBACLR    0x05B68 /* MSI-X PBA Clear */
 #define E1000_FFLT_DBG  0x05F04 /* Debug Register */
 #define E1000_HICR      0x08F00 /* Host Inteface Control */
 
-#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
-#define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */
-#define E1000_TIMINCA    0x0B608 /* Increment attributes register - RW */
-#define E1000_RXSTMPL    0x0B624 /* Rx timestamp Low - RO */
-#define E1000_RXSTMPH    0x0B628 /* Rx timestamp High - RO */
-#define E1000_TXSTMPL    0x0B618 /* Tx timestamp value Low - RO */
-#define E1000_TXSTMPH    0x0B61C /* Tx timestamp value High - RO */
-#define E1000_SYSTIML    0x0B600 /* System time register Low - RO */
-#define E1000_SYSTIMH    0x0B604 /* System time register High - RO */
-#define E1000_TIMINCA    0x0B608 /* Increment attributes register - RW */
 #define E1000_RXMTRL     0x0B634 /* Time sync Rx EtherType and Msg Type - RW */
 #define E1000_RXUDP      0x0B638 /* Time Sync Rx UDP Port - RW */
-#define E1000_RXSATRL    0x0B62C /* Rx timestamp attribute low - RO */
-#define E1000_RXSATRH    0x0B630 /* Rx timestamp attribute high - RO */
-#define E1000_TIMADJL    0x0B60C /* Time Adjustment Offset register Low - RW */
-#define E1000_TIMADJH    0x0B610 /* Time Adjustment Offset register High - RW */
 #define E1000_RXCFGL     0x0B634 /* RX Ethertype and Message Type - RW*/
 
-/* RSS registers */
+#define E1000_MRQC_ENABLED(mrqc) (((mrqc) & (BIT(0) | BIT(1))) == BIT(0))
+
 #define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
-#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
-#define E1000_RETA      0x05C00 /* Redirection Table - RW Array */
-#define E1000_RSSRK     0x05C80 /* RSS Random Key - RW Array */
 #define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
 #define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
 
-#define E1000_MRQC_ENABLED(mrqc) (((mrqc) & (BIT(0) | BIT(1))) == BIT(0))
-
-#define E1000_RETA_IDX(hash)        ((hash) & (BIT(7) - 1))
-#define E1000_RETA_VAL(reta, hash)  (((uint8_t *)(reta))[E1000_RETA_IDX(hash)])
 #define E1000_RSS_QUEUE(reta, hash) ((E1000_RETA_VAL(reta, hash) & BIT(7)) >> 7)
 
-#define E1000_MRQC_EN_TCPIPV4(mrqc) ((mrqc) & BIT(16))
-#define E1000_MRQC_EN_IPV4(mrqc)    ((mrqc) & BIT(17))
-#define E1000_MRQC_EN_TCPIPV6(mrqc) ((mrqc) & BIT(18))
-#define E1000_MRQC_EN_IPV6EX(mrqc)  ((mrqc) & BIT(19))
-#define E1000_MRQC_EN_IPV6(mrqc)    ((mrqc) & BIT(20))
-
-#define E1000_MRQ_RSS_TYPE_NONE     (0)
-#define E1000_MRQ_RSS_TYPE_IPV4TCP  (1)
-#define E1000_MRQ_RSS_TYPE_IPV4     (2)
-#define E1000_MRQ_RSS_TYPE_IPV6TCP  (3)
-#define E1000_MRQ_RSS_TYPE_IPV6EX   (4)
-#define E1000_MRQ_RSS_TYPE_IPV6     (5)
-
-#define E1000_ICR_ASSERTED BIT(31)
-#define E1000_EIAC_MASK    0x01F00000
-
 /* [TR]DBAL and [TR]DLEN masks */
 #define E1000_XDBAL_MASK            (~(BIT(4) - 1))
 #define E1000_XDLEN_MASK            ((BIT(20) - 1) & (~(BIT(7) - 1)))
@@ -444,18 +172,8 @@
 
 #define E1000_IVAR_TX_INT_EVERY_WB  BIT(31)
 
-/* RFCTL register bits */
-#define E1000_RFCTL_ISCSI_DIS           0x00000001
-#define E1000_RFCTL_NFSW_DIS            0x00000040
-#define E1000_RFCTL_NFSR_DIS            0x00000080
-#define E1000_RFCTL_IPV6_DIS            0x00000400
-#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
 #define E1000_RFCTL_ACK_DIS             0x00001000
 #define E1000_RFCTL_ACK_DATA_DIS        0x00002000
-#define E1000_RFCTL_IPFRSP_DIS          0x00004000
-#define E1000_RFCTL_EXTEN               0x00008000
-#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
-#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
 
 /* PSRCTL parsing */
 #define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
@@ -470,9 +188,6 @@
 
 #define E1000_PSRCTL_BUFFS_PER_DESC 4
 
-/* TARC* parsing */
-#define E1000_TARC_ENABLE BIT(10)
-
 /* PHY 1000 MII Register/Bit Definitions */
 /* 82574-specific registers */
 #define PHY_COPPER_CTRL1      0x10 /* Copper Specific Control Register 1 */
@@ -525,262 +240,6 @@
 #define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
 #define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
 
-/* SW Semaphore Register */
-#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
-#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
-#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
-
-#define E1000_SWSM2_LOCK        0x00000002 /* Secondary driver semaphore bit */
-
-/* Interrupt Cause Read */
-#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
-#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
-#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
-#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
-#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
-#define E1000_ICR_RXO           0x00000040 /* rx overrun */
-#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
-#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
-#define E1000_ICR_RXCFG         0x00000400 /* RX /c/ ordered set */
-#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
-#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
-#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
-#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
-#define E1000_ICR_TXD_LOW       0x00008000
-#define E1000_ICR_SRPD          0x00010000
-#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
-#define E1000_ICR_MNG           0x00040000 /* Manageability event */
-#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
-#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
-#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */
-#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */
-#define E1000_ICR_HOST_ARB_PAR  0x00400000 /* host arb read buffer parity error */
-#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
-#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */
-#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */
-#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
-#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW bit in the FWSM */
-#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates an interrupt */
-#define E1000_ICR_EPRST         0x00100000 /* ME handware reset occurs */
-#define E1000_ICR_RXQ0          0x00100000 /* Rx Queue 0 Interrupt */
-#define E1000_ICR_RXQ1          0x00200000 /* Rx Queue 1 Interrupt */
-#define E1000_ICR_TXQ0          0x00400000 /* Tx Queue 0 Interrupt */
-#define E1000_ICR_TXQ1          0x00800000 /* Tx Queue 1 Interrupt */
-#define E1000_ICR_OTHER         0x01000000 /* Other Interrupts */
-
-#define E1000_ICR_OTHER_CAUSES (E1000_ICR_LSC  | \
-                                E1000_ICR_RXO  | \
-                                E1000_ICR_MDAC | \
-                                E1000_ICR_SRPD | \
-                                E1000_ICR_ACK  | \
-                                E1000_ICR_MNG)
-
-/* Interrupt Cause Set */
-#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
-#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
-#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
-#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
-#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
-#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
-#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
-#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
-#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
-#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
-#define E1000_ICS_SRPD      E1000_ICR_SRPD
-#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
-#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
-#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
-#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
-#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
-#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
-#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
-#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
-#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
-#define E1000_ICS_DSW       E1000_ICR_DSW
-#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
-#define E1000_ICS_EPRST     E1000_ICR_EPRST
-
-/* Interrupt Mask Set */
-#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
-#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
-#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
-#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
-#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
-#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
-#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
-#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
-#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
-#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
-#define E1000_IMS_SRPD      E1000_ICR_SRPD
-#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
-#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
-#define E1000_IMS_RXQ0      E1000_ICR_RXQ0
-#define E1000_IMS_RXQ1      E1000_ICR_RXQ1
-#define E1000_IMS_TXQ0      E1000_ICR_TXQ0
-#define E1000_IMS_TXQ1      E1000_ICR_TXQ1
-#define E1000_IMS_OTHER     E1000_ICR_OTHER
-#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
-#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
-#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
-#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
-#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
-#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
-#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
-#define E1000_IMS_DSW       E1000_ICR_DSW
-#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
-#define E1000_IMS_EPRST     E1000_ICR_EPRST
-
-/* Interrupt Mask Clear */
-#define E1000_IMC_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
-#define E1000_IMC_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
-#define E1000_IMC_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_IMC_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_IMC_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_IMC_RXO       E1000_ICR_RXO       /* rx overrun */
-#define E1000_IMC_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-#define E1000_IMC_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
-#define E1000_IMC_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
-#define E1000_IMC_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
-#define E1000_IMC_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
-#define E1000_IMC_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
-#define E1000_IMC_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
-#define E1000_IMC_TXD_LOW   E1000_ICR_TXD_LOW
-#define E1000_IMC_SRPD      E1000_ICR_SRPD
-#define E1000_IMC_ACK       E1000_ICR_ACK       /* Receive Ack frame */
-#define E1000_IMC_MNG       E1000_ICR_MNG       /* Manageability event */
-#define E1000_IMC_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
-#define E1000_IMC_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
-#define E1000_IMC_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
-#define E1000_IMC_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
-#define E1000_IMC_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
-#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
-#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
-#define E1000_IMC_DSW       E1000_ICR_DSW
-#define E1000_IMC_PHYINT    E1000_ICR_PHYINT
-#define E1000_IMC_EPRST     E1000_ICR_EPRST
-
-/* Receive Control */
-#define E1000_RCTL_RST            0x00000001    /* Software reset */
-#define E1000_RCTL_EN             0x00000002    /* enable */
-#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
-#define E1000_RCTL_UPE            0x00000008    /* unicast promiscuous enable */
-#define E1000_RCTL_MPE            0x00000010    /* multicast promiscuous enab */
-#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
-#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
-#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
-#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
-#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
-#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
-#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
-#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
-#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min threshold size */
-#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min threshold size */
-#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
-#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
-#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
-#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
-#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
-#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
-#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
-#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
-#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
-#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
-#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
-#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
-#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
-#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
-#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
-#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
-#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
-#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
-#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
-#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
-#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
-#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
-#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
-
-
-#define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
-#define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
-#define E1000_EEPROM_RW_REG_DATA   16   /* Offset to data in EEPROM read/write registers */
-#define E1000_EEPROM_RW_REG_DONE   0x10 /* Offset to READ/WRITE done bit */
-#define E1000_EEPROM_RW_REG_START  1    /* First bit for telling part to start operation */
-#define E1000_EEPROM_RW_ADDR_SHIFT 8    /* Shift to the address bits */
-#define E1000_EEPROM_POLL_WRITE    1    /* Flag for polling for write complete */
-#define E1000_EEPROM_POLL_READ     0    /* Flag for polling for read complete */
-
-/* 82574 EERD/EEWR registers layout */
-#define E1000_EERW_START        BIT(0)
-#define E1000_EERW_DONE         BIT(1)
-#define E1000_EERW_ADDR_SHIFT   2
-#define E1000_EERW_ADDR_MASK    ((1L << 14) - 1)
-#define E1000_EERW_DATA_SHIFT   16
-#define E1000_EERW_DATA_MASK   ((1L << 16) - 1)
-
-/* Register Bit Masks */
-/* Device Control */
-#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
-#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
-#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
-#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
-#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
-#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
-#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
-#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
-#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
-#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
-#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
-#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
-#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
-#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
-#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
-#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
-#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
-#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
-#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
-#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */
-#define E1000_CTRL_SPD_SHIFT 8          /* Speed Select Shift */
-
-#define E1000_CTRL_EXT_ASDCHK  0x00001000 /* auto speed detection check */
-#define E1000_CTRL_EXT_EE_RST  0x00002000 /* EEPROM reset */
-#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */
-#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
-#define E1000_CTRL_EXT_EIAME   0x01000000
-#define E1000_CTRL_EXT_IAME    0x08000000 /* Int ACK Auto-mask */
-#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
-#define E1000_CTRL_EXT_INT_TIMERS_CLEAR_ENA 0x20000000
-#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
-
-#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
-#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
-#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
-#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
-#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
-#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
-#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
-#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
-#define E1000_CTRL_ADVD3WUC 0x00100000  /* D3 WUC */
-#define E1000_CTRL_RST      0x04000000  /* Global reset */
-#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
-#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
-#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
-#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
-#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
-#define E1000_CTRL_SW2FW_INT 0x02000000  /* Initiate an interrupt to manageability engine */
-
-/* Device Status */
-#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
-#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
 #define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
 #define E1000_STATUS_FUNC_SHIFT 2
 #define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
@@ -788,9 +247,6 @@
 #define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
 #define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
 #define E1000_STATUS_SPEED_MASK 0x000000C0
-#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
-#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
-#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
 #define E1000_STATUS_LAN_INIT_DONE 0x00000200   /* Lan Init Completion
                                                    by EEPROM/Flash */
 #define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
@@ -798,9 +254,7 @@
 #define E1000_STATUS_ASDV_100   0x00000100      /* ASDV 100Mb */
 #define E1000_STATUS_ASDV_1000  0x00000200      /* ASDV 1Gb */
 #define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state. Clear on write '0'. */
-#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
 #define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
-#define E1000_STATUS_PHYRA      0x00000400      /* PHY Reset Asserted */
 #define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
 #define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
 #define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
@@ -818,111 +272,6 @@
 #define E1000_STATUS_SPEED_SHIFT  6
 #define E1000_STATUS_ASDV_SHIFT   8
 
-/* EEPROM/Flash Control */
-#define E1000_EECD_SK        0x00000001 /* EEPROM Clock */
-#define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
-#define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
-#define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
-#define E1000_EECD_FWE_MASK  0x00000030
-#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
-#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
-#define E1000_EECD_FWE_SHIFT 4
-#define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
-#define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
-#define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
-#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
-#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
-                                         * (0-small, 1-large) */
-#define E1000_EECD_TYPE      0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
-#ifndef E1000_EEPROM_GRANT_ATTEMPTS
-#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
-#endif
-#define E1000_EECD_AUTO_RD          0x00000200  /* EEPROM Auto Read done */
-#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* EEprom Size */
-#define E1000_EECD_SIZE_EX_SHIFT    11
-#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
-#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
-#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
-#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
-#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
-#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
-#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
-
-
-#define E1000_EECD_SECVAL_SHIFT      22
-#define E1000_STM_OPCODE     0xDB00
-#define E1000_HICR_FW_RESET  0xC0
-
-#define E1000_SHADOW_RAM_WORDS     2048
-#define E1000_ICH_NVM_SIG_WORD     0x13
-#define E1000_ICH_NVM_SIG_MASK     0xC0
-
-/* MDI Control */
-#define E1000_MDIC_DATA_MASK 0x0000FFFF
-#define E1000_MDIC_REG_MASK  0x001F0000
-#define E1000_MDIC_REG_SHIFT 16
-#define E1000_MDIC_PHY_MASK  0x03E00000
-#define E1000_MDIC_PHY_SHIFT 21
-#define E1000_MDIC_OP_WRITE  0x04000000
-#define E1000_MDIC_OP_READ   0x08000000
-#define E1000_MDIC_READY     0x10000000
-#define E1000_MDIC_INT_EN    0x20000000
-#define E1000_MDIC_ERROR     0x40000000
-
-/* Rx Interrupt Delay Timer */
-#define E1000_RDTR_FPD       BIT(31)
-
-/* Tx Interrupt Delay Timer */
-#define E1000_TIDV_FPD       BIT(31)
-
-/* Delay increments in nanoseconds for delayed interrupts registers */
-#define E1000_INTR_DELAY_NS_RES (1024)
-
-/* Delay increments in nanoseconds for interrupt throttling registers */
-#define E1000_INTR_THROTTLING_NS_RES (256)
-
-/* EEPROM Commands - Microwire */
-#define EEPROM_READ_OPCODE_MICROWIRE  0x6  /* EEPROM read opcode */
-#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5  /* EEPROM write opcode */
-#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7  /* EEPROM erase opcode */
-#define EEPROM_EWEN_OPCODE_MICROWIRE  0x13 /* EEPROM erase/write enable */
-#define EEPROM_EWDS_OPCODE_MICROWIRE  0x10 /* EEPROM erast/write disable */
-
-/* EEPROM Word Offsets */
-#define EEPROM_COMPAT                 0x0003
-#define EEPROM_ID_LED_SETTINGS        0x0004
-#define EEPROM_VERSION                0x0005
-#define EEPROM_SERDES_AMPLITUDE       0x0006 /* For SERDES output amplitude adjustment. */
-#define EEPROM_PHY_CLASS_WORD         0x0007
-#define EEPROM_INIT_CONTROL1_REG      0x000A
-#define EEPROM_INIT_CONTROL2_REG      0x000F
-#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010
-#define EEPROM_INIT_CONTROL3_PORT_B   0x0014
-#define EEPROM_INIT_3GIO_3            0x001A
-#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020
-#define EEPROM_INIT_CONTROL3_PORT_A   0x0024
-#define EEPROM_CFG                    0x0012
-#define EEPROM_FLASH_VERSION          0x0032
-#define EEPROM_CHECKSUM_REG           0x003F
-
-#define E1000_EEPROM_CFG_DONE         0x00040000   /* MNG config cycle done */
-#define E1000_EEPROM_CFG_DONE_PORT_1  0x00080000   /* ...for second port */
-
-/* PCI Express Control */
-/* 3GIO Control Register - GCR (0x05B00; RW) */
-#define E1000_L0S_ADJUST              (1 << 9)
-#define E1000_L1_ENTRY_LATENCY_MSB    (1 << 23)
-#define E1000_L1_ENTRY_LATENCY_LSB    (1 << 25 | 1 << 26)
-
-#define E1000_L0S_ADJUST              (1 << 9)
-#define E1000_L1_ENTRY_LATENCY_MSB    (1 << 23)
-#define E1000_L1_ENTRY_LATENCY_LSB    (1 << 25 | 1 << 26)
-
-#define E1000_GCR_RO_BITS             (1 << 23 | 1 << 25 | 1 << 26)
-
-/* MSI-X PBA Clear register */
-#define E1000_PBACLR_VALID_MASK       (BIT(5) - 1)
-
 /* Transmit Descriptor */
 struct e1000_tx_desc {
     uint64_t buffer_addr;       /* Address of the descriptor's data buffer */
@@ -944,277 +293,7 @@ struct e1000_tx_desc {
     } upper;
 };
 
-/* Transmit Descriptor bit definitions */
-#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
-#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
 #define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
 #define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
-#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
-#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
-#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
-#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
-#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
-#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
-#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
-#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
-#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
-#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
-#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
-#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
-#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
-#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
-#define E1000_TXD_CMD_SNAP   0x40000000 /* Update SNAP header */
-#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
-#define E1000_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
-
-/* Transmit Control */
-#define E1000_TCTL_RST    0x00000001    /* software reset */
-#define E1000_TCTL_EN     0x00000002    /* enable tx */
-#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
-#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
-#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
-#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
-#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
-#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
-#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
-#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
-#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
-
-/* Legacy Receive Descriptor */
-struct e1000_rx_desc {
-    uint64_t buffer_addr; /* Address of the descriptor's data buffer */
-    uint16_t length;     /* Length of data DMAed into data buffer */
-    uint16_t csum;       /* Packet checksum */
-    uint8_t status;      /* Descriptor status */
-    uint8_t errors;      /* Descriptor Errors */
-    uint16_t special;
-};
-
-/* Extended Receive Descriptor */
-union e1000_rx_desc_extended {
-    struct {
-        uint64_t buffer_addr;
-        uint64_t reserved;
-    } read;
-    struct {
-        struct {
-            uint32_t mrq;           /* Multiple Rx Queues */
-            union {
-                uint32_t rss;       /* RSS Hash */
-                struct {
-                    uint16_t ip_id; /* IP id */
-                    uint16_t csum;  /* Packet Checksum */
-                } csum_ip;
-            } hi_dword;
-        } lower;
-        struct {
-            uint32_t status_error;  /* ext status/error */
-            uint16_t length;
-            uint16_t vlan;          /* VLAN tag */
-        } upper;
-    } wb;                           /* writeback */
-};
-
-#define MAX_PS_BUFFERS 4
-
-/* Number of packet split data buffers (not including the header buffer) */
-#define PS_PAGE_BUFFERS    (MAX_PS_BUFFERS - 1)
-
-/* Receive Descriptor - Packet Split */
-union e1000_rx_desc_packet_split {
-    struct {
-        /* one buffer for protocol header(s), three data buffers */
-        uint64_t buffer_addr[MAX_PS_BUFFERS];
-    } read;
-    struct {
-        struct {
-            uint32_t mrq;          /* Multiple Rx Queues */
-            union {
-                uint32_t rss;          /* RSS Hash */
-                struct {
-                    uint16_t ip_id;    /* IP id */
-                    uint16_t csum;     /* Packet Checksum */
-                } csum_ip;
-            } hi_dword;
-        } lower;
-        struct {
-            uint32_t status_error;     /* ext status/error */
-            uint16_t length0;      /* length of buffer 0 */
-            uint16_t vlan;         /* VLAN tag */
-        } middle;
-        struct {
-            uint16_t header_status;
-            /* length of buffers 1-3 */
-            uint16_t length[PS_PAGE_BUFFERS];
-        } upper;
-        uint64_t reserved;
-    } wb; /* writeback */
-};
-
-/* Receive Checksum Control bits */
-#define E1000_RXCSUM_IPOFLD     0x100   /* IP Checksum Offload Enable */
-#define E1000_RXCSUM_TUOFLD     0x200   /* TCP/UDP Checksum Offload Enable */
-#define E1000_RXCSUM_PCSD       0x2000  /* Packet Checksum Disable */
-
-#define E1000_RING_DESC_LEN       (16)
-#define E1000_RING_DESC_LEN_SHIFT (4)
-
-#define E1000_MIN_RX_DESC_LEN   E1000_RING_DESC_LEN
-
-/* Receive Descriptor bit definitions */
-#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
-#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
-#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
-#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
-#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
-#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
-#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
-#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
-#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
-#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
-#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
-#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
-#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
-#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
-#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
-#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
-#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
-#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
-#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
-#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
-#define E1000_RXD_SPC_PRI_SHIFT 13
-#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
-#define E1000_RXD_SPC_CFI_SHIFT 12
-
-/* RX packet types */
-#define E1000_RXD_PKT_MAC       (0)
-#define E1000_RXD_PKT_IP4       (1)
-#define E1000_RXD_PKT_IP4_XDP   (2)
-#define E1000_RXD_PKT_IP6       (5)
-#define E1000_RXD_PKT_IP6_XDP   (6)
-
-#define E1000_RXD_PKT_TYPE(t) ((t) << 16)
-
-#define E1000_RXDEXT_STATERR_CE    0x01000000
-#define E1000_RXDEXT_STATERR_SE    0x02000000
-#define E1000_RXDEXT_STATERR_SEQ   0x04000000
-#define E1000_RXDEXT_STATERR_CXE   0x10000000
-#define E1000_RXDEXT_STATERR_TCPE  0x20000000
-#define E1000_RXDEXT_STATERR_IPE   0x40000000
-#define E1000_RXDEXT_STATERR_RXE   0x80000000
-
-#define E1000_RXDPS_HDRSTAT_HDRSP        0x00008000
-#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK  0x000003FF
-
-/* Receive Address */
-#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
-
-/* Offload Context Descriptor */
-struct e1000_context_desc {
-    union {
-        uint32_t ip_config;
-        struct {
-            uint8_t ipcss;      /* IP checksum start */
-            uint8_t ipcso;      /* IP checksum offset */
-            uint16_t ipcse;     /* IP checksum end */
-        } ip_fields;
-    } lower_setup;
-    union {
-        uint32_t tcp_config;
-        struct {
-            uint8_t tucss;      /* TCP checksum start */
-            uint8_t tucso;      /* TCP checksum offset */
-            uint16_t tucse;     /* TCP checksum end */
-        } tcp_fields;
-    } upper_setup;
-    uint32_t cmd_and_length;    /* */
-    union {
-        uint32_t data;
-        struct {
-            uint8_t status;     /* Descriptor status */
-            uint8_t hdr_len;    /* Header length */
-            uint16_t mss;       /* Maximum segment size */
-        } fields;
-    } tcp_seg_setup;
-};
-
-/* Offload data descriptor */
-struct e1000_data_desc {
-    uint64_t buffer_addr;       /* Address of the descriptor's buffer address */
-    union {
-        uint32_t data;
-        struct {
-            uint16_t length;    /* Data buffer length */
-            uint8_t typ_len_ext;        /* */
-            uint8_t cmd;        /* */
-        } flags;
-    } lower;
-    union {
-        uint32_t data;
-        struct {
-            uint8_t status;     /* Descriptor status */
-            uint8_t popts;      /* Packet Options */
-            uint16_t special;   /* */
-        } fields;
-    } upper;
-};
-
-/* Filters */
-#define E1000_NUM_UNICAST          16  /* Unicast filter entries */
-#define E1000_MC_TBL_SIZE          128 /* Multicast Filter Table (4096 bits) */
-#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
-
-/* Management Control */
-#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
-#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
-#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
-#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
-#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
-#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
-#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
-#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
-#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
-#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery
-                                             * Filtering */
-#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
-#define E1000_MANC_DIS_IP_CHK_ARP  0x10000000 /* Disable IP address chacking */
-                                              /*for ARP packets - in 82574 */
-#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
-#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
-#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
-#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
-#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
-#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000 /* Enable MAC address
-                                                    * filtering */
-#define E1000_MANC_EN_MNG2HOST   0x00200000 /* Enable MNG packets to host
-                                             * memory */
-#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000 /* Enable IP address
-                                                    * filtering */
-#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
-#define E1000_MANC_BR_EN         0x01000000 /* Enable broadcast filtering */
-#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
-#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
-#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
-#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
-#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
-#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
-
-#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
-#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
-
-/* FACTPS Control */
-#define E1000_FACTPS_LAN0_ON     0x00000004 /* Lan 0 enable */
-
-/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
-#define EEPROM_SUM 0xBABA
-
-/* I/O-Mapped Access to Internal Registers, Memories, and Flash */
-#define E1000_IOADDR 0x00
-#define E1000_IODATA 0x04
-
-#define E1000_VFTA_ENTRY_SHIFT          5
-#define E1000_VFTA_ENTRY_MASK           0x7F
-#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F
 
 #endif /* HW_E1000_REGS_H */
diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c
index ec274319c4..a0c4693330 100644
--- a/hw/net/e1000e.c
+++ b/hw/net/e1000e.c
@@ -48,8 +48,7 @@
 #include "hw/qdev-properties.h"
 #include "migration/vmstate.h"
 
-#include "e1000_regs.h"
-
+#include "e1000_common.h"
 #include "e1000x_common.h"
 #include "e1000e_core.h"
 
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
index d143f2ae6f..e874d417ed 100644
--- a/hw/net/e1000e_core.c
+++ b/hw/net/e1000e_core.c
@@ -45,6 +45,7 @@
 #include "net_tx_pkt.h"
 #include "net_rx_pkt.h"
 
+#include "e1000_common.h"
 #include "e1000x_common.h"
 #include "e1000e_core.h"
 
diff --git a/hw/net/e1000x_common.c b/hw/net/e1000x_common.c
index b3bbf31582..19e30635ea 100644
--- a/hw/net/e1000x_common.c
+++ b/hw/net/e1000x_common.c
@@ -29,6 +29,7 @@
 #include "net/eth.h"
 #include "net/net.h"
 
+#include "e1000_common.h"
 #include "e1000x_common.h"
 
 #include "trace.h"
diff --git a/hw/net/e1000x_common.h b/hw/net/e1000x_common.h
index b991d814b1..fb705c3f21 100644
--- a/hw/net/e1000x_common.h
+++ b/hw/net/e1000x_common.h
@@ -25,80 +25,6 @@
 #ifndef HW_NET_E1000X_COMMON_H
 #define HW_NET_E1000X_COMMON_H
 
-#include "e1000_regs.h"
-
-#define defreg(x)   x = (E1000_##x >> 2)
-enum {
-    defreg(CTRL),    defreg(EECD),    defreg(EERD),    defreg(GPRC),
-    defreg(GPTC),    defreg(ICR),     defreg(ICS),     defreg(IMC),
-    defreg(IMS),     defreg(LEDCTL),  defreg(MANC),    defreg(MDIC),
-    defreg(MPC),     defreg(PBA),     defreg(RCTL),    defreg(RDBAH0),
-    defreg(RDBAL0),  defreg(RDH0),    defreg(RDLEN0),  defreg(RDT0),
-    defreg(STATUS),  defreg(SWSM),    defreg(TCTL),    defreg(TDBAH),
-    defreg(TDBAL),   defreg(TDH),     defreg(TDLEN),   defreg(TDT),
-    defreg(TDLEN1),  defreg(TDBAL1),  defreg(TDBAH1),  defreg(TDH1),
-    defreg(TDT1),    defreg(TORH),    defreg(TORL),    defreg(TOTH),
-    defreg(TOTL),    defreg(TPR),     defreg(TPT),     defreg(TXDCTL),
-    defreg(WUFC),    defreg(RA),      defreg(MTA),     defreg(CRCERRS),
-    defreg(VFTA),    defreg(VET),     defreg(RDTR),    defreg(RADV),
-    defreg(TADV),    defreg(ITR),     defreg(SCC),     defreg(ECOL),
-    defreg(MCC),     defreg(LATECOL), defreg(COLC),    defreg(DC),
-    defreg(TNCRS),   defreg(SEQEC),   defreg(CEXTERR), defreg(RLEC),
-    defreg(XONRXC),  defreg(XONTXC),  defreg(XOFFRXC), defreg(XOFFTXC),
-    defreg(FCRUC),   defreg(AIT),     defreg(TDFH),    defreg(TDFT),
-    defreg(TDFHS),   defreg(TDFTS),   defreg(TDFPC),   defreg(WUC),
-    defreg(WUS),     defreg(POEMB),   defreg(PBS),     defreg(RDFH),
-    defreg(RDFT),    defreg(RDFHS),   defreg(RDFTS),   defreg(RDFPC),
-    defreg(PBM),     defreg(IPAV),    defreg(IP4AT),   defreg(IP6AT),
-    defreg(WUPM),    defreg(FFLT),    defreg(FFMT),    defreg(FFVT),
-    defreg(TARC0),   defreg(TARC1),   defreg(IAM),     defreg(EXTCNF_CTRL),
-    defreg(GCR),     defreg(TIMINCA), defreg(EIAC),    defreg(CTRL_EXT),
-    defreg(IVAR),    defreg(MFUTP01), defreg(MFUTP23), defreg(MANC2H),
-    defreg(MFVAL),   defreg(MDEF),    defreg(FACTPS),  defreg(FTFT),
-    defreg(RUC),     defreg(ROC),     defreg(RFC),     defreg(RJC),
-    defreg(PRC64),   defreg(PRC127),  defreg(PRC255),  defreg(PRC511),
-    defreg(PRC1023), defreg(PRC1522), defreg(PTC64),   defreg(PTC127),
-    defreg(PTC255),  defreg(PTC511),  defreg(PTC1023), defreg(PTC1522),
-    defreg(GORCL),   defreg(GORCH),   defreg(GOTCL),   defreg(GOTCH),
-    defreg(RNBC),    defreg(BPRC),    defreg(MPRC),    defreg(RFCTL),
-    defreg(PSRCTL),  defreg(MPTC),    defreg(BPTC),    defreg(TSCTFC),
-    defreg(IAC),     defreg(MGTPRC),  defreg(MGTPDC),  defreg(MGTPTC),
-    defreg(TSCTC),   defreg(RXCSUM),  defreg(FUNCTAG), defreg(GSCL_1),
-    defreg(GSCL_2),  defreg(GSCL_3),  defreg(GSCL_4),  defreg(GSCN_0),
-    defreg(GSCN_1),  defreg(GSCN_2),  defreg(GSCN_3),  defreg(GCR2),
-    defreg(RAID),    defreg(RSRPD),   defreg(TIDV),    defreg(EITR),
-    defreg(MRQC),    defreg(RETA),    defreg(RSSRK),   defreg(RDBAH1),
-    defreg(RDBAL1),  defreg(RDLEN1),  defreg(RDH1),    defreg(RDT1),
-    defreg(PBACLR),  defreg(FCAL),    defreg(FCAH),    defreg(FCT),
-    defreg(FCRTH),   defreg(FCRTL),   defreg(FCTTV),   defreg(FCRTV),
-    defreg(FLA),     defreg(EEWR),    defreg(FLOP),    defreg(FLOL),
-    defreg(FLSWCTL), defreg(FLSWCNT), defreg(RXDCTL),  defreg(RXDCTL1),
-    defreg(MAVTV0),  defreg(MAVTV1),  defreg(MAVTV2),  defreg(MAVTV3),
-    defreg(TXSTMPL), defreg(TXSTMPH), defreg(SYSTIML), defreg(SYSTIMH),
-    defreg(RXCFGL),  defreg(RXUDP),   defreg(TIMADJL), defreg(TIMADJH),
-    defreg(RXSTMPH), defreg(RXSTMPL), defreg(RXSATRL), defreg(RXSATRH),
-    defreg(FLASHT),  defreg(TIPG),    defreg(RDH),     defreg(RDT),
-    defreg(RDLEN),   defreg(RDBAH),   defreg(RDBAL),
-    defreg(TXDCTL1),
-    defreg(FLSWDATA),
-    defreg(CTRL_DUP),
-    defreg(EXTCNF_SIZE),
-    defreg(EEMNGCTL),
-    defreg(EEMNGDATA),
-    defreg(FLMNGCTL),
-    defreg(FLMNGDATA),
-    defreg(FLMNGCNT),
-    defreg(TSYNCRXCTL),
-    defreg(TSYNCTXCTL),
-
-    /* Aliases */
-    defreg(RDH0_A),  defreg(RDT0_A),  defreg(RDTR_A),  defreg(RDFH_A),
-    defreg(RDFT_A),  defreg(TDH_A),   defreg(TDT_A),   defreg(TIDV_A),
-    defreg(TDFH_A),  defreg(TDFT_A),  defreg(RA_A),    defreg(RDBAL0_A),
-    defreg(TDBAL_A), defreg(TDLEN_A), defreg(VFTA_A),  defreg(RDLEN0_A),
-    defreg(FCRTL_A), defreg(FCRTH_A)
-};
-
 static inline void
 e1000x_inc_reg_if_not_full(uint32_t *mac, int index)
 {
diff --git a/hw/net/e1000x_regs.h b/hw/net/e1000x_regs.h
new file mode 100644
index 0000000000..fb5b861135
--- /dev/null
+++ b/hw/net/e1000x_regs.h
@@ -0,0 +1,940 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2006 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, see <http://www.gnu.org/licenses/>.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_hw.h
+ * Structures, enums, and macros for the MAC
+ */
+
+#ifndef HW_E1000X_REGS_H
+#define HW_E1000X_REGS_H
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542               0x1000
+#define E1000_DEV_ID_82543GC_FIBER       0x1001
+#define E1000_DEV_ID_82543GC_COPPER      0x1004
+#define E1000_DEV_ID_82544EI_COPPER      0x1008
+#define E1000_DEV_ID_82544EI_FIBER       0x1009
+#define E1000_DEV_ID_82544GC_COPPER      0x100C
+#define E1000_DEV_ID_82544GC_LOM         0x100D
+#define E1000_DEV_ID_82540EM             0x100E
+#define E1000_DEV_ID_82540EM_LOM         0x1015
+#define E1000_DEV_ID_82540EP_LOM         0x1016
+#define E1000_DEV_ID_82540EP             0x1017
+#define E1000_DEV_ID_82540EP_LP          0x101E
+#define E1000_DEV_ID_82545EM_COPPER      0x100F
+#define E1000_DEV_ID_82545EM_FIBER       0x1011
+#define E1000_DEV_ID_82545GM_COPPER      0x1026
+#define E1000_DEV_ID_82545GM_FIBER       0x1027
+#define E1000_DEV_ID_82545GM_SERDES      0x1028
+#define E1000_DEV_ID_82546EB_COPPER      0x1010
+#define E1000_DEV_ID_82546EB_FIBER       0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
+#define E1000_DEV_ID_82541EI             0x1013
+#define E1000_DEV_ID_82541EI_MOBILE      0x1018
+#define E1000_DEV_ID_82541ER_LOM         0x1014
+#define E1000_DEV_ID_82541ER             0x1078
+#define E1000_DEV_ID_82547GI             0x1075
+#define E1000_DEV_ID_82541GI             0x1076
+#define E1000_DEV_ID_82541GI_MOBILE      0x1077
+#define E1000_DEV_ID_82541GI_LF          0x107C
+#define E1000_DEV_ID_82546GB_COPPER      0x1079
+#define E1000_DEV_ID_82546GB_FIBER       0x107A
+#define E1000_DEV_ID_82546GB_SERDES      0x107B
+#define E1000_DEV_ID_82546GB_PCIE        0x108A
+#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
+#define E1000_DEV_ID_82547EI             0x1019
+#define E1000_DEV_ID_82547EI_MOBILE      0x101A
+#define E1000_DEV_ID_82571EB_COPPER      0x105E
+#define E1000_DEV_ID_82571EB_FIBER       0x105F
+#define E1000_DEV_ID_82571EB_SERDES      0x1060
+#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
+#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
+#define E1000_DEV_ID_82571EB_QUAD_FIBER  0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE  0x10BC
+#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
+#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA
+#define E1000_DEV_ID_82572EI_COPPER      0x107D
+#define E1000_DEV_ID_82572EI_FIBER       0x107E
+#define E1000_DEV_ID_82572EI_SERDES      0x107F
+#define E1000_DEV_ID_82572EI             0x10B9
+#define E1000_DEV_ID_82573E              0x108B
+#define E1000_DEV_ID_82573E_IAMT         0x108C
+#define E1000_DEV_ID_82573L              0x109A
+#define E1000_DEV_ID_82574L              0x10D3
+#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT     0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT     0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT     0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT     0x10BB
+
+#define E1000_DEV_ID_ICH8_IGP_M_AMT      0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT        0x104A
+#define E1000_DEV_ID_ICH8_IGP_C          0x104B
+#define E1000_DEV_ID_ICH8_IFE            0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT         0x10C4
+#define E1000_DEV_ID_ICH8_IFE_G          0x10C5
+#define E1000_DEV_ID_ICH8_IGP_M          0x104D
+
+/* Device Specific Register Defaults */
+#define E1000_PHY_ID2_82541x 0x380
+#define E1000_PHY_ID2_82544x 0xC30
+#define E1000_PHY_ID2_8254xx_DEFAULT 0xC20 /* 82540x, 82545x, and 82546x */
+#define E1000_PHY_ID2_82573x 0xCC0
+#define E1000_PHY_ID2_82574x 0xCB1
+
+/* Register Set. (82543, 82544)
+ *
+ * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
+ * These registers are physically located on the NIC, but are mapped into the
+ * host memory address space.
+ *
+ * RW - register is both readable and writable
+ * RO - register is read only
+ * WO - register is write only
+ * R/clr - register is read only and is cleared when read
+ * A - register array
+ */
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_FLA      0x0001C  /* Flash Access - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_SCTL     0x00024  /* SerDes Control - RW */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
+#define E1000_RCTL     0x00100  /* RX Control - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TCTL     0x00400  /* TX Control - RW */
+#define E1000_TCTL_EXT 0x00404  /* Extended TX Control - RW */
+#define E1000_TIPG     0x00410  /* TX Inter-packet gap -RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_EEMNGDATA    0x01014 /* MNG EEPROM Read/Write data */
+#define E1000_FLMNGCTL     0x01018 /* MNG Flash Control */
+#define E1000_FLMNGDATA    0x0101C /* MNG FLASH Read data */
+#define E1000_FLMNGCNT     0x01020 /* MNG FLASH Read Counter */
+#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
+#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTL_A  0x00168  /* Alias to FCRTL */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_RDFH     0x02410  /* Receive Data FIFO Head Register - RW */
+#define E1000_RDFH_A   0x08000  /* Alias to RDFH */
+#define E1000_RDFT     0x02418  /* Receive Data FIFO Tail Register - RW */
+#define E1000_RDFT_A   0x08008  /* Alias to RDFT */
+#define E1000_RDFHS    0x02420  /* Receive Data FIFO Head Saved Register - RW */
+#define E1000_RDFTS    0x02428  /* Receive Data FIFO Tail Saved Register - RW */
+#define E1000_RDFPC    0x02430  /* Receive Data FIFO Packet Count - RW */
+#define E1000_TDFH     0x03410  /* TX Data FIFO Head - RW */
+#define E1000_TDFH_A   0x08010  /* Alias to TDFH */
+#define E1000_TDFT     0x03418  /* TX Data FIFO Tail - RW */
+#define E1000_TDFT_A   0x08018  /* Alias to TDFT */
+#define E1000_TDFHS    0x03420  /* TX Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428  /* TX Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430  /* TX Data FIFO Packet Count - RW */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* TX-No CRS - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON RX Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON TX Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF RX Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF TX Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control RX Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets RX (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets RX (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets RX (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets RX (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets RX (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets RX (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets RX Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets RX Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets RX Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets TX Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets RX Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets RX Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets TX Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets TX Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* RX No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* RX Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* RX Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* RX Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* RX Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets RX Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets TX Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets RX Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets RX High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets TX Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets TX High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets RX - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets TX - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets TX (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets TX (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets TX (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets TX (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets TX (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets TX (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets TX Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
+#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
+#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
+#define E1000_MAVTV0   0x05010  /* Management VLAN TAG Value 0 */
+#define E1000_MAVTV1   0x05014  /* Management VLAN TAG Value 1 */
+#define E1000_MAVTV2   0x05018  /* Management VLAN TAG Value 2 */
+#define E1000_MAVTV3   0x0501c  /* Management VLAN TAG Value 3 */
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_RA_A     0x00040  /* Alias to RA */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_VFTA_A   0x00600  /* Alias to VFTA */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
+#define E1000_MFVAL    0x05824  /* Manageability Filters Valid - RW */
+#define E1000_MDEF     0x05890  /* Manageability Decision Filters - RW Array */
+#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
+#define E1000_FTFT     0x09400  /* Flexible TCO Filter Table - RW Array */
+
+#define E1000_MANC2H     0x05860 /* Management Control To Host - RW */
+#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
+
+#define E1000_GCR       0x05B00 /* PCI-Ex Control */
+#define E1000_FUNCTAG   0x05B08 /* Function-Tag Register */
+#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_GSCN_0    0x05B20 /* 3GIO Statistic Counter Register #0 */
+#define E1000_GSCN_1    0x05B24 /* 3GIO Statistic Counter Register #1 */
+#define E1000_GSCN_2    0x05B28 /* 3GIO Statistic Counter Register #2 */
+#define E1000_GSCN_3    0x05B2C /* 3GIO Statistic Counter Register #3 */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_PBACLR    0x05B68 /* MSI-X PBA Clear */
+
+#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
+#define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */
+#define E1000_TIMINCA    0x0B608 /* Increment attributes register - RW */
+#define E1000_RXSTMPL    0x0B624 /* Rx timestamp Low - RO */
+#define E1000_RXSTMPH    0x0B628 /* Rx timestamp High - RO */
+#define E1000_TXSTMPL    0x0B618 /* Tx timestamp value Low - RO */
+#define E1000_TXSTMPH    0x0B61C /* Tx timestamp value High - RO */
+#define E1000_SYSTIML    0x0B600 /* System time register Low - RO */
+#define E1000_SYSTIMH    0x0B604 /* System time register High - RO */
+#define E1000_TIMINCA    0x0B608 /* Increment attributes register - RW */
+#define E1000_RXSATRL    0x0B62C /* Rx timestamp attribute low - RO */
+#define E1000_RXSATRH    0x0B630 /* Rx timestamp attribute high - RO */
+#define E1000_TIMADJL    0x0B60C /* Time Adjustment Offset register Low - RW */
+#define E1000_TIMADJH    0x0B610 /* Time Adjustment Offset register High - RW */
+
+/* RSS registers */
+#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
+#define E1000_RETA      0x05C00 /* Redirection Table - RW Array */
+#define E1000_RSSRK     0x05C80 /* RSS Random Key - RW Array */
+
+#define E1000_RETA_IDX(hash)        ((hash) & (BIT(7) - 1))
+#define E1000_RETA_VAL(reta, hash)  (((uint8_t *)(reta))[E1000_RETA_IDX(hash)])
+
+#define E1000_MRQC_EN_TCPIPV4(mrqc) ((mrqc) & BIT(16))
+#define E1000_MRQC_EN_IPV4(mrqc)    ((mrqc) & BIT(17))
+#define E1000_MRQC_EN_TCPIPV6(mrqc) ((mrqc) & BIT(18))
+#define E1000_MRQC_EN_IPV6EX(mrqc)  ((mrqc) & BIT(19))
+#define E1000_MRQC_EN_IPV6(mrqc)    ((mrqc) & BIT(20))
+
+#define E1000_MRQ_RSS_TYPE_NONE     (0)
+#define E1000_MRQ_RSS_TYPE_IPV4TCP  (1)
+#define E1000_MRQ_RSS_TYPE_IPV4     (2)
+#define E1000_MRQ_RSS_TYPE_IPV6TCP  (3)
+#define E1000_MRQ_RSS_TYPE_IPV6EX   (4)
+#define E1000_MRQ_RSS_TYPE_IPV6     (5)
+
+#define E1000_ICR_ASSERTED BIT(31)
+#define E1000_EIAC_MASK    0x01F00000
+
+/* RFCTL register bits */
+#define E1000_RFCTL_ISCSI_DIS           0x00000001
+#define E1000_RFCTL_NFSW_DIS            0x00000040
+#define E1000_RFCTL_NFSR_DIS            0x00000080
+#define E1000_RFCTL_IPV6_DIS            0x00000400
+#define E1000_RFCTL_IPV6_XSUM_DIS       0x00000800
+#define E1000_RFCTL_IPFRSP_DIS          0x00004000
+#define E1000_RFCTL_EXTEN               0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
+
+/* TARC* parsing */
+#define E1000_TARC_ENABLE BIT(10)
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
+
+#define E1000_SWSM2_LOCK        0x00000002 /* Secondary driver semaphore bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO           0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG         0x00000400 /* RX /c/ ordered set */
+#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW       0x00008000
+#define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
+#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_ICR_HOST_ARB_PAR  0x00400000 /* host arb read buffer parity error */
+#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
+#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW bit in the FWSM */
+#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates an interrupt */
+#define E1000_ICR_EPRST         0x00100000 /* ME handware reset occurs */
+#define E1000_ICR_RXQ0          0x00100000 /* Rx Queue 0 Interrupt */
+#define E1000_ICR_RXQ1          0x00200000 /* Rx Queue 1 Interrupt */
+#define E1000_ICR_TXQ0          0x00400000 /* Tx Queue 0 Interrupt */
+#define E1000_ICR_TXQ1          0x00800000 /* Tx Queue 1 Interrupt */
+#define E1000_ICR_OTHER         0x01000000 /* Other Interrupts */
+
+#define E1000_ICR_OTHER_CAUSES (E1000_ICR_LSC  | \
+                                E1000_ICR_RXO  | \
+                                E1000_ICR_MDAC | \
+                                E1000_ICR_SRPD | \
+                                E1000_ICR_ACK  | \
+                                E1000_ICR_MNG)
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
+#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD      E1000_ICR_SRPD
+#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
+#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
+#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICS_DSW       E1000_ICR_DSW
+#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
+#define E1000_ICS_EPRST     E1000_ICR_EPRST
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
+#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD      E1000_ICR_SRPD
+#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMS_RXQ0      E1000_ICR_RXQ0
+#define E1000_IMS_RXQ1      E1000_ICR_RXQ1
+#define E1000_IMS_TXQ0      E1000_ICR_TXQ0
+#define E1000_IMS_TXQ1      E1000_ICR_TXQ1
+#define E1000_IMS_OTHER     E1000_ICR_OTHER
+#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
+#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
+#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMS_DSW       E1000_ICR_DSW
+#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMS_EPRST     E1000_ICR_EPRST
+
+/* Interrupt Mask Clear */
+#define E1000_IMC_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_IMC_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMC_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMC_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMC_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMC_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMC_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMC_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMC_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
+#define E1000_IMC_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMC_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMC_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMC_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMC_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMC_SRPD      E1000_ICR_SRPD
+#define E1000_IMC_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMC_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMC_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_IMC_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_IMC_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_IMC_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
+#define E1000_IMC_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
+#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMC_DSW       E1000_ICR_DSW
+#define E1000_IMC_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMC_EPRST     E1000_ICR_EPRST
+
+/* Receive Control */
+#define E1000_RCTL_RST            0x00000001    /* Software reset */
+#define E1000_RCTL_EN             0x00000002    /* enable */
+#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
+#define E1000_RCTL_UPE            0x00000008    /* unicast promiscuous enable */
+#define E1000_RCTL_MPE            0x00000010    /* multicast promiscuous enab */
+#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
+#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
+#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
+#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
+#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
+#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
+#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
+#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
+#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
+#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
+#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
+#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
+
+
+#define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
+#define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
+#define E1000_EEPROM_RW_REG_DATA   16   /* Offset to data in EEPROM read/write registers */
+#define E1000_EEPROM_RW_REG_DONE   0x10 /* Offset to READ/WRITE done bit */
+#define E1000_EEPROM_RW_REG_START  1    /* First bit for telling part to start operation */
+#define E1000_EEPROM_RW_ADDR_SHIFT 8    /* Shift to the address bits */
+#define E1000_EEPROM_POLL_WRITE    1    /* Flag for polling for write complete */
+#define E1000_EEPROM_POLL_READ     0    /* Flag for polling for read complete */
+
+/* 82574 EERD/EEWR registers layout */
+#define E1000_EERW_START        BIT(0)
+#define E1000_EERW_DONE         BIT(1)
+#define E1000_EERW_ADDR_SHIFT   2
+#define E1000_EERW_ADDR_MASK    ((1L << 14) - 1)
+#define E1000_EERW_DATA_SHIFT   16
+#define E1000_EERW_DATA_MASK   ((1L << 16) - 1)
+
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
+#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */
+#define E1000_CTRL_SPD_SHIFT 8          /* Speed Select Shift */
+
+#define E1000_CTRL_EXT_ASDCHK  0x00001000 /* auto speed detection check */
+#define E1000_CTRL_EXT_EE_RST  0x00002000 /* EEPROM reset */
+#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */
+#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
+#define E1000_CTRL_EXT_EIAME   0x01000000
+#define E1000_CTRL_EXT_IAME    0x08000000 /* Int ACK Auto-mask */
+#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
+#define E1000_CTRL_EXT_INT_TIMERS_CLEAR_ENA 0x20000000
+#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
+
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_ADVD3WUC 0x00100000  /* D3 WUC */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000  /* Initiate an interrupt to manageability engine */
+
+/* Device Status */
+#define E1000_STATUS_FD                 0x00000001 /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU                 0x00000002 /* Link up.0=no,1=link */
+#define E1000_STATUS_SPEED_10           0x00000000 /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100          0x00000040 /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000         0x00000080 /* Speed 1000Mb/s */
+#define E1000_STATUS_PHYRA              0x00000400 /* PHY Reset Asserted */
+#define E1000_STATUS_GIO_MASTER_ENABLE  0x00080000
+
+/* EEPROM/Flash Control */
+#define E1000_EECD_SK        0x00000001 /* EEPROM Clock */
+#define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
+#define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030
+#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
+#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
+                                         * (0-small, 1-large) */
+#define E1000_EECD_TYPE      0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
+#ifndef E1000_EEPROM_GRANT_ATTEMPTS
+#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
+#define E1000_EECD_AUTO_RD          0x00000200  /* EEPROM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* EEprom Size */
+#define E1000_EECD_SIZE_EX_SHIFT    11
+#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+
+
+#define E1000_EECD_SECVAL_SHIFT      22
+#define E1000_STM_OPCODE     0xDB00
+#define E1000_HICR_FW_RESET  0xC0
+
+#define E1000_SHADOW_RAM_WORDS     2048
+#define E1000_ICH_NVM_SIG_WORD     0x13
+#define E1000_ICH_NVM_SIG_MASK     0xC0
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* Rx Interrupt Delay Timer */
+#define E1000_RDTR_FPD       BIT(31)
+
+/* Tx Interrupt Delay Timer */
+#define E1000_TIDV_FPD       BIT(31)
+
+/* Delay increments in nanoseconds for delayed interrupts registers */
+#define E1000_INTR_DELAY_NS_RES (1024)
+
+/* Delay increments in nanoseconds for interrupt throttling registers */
+#define E1000_INTR_THROTTLING_NS_RES (256)
+
+/* EEPROM Commands - Microwire */
+#define EEPROM_READ_OPCODE_MICROWIRE  0x6  /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5  /* EEPROM write opcode */
+#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7  /* EEPROM erase opcode */
+#define EEPROM_EWEN_OPCODE_MICROWIRE  0x13 /* EEPROM erase/write enable */
+#define EEPROM_EWDS_OPCODE_MICROWIRE  0x10 /* EEPROM erast/write disable */
+
+/* EEPROM Word Offsets */
+#define EEPROM_COMPAT                 0x0003
+#define EEPROM_ID_LED_SETTINGS        0x0004
+#define EEPROM_VERSION                0x0005
+#define EEPROM_SERDES_AMPLITUDE       0x0006 /* For SERDES output amplitude adjustment. */
+#define EEPROM_PHY_CLASS_WORD         0x0007
+#define EEPROM_INIT_CONTROL1_REG      0x000A
+#define EEPROM_INIT_CONTROL2_REG      0x000F
+#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010
+#define EEPROM_INIT_CONTROL3_PORT_B   0x0014
+#define EEPROM_INIT_3GIO_3            0x001A
+#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020
+#define EEPROM_INIT_CONTROL3_PORT_A   0x0024
+#define EEPROM_CFG                    0x0012
+#define EEPROM_FLASH_VERSION          0x0032
+#define EEPROM_CHECKSUM_REG           0x003F
+
+#define E1000_EEPROM_CFG_DONE         0x00040000   /* MNG config cycle done */
+#define E1000_EEPROM_CFG_DONE_PORT_1  0x00080000   /* ...for second port */
+
+/* PCI Express Control */
+/* 3GIO Control Register - GCR (0x05B00; RW) */
+#define E1000_L0S_ADJUST              (1 << 9)
+#define E1000_L1_ENTRY_LATENCY_MSB    (1 << 23)
+#define E1000_L1_ENTRY_LATENCY_LSB    (1 << 25 | 1 << 26)
+
+#define E1000_L0S_ADJUST              (1 << 9)
+#define E1000_L1_ENTRY_LATENCY_MSB    (1 << 23)
+#define E1000_L1_ENTRY_LATENCY_LSB    (1 << 25 | 1 << 26)
+
+#define E1000_GCR_RO_BITS             (1 << 23 | 1 << 25 | 1 << 26)
+
+/* MSI-X PBA Clear register */
+#define E1000_PBACLR_VALID_MASK       (BIT(5) - 1)
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_CMD_SNAP   0x40000000 /* Update SNAP header */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+#define E1000_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
+
+/* Legacy Receive Descriptor */
+struct e1000_rx_desc {
+    uint64_t buffer_addr; /* Address of the descriptor's data buffer */
+    uint16_t length;     /* Length of data DMAed into data buffer */
+    uint16_t csum;       /* Packet checksum */
+    uint8_t status;      /* Descriptor status */
+    uint8_t errors;      /* Descriptor Errors */
+    uint16_t special;
+};
+
+/* Extended Receive Descriptor */
+union e1000_rx_desc_extended {
+    struct {
+        uint64_t buffer_addr;
+        uint64_t reserved;
+    } read;
+    struct {
+        struct {
+            uint32_t mrq;           /* Multiple Rx Queues */
+            union {
+                uint32_t rss;       /* RSS Hash */
+                struct {
+                    uint16_t ip_id; /* IP id */
+                    uint16_t csum;  /* Packet Checksum */
+                } csum_ip;
+            } hi_dword;
+        } lower;
+        struct {
+            uint32_t status_error;  /* ext status/error */
+            uint16_t length;
+            uint16_t vlan;          /* VLAN tag */
+        } upper;
+    } wb;                           /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+
+/* Number of packet split data buffers (not including the header buffer) */
+#define PS_PAGE_BUFFERS    (MAX_PS_BUFFERS - 1)
+
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+    struct {
+        /* one buffer for protocol header(s), three data buffers */
+        uint64_t buffer_addr[MAX_PS_BUFFERS];
+    } read;
+    struct {
+        struct {
+            uint32_t mrq;          /* Multiple Rx Queues */
+            union {
+                uint32_t rss;          /* RSS Hash */
+                struct {
+                    uint16_t ip_id;    /* IP id */
+                    uint16_t csum;     /* Packet Checksum */
+                } csum_ip;
+            } hi_dword;
+        } lower;
+        struct {
+            uint32_t status_error;     /* ext status/error */
+            uint16_t length0;      /* length of buffer 0 */
+            uint16_t vlan;         /* VLAN tag */
+        } middle;
+        struct {
+            uint16_t header_status;
+            /* length of buffers 1-3 */
+            uint16_t length[PS_PAGE_BUFFERS];
+        } upper;
+        uint64_t reserved;
+    } wb; /* writeback */
+};
+
+/* Receive Checksum Control bits */
+#define E1000_RXCSUM_IPOFLD     0x100   /* IP Checksum Offload Enable */
+#define E1000_RXCSUM_TUOFLD     0x200   /* TCP/UDP Checksum Offload Enable */
+#define E1000_RXCSUM_PCSD       0x2000  /* Packet Checksum Disable */
+
+#define E1000_RING_DESC_LEN       (16)
+#define E1000_RING_DESC_LEN_SHIFT (4)
+
+#define E1000_MIN_RX_DESC_LEN   E1000_RING_DESC_LEN
+
+/* Receive Descriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
+#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
+#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 13
+#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+/* RX packet types */
+#define E1000_RXD_PKT_MAC       (0)
+#define E1000_RXD_PKT_IP4       (1)
+#define E1000_RXD_PKT_IP4_XDP   (2)
+#define E1000_RXD_PKT_IP6       (5)
+#define E1000_RXD_PKT_IP6_XDP   (6)
+
+#define E1000_RXD_PKT_TYPE(t) ((t) << 16)
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP        0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK  0x000003FF
+
+/* Receive Address */
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+    union {
+        uint32_t ip_config;
+        struct {
+            uint8_t ipcss;      /* IP checksum start */
+            uint8_t ipcso;      /* IP checksum offset */
+            uint16_t ipcse;     /* IP checksum end */
+        } ip_fields;
+    } lower_setup;
+    union {
+        uint32_t tcp_config;
+        struct {
+            uint8_t tucss;      /* TCP checksum start */
+            uint8_t tucso;      /* TCP checksum offset */
+            uint16_t tucse;     /* TCP checksum end */
+        } tcp_fields;
+    } upper_setup;
+    uint32_t cmd_and_length;    /* */
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t hdr_len;    /* Header length */
+            uint16_t mss;       /* Maximum segment size */
+        } fields;
+    } tcp_seg_setup;
+};
+
+/* Filters */
+#define E1000_NUM_UNICAST          16  /* Unicast filter entries */
+#define E1000_MC_TBL_SIZE          128 /* Multicast Filter Table (4096 bits) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery
+                                             * Filtering */
+#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
+#define E1000_MANC_DIS_IP_CHK_ARP  0x10000000 /* Disable IP address chacking */
+                                              /*for ARP packets - in 82574 */
+#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000 /* Enable MAC address
+                                                    * filtering */
+#define E1000_MANC_EN_MNG2HOST   0x00200000 /* Enable MNG packets to host
+                                             * memory */
+#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000 /* Enable IP address
+                                                    * filtering */
+#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN         0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
+
+/* FACTPS Control */
+#define E1000_FACTPS_LAN0_ON     0x00000004 /* Lan 0 enable */
+
+/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
+#define EEPROM_SUM 0xBABA
+
+/* I/O-Mapped Access to Internal Registers, Memories, and Flash */
+#define E1000_IOADDR 0x00
+#define E1000_IODATA 0x04
+
+#define E1000_VFTA_ENTRY_SHIFT          5
+#define E1000_VFTA_ENTRY_MASK           0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F
+
+#endif /* HW_E1000_REGS_H */
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 04/13] igb: Copy e1000e code
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
                   ` (2 preceding siblings ...)
  2023-01-14  4:09 ` [PATCH v2 03/13] e1000: Split header files Akihiko Odaki
@ 2023-01-14  4:09 ` Akihiko Odaki
  2023-01-14  4:09 ` [PATCH v2 05/13] igb: Rename identifiers Akihiko Odaki
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:09 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich, Gal Hammer

Start off igb implementation by copying e1000e code first as igb
resembles e1000e.

Signed-off-by: Gal Hammer <gal.hammer@sap.com>
Signed-off-by: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 MAINTAINERS         |    5 +
 hw/net/igb.c        |  727 +++++++++
 hw/net/igb_common.h |  102 ++
 hw/net/igb_core.c   | 3568 +++++++++++++++++++++++++++++++++++++++++++
 hw/net/igb_core.h   |  156 ++
 5 files changed, 4558 insertions(+)
 create mode 100644 hw/net/igb.c
 create mode 100644 hw/net/igb_common.h
 create mode 100644 hw/net/igb_core.c
 create mode 100644 hw/net/igb_core.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 6982be48c6..8c59cd28a3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2218,6 +2218,11 @@ S: Maintained
 F: hw/net/e1000e*
 F: tests/qtest/fuzz-e1000e-test.c
 
+igb
+M: Akihiko Odaki <akihiko.odaki@daynix.com>
+S: Maintained
+F: hw/net/igb*
+
 eepro100
 M: Stefan Weil <sw@weilnetz.de>
 S: Maintained
diff --git a/hw/net/igb.c b/hw/net/igb.c
new file mode 100644
index 0000000000..a0c4693330
--- /dev/null
+++ b/hw/net/igb.c
@@ -0,0 +1,727 @@
+/*
+ * QEMU INTEL 82574 GbE NIC emulation
+ *
+ * Software developer's manuals:
+ * http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
+ *
+ * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Leonid Bloch <leonid@daynix.com>
+ * Yan Vugenfirer <yan@daynix.com>
+ *
+ * Based on work done by:
+ * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
+ * Copyright (c) 2008 Qumranet
+ * Based on work done by:
+ * Copyright (c) 2007 Dan Aloni
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "net/eth.h"
+#include "net/net.h"
+#include "net/tap.h"
+#include "qemu/module.h"
+#include "qemu/range.h"
+#include "sysemu/sysemu.h"
+#include "hw/hw.h"
+#include "hw/net/mii.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/msix.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+
+#include "e1000_common.h"
+#include "e1000x_common.h"
+#include "e1000e_core.h"
+
+#include "trace.h"
+#include "qapi/error.h"
+#include "qom/object.h"
+
+#define TYPE_E1000E "e1000e"
+OBJECT_DECLARE_SIMPLE_TYPE(E1000EState, E1000E)
+
+struct E1000EState {
+    PCIDevice parent_obj;
+    NICState *nic;
+    NICConf conf;
+
+    MemoryRegion mmio;
+    MemoryRegion flash;
+    MemoryRegion io;
+    MemoryRegion msix;
+
+    uint32_t ioaddr;
+
+    uint16_t subsys_ven;
+    uint16_t subsys;
+
+    uint16_t subsys_ven_used;
+    uint16_t subsys_used;
+
+    bool disable_vnet;
+
+    E1000ECore core;
+    bool init_vet;
+};
+
+#define E1000E_MMIO_IDX     0
+#define E1000E_FLASH_IDX    1
+#define E1000E_IO_IDX       2
+#define E1000E_MSIX_IDX     3
+
+#define E1000E_MMIO_SIZE    (128 * KiB)
+#define E1000E_FLASH_SIZE   (128 * KiB)
+#define E1000E_IO_SIZE      (32)
+#define E1000E_MSIX_SIZE    (16 * KiB)
+
+#define E1000E_MSIX_TABLE   (0x0000)
+#define E1000E_MSIX_PBA     (0x2000)
+
+static uint64_t
+e1000e_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+    E1000EState *s = opaque;
+    return e1000e_core_read(&s->core, addr, size);
+}
+
+static void
+e1000e_mmio_write(void *opaque, hwaddr addr,
+                   uint64_t val, unsigned size)
+{
+    E1000EState *s = opaque;
+    e1000e_core_write(&s->core, addr, val, size);
+}
+
+static bool
+e1000e_io_get_reg_index(E1000EState *s, uint32_t *idx)
+{
+    if (s->ioaddr < 0x1FFFF) {
+        *idx = s->ioaddr;
+        return true;
+    }
+
+    if (s->ioaddr < 0x7FFFF) {
+        trace_e1000e_wrn_io_addr_undefined(s->ioaddr);
+        return false;
+    }
+
+    if (s->ioaddr < 0xFFFFF) {
+        trace_e1000e_wrn_io_addr_flash(s->ioaddr);
+        return false;
+    }
+
+    trace_e1000e_wrn_io_addr_unknown(s->ioaddr);
+    return false;
+}
+
+static uint64_t
+e1000e_io_read(void *opaque, hwaddr addr, unsigned size)
+{
+    E1000EState *s = opaque;
+    uint32_t idx = 0;
+    uint64_t val;
+
+    switch (addr) {
+    case E1000_IOADDR:
+        trace_e1000e_io_read_addr(s->ioaddr);
+        return s->ioaddr;
+    case E1000_IODATA:
+        if (e1000e_io_get_reg_index(s, &idx)) {
+            val = e1000e_core_read(&s->core, idx, sizeof(val));
+            trace_e1000e_io_read_data(idx, val);
+            return val;
+        }
+        return 0;
+    default:
+        trace_e1000e_wrn_io_read_unknown(addr);
+        return 0;
+    }
+}
+
+static void
+e1000e_io_write(void *opaque, hwaddr addr,
+                uint64_t val, unsigned size)
+{
+    E1000EState *s = opaque;
+    uint32_t idx = 0;
+
+    switch (addr) {
+    case E1000_IOADDR:
+        trace_e1000e_io_write_addr(val);
+        s->ioaddr = (uint32_t) val;
+        return;
+    case E1000_IODATA:
+        if (e1000e_io_get_reg_index(s, &idx)) {
+            trace_e1000e_io_write_data(idx, val);
+            e1000e_core_write(&s->core, idx, val, sizeof(val));
+        }
+        return;
+    default:
+        trace_e1000e_wrn_io_write_unknown(addr);
+        return;
+    }
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read = e1000e_mmio_read,
+    .write = e1000e_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps io_ops = {
+    .read = e1000e_io_read,
+    .write = e1000e_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static bool
+e1000e_nc_can_receive(NetClientState *nc)
+{
+    E1000EState *s = qemu_get_nic_opaque(nc);
+    return e1000e_can_receive(&s->core);
+}
+
+static ssize_t
+e1000e_nc_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
+{
+    E1000EState *s = qemu_get_nic_opaque(nc);
+    return e1000e_receive_iov(&s->core, iov, iovcnt);
+}
+
+static ssize_t
+e1000e_nc_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    E1000EState *s = qemu_get_nic_opaque(nc);
+    return e1000e_receive(&s->core, buf, size);
+}
+
+static void
+e1000e_set_link_status(NetClientState *nc)
+{
+    E1000EState *s = qemu_get_nic_opaque(nc);
+    e1000e_core_set_link_status(&s->core);
+}
+
+static NetClientInfo net_e1000e_info = {
+    .type = NET_CLIENT_DRIVER_NIC,
+    .size = sizeof(NICState),
+    .can_receive = e1000e_nc_can_receive,
+    .receive = e1000e_nc_receive,
+    .receive_iov = e1000e_nc_receive_iov,
+    .link_status_changed = e1000e_set_link_status,
+};
+
+/*
+ * EEPROM (NVM) contents documented in Table 36, section 6.1
+ * and generally 6.1.2 Software accessed words.
+ */
+static const uint16_t e1000e_eeprom_template[64] = {
+  /*        Address        |    Compat.    | ImVer |   Compat.     */
+    0x0000, 0x0000, 0x0000, 0x0420, 0xf746, 0x2010, 0xffff, 0xffff,
+  /*      PBA      |ICtrl1 | SSID  | SVID  | DevID |-------|ICtrl2 */
+    0x0000, 0x0000, 0x026b, 0x0000, 0x8086, 0x0000, 0x0000, 0x8058,
+  /*    NVM words 1,2,3    |-------------------------------|PCI-EID*/
+    0x0000, 0x2001, 0x7e7c, 0xffff, 0x1000, 0x00c8, 0x0000, 0x2704,
+  /* PCIe Init. Conf 1,2,3 |PCICtrl|PHY|LD1|-------| RevID | LD0,2 */
+    0x6cc9, 0x3150, 0x070e, 0x460b, 0x2d84, 0x0100, 0xf000, 0x0706,
+  /* FLPAR |FLANADD|LAN-PWR|FlVndr |ICtrl3 |APTSMBA|APTRxEP|APTSMBC*/
+    0x6000, 0x0080, 0x0f04, 0x7fff, 0x4f01, 0xc600, 0x0000, 0x20ff,
+  /* APTIF | APTMC |APTuCP |LSWFWID|MSWFWID|NC-SIMC|NC-SIC | VPDP  */
+    0x0028, 0x0003, 0x0000, 0x0000, 0x0000, 0x0003, 0x0000, 0xffff,
+  /*                            SW Section                         */
+    0x0100, 0xc000, 0x121c, 0xc007, 0xffff, 0xffff, 0xffff, 0xffff,
+  /*                      SW Section                       |CHKSUM */
+    0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0120, 0xffff, 0x0000,
+};
+
+static void e1000e_core_realize(E1000EState *s)
+{
+    s->core.owner = &s->parent_obj;
+    s->core.owner_nic = s->nic;
+}
+
+static void
+e1000e_unuse_msix_vectors(E1000EState *s, int num_vectors)
+{
+    int i;
+    for (i = 0; i < num_vectors; i++) {
+        msix_vector_unuse(PCI_DEVICE(s), i);
+    }
+}
+
+static void
+e1000e_use_msix_vectors(E1000EState *s, int num_vectors)
+{
+    int i;
+    for (i = 0; i < num_vectors; i++) {
+        msix_vector_use(PCI_DEVICE(s), i);
+    }
+}
+
+static void
+e1000e_init_msix(E1000EState *s)
+{
+    int res = msix_init(PCI_DEVICE(s), E1000E_MSIX_VEC_NUM,
+                        &s->msix,
+                        E1000E_MSIX_IDX, E1000E_MSIX_TABLE,
+                        &s->msix,
+                        E1000E_MSIX_IDX, E1000E_MSIX_PBA,
+                        0xA0, NULL);
+
+    if (res < 0) {
+        trace_e1000e_msix_init_fail(res);
+    } else {
+        e1000e_use_msix_vectors(s, E1000E_MSIX_VEC_NUM);
+    }
+}
+
+static void
+e1000e_cleanup_msix(E1000EState *s)
+{
+    if (msix_present(PCI_DEVICE(s))) {
+        e1000e_unuse_msix_vectors(s, E1000E_MSIX_VEC_NUM);
+        msix_uninit(PCI_DEVICE(s), &s->msix, &s->msix);
+    }
+}
+
+static void
+e1000e_init_net_peer(E1000EState *s, PCIDevice *pci_dev, uint8_t *macaddr)
+{
+    DeviceState *dev = DEVICE(pci_dev);
+    NetClientState *nc;
+    int i;
+
+    s->nic = qemu_new_nic(&net_e1000e_info, &s->conf,
+        object_get_typename(OBJECT(s)), dev->id, s);
+
+    s->core.max_queue_num = s->conf.peers.queues ? s->conf.peers.queues - 1 : 0;
+
+    trace_e1000e_mac_set_permanent(MAC_ARG(macaddr));
+    memcpy(s->core.permanent_mac, macaddr, sizeof(s->core.permanent_mac));
+
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), macaddr);
+
+    /* Setup virtio headers */
+    if (s->disable_vnet) {
+        s->core.has_vnet = false;
+        trace_e1000e_cfg_support_virtio(false);
+        return;
+    } else {
+        s->core.has_vnet = true;
+    }
+
+    for (i = 0; i < s->conf.peers.queues; i++) {
+        nc = qemu_get_subqueue(s->nic, i);
+        if (!nc->peer || !qemu_has_vnet_hdr(nc->peer)) {
+            s->core.has_vnet = false;
+            trace_e1000e_cfg_support_virtio(false);
+            return;
+        }
+    }
+
+    trace_e1000e_cfg_support_virtio(true);
+
+    for (i = 0; i < s->conf.peers.queues; i++) {
+        nc = qemu_get_subqueue(s->nic, i);
+        qemu_set_vnet_hdr_len(nc->peer, sizeof(struct virtio_net_hdr));
+        qemu_using_vnet_hdr(nc->peer, true);
+    }
+}
+
+static inline uint64_t
+e1000e_gen_dsn(uint8_t *mac)
+{
+    return (uint64_t)(mac[5])        |
+           (uint64_t)(mac[4])  << 8  |
+           (uint64_t)(mac[3])  << 16 |
+           (uint64_t)(0x00FF)  << 24 |
+           (uint64_t)(0x00FF)  << 32 |
+           (uint64_t)(mac[2])  << 40 |
+           (uint64_t)(mac[1])  << 48 |
+           (uint64_t)(mac[0])  << 56;
+}
+
+static int
+e1000e_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc)
+{
+    Error *local_err = NULL;
+    int ret = pci_add_capability(pdev, PCI_CAP_ID_PM, offset,
+                                 PCI_PM_SIZEOF, &local_err);
+
+    if (local_err) {
+        error_report_err(local_err);
+        return ret;
+    }
+
+    pci_set_word(pdev->config + offset + PCI_PM_PMC,
+                 PCI_PM_CAP_VER_1_1 |
+                 pmc);
+
+    pci_set_word(pdev->wmask + offset + PCI_PM_CTRL,
+                 PCI_PM_CTRL_STATE_MASK |
+                 PCI_PM_CTRL_PME_ENABLE |
+                 PCI_PM_CTRL_DATA_SEL_MASK);
+
+    pci_set_word(pdev->w1cmask + offset + PCI_PM_CTRL,
+                 PCI_PM_CTRL_PME_STATUS);
+
+    return ret;
+}
+
+static void e1000e_write_config(PCIDevice *pci_dev, uint32_t address,
+                                uint32_t val, int len)
+{
+    E1000EState *s = E1000E(pci_dev);
+
+    pci_default_write_config(pci_dev, address, val, len);
+
+    if (range_covers_byte(address, len, PCI_COMMAND) &&
+        (pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
+        e1000e_start_recv(&s->core);
+    }
+}
+
+static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp)
+{
+    static const uint16_t e1000e_pmrb_offset = 0x0C8;
+    static const uint16_t e1000e_pcie_offset = 0x0E0;
+    static const uint16_t e1000e_aer_offset =  0x100;
+    static const uint16_t e1000e_dsn_offset =  0x140;
+    E1000EState *s = E1000E(pci_dev);
+    uint8_t *macaddr;
+    int ret;
+
+    trace_e1000e_cb_pci_realize();
+
+    pci_dev->config_write = e1000e_write_config;
+
+    pci_dev->config[PCI_CACHE_LINE_SIZE] = 0x10;
+    pci_dev->config[PCI_INTERRUPT_PIN] = 1;
+
+    pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, s->subsys_ven);
+    pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, s->subsys);
+
+    s->subsys_ven_used = s->subsys_ven;
+    s->subsys_used = s->subsys;
+
+    /* Define IO/MMIO regions */
+    memory_region_init_io(&s->mmio, OBJECT(s), &mmio_ops, s,
+                          "e1000e-mmio", E1000E_MMIO_SIZE);
+    pci_register_bar(pci_dev, E1000E_MMIO_IDX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
+
+    /*
+     * We provide a dummy implementation for the flash BAR
+     * for drivers that may theoretically probe for its presence.
+     */
+    memory_region_init(&s->flash, OBJECT(s),
+                       "e1000e-flash", E1000E_FLASH_SIZE);
+    pci_register_bar(pci_dev, E1000E_FLASH_IDX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &s->flash);
+
+    memory_region_init_io(&s->io, OBJECT(s), &io_ops, s,
+                          "e1000e-io", E1000E_IO_SIZE);
+    pci_register_bar(pci_dev, E1000E_IO_IDX,
+                     PCI_BASE_ADDRESS_SPACE_IO, &s->io);
+
+    memory_region_init(&s->msix, OBJECT(s), "e1000e-msix",
+                       E1000E_MSIX_SIZE);
+    pci_register_bar(pci_dev, E1000E_MSIX_IDX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &s->msix);
+
+    /* Create networking backend */
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    macaddr = s->conf.macaddr.a;
+
+    e1000e_init_msix(s);
+
+    if (pcie_endpoint_cap_v1_init(pci_dev, e1000e_pcie_offset) < 0) {
+        hw_error("Failed to initialize PCIe capability");
+    }
+
+    ret = msi_init(PCI_DEVICE(s), 0xD0, 1, true, false, NULL);
+    if (ret) {
+        trace_e1000e_msi_init_fail(ret);
+    }
+
+    if (e1000e_add_pm_capability(pci_dev, e1000e_pmrb_offset,
+                                  PCI_PM_CAP_DSI) < 0) {
+        hw_error("Failed to initialize PM capability");
+    }
+
+    if (pcie_aer_init(pci_dev, PCI_ERR_VER, e1000e_aer_offset,
+                      PCI_ERR_SIZEOF, NULL) < 0) {
+        hw_error("Failed to initialize AER capability");
+    }
+
+    pcie_dev_ser_num_init(pci_dev, e1000e_dsn_offset,
+                          e1000e_gen_dsn(macaddr));
+
+    e1000e_init_net_peer(s, pci_dev, macaddr);
+
+    /* Initialize core */
+    e1000e_core_realize(s);
+
+    e1000e_core_pci_realize(&s->core,
+                            e1000e_eeprom_template,
+                            sizeof(e1000e_eeprom_template),
+                            macaddr);
+}
+
+static void e1000e_pci_uninit(PCIDevice *pci_dev)
+{
+    E1000EState *s = E1000E(pci_dev);
+
+    trace_e1000e_cb_pci_uninit();
+
+    e1000e_core_pci_uninit(&s->core);
+
+    pcie_aer_exit(pci_dev);
+    pcie_cap_exit(pci_dev);
+
+    qemu_del_nic(s->nic);
+
+    e1000e_cleanup_msix(s);
+    msi_uninit(pci_dev);
+}
+
+static void e1000e_qdev_reset_hold(Object *obj)
+{
+    E1000EState *s = E1000E(obj);
+
+    trace_e1000e_cb_qdev_reset_hold();
+
+    e1000e_core_reset(&s->core);
+
+    if (s->init_vet) {
+        s->core.mac[VET] = ETH_P_VLAN;
+    }
+}
+
+static int e1000e_pre_save(void *opaque)
+{
+    E1000EState *s = opaque;
+
+    trace_e1000e_cb_pre_save();
+
+    e1000e_core_pre_save(&s->core);
+
+    return 0;
+}
+
+static int e1000e_post_load(void *opaque, int version_id)
+{
+    E1000EState *s = opaque;
+
+    trace_e1000e_cb_post_load();
+
+    if ((s->subsys != s->subsys_used) ||
+        (s->subsys_ven != s->subsys_ven_used)) {
+        fprintf(stderr,
+            "ERROR: Cannot migrate while device properties "
+            "(subsys/subsys_ven) differ");
+        return -1;
+    }
+
+    return e1000e_core_post_load(&s->core);
+}
+
+static const VMStateDescription e1000e_vmstate_tx = {
+    .name = "e1000e-tx",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(sum_needed, struct e1000e_tx),
+        VMSTATE_UINT8(props.ipcss, struct e1000e_tx),
+        VMSTATE_UINT8(props.ipcso, struct e1000e_tx),
+        VMSTATE_UINT16(props.ipcse, struct e1000e_tx),
+        VMSTATE_UINT8(props.tucss, struct e1000e_tx),
+        VMSTATE_UINT8(props.tucso, struct e1000e_tx),
+        VMSTATE_UINT16(props.tucse, struct e1000e_tx),
+        VMSTATE_UINT8(props.hdr_len, struct e1000e_tx),
+        VMSTATE_UINT16(props.mss, struct e1000e_tx),
+        VMSTATE_UINT32(props.paylen, struct e1000e_tx),
+        VMSTATE_INT8(props.ip, struct e1000e_tx),
+        VMSTATE_INT8(props.tcp, struct e1000e_tx),
+        VMSTATE_BOOL(props.tse, struct e1000e_tx),
+        VMSTATE_BOOL(cptse, struct e1000e_tx),
+        VMSTATE_BOOL(skip_cp, struct e1000e_tx),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription e1000e_vmstate_intr_timer = {
+    .name = "e1000e-intr-timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_TIMER_PTR(timer, E1000IntrDelayTimer),
+        VMSTATE_BOOL(running, E1000IntrDelayTimer),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define VMSTATE_E1000E_INTR_DELAY_TIMER(_f, _s)                     \
+    VMSTATE_STRUCT(_f, _s, 0,                                       \
+                   e1000e_vmstate_intr_timer, E1000IntrDelayTimer)
+
+#define VMSTATE_E1000E_INTR_DELAY_TIMER_ARRAY(_f, _s, _num)         \
+    VMSTATE_STRUCT_ARRAY(_f, _s, _num, 0,                           \
+                         e1000e_vmstate_intr_timer, E1000IntrDelayTimer)
+
+static const VMStateDescription e1000e_vmstate = {
+    .name = "e1000e",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .pre_save = e1000e_pre_save,
+    .post_load = e1000e_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(parent_obj, E1000EState),
+        VMSTATE_MSIX(parent_obj, E1000EState),
+
+        VMSTATE_UINT32(ioaddr, E1000EState),
+        VMSTATE_UINT32(core.rxbuf_min_shift, E1000EState),
+        VMSTATE_UINT8(core.rx_desc_len, E1000EState),
+        VMSTATE_UINT32_ARRAY(core.rxbuf_sizes, E1000EState,
+                             E1000_PSRCTL_BUFFS_PER_DESC),
+        VMSTATE_UINT32(core.rx_desc_buf_size, E1000EState),
+        VMSTATE_UINT16_ARRAY(core.eeprom, E1000EState, E1000E_EEPROM_SIZE),
+        VMSTATE_UINT16_2DARRAY(core.phy, E1000EState,
+                               E1000E_PHY_PAGES, E1000E_PHY_PAGE_SIZE),
+        VMSTATE_UINT32_ARRAY(core.mac, E1000EState, E1000E_MAC_SIZE),
+        VMSTATE_UINT8_ARRAY(core.permanent_mac, E1000EState, ETH_ALEN),
+
+        VMSTATE_UINT32(core.delayed_causes, E1000EState),
+
+        VMSTATE_UINT16(subsys, E1000EState),
+        VMSTATE_UINT16(subsys_ven, E1000EState),
+
+        VMSTATE_E1000E_INTR_DELAY_TIMER(core.rdtr, E1000EState),
+        VMSTATE_E1000E_INTR_DELAY_TIMER(core.radv, E1000EState),
+        VMSTATE_E1000E_INTR_DELAY_TIMER(core.raid, E1000EState),
+        VMSTATE_E1000E_INTR_DELAY_TIMER(core.tadv, E1000EState),
+        VMSTATE_E1000E_INTR_DELAY_TIMER(core.tidv, E1000EState),
+
+        VMSTATE_E1000E_INTR_DELAY_TIMER(core.itr, E1000EState),
+        VMSTATE_UNUSED(1),
+
+        VMSTATE_E1000E_INTR_DELAY_TIMER_ARRAY(core.eitr, E1000EState,
+                                              E1000E_MSIX_VEC_NUM),
+        VMSTATE_UNUSED(E1000E_MSIX_VEC_NUM),
+
+        VMSTATE_UINT32(core.itr_guest_value, E1000EState),
+        VMSTATE_UINT32_ARRAY(core.eitr_guest_value, E1000EState,
+                             E1000E_MSIX_VEC_NUM),
+
+        VMSTATE_UINT16(core.vet, E1000EState),
+
+        VMSTATE_STRUCT_ARRAY(core.tx, E1000EState, E1000E_NUM_QUEUES, 0,
+                             e1000e_vmstate_tx, struct e1000e_tx),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static PropertyInfo e1000e_prop_disable_vnet,
+                    e1000e_prop_subsys_ven,
+                    e1000e_prop_subsys;
+
+static Property e1000e_properties[] = {
+    DEFINE_NIC_PROPERTIES(E1000EState, conf),
+    DEFINE_PROP_SIGNED("disable_vnet_hdr", E1000EState, disable_vnet, false,
+                        e1000e_prop_disable_vnet, bool),
+    DEFINE_PROP_SIGNED("subsys_ven", E1000EState, subsys_ven,
+                        PCI_VENDOR_ID_INTEL,
+                        e1000e_prop_subsys_ven, uint16_t),
+    DEFINE_PROP_SIGNED("subsys", E1000EState, subsys, 0,
+                        e1000e_prop_subsys, uint16_t),
+    DEFINE_PROP_BOOL("init-vet", E1000EState, init_vet, true),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void e1000e_class_init(ObjectClass *class, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(class);
+    ResettableClass *rc = RESETTABLE_CLASS(class);
+    PCIDeviceClass *c = PCI_DEVICE_CLASS(class);
+
+    c->realize = e1000e_pci_realize;
+    c->exit = e1000e_pci_uninit;
+    c->vendor_id = PCI_VENDOR_ID_INTEL;
+    c->device_id = E1000_DEV_ID_82574L;
+    c->revision = 0;
+    c->romfile = "efi-e1000e.rom";
+    c->class_id = PCI_CLASS_NETWORK_ETHERNET;
+
+    rc->phases.hold = e1000e_qdev_reset_hold;
+
+    dc->desc = "Intel 82574L GbE Controller";
+    dc->vmsd = &e1000e_vmstate;
+
+    e1000e_prop_disable_vnet = qdev_prop_uint8;
+    e1000e_prop_disable_vnet.description = "Do not use virtio headers, "
+                                           "perform SW offloads emulation "
+                                           "instead";
+
+    e1000e_prop_subsys_ven = qdev_prop_uint16;
+    e1000e_prop_subsys_ven.description = "PCI device Subsystem Vendor ID";
+
+    e1000e_prop_subsys = qdev_prop_uint16;
+    e1000e_prop_subsys.description = "PCI device Subsystem ID";
+
+    device_class_set_props(dc, e1000e_properties);
+    set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
+}
+
+static void e1000e_instance_init(Object *obj)
+{
+    E1000EState *s = E1000E(obj);
+    device_add_bootindex_property(obj, &s->conf.bootindex,
+                                  "bootindex", "/ethernet-phy@0",
+                                  DEVICE(obj));
+}
+
+static const TypeInfo e1000e_info = {
+    .name = TYPE_E1000E,
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(E1000EState),
+    .class_init = e1000e_class_init,
+    .instance_init = e1000e_instance_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_PCIE_DEVICE },
+        { }
+    },
+};
+
+static void e1000e_register_types(void)
+{
+    type_register_static(&e1000e_info);
+}
+
+type_init(e1000e_register_types)
diff --git a/hw/net/igb_common.h b/hw/net/igb_common.h
new file mode 100644
index 0000000000..48feda7404
--- /dev/null
+++ b/hw/net/igb_common.h
@@ -0,0 +1,102 @@
+/*
+ * QEMU e1000(e) emulation - shared definitions
+ *
+ * Copyright (c) 2008 Qumranet
+ *
+ * Based on work done by:
+ * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
+ * Copyright (c) 2007 Dan Aloni
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_NET_E1000_COMMON_H
+#define HW_NET_E1000_COMMON_H
+
+#include "e1000_regs.h"
+
+#define defreg(x)   x = (E1000_##x >> 2)
+enum {
+    defreg(CTRL),    defreg(EECD),    defreg(EERD),    defreg(GPRC),
+    defreg(GPTC),    defreg(ICR),     defreg(ICS),     defreg(IMC),
+    defreg(IMS),     defreg(LEDCTL),  defreg(MANC),    defreg(MDIC),
+    defreg(MPC),     defreg(PBA),     defreg(RCTL),    defreg(RDBAH0),
+    defreg(RDBAL0),  defreg(RDH0),    defreg(RDLEN0),  defreg(RDT0),
+    defreg(STATUS),  defreg(SWSM),    defreg(TCTL),    defreg(TDBAH),
+    defreg(TDBAL),   defreg(TDH),     defreg(TDLEN),   defreg(TDT),
+    defreg(TDLEN1),  defreg(TDBAL1),  defreg(TDBAH1),  defreg(TDH1),
+    defreg(TDT1),    defreg(TORH),    defreg(TORL),    defreg(TOTH),
+    defreg(TOTL),    defreg(TPR),     defreg(TPT),     defreg(TXDCTL),
+    defreg(WUFC),    defreg(RA),      defreg(MTA),     defreg(CRCERRS),
+    defreg(VFTA),    defreg(VET),     defreg(RDTR),    defreg(RADV),
+    defreg(TADV),    defreg(ITR),     defreg(SCC),     defreg(ECOL),
+    defreg(MCC),     defreg(LATECOL), defreg(COLC),    defreg(DC),
+    defreg(TNCRS),   defreg(SEQEC),   defreg(CEXTERR), defreg(RLEC),
+    defreg(XONRXC),  defreg(XONTXC),  defreg(XOFFRXC), defreg(XOFFTXC),
+    defreg(FCRUC),   defreg(AIT),     defreg(TDFH),    defreg(TDFT),
+    defreg(TDFHS),   defreg(TDFTS),   defreg(TDFPC),   defreg(WUC),
+    defreg(WUS),     defreg(POEMB),   defreg(PBS),     defreg(RDFH),
+    defreg(RDFT),    defreg(RDFHS),   defreg(RDFTS),   defreg(RDFPC),
+    defreg(PBM),     defreg(IPAV),    defreg(IP4AT),   defreg(IP6AT),
+    defreg(WUPM),    defreg(FFLT),    defreg(FFMT),    defreg(FFVT),
+    defreg(TARC0),   defreg(TARC1),   defreg(IAM),     defreg(EXTCNF_CTRL),
+    defreg(GCR),     defreg(TIMINCA), defreg(EIAC),    defreg(CTRL_EXT),
+    defreg(IVAR),    defreg(MFUTP01), defreg(MFUTP23), defreg(MANC2H),
+    defreg(MFVAL),   defreg(MDEF),    defreg(FACTPS),  defreg(FTFT),
+    defreg(RUC),     defreg(ROC),     defreg(RFC),     defreg(RJC),
+    defreg(PRC64),   defreg(PRC127),  defreg(PRC255),  defreg(PRC511),
+    defreg(PRC1023), defreg(PRC1522), defreg(PTC64),   defreg(PTC127),
+    defreg(PTC255),  defreg(PTC511),  defreg(PTC1023), defreg(PTC1522),
+    defreg(GORCL),   defreg(GORCH),   defreg(GOTCL),   defreg(GOTCH),
+    defreg(RNBC),    defreg(BPRC),    defreg(MPRC),    defreg(RFCTL),
+    defreg(PSRCTL),  defreg(MPTC),    defreg(BPTC),    defreg(TSCTFC),
+    defreg(IAC),     defreg(MGTPRC),  defreg(MGTPDC),  defreg(MGTPTC),
+    defreg(TSCTC),   defreg(RXCSUM),  defreg(FUNCTAG), defreg(GSCL_1),
+    defreg(GSCL_2),  defreg(GSCL_3),  defreg(GSCL_4),  defreg(GSCN_0),
+    defreg(GSCN_1),  defreg(GSCN_2),  defreg(GSCN_3),  defreg(GCR2),
+    defreg(RAID),    defreg(RSRPD),   defreg(TIDV),    defreg(EITR),
+    defreg(MRQC),    defreg(RETA),    defreg(RSSRK),   defreg(RDBAH1),
+    defreg(RDBAL1),  defreg(RDLEN1),  defreg(RDH1),    defreg(RDT1),
+    defreg(PBACLR),  defreg(FCAL),    defreg(FCAH),    defreg(FCT),
+    defreg(FCRTH),   defreg(FCRTL),   defreg(FCTTV),   defreg(FCRTV),
+    defreg(FLA),     defreg(EEWR),    defreg(FLOP),    defreg(FLOL),
+    defreg(FLSWCTL), defreg(FLSWCNT), defreg(RXDCTL),  defreg(RXDCTL1),
+    defreg(MAVTV0),  defreg(MAVTV1),  defreg(MAVTV2),  defreg(MAVTV3),
+    defreg(TXSTMPL), defreg(TXSTMPH), defreg(SYSTIML), defreg(SYSTIMH),
+    defreg(RXCFGL),  defreg(RXUDP),   defreg(TIMADJL), defreg(TIMADJH),
+    defreg(RXSTMPH), defreg(RXSTMPL), defreg(RXSATRL), defreg(RXSATRH),
+    defreg(FLASHT),  defreg(TIPG),    defreg(RDH),     defreg(RDT),
+    defreg(RDLEN),   defreg(RDBAH),   defreg(RDBAL),
+    defreg(TXDCTL1),
+    defreg(FLSWDATA),
+    defreg(CTRL_DUP),
+    defreg(EXTCNF_SIZE),
+    defreg(EEMNGCTL),
+    defreg(EEMNGDATA),
+    defreg(FLMNGCTL),
+    defreg(FLMNGDATA),
+    defreg(FLMNGCNT),
+    defreg(TSYNCRXCTL),
+    defreg(TSYNCTXCTL),
+
+    /* Aliases */
+    defreg(RDH0_A),  defreg(RDT0_A),  defreg(RDTR_A),  defreg(RDFH_A),
+    defreg(RDFT_A),  defreg(TDH_A),   defreg(TDT_A),   defreg(TIDV_A),
+    defreg(TDFH_A),  defreg(TDFT_A),  defreg(RA_A),    defreg(RDBAL0_A),
+    defreg(TDBAL_A), defreg(TDLEN_A), defreg(VFTA_A),  defreg(RDLEN0_A),
+    defreg(FCRTL_A), defreg(FCRTH_A)
+};
+
+#endif
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
new file mode 100644
index 0000000000..e874d417ed
--- /dev/null
+++ b/hw/net/igb_core.c
@@ -0,0 +1,3568 @@
+/*
+ * Core code for QEMU e1000e emulation
+ *
+ * Software developer's manuals:
+ * http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
+ *
+ * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Leonid Bloch <leonid@daynix.com>
+ * Yan Vugenfirer <yan@daynix.com>
+ *
+ * Based on work done by:
+ * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
+ * Copyright (c) 2008 Qumranet
+ * Based on work done by:
+ * Copyright (c) 2007 Dan Aloni
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "net/net.h"
+#include "net/tap.h"
+#include "hw/net/mii.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/msix.h"
+#include "sysemu/runstate.h"
+
+#include "net_tx_pkt.h"
+#include "net_rx_pkt.h"
+
+#include "e1000_common.h"
+#include "e1000x_common.h"
+#include "e1000e_core.h"
+
+#include "trace.h"
+
+/* No more then 7813 interrupts per second according to spec 10.2.4.2 */
+#define E1000E_MIN_XITR     (500)
+
+#define E1000E_MAX_TX_FRAGS (64)
+
+union e1000_rx_desc_union {
+    struct e1000_rx_desc legacy;
+    union e1000_rx_desc_extended extended;
+    union e1000_rx_desc_packet_split packet_split;
+};
+
+static inline void
+e1000e_set_interrupt_cause(E1000ECore *core, uint32_t val);
+
+static void e1000e_reset(E1000ECore *core, bool sw);
+
+static inline void
+e1000e_process_ts_option(E1000ECore *core, struct e1000_tx_desc *dp)
+{
+    if (le32_to_cpu(dp->upper.data) & E1000_TXD_EXTCMD_TSTAMP) {
+        trace_e1000e_wrn_no_ts_support();
+    }
+}
+
+static inline void
+e1000e_process_snap_option(E1000ECore *core, uint32_t cmd_and_length)
+{
+    if (cmd_and_length & E1000_TXD_CMD_SNAP) {
+        trace_e1000e_wrn_no_snap_support();
+    }
+}
+
+static inline void
+e1000e_raise_legacy_irq(E1000ECore *core)
+{
+    trace_e1000e_irq_legacy_notify(true);
+    e1000x_inc_reg_if_not_full(core->mac, IAC);
+    pci_set_irq(core->owner, 1);
+}
+
+static inline void
+e1000e_lower_legacy_irq(E1000ECore *core)
+{
+    trace_e1000e_irq_legacy_notify(false);
+    pci_set_irq(core->owner, 0);
+}
+
+static inline void
+e1000e_intrmgr_rearm_timer(E1000IntrDelayTimer *timer)
+{
+    int64_t delay_ns = (int64_t) timer->core->mac[timer->delay_reg] *
+                                 timer->delay_resolution_ns;
+
+    trace_e1000e_irq_rearm_timer(timer->delay_reg << 2, delay_ns);
+
+    timer_mod(timer->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + delay_ns);
+
+    timer->running = true;
+}
+
+static void
+e1000e_intmgr_timer_resume(E1000IntrDelayTimer *timer)
+{
+    if (timer->running) {
+        e1000e_intrmgr_rearm_timer(timer);
+    }
+}
+
+static void
+e1000e_intmgr_timer_pause(E1000IntrDelayTimer *timer)
+{
+    if (timer->running) {
+        timer_del(timer->timer);
+    }
+}
+
+static inline void
+e1000e_intrmgr_stop_timer(E1000IntrDelayTimer *timer)
+{
+    if (timer->running) {
+        timer_del(timer->timer);
+        timer->running = false;
+    }
+}
+
+static inline void
+e1000e_intrmgr_fire_delayed_interrupts(E1000ECore *core)
+{
+    trace_e1000e_irq_fire_delayed_interrupts();
+    e1000e_set_interrupt_cause(core, 0);
+}
+
+static void
+e1000e_intrmgr_on_timer(void *opaque)
+{
+    E1000IntrDelayTimer *timer = opaque;
+
+    trace_e1000e_irq_throttling_timer(timer->delay_reg << 2);
+
+    timer->running = false;
+    e1000e_intrmgr_fire_delayed_interrupts(timer->core);
+}
+
+static void
+e1000e_intrmgr_on_throttling_timer(void *opaque)
+{
+    E1000IntrDelayTimer *timer = opaque;
+
+    assert(!msix_enabled(timer->core->owner));
+
+    timer->running = false;
+
+    if (msi_enabled(timer->core->owner)) {
+        trace_e1000e_irq_msi_notify_postponed();
+        /* Clear msi_causes_pending to fire MSI eventually */
+        timer->core->msi_causes_pending = 0;
+        e1000e_set_interrupt_cause(timer->core, 0);
+    } else {
+        trace_e1000e_irq_legacy_notify_postponed();
+        e1000e_set_interrupt_cause(timer->core, 0);
+    }
+}
+
+static void
+e1000e_intrmgr_on_msix_throttling_timer(void *opaque)
+{
+    E1000IntrDelayTimer *timer = opaque;
+    int idx = timer - &timer->core->eitr[0];
+
+    assert(msix_enabled(timer->core->owner));
+
+    timer->running = false;
+
+    trace_e1000e_irq_msix_notify_postponed_vec(idx);
+    msix_notify(timer->core->owner, idx);
+}
+
+static void
+e1000e_intrmgr_initialize_all_timers(E1000ECore *core, bool create)
+{
+    int i;
+
+    core->radv.delay_reg = RADV;
+    core->rdtr.delay_reg = RDTR;
+    core->raid.delay_reg = RAID;
+    core->tadv.delay_reg = TADV;
+    core->tidv.delay_reg = TIDV;
+
+    core->radv.delay_resolution_ns = E1000_INTR_DELAY_NS_RES;
+    core->rdtr.delay_resolution_ns = E1000_INTR_DELAY_NS_RES;
+    core->raid.delay_resolution_ns = E1000_INTR_DELAY_NS_RES;
+    core->tadv.delay_resolution_ns = E1000_INTR_DELAY_NS_RES;
+    core->tidv.delay_resolution_ns = E1000_INTR_DELAY_NS_RES;
+
+    core->radv.core = core;
+    core->rdtr.core = core;
+    core->raid.core = core;
+    core->tadv.core = core;
+    core->tidv.core = core;
+
+    core->itr.core = core;
+    core->itr.delay_reg = ITR;
+    core->itr.delay_resolution_ns = E1000_INTR_THROTTLING_NS_RES;
+
+    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
+        core->eitr[i].core = core;
+        core->eitr[i].delay_reg = EITR + i;
+        core->eitr[i].delay_resolution_ns = E1000_INTR_THROTTLING_NS_RES;
+    }
+
+    if (!create) {
+        return;
+    }
+
+    core->radv.timer =
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->radv);
+    core->rdtr.timer =
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->rdtr);
+    core->raid.timer =
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->raid);
+
+    core->tadv.timer =
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->tadv);
+    core->tidv.timer =
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->tidv);
+
+    core->itr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                   e1000e_intrmgr_on_throttling_timer,
+                                   &core->itr);
+
+    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
+        core->eitr[i].timer =
+            timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                         e1000e_intrmgr_on_msix_throttling_timer,
+                         &core->eitr[i]);
+    }
+}
+
+static inline void
+e1000e_intrmgr_stop_delay_timers(E1000ECore *core)
+{
+    e1000e_intrmgr_stop_timer(&core->radv);
+    e1000e_intrmgr_stop_timer(&core->rdtr);
+    e1000e_intrmgr_stop_timer(&core->raid);
+    e1000e_intrmgr_stop_timer(&core->tidv);
+    e1000e_intrmgr_stop_timer(&core->tadv);
+}
+
+static bool
+e1000e_intrmgr_delay_rx_causes(E1000ECore *core, uint32_t *causes)
+{
+    uint32_t delayable_causes;
+    uint32_t rdtr = core->mac[RDTR];
+    uint32_t radv = core->mac[RADV];
+    uint32_t raid = core->mac[RAID];
+
+    if (msix_enabled(core->owner)) {
+        return false;
+    }
+
+    delayable_causes = E1000_ICR_RXQ0 |
+                       E1000_ICR_RXQ1 |
+                       E1000_ICR_RXT0;
+
+    if (!(core->mac[RFCTL] & E1000_RFCTL_ACK_DIS)) {
+        delayable_causes |= E1000_ICR_ACK;
+    }
+
+    /* Clean up all causes that may be delayed */
+    core->delayed_causes |= *causes & delayable_causes;
+    *causes &= ~delayable_causes;
+
+    /*
+     * Check if delayed RX interrupts disabled by client
+     * or if there are causes that cannot be delayed
+     */
+    if ((rdtr == 0) || (*causes != 0)) {
+        return false;
+    }
+
+    /*
+     * Check if delayed RX ACK interrupts disabled by client
+     * and there is an ACK packet received
+     */
+    if ((raid == 0) && (core->delayed_causes & E1000_ICR_ACK)) {
+        return false;
+    }
+
+    /* All causes delayed */
+    e1000e_intrmgr_rearm_timer(&core->rdtr);
+
+    if (!core->radv.running && (radv != 0)) {
+        e1000e_intrmgr_rearm_timer(&core->radv);
+    }
+
+    if (!core->raid.running && (core->delayed_causes & E1000_ICR_ACK)) {
+        e1000e_intrmgr_rearm_timer(&core->raid);
+    }
+
+    return true;
+}
+
+static bool
+e1000e_intrmgr_delay_tx_causes(E1000ECore *core, uint32_t *causes)
+{
+    static const uint32_t delayable_causes = E1000_ICR_TXQ0 |
+                                             E1000_ICR_TXQ1 |
+                                             E1000_ICR_TXQE |
+                                             E1000_ICR_TXDW;
+
+    if (msix_enabled(core->owner)) {
+        return false;
+    }
+
+    /* Clean up all causes that may be delayed */
+    core->delayed_causes |= *causes & delayable_causes;
+    *causes &= ~delayable_causes;
+
+    /* If there are causes that cannot be delayed */
+    if (*causes != 0) {
+        return false;
+    }
+
+    /* All causes delayed */
+    e1000e_intrmgr_rearm_timer(&core->tidv);
+
+    if (!core->tadv.running && (core->mac[TADV] != 0)) {
+        e1000e_intrmgr_rearm_timer(&core->tadv);
+    }
+
+    return true;
+}
+
+static uint32_t
+e1000e_intmgr_collect_delayed_causes(E1000ECore *core)
+{
+    uint32_t res;
+
+    if (msix_enabled(core->owner)) {
+        assert(core->delayed_causes == 0);
+        return 0;
+    }
+
+    res = core->delayed_causes;
+    core->delayed_causes = 0;
+
+    e1000e_intrmgr_stop_delay_timers(core);
+
+    return res;
+}
+
+static void
+e1000e_intrmgr_fire_all_timers(E1000ECore *core)
+{
+    int i;
+    uint32_t val = e1000e_intmgr_collect_delayed_causes(core);
+
+    trace_e1000e_irq_adding_delayed_causes(val, core->mac[ICR]);
+    core->mac[ICR] |= val;
+
+    if (core->itr.running) {
+        timer_del(core->itr.timer);
+        e1000e_intrmgr_on_throttling_timer(&core->itr);
+    }
+
+    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
+        if (core->eitr[i].running) {
+            timer_del(core->eitr[i].timer);
+            e1000e_intrmgr_on_msix_throttling_timer(&core->eitr[i]);
+        }
+    }
+}
+
+static void
+e1000e_intrmgr_resume(E1000ECore *core)
+{
+    int i;
+
+    e1000e_intmgr_timer_resume(&core->radv);
+    e1000e_intmgr_timer_resume(&core->rdtr);
+    e1000e_intmgr_timer_resume(&core->raid);
+    e1000e_intmgr_timer_resume(&core->tidv);
+    e1000e_intmgr_timer_resume(&core->tadv);
+
+    e1000e_intmgr_timer_resume(&core->itr);
+
+    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
+        e1000e_intmgr_timer_resume(&core->eitr[i]);
+    }
+}
+
+static void
+e1000e_intrmgr_pause(E1000ECore *core)
+{
+    int i;
+
+    e1000e_intmgr_timer_pause(&core->radv);
+    e1000e_intmgr_timer_pause(&core->rdtr);
+    e1000e_intmgr_timer_pause(&core->raid);
+    e1000e_intmgr_timer_pause(&core->tidv);
+    e1000e_intmgr_timer_pause(&core->tadv);
+
+    e1000e_intmgr_timer_pause(&core->itr);
+
+    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
+        e1000e_intmgr_timer_pause(&core->eitr[i]);
+    }
+}
+
+static void
+e1000e_intrmgr_reset(E1000ECore *core)
+{
+    int i;
+
+    core->delayed_causes = 0;
+
+    e1000e_intrmgr_stop_delay_timers(core);
+
+    e1000e_intrmgr_stop_timer(&core->itr);
+
+    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
+        e1000e_intrmgr_stop_timer(&core->eitr[i]);
+    }
+}
+
+static void
+e1000e_intrmgr_pci_unint(E1000ECore *core)
+{
+    int i;
+
+    timer_free(core->radv.timer);
+    timer_free(core->rdtr.timer);
+    timer_free(core->raid.timer);
+
+    timer_free(core->tadv.timer);
+    timer_free(core->tidv.timer);
+
+    timer_free(core->itr.timer);
+
+    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
+        timer_free(core->eitr[i].timer);
+    }
+}
+
+static void
+e1000e_intrmgr_pci_realize(E1000ECore *core)
+{
+    e1000e_intrmgr_initialize_all_timers(core, true);
+}
+
+static inline bool
+e1000e_rx_csum_enabled(E1000ECore *core)
+{
+    return (core->mac[RXCSUM] & E1000_RXCSUM_PCSD) ? false : true;
+}
+
+static inline bool
+e1000e_rx_use_legacy_descriptor(E1000ECore *core)
+{
+    return (core->mac[RFCTL] & E1000_RFCTL_EXTEN) ? false : true;
+}
+
+static inline bool
+e1000e_rx_use_ps_descriptor(E1000ECore *core)
+{
+    return !e1000e_rx_use_legacy_descriptor(core) &&
+           (core->mac[RCTL] & E1000_RCTL_DTYP_PS);
+}
+
+static inline bool
+e1000e_rss_enabled(E1000ECore *core)
+{
+    return E1000_MRQC_ENABLED(core->mac[MRQC]) &&
+           !e1000e_rx_csum_enabled(core) &&
+           !e1000e_rx_use_legacy_descriptor(core);
+}
+
+typedef struct E1000E_RSSInfo_st {
+    bool enabled;
+    uint32_t hash;
+    uint32_t queue;
+    uint32_t type;
+} E1000E_RSSInfo;
+
+static uint32_t
+e1000e_rss_get_hash_type(E1000ECore *core, struct NetRxPkt *pkt)
+{
+    bool isip4, isip6, isudp, istcp;
+
+    assert(e1000e_rss_enabled(core));
+
+    net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
+
+    if (isip4) {
+        bool fragment = net_rx_pkt_get_ip4_info(pkt)->fragment;
+
+        trace_e1000e_rx_rss_ip4(fragment, istcp, core->mac[MRQC],
+                                E1000_MRQC_EN_TCPIPV4(core->mac[MRQC]),
+                                E1000_MRQC_EN_IPV4(core->mac[MRQC]));
+
+        if (!fragment && istcp && E1000_MRQC_EN_TCPIPV4(core->mac[MRQC])) {
+            return E1000_MRQ_RSS_TYPE_IPV4TCP;
+        }
+
+        if (E1000_MRQC_EN_IPV4(core->mac[MRQC])) {
+            return E1000_MRQ_RSS_TYPE_IPV4;
+        }
+    } else if (isip6) {
+        eth_ip6_hdr_info *ip6info = net_rx_pkt_get_ip6_info(pkt);
+
+        bool ex_dis = core->mac[RFCTL] & E1000_RFCTL_IPV6_EX_DIS;
+        bool new_ex_dis = core->mac[RFCTL] & E1000_RFCTL_NEW_IPV6_EXT_DIS;
+
+        /*
+         * Following two traces must not be combined because resulting
+         * event will have 11 arguments totally and some trace backends
+         * (at least "ust") have limitation of maximum 10 arguments per
+         * event. Events with more arguments fail to compile for
+         * backends like these.
+         */
+        trace_e1000e_rx_rss_ip6_rfctl(core->mac[RFCTL]);
+        trace_e1000e_rx_rss_ip6(ex_dis, new_ex_dis, istcp,
+                                ip6info->has_ext_hdrs,
+                                ip6info->rss_ex_dst_valid,
+                                ip6info->rss_ex_src_valid,
+                                core->mac[MRQC],
+                                E1000_MRQC_EN_TCPIPV6(core->mac[MRQC]),
+                                E1000_MRQC_EN_IPV6EX(core->mac[MRQC]),
+                                E1000_MRQC_EN_IPV6(core->mac[MRQC]));
+
+        if ((!ex_dis || !ip6info->has_ext_hdrs) &&
+            (!new_ex_dis || !(ip6info->rss_ex_dst_valid ||
+                              ip6info->rss_ex_src_valid))) {
+
+            if (istcp && !ip6info->fragment &&
+                E1000_MRQC_EN_TCPIPV6(core->mac[MRQC])) {
+                return E1000_MRQ_RSS_TYPE_IPV6TCP;
+            }
+
+            if (E1000_MRQC_EN_IPV6EX(core->mac[MRQC])) {
+                return E1000_MRQ_RSS_TYPE_IPV6EX;
+            }
+
+        }
+
+        if (E1000_MRQC_EN_IPV6(core->mac[MRQC])) {
+            return E1000_MRQ_RSS_TYPE_IPV6;
+        }
+
+    }
+
+    return E1000_MRQ_RSS_TYPE_NONE;
+}
+
+static uint32_t
+e1000e_rss_calc_hash(E1000ECore *core,
+                     struct NetRxPkt *pkt,
+                     E1000E_RSSInfo *info)
+{
+    NetRxPktRssType type;
+
+    assert(e1000e_rss_enabled(core));
+
+    switch (info->type) {
+    case E1000_MRQ_RSS_TYPE_IPV4:
+        type = NetPktRssIpV4;
+        break;
+    case E1000_MRQ_RSS_TYPE_IPV4TCP:
+        type = NetPktRssIpV4Tcp;
+        break;
+    case E1000_MRQ_RSS_TYPE_IPV6TCP:
+        type = NetPktRssIpV6TcpEx;
+        break;
+    case E1000_MRQ_RSS_TYPE_IPV6:
+        type = NetPktRssIpV6;
+        break;
+    case E1000_MRQ_RSS_TYPE_IPV6EX:
+        type = NetPktRssIpV6Ex;
+        break;
+    default:
+        assert(false);
+        return 0;
+    }
+
+    return net_rx_pkt_calc_rss_hash(pkt, type, (uint8_t *) &core->mac[RSSRK]);
+}
+
+static void
+e1000e_rss_parse_packet(E1000ECore *core,
+                        struct NetRxPkt *pkt,
+                        E1000E_RSSInfo *info)
+{
+    trace_e1000e_rx_rss_started();
+
+    if (!e1000e_rss_enabled(core)) {
+        info->enabled = false;
+        info->hash = 0;
+        info->queue = 0;
+        info->type = 0;
+        trace_e1000e_rx_rss_disabled();
+        return;
+    }
+
+    info->enabled = true;
+
+    info->type = e1000e_rss_get_hash_type(core, pkt);
+
+    trace_e1000e_rx_rss_type(info->type);
+
+    if (info->type == E1000_MRQ_RSS_TYPE_NONE) {
+        info->hash = 0;
+        info->queue = 0;
+        return;
+    }
+
+    info->hash = e1000e_rss_calc_hash(core, pkt, info);
+    info->queue = E1000_RSS_QUEUE(&core->mac[RETA], info->hash);
+}
+
+static void
+e1000e_setup_tx_offloads(E1000ECore *core, struct e1000e_tx *tx)
+{
+    if (tx->props.tse && tx->cptse) {
+        net_tx_pkt_build_vheader(tx->tx_pkt, true, true, tx->props.mss);
+        net_tx_pkt_update_ip_checksums(tx->tx_pkt);
+        e1000x_inc_reg_if_not_full(core->mac, TSCTC);
+        return;
+    }
+
+    if (tx->sum_needed & E1000_TXD_POPTS_TXSM) {
+        net_tx_pkt_build_vheader(tx->tx_pkt, false, true, 0);
+    }
+
+    if (tx->sum_needed & E1000_TXD_POPTS_IXSM) {
+        net_tx_pkt_update_ip_hdr_checksum(tx->tx_pkt);
+    }
+}
+
+static bool
+e1000e_tx_pkt_send(E1000ECore *core, struct e1000e_tx *tx, int queue_index)
+{
+    int target_queue = MIN(core->max_queue_num, queue_index);
+    NetClientState *queue = qemu_get_subqueue(core->owner_nic, target_queue);
+
+    e1000e_setup_tx_offloads(core, tx);
+
+    net_tx_pkt_dump(tx->tx_pkt);
+
+    if ((core->phy[0][MII_BMCR] & MII_BMCR_LOOPBACK) ||
+        ((core->mac[RCTL] & E1000_RCTL_LBM_MAC) == E1000_RCTL_LBM_MAC)) {
+        return net_tx_pkt_send_loopback(tx->tx_pkt, queue);
+    } else {
+        return net_tx_pkt_send(tx->tx_pkt, queue);
+    }
+}
+
+static void
+e1000e_on_tx_done_update_stats(E1000ECore *core, struct NetTxPkt *tx_pkt)
+{
+    static const int PTCregs[6] = { PTC64, PTC127, PTC255, PTC511,
+                                    PTC1023, PTC1522 };
+
+    size_t tot_len = net_tx_pkt_get_total_len(tx_pkt);
+
+    e1000x_increase_size_stats(core->mac, PTCregs, tot_len);
+    e1000x_inc_reg_if_not_full(core->mac, TPT);
+    e1000x_grow_8reg_if_not_full(core->mac, TOTL, tot_len);
+
+    switch (net_tx_pkt_get_packet_type(tx_pkt)) {
+    case ETH_PKT_BCAST:
+        e1000x_inc_reg_if_not_full(core->mac, BPTC);
+        break;
+    case ETH_PKT_MCAST:
+        e1000x_inc_reg_if_not_full(core->mac, MPTC);
+        break;
+    case ETH_PKT_UCAST:
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    core->mac[GPTC] = core->mac[TPT];
+    core->mac[GOTCL] = core->mac[TOTL];
+    core->mac[GOTCH] = core->mac[TOTH];
+}
+
+static void
+e1000e_process_tx_desc(E1000ECore *core,
+                       struct e1000e_tx *tx,
+                       struct e1000_tx_desc *dp,
+                       int queue_index)
+{
+    uint32_t txd_lower = le32_to_cpu(dp->lower.data);
+    uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D);
+    unsigned int split_size = txd_lower & 0xffff;
+    uint64_t addr;
+    struct e1000_context_desc *xp = (struct e1000_context_desc *)dp;
+    bool eop = txd_lower & E1000_TXD_CMD_EOP;
+
+    if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */
+        e1000x_read_tx_ctx_descr(xp, &tx->props);
+        e1000e_process_snap_option(core, le32_to_cpu(xp->cmd_and_length));
+        return;
+    } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
+        /* data descriptor */
+        tx->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
+        tx->cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
+        e1000e_process_ts_option(core, dp);
+    } else {
+        /* legacy descriptor */
+        e1000e_process_ts_option(core, dp);
+        tx->cptse = 0;
+    }
+
+    addr = le64_to_cpu(dp->buffer_addr);
+
+    if (!tx->skip_cp) {
+        if (!net_tx_pkt_add_raw_fragment(tx->tx_pkt, addr, split_size)) {
+            tx->skip_cp = true;
+        }
+    }
+
+    if (eop) {
+        if (!tx->skip_cp && net_tx_pkt_parse(tx->tx_pkt)) {
+            if (e1000x_vlan_enabled(core->mac) &&
+                e1000x_is_vlan_txd(txd_lower)) {
+                net_tx_pkt_setup_vlan_header_ex(tx->tx_pkt,
+                    le16_to_cpu(dp->upper.fields.special), core->mac[VET]);
+            }
+            if (e1000e_tx_pkt_send(core, tx, queue_index)) {
+                e1000e_on_tx_done_update_stats(core, tx->tx_pkt);
+            }
+        }
+
+        tx->skip_cp = false;
+        net_tx_pkt_reset(tx->tx_pkt);
+
+        tx->sum_needed = 0;
+        tx->cptse = 0;
+    }
+}
+
+static inline uint32_t
+e1000e_tx_wb_interrupt_cause(E1000ECore *core, int queue_idx)
+{
+    if (!msix_enabled(core->owner)) {
+        return E1000_ICR_TXDW;
+    }
+
+    return (queue_idx == 0) ? E1000_ICR_TXQ0 : E1000_ICR_TXQ1;
+}
+
+static inline uint32_t
+e1000e_rx_wb_interrupt_cause(E1000ECore *core, int queue_idx,
+                             bool min_threshold_hit)
+{
+    if (!msix_enabled(core->owner)) {
+        return E1000_ICS_RXT0 | (min_threshold_hit ? E1000_ICS_RXDMT0 : 0);
+    }
+
+    return (queue_idx == 0) ? E1000_ICR_RXQ0 : E1000_ICR_RXQ1;
+}
+
+static uint32_t
+e1000e_txdesc_writeback(E1000ECore *core, dma_addr_t base,
+                        struct e1000_tx_desc *dp, bool *ide, int queue_idx)
+{
+    uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data);
+
+    if (!(txd_lower & E1000_TXD_CMD_RS) &&
+        !(core->mac[IVAR] & E1000_IVAR_TX_INT_EVERY_WB)) {
+        return 0;
+    }
+
+    *ide = (txd_lower & E1000_TXD_CMD_IDE) ? true : false;
+
+    txd_upper = le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD;
+
+    dp->upper.data = cpu_to_le32(txd_upper);
+    pci_dma_write(core->owner, base + ((char *)&dp->upper - (char *)dp),
+                  &dp->upper, sizeof(dp->upper));
+    return e1000e_tx_wb_interrupt_cause(core, queue_idx);
+}
+
+typedef struct E1000E_RingInfo_st {
+    int dbah;
+    int dbal;
+    int dlen;
+    int dh;
+    int dt;
+    int idx;
+} E1000E_RingInfo;
+
+static inline bool
+e1000e_ring_empty(E1000ECore *core, const E1000E_RingInfo *r)
+{
+    return core->mac[r->dh] == core->mac[r->dt] ||
+                core->mac[r->dt] >= core->mac[r->dlen] / E1000_RING_DESC_LEN;
+}
+
+static inline uint64_t
+e1000e_ring_base(E1000ECore *core, const E1000E_RingInfo *r)
+{
+    uint64_t bah = core->mac[r->dbah];
+    uint64_t bal = core->mac[r->dbal];
+
+    return (bah << 32) + bal;
+}
+
+static inline uint64_t
+e1000e_ring_head_descr(E1000ECore *core, const E1000E_RingInfo *r)
+{
+    return e1000e_ring_base(core, r) + E1000_RING_DESC_LEN * core->mac[r->dh];
+}
+
+static inline void
+e1000e_ring_advance(E1000ECore *core, const E1000E_RingInfo *r, uint32_t count)
+{
+    core->mac[r->dh] += count;
+
+    if (core->mac[r->dh] * E1000_RING_DESC_LEN >= core->mac[r->dlen]) {
+        core->mac[r->dh] = 0;
+    }
+}
+
+static inline uint32_t
+e1000e_ring_free_descr_num(E1000ECore *core, const E1000E_RingInfo *r)
+{
+    trace_e1000e_ring_free_space(r->idx, core->mac[r->dlen],
+                                 core->mac[r->dh],  core->mac[r->dt]);
+
+    if (core->mac[r->dh] <= core->mac[r->dt]) {
+        return core->mac[r->dt] - core->mac[r->dh];
+    }
+
+    if (core->mac[r->dh] > core->mac[r->dt]) {
+        return core->mac[r->dlen] / E1000_RING_DESC_LEN +
+               core->mac[r->dt] - core->mac[r->dh];
+    }
+
+    g_assert_not_reached();
+    return 0;
+}
+
+static inline bool
+e1000e_ring_enabled(E1000ECore *core, const E1000E_RingInfo *r)
+{
+    return core->mac[r->dlen] > 0;
+}
+
+static inline uint32_t
+e1000e_ring_len(E1000ECore *core, const E1000E_RingInfo *r)
+{
+    return core->mac[r->dlen];
+}
+
+typedef struct E1000E_TxRing_st {
+    const E1000E_RingInfo *i;
+    struct e1000e_tx *tx;
+} E1000E_TxRing;
+
+static inline int
+e1000e_mq_queue_idx(int base_reg_idx, int reg_idx)
+{
+    return (reg_idx - base_reg_idx) / (0x100 >> 2);
+}
+
+static inline void
+e1000e_tx_ring_init(E1000ECore *core, E1000E_TxRing *txr, int idx)
+{
+    static const E1000E_RingInfo i[E1000E_NUM_QUEUES] = {
+        { TDBAH,  TDBAL,  TDLEN,  TDH,  TDT, 0 },
+        { TDBAH1, TDBAL1, TDLEN1, TDH1, TDT1, 1 }
+    };
+
+    assert(idx < ARRAY_SIZE(i));
+
+    txr->i     = &i[idx];
+    txr->tx    = &core->tx[idx];
+}
+
+typedef struct E1000E_RxRing_st {
+    const E1000E_RingInfo *i;
+} E1000E_RxRing;
+
+static inline void
+e1000e_rx_ring_init(E1000ECore *core, E1000E_RxRing *rxr, int idx)
+{
+    static const E1000E_RingInfo i[E1000E_NUM_QUEUES] = {
+        { RDBAH0, RDBAL0, RDLEN0, RDH0, RDT0, 0 },
+        { RDBAH1, RDBAL1, RDLEN1, RDH1, RDT1, 1 }
+    };
+
+    assert(idx < ARRAY_SIZE(i));
+
+    rxr->i      = &i[idx];
+}
+
+static void
+e1000e_start_xmit(E1000ECore *core, const E1000E_TxRing *txr)
+{
+    dma_addr_t base;
+    struct e1000_tx_desc desc;
+    bool ide = false;
+    const E1000E_RingInfo *txi = txr->i;
+    uint32_t cause = E1000_ICS_TXQE;
+
+    if (!(core->mac[TCTL] & E1000_TCTL_EN)) {
+        trace_e1000e_tx_disabled();
+        return;
+    }
+
+    while (!e1000e_ring_empty(core, txi)) {
+        base = e1000e_ring_head_descr(core, txi);
+
+        pci_dma_read(core->owner, base, &desc, sizeof(desc));
+
+        trace_e1000e_tx_descr((void *)(intptr_t)desc.buffer_addr,
+                              desc.lower.data, desc.upper.data);
+
+        e1000e_process_tx_desc(core, txr->tx, &desc, txi->idx);
+        cause |= e1000e_txdesc_writeback(core, base, &desc, &ide, txi->idx);
+
+        e1000e_ring_advance(core, txi, 1);
+    }
+
+    if (!ide || !e1000e_intrmgr_delay_tx_causes(core, &cause)) {
+        e1000e_set_interrupt_cause(core, cause);
+    }
+}
+
+static bool
+e1000e_has_rxbufs(E1000ECore *core, const E1000E_RingInfo *r,
+                  size_t total_size)
+{
+    uint32_t bufs = e1000e_ring_free_descr_num(core, r);
+
+    trace_e1000e_rx_has_buffers(r->idx, bufs, total_size,
+                                core->rx_desc_buf_size);
+
+    return total_size <= bufs / (core->rx_desc_len / E1000_MIN_RX_DESC_LEN) *
+                         core->rx_desc_buf_size;
+}
+
+void
+e1000e_start_recv(E1000ECore *core)
+{
+    int i;
+
+    trace_e1000e_rx_start_recv();
+
+    for (i = 0; i <= core->max_queue_num; i++) {
+        qemu_flush_queued_packets(qemu_get_subqueue(core->owner_nic, i));
+    }
+}
+
+bool
+e1000e_can_receive(E1000ECore *core)
+{
+    int i;
+
+    if (!e1000x_rx_ready(core->owner, core->mac)) {
+        return false;
+    }
+
+    for (i = 0; i < E1000E_NUM_QUEUES; i++) {
+        E1000E_RxRing rxr;
+
+        e1000e_rx_ring_init(core, &rxr, i);
+        if (e1000e_ring_enabled(core, rxr.i) &&
+            e1000e_has_rxbufs(core, rxr.i, 1)) {
+            trace_e1000e_rx_can_recv();
+            return true;
+        }
+    }
+
+    trace_e1000e_rx_can_recv_rings_full();
+    return false;
+}
+
+ssize_t
+e1000e_receive(E1000ECore *core, const uint8_t *buf, size_t size)
+{
+    const struct iovec iov = {
+        .iov_base = (uint8_t *)buf,
+        .iov_len = size
+    };
+
+    return e1000e_receive_iov(core, &iov, 1);
+}
+
+static inline bool
+e1000e_rx_l3_cso_enabled(E1000ECore *core)
+{
+    return !!(core->mac[RXCSUM] & E1000_RXCSUM_IPOFLD);
+}
+
+static inline bool
+e1000e_rx_l4_cso_enabled(E1000ECore *core)
+{
+    return !!(core->mac[RXCSUM] & E1000_RXCSUM_TUOFLD);
+}
+
+static bool
+e1000e_receive_filter(E1000ECore *core, const uint8_t *buf, int size)
+{
+    uint32_t rctl = core->mac[RCTL];
+
+    if (e1000x_is_vlan_packet(buf, core->mac[VET]) &&
+        e1000x_vlan_rx_filter_enabled(core->mac)) {
+        uint16_t vid = lduw_be_p(&PKT_GET_VLAN_HDR(buf)->h_tci);
+        uint32_t vfta =
+            ldl_le_p((uint32_t *)(core->mac + VFTA) +
+                     ((vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK));
+        if ((vfta & (1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK))) == 0) {
+            trace_e1000e_rx_flt_vlan_mismatch(vid);
+            return false;
+        } else {
+            trace_e1000e_rx_flt_vlan_match(vid);
+        }
+    }
+
+    switch (net_rx_pkt_get_packet_type(core->rx_pkt)) {
+    case ETH_PKT_UCAST:
+        if (rctl & E1000_RCTL_UPE) {
+            return true; /* promiscuous ucast */
+        }
+        break;
+
+    case ETH_PKT_BCAST:
+        if (rctl & E1000_RCTL_BAM) {
+            return true; /* broadcast enabled */
+        }
+        break;
+
+    case ETH_PKT_MCAST:
+        if (rctl & E1000_RCTL_MPE) {
+            return true; /* promiscuous mcast */
+        }
+        break;
+
+    default:
+        g_assert_not_reached();
+    }
+
+    return e1000x_rx_group_filter(core->mac, buf);
+}
+
+static inline void
+e1000e_read_lgcy_rx_descr(E1000ECore *core, struct e1000_rx_desc *desc,
+                          hwaddr *buff_addr)
+{
+    *buff_addr = le64_to_cpu(desc->buffer_addr);
+}
+
+static inline void
+e1000e_read_ext_rx_descr(E1000ECore *core, union e1000_rx_desc_extended *desc,
+                         hwaddr *buff_addr)
+{
+    *buff_addr = le64_to_cpu(desc->read.buffer_addr);
+}
+
+static inline void
+e1000e_read_ps_rx_descr(E1000ECore *core,
+                        union e1000_rx_desc_packet_split *desc,
+                        hwaddr buff_addr[MAX_PS_BUFFERS])
+{
+    int i;
+
+    for (i = 0; i < MAX_PS_BUFFERS; i++) {
+        buff_addr[i] = le64_to_cpu(desc->read.buffer_addr[i]);
+    }
+
+    trace_e1000e_rx_desc_ps_read(buff_addr[0], buff_addr[1],
+                                 buff_addr[2], buff_addr[3]);
+}
+
+static inline void
+e1000e_read_rx_descr(E1000ECore *core, union e1000_rx_desc_union *desc,
+                     hwaddr buff_addr[MAX_PS_BUFFERS])
+{
+    if (e1000e_rx_use_legacy_descriptor(core)) {
+        e1000e_read_lgcy_rx_descr(core, &desc->legacy, &buff_addr[0]);
+        buff_addr[1] = buff_addr[2] = buff_addr[3] = 0;
+    } else {
+        if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) {
+            e1000e_read_ps_rx_descr(core, &desc->packet_split, buff_addr);
+        } else {
+            e1000e_read_ext_rx_descr(core, &desc->extended, &buff_addr[0]);
+            buff_addr[1] = buff_addr[2] = buff_addr[3] = 0;
+        }
+    }
+}
+
+static void
+e1000e_verify_csum_in_sw(E1000ECore *core,
+                         struct NetRxPkt *pkt,
+                         uint32_t *status_flags,
+                         bool istcp, bool isudp)
+{
+    bool csum_valid;
+    uint32_t csum_error;
+
+    if (e1000e_rx_l3_cso_enabled(core)) {
+        if (!net_rx_pkt_validate_l3_csum(pkt, &csum_valid)) {
+            trace_e1000e_rx_metadata_l3_csum_validation_failed();
+        } else {
+            csum_error = csum_valid ? 0 : E1000_RXDEXT_STATERR_IPE;
+            *status_flags |= E1000_RXD_STAT_IPCS | csum_error;
+        }
+    } else {
+        trace_e1000e_rx_metadata_l3_cso_disabled();
+    }
+
+    if (!e1000e_rx_l4_cso_enabled(core)) {
+        trace_e1000e_rx_metadata_l4_cso_disabled();
+        return;
+    }
+
+    if (!net_rx_pkt_validate_l4_csum(pkt, &csum_valid)) {
+        trace_e1000e_rx_metadata_l4_csum_validation_failed();
+        return;
+    }
+
+    csum_error = csum_valid ? 0 : E1000_RXDEXT_STATERR_TCPE;
+
+    if (istcp) {
+        *status_flags |= E1000_RXD_STAT_TCPCS |
+                         csum_error;
+    } else if (isudp) {
+        *status_flags |= E1000_RXD_STAT_TCPCS |
+                         E1000_RXD_STAT_UDPCS |
+                         csum_error;
+    }
+}
+
+static inline bool
+e1000e_is_tcp_ack(E1000ECore *core, struct NetRxPkt *rx_pkt)
+{
+    if (!net_rx_pkt_is_tcp_ack(rx_pkt)) {
+        return false;
+    }
+
+    if (core->mac[RFCTL] & E1000_RFCTL_ACK_DATA_DIS) {
+        return !net_rx_pkt_has_tcp_data(rx_pkt);
+    }
+
+    return true;
+}
+
+static void
+e1000e_build_rx_metadata(E1000ECore *core,
+                         struct NetRxPkt *pkt,
+                         bool is_eop,
+                         const E1000E_RSSInfo *rss_info,
+                         uint32_t *rss, uint32_t *mrq,
+                         uint32_t *status_flags,
+                         uint16_t *ip_id,
+                         uint16_t *vlan_tag)
+{
+    struct virtio_net_hdr *vhdr;
+    bool isip4, isip6, istcp, isudp;
+    uint32_t pkt_type;
+
+    *status_flags = E1000_RXD_STAT_DD;
+
+    /* No additional metadata needed for non-EOP descriptors */
+    if (!is_eop) {
+        goto func_exit;
+    }
+
+    *status_flags |= E1000_RXD_STAT_EOP;
+
+    net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
+    trace_e1000e_rx_metadata_protocols(isip4, isip6, isudp, istcp);
+
+    /* VLAN state */
+    if (net_rx_pkt_is_vlan_stripped(pkt)) {
+        *status_flags |= E1000_RXD_STAT_VP;
+        *vlan_tag = cpu_to_le16(net_rx_pkt_get_vlan_tag(pkt));
+        trace_e1000e_rx_metadata_vlan(*vlan_tag);
+    }
+
+    /* Packet parsing results */
+    if ((core->mac[RXCSUM] & E1000_RXCSUM_PCSD) != 0) {
+        if (rss_info->enabled) {
+            *rss = cpu_to_le32(rss_info->hash);
+            *mrq = cpu_to_le32(rss_info->type | (rss_info->queue << 8));
+            trace_e1000e_rx_metadata_rss(*rss, *mrq);
+        }
+    } else if (isip4) {
+            *status_flags |= E1000_RXD_STAT_IPIDV;
+            *ip_id = cpu_to_le16(net_rx_pkt_get_ip_id(pkt));
+            trace_e1000e_rx_metadata_ip_id(*ip_id);
+    }
+
+    if (istcp && e1000e_is_tcp_ack(core, pkt)) {
+        *status_flags |= E1000_RXD_STAT_ACK;
+        trace_e1000e_rx_metadata_ack();
+    }
+
+    if (isip6 && (core->mac[RFCTL] & E1000_RFCTL_IPV6_DIS)) {
+        trace_e1000e_rx_metadata_ipv6_filtering_disabled();
+        pkt_type = E1000_RXD_PKT_MAC;
+    } else if (istcp || isudp) {
+        pkt_type = isip4 ? E1000_RXD_PKT_IP4_XDP : E1000_RXD_PKT_IP6_XDP;
+    } else if (isip4 || isip6) {
+        pkt_type = isip4 ? E1000_RXD_PKT_IP4 : E1000_RXD_PKT_IP6;
+    } else {
+        pkt_type = E1000_RXD_PKT_MAC;
+    }
+
+    *status_flags |= E1000_RXD_PKT_TYPE(pkt_type);
+    trace_e1000e_rx_metadata_pkt_type(pkt_type);
+
+    /* RX CSO information */
+    if (isip6 && (core->mac[RFCTL] & E1000_RFCTL_IPV6_XSUM_DIS)) {
+        trace_e1000e_rx_metadata_ipv6_sum_disabled();
+        goto func_exit;
+    }
+
+    if (!net_rx_pkt_has_virt_hdr(pkt)) {
+        trace_e1000e_rx_metadata_no_virthdr();
+        e1000e_verify_csum_in_sw(core, pkt, status_flags, istcp, isudp);
+        goto func_exit;
+    }
+
+    vhdr = net_rx_pkt_get_vhdr(pkt);
+
+    if (!(vhdr->flags & VIRTIO_NET_HDR_F_DATA_VALID) &&
+        !(vhdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) {
+        trace_e1000e_rx_metadata_virthdr_no_csum_info();
+        e1000e_verify_csum_in_sw(core, pkt, status_flags, istcp, isudp);
+        goto func_exit;
+    }
+
+    if (e1000e_rx_l3_cso_enabled(core)) {
+        *status_flags |= isip4 ? E1000_RXD_STAT_IPCS : 0;
+    } else {
+        trace_e1000e_rx_metadata_l3_cso_disabled();
+    }
+
+    if (e1000e_rx_l4_cso_enabled(core)) {
+        if (istcp) {
+            *status_flags |= E1000_RXD_STAT_TCPCS;
+        } else if (isudp) {
+            *status_flags |= E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS;
+        }
+    } else {
+        trace_e1000e_rx_metadata_l4_cso_disabled();
+    }
+
+    trace_e1000e_rx_metadata_status_flags(*status_flags);
+
+func_exit:
+    *status_flags = cpu_to_le32(*status_flags);
+}
+
+static inline void
+e1000e_write_lgcy_rx_descr(E1000ECore *core, struct e1000_rx_desc *desc,
+                           struct NetRxPkt *pkt,
+                           const E1000E_RSSInfo *rss_info,
+                           uint16_t length)
+{
+    uint32_t status_flags, rss, mrq;
+    uint16_t ip_id;
+
+    assert(!rss_info->enabled);
+
+    desc->length = cpu_to_le16(length);
+    desc->csum = 0;
+
+    e1000e_build_rx_metadata(core, pkt, pkt != NULL,
+                             rss_info,
+                             &rss, &mrq,
+                             &status_flags, &ip_id,
+                             &desc->special);
+    desc->errors = (uint8_t) (le32_to_cpu(status_flags) >> 24);
+    desc->status = (uint8_t) le32_to_cpu(status_flags);
+}
+
+static inline void
+e1000e_write_ext_rx_descr(E1000ECore *core, union e1000_rx_desc_extended *desc,
+                          struct NetRxPkt *pkt,
+                          const E1000E_RSSInfo *rss_info,
+                          uint16_t length)
+{
+    memset(&desc->wb, 0, sizeof(desc->wb));
+
+    desc->wb.upper.length = cpu_to_le16(length);
+
+    e1000e_build_rx_metadata(core, pkt, pkt != NULL,
+                             rss_info,
+                             &desc->wb.lower.hi_dword.rss,
+                             &desc->wb.lower.mrq,
+                             &desc->wb.upper.status_error,
+                             &desc->wb.lower.hi_dword.csum_ip.ip_id,
+                             &desc->wb.upper.vlan);
+}
+
+static inline void
+e1000e_write_ps_rx_descr(E1000ECore *core,
+                         union e1000_rx_desc_packet_split *desc,
+                         struct NetRxPkt *pkt,
+                         const E1000E_RSSInfo *rss_info,
+                         size_t ps_hdr_len,
+                         uint16_t(*written)[MAX_PS_BUFFERS])
+{
+    int i;
+
+    memset(&desc->wb, 0, sizeof(desc->wb));
+
+    desc->wb.middle.length0 = cpu_to_le16((*written)[0]);
+
+    for (i = 0; i < PS_PAGE_BUFFERS; i++) {
+        desc->wb.upper.length[i] = cpu_to_le16((*written)[i + 1]);
+    }
+
+    e1000e_build_rx_metadata(core, pkt, pkt != NULL,
+                             rss_info,
+                             &desc->wb.lower.hi_dword.rss,
+                             &desc->wb.lower.mrq,
+                             &desc->wb.middle.status_error,
+                             &desc->wb.lower.hi_dword.csum_ip.ip_id,
+                             &desc->wb.middle.vlan);
+
+    desc->wb.upper.header_status =
+        cpu_to_le16(ps_hdr_len | (ps_hdr_len ? E1000_RXDPS_HDRSTAT_HDRSP : 0));
+
+    trace_e1000e_rx_desc_ps_write((*written)[0], (*written)[1],
+                                  (*written)[2], (*written)[3]);
+}
+
+static inline void
+e1000e_write_rx_descr(E1000ECore *core, union e1000_rx_desc_union *desc,
+struct NetRxPkt *pkt, const E1000E_RSSInfo *rss_info,
+    size_t ps_hdr_len, uint16_t(*written)[MAX_PS_BUFFERS])
+{
+    if (e1000e_rx_use_legacy_descriptor(core)) {
+        assert(ps_hdr_len == 0);
+        e1000e_write_lgcy_rx_descr(core, &desc->legacy, pkt, rss_info,
+                                   (*written)[0]);
+    } else {
+        if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) {
+            e1000e_write_ps_rx_descr(core, &desc->packet_split, pkt, rss_info,
+                                      ps_hdr_len, written);
+        } else {
+            assert(ps_hdr_len == 0);
+            e1000e_write_ext_rx_descr(core, &desc->extended, pkt, rss_info,
+                                       (*written)[0]);
+        }
+    }
+}
+
+static inline void
+e1000e_pci_dma_write_rx_desc(E1000ECore *core, dma_addr_t addr,
+                             union e1000_rx_desc_union *desc, dma_addr_t len)
+{
+    PCIDevice *dev = core->owner;
+
+    if (e1000e_rx_use_legacy_descriptor(core)) {
+        struct e1000_rx_desc *d = &desc->legacy;
+        size_t offset = offsetof(struct e1000_rx_desc, status);
+        uint8_t status = d->status;
+
+        d->status &= ~E1000_RXD_STAT_DD;
+        pci_dma_write(dev, addr, desc, len);
+
+        if (status & E1000_RXD_STAT_DD) {
+            d->status = status;
+            pci_dma_write(dev, addr + offset, &status, sizeof(status));
+        }
+    } else {
+        if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) {
+            union e1000_rx_desc_packet_split *d = &desc->packet_split;
+            size_t offset = offsetof(union e1000_rx_desc_packet_split,
+                wb.middle.status_error);
+            uint32_t status = d->wb.middle.status_error;
+
+            d->wb.middle.status_error &= ~E1000_RXD_STAT_DD;
+            pci_dma_write(dev, addr, desc, len);
+
+            if (status & E1000_RXD_STAT_DD) {
+                d->wb.middle.status_error = status;
+                pci_dma_write(dev, addr + offset, &status, sizeof(status));
+            }
+        } else {
+            union e1000_rx_desc_extended *d = &desc->extended;
+            size_t offset = offsetof(union e1000_rx_desc_extended,
+                wb.upper.status_error);
+            uint32_t status = d->wb.upper.status_error;
+
+            d->wb.upper.status_error &= ~E1000_RXD_STAT_DD;
+            pci_dma_write(dev, addr, desc, len);
+
+            if (status & E1000_RXD_STAT_DD) {
+                d->wb.upper.status_error = status;
+                pci_dma_write(dev, addr + offset, &status, sizeof(status));
+            }
+        }
+    }
+}
+
+typedef struct e1000e_ba_state_st {
+    uint16_t written[MAX_PS_BUFFERS];
+    uint8_t cur_idx;
+} e1000e_ba_state;
+
+static inline void
+e1000e_write_hdr_to_rx_buffers(E1000ECore *core,
+                               hwaddr ba[MAX_PS_BUFFERS],
+                               e1000e_ba_state *bastate,
+                               const char *data,
+                               dma_addr_t data_len)
+{
+    assert(data_len <= core->rxbuf_sizes[0] - bastate->written[0]);
+
+    pci_dma_write(core->owner, ba[0] + bastate->written[0], data, data_len);
+    bastate->written[0] += data_len;
+
+    bastate->cur_idx = 1;
+}
+
+static void
+e1000e_write_to_rx_buffers(E1000ECore *core,
+                           hwaddr ba[MAX_PS_BUFFERS],
+                           e1000e_ba_state *bastate,
+                           const char *data,
+                           dma_addr_t data_len)
+{
+    while (data_len > 0) {
+        uint32_t cur_buf_len = core->rxbuf_sizes[bastate->cur_idx];
+        uint32_t cur_buf_bytes_left = cur_buf_len -
+                                      bastate->written[bastate->cur_idx];
+        uint32_t bytes_to_write = MIN(data_len, cur_buf_bytes_left);
+
+        trace_e1000e_rx_desc_buff_write(bastate->cur_idx,
+                                        ba[bastate->cur_idx],
+                                        bastate->written[bastate->cur_idx],
+                                        data,
+                                        bytes_to_write);
+
+        pci_dma_write(core->owner,
+            ba[bastate->cur_idx] + bastate->written[bastate->cur_idx],
+            data, bytes_to_write);
+
+        bastate->written[bastate->cur_idx] += bytes_to_write;
+        data += bytes_to_write;
+        data_len -= bytes_to_write;
+
+        if (bastate->written[bastate->cur_idx] == cur_buf_len) {
+            bastate->cur_idx++;
+        }
+
+        assert(bastate->cur_idx < MAX_PS_BUFFERS);
+    }
+}
+
+static void
+e1000e_update_rx_stats(E1000ECore *core,
+                       size_t data_size,
+                       size_t data_fcs_size)
+{
+    e1000x_update_rx_total_stats(core->mac, data_size, data_fcs_size);
+
+    switch (net_rx_pkt_get_packet_type(core->rx_pkt)) {
+    case ETH_PKT_BCAST:
+        e1000x_inc_reg_if_not_full(core->mac, BPRC);
+        break;
+
+    case ETH_PKT_MCAST:
+        e1000x_inc_reg_if_not_full(core->mac, MPRC);
+        break;
+
+    default:
+        break;
+    }
+}
+
+static inline bool
+e1000e_rx_descr_threshold_hit(E1000ECore *core, const E1000E_RingInfo *rxi)
+{
+    return e1000e_ring_free_descr_num(core, rxi) ==
+           e1000e_ring_len(core, rxi) >> core->rxbuf_min_shift;
+}
+
+static bool
+e1000e_do_ps(E1000ECore *core, struct NetRxPkt *pkt, size_t *hdr_len)
+{
+    bool isip4, isip6, isudp, istcp;
+    bool fragment;
+
+    if (!e1000e_rx_use_ps_descriptor(core)) {
+        return false;
+    }
+
+    net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
+
+    if (isip4) {
+        fragment = net_rx_pkt_get_ip4_info(pkt)->fragment;
+    } else if (isip6) {
+        fragment = net_rx_pkt_get_ip6_info(pkt)->fragment;
+    } else {
+        return false;
+    }
+
+    if (fragment && (core->mac[RFCTL] & E1000_RFCTL_IPFRSP_DIS)) {
+        return false;
+    }
+
+    if (!fragment && (isudp || istcp)) {
+        *hdr_len = net_rx_pkt_get_l5_hdr_offset(pkt);
+    } else {
+        *hdr_len = net_rx_pkt_get_l4_hdr_offset(pkt);
+    }
+
+    if ((*hdr_len > core->rxbuf_sizes[0]) ||
+        (*hdr_len > net_rx_pkt_get_total_len(pkt))) {
+        return false;
+    }
+
+    return true;
+}
+
+static void
+e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
+                             const E1000E_RxRing *rxr,
+                             const E1000E_RSSInfo *rss_info)
+{
+    PCIDevice *d = core->owner;
+    dma_addr_t base;
+    union e1000_rx_desc_union desc;
+    size_t desc_size;
+    size_t desc_offset = 0;
+    size_t iov_ofs = 0;
+
+    struct iovec *iov = net_rx_pkt_get_iovec(pkt);
+    size_t size = net_rx_pkt_get_total_len(pkt);
+    size_t total_size = size + e1000x_fcs_len(core->mac);
+    const E1000E_RingInfo *rxi;
+    size_t ps_hdr_len = 0;
+    bool do_ps = e1000e_do_ps(core, pkt, &ps_hdr_len);
+    bool is_first = true;
+
+    rxi = rxr->i;
+
+    do {
+        hwaddr ba[MAX_PS_BUFFERS];
+        e1000e_ba_state bastate = { { 0 } };
+        bool is_last = false;
+
+        desc_size = total_size - desc_offset;
+
+        if (desc_size > core->rx_desc_buf_size) {
+            desc_size = core->rx_desc_buf_size;
+        }
+
+        if (e1000e_ring_empty(core, rxi)) {
+            return;
+        }
+
+        base = e1000e_ring_head_descr(core, rxi);
+
+        pci_dma_read(d, base, &desc, core->rx_desc_len);
+
+        trace_e1000e_rx_descr(rxi->idx, base, core->rx_desc_len);
+
+        e1000e_read_rx_descr(core, &desc, ba);
+
+        if (ba[0]) {
+            if (desc_offset < size) {
+                static const uint32_t fcs_pad;
+                size_t iov_copy;
+                size_t copy_size = size - desc_offset;
+                if (copy_size > core->rx_desc_buf_size) {
+                    copy_size = core->rx_desc_buf_size;
+                }
+
+                /* For PS mode copy the packet header first */
+                if (do_ps) {
+                    if (is_first) {
+                        size_t ps_hdr_copied = 0;
+                        do {
+                            iov_copy = MIN(ps_hdr_len - ps_hdr_copied,
+                                           iov->iov_len - iov_ofs);
+
+                            e1000e_write_hdr_to_rx_buffers(core, ba, &bastate,
+                                                      iov->iov_base, iov_copy);
+
+                            copy_size -= iov_copy;
+                            ps_hdr_copied += iov_copy;
+
+                            iov_ofs += iov_copy;
+                            if (iov_ofs == iov->iov_len) {
+                                iov++;
+                                iov_ofs = 0;
+                            }
+                        } while (ps_hdr_copied < ps_hdr_len);
+
+                        is_first = false;
+                    } else {
+                        /* Leave buffer 0 of each descriptor except first */
+                        /* empty as per spec 7.1.5.1                      */
+                        e1000e_write_hdr_to_rx_buffers(core, ba, &bastate,
+                                                       NULL, 0);
+                    }
+                }
+
+                /* Copy packet payload */
+                while (copy_size) {
+                    iov_copy = MIN(copy_size, iov->iov_len - iov_ofs);
+
+                    e1000e_write_to_rx_buffers(core, ba, &bastate,
+                                            iov->iov_base + iov_ofs, iov_copy);
+
+                    copy_size -= iov_copy;
+                    iov_ofs += iov_copy;
+                    if (iov_ofs == iov->iov_len) {
+                        iov++;
+                        iov_ofs = 0;
+                    }
+                }
+
+                if (desc_offset + desc_size >= total_size) {
+                    /* Simulate FCS checksum presence in the last descriptor */
+                    e1000e_write_to_rx_buffers(core, ba, &bastate,
+                          (const char *) &fcs_pad, e1000x_fcs_len(core->mac));
+                }
+            }
+        } else { /* as per intel docs; skip descriptors with null buf addr */
+            trace_e1000e_rx_null_descriptor();
+        }
+        desc_offset += desc_size;
+        if (desc_offset >= total_size) {
+            is_last = true;
+        }
+
+        e1000e_write_rx_descr(core, &desc, is_last ? core->rx_pkt : NULL,
+                           rss_info, do_ps ? ps_hdr_len : 0, &bastate.written);
+        e1000e_pci_dma_write_rx_desc(core, base, &desc, core->rx_desc_len);
+
+        e1000e_ring_advance(core, rxi,
+                            core->rx_desc_len / E1000_MIN_RX_DESC_LEN);
+
+    } while (desc_offset < total_size);
+
+    e1000e_update_rx_stats(core, size, total_size);
+}
+
+static inline void
+e1000e_rx_fix_l4_csum(E1000ECore *core, struct NetRxPkt *pkt)
+{
+    if (net_rx_pkt_has_virt_hdr(pkt)) {
+        struct virtio_net_hdr *vhdr = net_rx_pkt_get_vhdr(pkt);
+
+        if (vhdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
+            net_rx_pkt_fix_l4_csum(pkt);
+        }
+    }
+}
+
+ssize_t
+e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt)
+{
+    static const int maximum_ethernet_hdr_len = (ETH_HLEN + 4);
+
+    uint32_t n = 0;
+    uint8_t min_buf[ETH_ZLEN];
+    struct iovec min_iov;
+    uint8_t *filter_buf;
+    size_t size, orig_size;
+    size_t iov_ofs = 0;
+    E1000E_RxRing rxr;
+    E1000E_RSSInfo rss_info;
+    size_t total_size;
+    ssize_t retval;
+    bool rdmts_hit;
+
+    trace_e1000e_rx_receive_iov(iovcnt);
+
+    if (!e1000x_hw_rx_enabled(core->mac)) {
+        return -1;
+    }
+
+    /* Pull virtio header in */
+    if (core->has_vnet) {
+        net_rx_pkt_set_vhdr_iovec(core->rx_pkt, iov, iovcnt);
+        iov_ofs = sizeof(struct virtio_net_hdr);
+    }
+
+    filter_buf = iov->iov_base + iov_ofs;
+    orig_size = iov_size(iov, iovcnt);
+    size = orig_size - iov_ofs;
+
+    /* Pad to minimum Ethernet frame length */
+    if (size < sizeof(min_buf)) {
+        iov_to_buf(iov, iovcnt, iov_ofs, min_buf, size);
+        memset(&min_buf[size], 0, sizeof(min_buf) - size);
+        e1000x_inc_reg_if_not_full(core->mac, RUC);
+        min_iov.iov_base = filter_buf = min_buf;
+        min_iov.iov_len = size = sizeof(min_buf);
+        iovcnt = 1;
+        iov = &min_iov;
+        iov_ofs = 0;
+    } else if (iov->iov_len < maximum_ethernet_hdr_len) {
+        /* This is very unlikely, but may happen. */
+        iov_to_buf(iov, iovcnt, iov_ofs, min_buf, maximum_ethernet_hdr_len);
+        filter_buf = min_buf;
+    }
+
+    /* Discard oversized packets if !LPE and !SBP. */
+    if (e1000x_is_oversized(core->mac, size)) {
+        return orig_size;
+    }
+
+    net_rx_pkt_set_packet_type(core->rx_pkt,
+        get_eth_packet_type(PKT_GET_ETH_HDR(filter_buf)));
+
+    if (!e1000e_receive_filter(core, filter_buf, size)) {
+        trace_e1000e_rx_flt_dropped();
+        return orig_size;
+    }
+
+    net_rx_pkt_attach_iovec_ex(core->rx_pkt, iov, iovcnt, iov_ofs,
+                               e1000x_vlan_enabled(core->mac), core->mac[VET]);
+
+    e1000e_rss_parse_packet(core, core->rx_pkt, &rss_info);
+    e1000e_rx_ring_init(core, &rxr, rss_info.queue);
+
+    trace_e1000e_rx_rss_dispatched_to_queue(rxr.i->idx);
+
+    total_size = net_rx_pkt_get_total_len(core->rx_pkt) +
+        e1000x_fcs_len(core->mac);
+
+    if (e1000e_has_rxbufs(core, rxr.i, total_size)) {
+        e1000e_rx_fix_l4_csum(core, core->rx_pkt);
+
+        e1000e_write_packet_to_guest(core, core->rx_pkt, &rxr, &rss_info);
+
+        retval = orig_size;
+
+        /* Perform small receive detection (RSRPD) */
+        if (total_size < core->mac[RSRPD]) {
+            n |= E1000_ICS_SRPD;
+        }
+
+        /* Perform ACK receive detection */
+        if  (!(core->mac[RFCTL] & E1000_RFCTL_ACK_DIS) &&
+             (e1000e_is_tcp_ack(core, core->rx_pkt))) {
+            n |= E1000_ICS_ACK;
+        }
+
+        /* Check if receive descriptor minimum threshold hit */
+        rdmts_hit = e1000e_rx_descr_threshold_hit(core, rxr.i);
+        n |= e1000e_rx_wb_interrupt_cause(core, rxr.i->idx, rdmts_hit);
+
+        trace_e1000e_rx_written_to_guest(n);
+    } else {
+        n |= E1000_ICS_RXO;
+        retval = 0;
+
+        trace_e1000e_rx_not_written_to_guest(n);
+    }
+
+    if (!e1000e_intrmgr_delay_rx_causes(core, &n)) {
+        trace_e1000e_rx_interrupt_set(n);
+        e1000e_set_interrupt_cause(core, n);
+    } else {
+        trace_e1000e_rx_interrupt_delayed(n);
+    }
+
+    return retval;
+}
+
+static inline bool
+e1000e_have_autoneg(E1000ECore *core)
+{
+    return core->phy[0][MII_BMCR] & MII_BMCR_AUTOEN;
+}
+
+static void e1000e_update_flowctl_status(E1000ECore *core)
+{
+    if (e1000e_have_autoneg(core) &&
+        core->phy[0][MII_BMSR] & MII_BMSR_AN_COMP) {
+        trace_e1000e_link_autoneg_flowctl(true);
+        core->mac[CTRL] |= E1000_CTRL_TFCE | E1000_CTRL_RFCE;
+    } else {
+        trace_e1000e_link_autoneg_flowctl(false);
+    }
+}
+
+static inline void
+e1000e_link_down(E1000ECore *core)
+{
+    e1000x_update_regs_on_link_down(core->mac, core->phy[0]);
+    e1000e_update_flowctl_status(core);
+}
+
+static inline void
+e1000e_set_phy_ctrl(E1000ECore *core, int index, uint16_t val)
+{
+    /* bits 0-5 reserved; MII_BMCR_[ANRESTART,RESET] are self clearing */
+    core->phy[0][MII_BMCR] = val & ~(0x3f |
+                                     MII_BMCR_RESET |
+                                     MII_BMCR_ANRESTART);
+
+    if ((val & MII_BMCR_ANRESTART) &&
+        e1000e_have_autoneg(core)) {
+        e1000x_restart_autoneg(core->mac, core->phy[0], core->autoneg_timer);
+    }
+}
+
+static void
+e1000e_set_phy_oem_bits(E1000ECore *core, int index, uint16_t val)
+{
+    core->phy[0][PHY_OEM_BITS] = val & ~BIT(10);
+
+    if (val & BIT(10)) {
+        e1000x_restart_autoneg(core->mac, core->phy[0], core->autoneg_timer);
+    }
+}
+
+static void
+e1000e_set_phy_page(E1000ECore *core, int index, uint16_t val)
+{
+    core->phy[0][PHY_PAGE] = val & PHY_PAGE_RW_MASK;
+}
+
+void
+e1000e_core_set_link_status(E1000ECore *core)
+{
+    NetClientState *nc = qemu_get_queue(core->owner_nic);
+    uint32_t old_status = core->mac[STATUS];
+
+    trace_e1000e_link_status_changed(nc->link_down ? false : true);
+
+    if (nc->link_down) {
+        e1000x_update_regs_on_link_down(core->mac, core->phy[0]);
+    } else {
+        if (e1000e_have_autoneg(core) &&
+            !(core->phy[0][MII_BMSR] & MII_BMSR_AN_COMP)) {
+            e1000x_restart_autoneg(core->mac, core->phy[0],
+                                   core->autoneg_timer);
+        } else {
+            e1000x_update_regs_on_link_up(core->mac, core->phy[0]);
+            e1000e_start_recv(core);
+        }
+    }
+
+    if (core->mac[STATUS] != old_status) {
+        e1000e_set_interrupt_cause(core, E1000_ICR_LSC);
+    }
+}
+
+static void
+e1000e_set_ctrl(E1000ECore *core, int index, uint32_t val)
+{
+    trace_e1000e_core_ctrl_write(index, val);
+
+    /* RST is self clearing */
+    core->mac[CTRL] = val & ~E1000_CTRL_RST;
+    core->mac[CTRL_DUP] = core->mac[CTRL];
+
+    trace_e1000e_link_set_params(
+        !!(val & E1000_CTRL_ASDE),
+        (val & E1000_CTRL_SPD_SEL) >> E1000_CTRL_SPD_SHIFT,
+        !!(val & E1000_CTRL_FRCSPD),
+        !!(val & E1000_CTRL_FRCDPX),
+        !!(val & E1000_CTRL_RFCE),
+        !!(val & E1000_CTRL_TFCE));
+
+    if (val & E1000_CTRL_RST) {
+        trace_e1000e_core_ctrl_sw_reset();
+        e1000e_reset(core, true);
+    }
+
+    if (val & E1000_CTRL_PHY_RST) {
+        trace_e1000e_core_ctrl_phy_reset();
+        core->mac[STATUS] |= E1000_STATUS_PHYRA;
+    }
+}
+
+static void
+e1000e_set_rfctl(E1000ECore *core, int index, uint32_t val)
+{
+    trace_e1000e_rx_set_rfctl(val);
+
+    if (!(val & E1000_RFCTL_ISCSI_DIS)) {
+        trace_e1000e_wrn_iscsi_filtering_not_supported();
+    }
+
+    if (!(val & E1000_RFCTL_NFSW_DIS)) {
+        trace_e1000e_wrn_nfsw_filtering_not_supported();
+    }
+
+    if (!(val & E1000_RFCTL_NFSR_DIS)) {
+        trace_e1000e_wrn_nfsr_filtering_not_supported();
+    }
+
+    core->mac[RFCTL] = val;
+}
+
+static void
+e1000e_calc_per_desc_buf_size(E1000ECore *core)
+{
+    int i;
+    core->rx_desc_buf_size = 0;
+
+    for (i = 0; i < ARRAY_SIZE(core->rxbuf_sizes); i++) {
+        core->rx_desc_buf_size += core->rxbuf_sizes[i];
+    }
+}
+
+static void
+e1000e_parse_rxbufsize(E1000ECore *core)
+{
+    uint32_t rctl = core->mac[RCTL];
+
+    memset(core->rxbuf_sizes, 0, sizeof(core->rxbuf_sizes));
+
+    if (rctl & E1000_RCTL_DTYP_MASK) {
+        uint32_t bsize;
+
+        bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE0_MASK;
+        core->rxbuf_sizes[0] = (bsize >> E1000_PSRCTL_BSIZE0_SHIFT) * 128;
+
+        bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE1_MASK;
+        core->rxbuf_sizes[1] = (bsize >> E1000_PSRCTL_BSIZE1_SHIFT) * 1024;
+
+        bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE2_MASK;
+        core->rxbuf_sizes[2] = (bsize >> E1000_PSRCTL_BSIZE2_SHIFT) * 1024;
+
+        bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE3_MASK;
+        core->rxbuf_sizes[3] = (bsize >> E1000_PSRCTL_BSIZE3_SHIFT) * 1024;
+    } else if (rctl & E1000_RCTL_FLXBUF_MASK) {
+        int flxbuf = rctl & E1000_RCTL_FLXBUF_MASK;
+        core->rxbuf_sizes[0] = (flxbuf >> E1000_RCTL_FLXBUF_SHIFT) * 1024;
+    } else {
+        core->rxbuf_sizes[0] = e1000x_rxbufsize(rctl);
+    }
+
+    trace_e1000e_rx_desc_buff_sizes(core->rxbuf_sizes[0], core->rxbuf_sizes[1],
+                                    core->rxbuf_sizes[2], core->rxbuf_sizes[3]);
+
+    e1000e_calc_per_desc_buf_size(core);
+}
+
+static void
+e1000e_calc_rxdesclen(E1000ECore *core)
+{
+    if (e1000e_rx_use_legacy_descriptor(core)) {
+        core->rx_desc_len = sizeof(struct e1000_rx_desc);
+    } else {
+        if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) {
+            core->rx_desc_len = sizeof(union e1000_rx_desc_packet_split);
+        } else {
+            core->rx_desc_len = sizeof(union e1000_rx_desc_extended);
+        }
+    }
+    trace_e1000e_rx_desc_len(core->rx_desc_len);
+}
+
+static void
+e1000e_set_rx_control(E1000ECore *core, int index, uint32_t val)
+{
+    core->mac[RCTL] = val;
+    trace_e1000e_rx_set_rctl(core->mac[RCTL]);
+
+    if (val & E1000_RCTL_EN) {
+        e1000e_parse_rxbufsize(core);
+        e1000e_calc_rxdesclen(core);
+        core->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1 +
+                                E1000_RING_DESC_LEN_SHIFT;
+
+        e1000e_start_recv(core);
+    }
+}
+
+static
+void(*e1000e_phyreg_writeops[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE])
+(E1000ECore *, int, uint16_t) = {
+    [0] = {
+        [MII_BMCR]     = e1000e_set_phy_ctrl,
+        [PHY_PAGE]     = e1000e_set_phy_page,
+        [PHY_OEM_BITS] = e1000e_set_phy_oem_bits
+    }
+};
+
+static inline void
+e1000e_clear_ims_bits(E1000ECore *core, uint32_t bits)
+{
+    trace_e1000e_irq_clear_ims(bits, core->mac[IMS], core->mac[IMS] & ~bits);
+    core->mac[IMS] &= ~bits;
+}
+
+static inline bool
+e1000e_postpone_interrupt(E1000IntrDelayTimer *timer)
+{
+    if (timer->running) {
+        trace_e1000e_irq_postponed_by_xitr(timer->delay_reg << 2);
+
+        return true;
+    }
+
+    if (timer->core->mac[timer->delay_reg] != 0) {
+        e1000e_intrmgr_rearm_timer(timer);
+    }
+
+    return false;
+}
+
+static inline bool
+e1000e_itr_should_postpone(E1000ECore *core)
+{
+    return e1000e_postpone_interrupt(&core->itr);
+}
+
+static inline bool
+e1000e_eitr_should_postpone(E1000ECore *core, int idx)
+{
+    return e1000e_postpone_interrupt(&core->eitr[idx]);
+}
+
+static void
+e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg)
+{
+    uint32_t effective_eiac;
+
+    if (E1000_IVAR_ENTRY_VALID(int_cfg)) {
+        uint32_t vec = E1000_IVAR_ENTRY_VEC(int_cfg);
+        if (vec < E1000E_MSIX_VEC_NUM) {
+            if (!e1000e_eitr_should_postpone(core, vec)) {
+                trace_e1000e_irq_msix_notify_vec(vec);
+                msix_notify(core->owner, vec);
+            }
+        } else {
+            trace_e1000e_wrn_msix_vec_wrong(cause, int_cfg);
+        }
+    } else {
+        trace_e1000e_wrn_msix_invalid(cause, int_cfg);
+    }
+
+    if (core->mac[CTRL_EXT] & E1000_CTRL_EXT_EIAME) {
+        trace_e1000e_irq_iam_clear_eiame(core->mac[IAM], cause);
+        core->mac[IAM] &= ~cause;
+    }
+
+    trace_e1000e_irq_icr_clear_eiac(core->mac[ICR], core->mac[EIAC]);
+
+    effective_eiac = core->mac[EIAC] & cause;
+
+    core->mac[ICR] &= ~effective_eiac;
+    core->msi_causes_pending &= ~effective_eiac;
+
+    if (!(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
+        core->mac[IMS] &= ~effective_eiac;
+    }
+}
+
+static void
+e1000e_msix_notify(E1000ECore *core, uint32_t causes)
+{
+    if (causes & E1000_ICR_RXQ0) {
+        e1000e_msix_notify_one(core, E1000_ICR_RXQ0,
+                               E1000_IVAR_RXQ0(core->mac[IVAR]));
+    }
+
+    if (causes & E1000_ICR_RXQ1) {
+        e1000e_msix_notify_one(core, E1000_ICR_RXQ1,
+                               E1000_IVAR_RXQ1(core->mac[IVAR]));
+    }
+
+    if (causes & E1000_ICR_TXQ0) {
+        e1000e_msix_notify_one(core, E1000_ICR_TXQ0,
+                               E1000_IVAR_TXQ0(core->mac[IVAR]));
+    }
+
+    if (causes & E1000_ICR_TXQ1) {
+        e1000e_msix_notify_one(core, E1000_ICR_TXQ1,
+                               E1000_IVAR_TXQ1(core->mac[IVAR]));
+    }
+
+    if (causes & E1000_ICR_OTHER) {
+        e1000e_msix_notify_one(core, E1000_ICR_OTHER,
+                               E1000_IVAR_OTHER(core->mac[IVAR]));
+    }
+}
+
+static void
+e1000e_msix_clear_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg)
+{
+    if (E1000_IVAR_ENTRY_VALID(int_cfg)) {
+        uint32_t vec = E1000_IVAR_ENTRY_VEC(int_cfg);
+        if (vec < E1000E_MSIX_VEC_NUM) {
+            trace_e1000e_irq_msix_pending_clearing(cause, int_cfg, vec);
+            msix_clr_pending(core->owner, vec);
+        } else {
+            trace_e1000e_wrn_msix_vec_wrong(cause, int_cfg);
+        }
+    } else {
+        trace_e1000e_wrn_msix_invalid(cause, int_cfg);
+    }
+}
+
+static void
+e1000e_msix_clear(E1000ECore *core, uint32_t causes)
+{
+    if (causes & E1000_ICR_RXQ0) {
+        e1000e_msix_clear_one(core, E1000_ICR_RXQ0,
+                              E1000_IVAR_RXQ0(core->mac[IVAR]));
+    }
+
+    if (causes & E1000_ICR_RXQ1) {
+        e1000e_msix_clear_one(core, E1000_ICR_RXQ1,
+                              E1000_IVAR_RXQ1(core->mac[IVAR]));
+    }
+
+    if (causes & E1000_ICR_TXQ0) {
+        e1000e_msix_clear_one(core, E1000_ICR_TXQ0,
+                              E1000_IVAR_TXQ0(core->mac[IVAR]));
+    }
+
+    if (causes & E1000_ICR_TXQ1) {
+        e1000e_msix_clear_one(core, E1000_ICR_TXQ1,
+                              E1000_IVAR_TXQ1(core->mac[IVAR]));
+    }
+
+    if (causes & E1000_ICR_OTHER) {
+        e1000e_msix_clear_one(core, E1000_ICR_OTHER,
+                              E1000_IVAR_OTHER(core->mac[IVAR]));
+    }
+}
+
+static inline void
+e1000e_fix_icr_asserted(E1000ECore *core)
+{
+    core->mac[ICR] &= ~E1000_ICR_ASSERTED;
+    if (core->mac[ICR]) {
+        core->mac[ICR] |= E1000_ICR_ASSERTED;
+    }
+
+    trace_e1000e_irq_fix_icr_asserted(core->mac[ICR]);
+}
+
+static void
+e1000e_send_msi(E1000ECore *core, bool msix)
+{
+    uint32_t causes = core->mac[ICR] & core->mac[IMS] & ~E1000_ICR_ASSERTED;
+
+    core->msi_causes_pending &= causes;
+    causes ^= core->msi_causes_pending;
+    if (causes == 0) {
+        return;
+    }
+    core->msi_causes_pending |= causes;
+
+    if (msix) {
+        e1000e_msix_notify(core, causes);
+    } else {
+        if (!e1000e_itr_should_postpone(core)) {
+            trace_e1000e_irq_msi_notify(causes);
+            msi_notify(core->owner, 0);
+        }
+    }
+}
+
+static void
+e1000e_update_interrupt_state(E1000ECore *core)
+{
+    bool interrupts_pending;
+    bool is_msix = msix_enabled(core->owner);
+
+    /* Set ICR[OTHER] for MSI-X */
+    if (is_msix) {
+        if (core->mac[ICR] & E1000_ICR_OTHER_CAUSES) {
+            core->mac[ICR] |= E1000_ICR_OTHER;
+            trace_e1000e_irq_add_msi_other(core->mac[ICR]);
+        }
+    }
+
+    e1000e_fix_icr_asserted(core);
+
+    /*
+     * Make sure ICR and ICS registers have the same value.
+     * The spec says that the ICS register is write-only.  However in practice,
+     * on real hardware ICS is readable, and for reads it has the same value as
+     * ICR (except that ICS does not have the clear on read behaviour of ICR).
+     *
+     * The VxWorks PRO/1000 driver uses this behaviour.
+     */
+    core->mac[ICS] = core->mac[ICR];
+
+    interrupts_pending = (core->mac[IMS] & core->mac[ICR]) ? true : false;
+    if (!interrupts_pending) {
+        core->msi_causes_pending = 0;
+    }
+
+    trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS],
+                                        core->mac[ICR], core->mac[IMS]);
+
+    if (is_msix || msi_enabled(core->owner)) {
+        if (interrupts_pending) {
+            e1000e_send_msi(core, is_msix);
+        }
+    } else {
+        if (interrupts_pending) {
+            if (!e1000e_itr_should_postpone(core)) {
+                e1000e_raise_legacy_irq(core);
+            }
+        } else {
+            e1000e_lower_legacy_irq(core);
+        }
+    }
+}
+
+static void
+e1000e_set_interrupt_cause(E1000ECore *core, uint32_t val)
+{
+    trace_e1000e_irq_set_cause_entry(val, core->mac[ICR]);
+
+    val |= e1000e_intmgr_collect_delayed_causes(core);
+    core->mac[ICR] |= val;
+
+    trace_e1000e_irq_set_cause_exit(val, core->mac[ICR]);
+
+    e1000e_update_interrupt_state(core);
+}
+
+static inline void
+e1000e_autoneg_timer(void *opaque)
+{
+    E1000ECore *core = opaque;
+    if (!qemu_get_queue(core->owner_nic)->link_down) {
+        e1000x_update_regs_on_autoneg_done(core->mac, core->phy[0]);
+        e1000e_start_recv(core);
+
+        e1000e_update_flowctl_status(core);
+        /* signal link status change to the guest */
+        e1000e_set_interrupt_cause(core, E1000_ICR_LSC);
+    }
+}
+
+static inline uint16_t
+e1000e_get_reg_index_with_offset(const uint16_t *mac_reg_access, hwaddr addr)
+{
+    uint16_t index = (addr & 0x1ffff) >> 2;
+    return index + (mac_reg_access[index] & 0xfffe);
+}
+
+static const char e1000e_phy_regcap[E1000E_PHY_PAGES][0x20] = {
+    [0] = {
+        [MII_BMCR]              = PHY_ANYPAGE | PHY_RW,
+        [MII_BMSR]              = PHY_ANYPAGE | PHY_R,
+        [MII_PHYID1]            = PHY_ANYPAGE | PHY_R,
+        [MII_PHYID2]            = PHY_ANYPAGE | PHY_R,
+        [MII_ANAR]              = PHY_ANYPAGE | PHY_RW,
+        [MII_ANLPAR]            = PHY_ANYPAGE | PHY_R,
+        [MII_ANER]              = PHY_ANYPAGE | PHY_R,
+        [MII_ANNP]              = PHY_ANYPAGE | PHY_RW,
+        [MII_ANLPRNP]           = PHY_ANYPAGE | PHY_R,
+        [MII_CTRL1000]          = PHY_ANYPAGE | PHY_RW,
+        [MII_STAT1000]          = PHY_ANYPAGE | PHY_R,
+        [MII_EXTSTAT]           = PHY_ANYPAGE | PHY_R,
+        [PHY_PAGE]              = PHY_ANYPAGE | PHY_RW,
+
+        [PHY_COPPER_CTRL1]      = PHY_RW,
+        [PHY_COPPER_STAT1]      = PHY_R,
+        [PHY_COPPER_CTRL3]      = PHY_RW,
+        [PHY_RX_ERR_CNTR]       = PHY_R,
+        [PHY_OEM_BITS]          = PHY_RW,
+        [PHY_BIAS_1]            = PHY_RW,
+        [PHY_BIAS_2]            = PHY_RW,
+        [PHY_COPPER_INT_ENABLE] = PHY_RW,
+        [PHY_COPPER_STAT2]      = PHY_R,
+        [PHY_COPPER_CTRL2]      = PHY_RW
+    },
+    [2] = {
+        [PHY_MAC_CTRL1]         = PHY_RW,
+        [PHY_MAC_INT_ENABLE]    = PHY_RW,
+        [PHY_MAC_STAT]          = PHY_R,
+        [PHY_MAC_CTRL2]         = PHY_RW
+    },
+    [3] = {
+        [PHY_LED_03_FUNC_CTRL1] = PHY_RW,
+        [PHY_LED_03_POL_CTRL]   = PHY_RW,
+        [PHY_LED_TIMER_CTRL]    = PHY_RW,
+        [PHY_LED_45_CTRL]       = PHY_RW
+    },
+    [5] = {
+        [PHY_1000T_SKEW]        = PHY_R,
+        [PHY_1000T_SWAP]        = PHY_R
+    },
+    [6] = {
+        [PHY_CRC_COUNTERS]      = PHY_R
+    }
+};
+
+static bool
+e1000e_phy_reg_check_cap(E1000ECore *core, uint32_t addr,
+                         char cap, uint8_t *page)
+{
+    *page =
+        (e1000e_phy_regcap[0][addr] & PHY_ANYPAGE) ? 0
+                                                    : core->phy[0][PHY_PAGE];
+
+    if (*page >= E1000E_PHY_PAGES) {
+        return false;
+    }
+
+    return e1000e_phy_regcap[*page][addr] & cap;
+}
+
+static void
+e1000e_phy_reg_write(E1000ECore *core, uint8_t page,
+                     uint32_t addr, uint16_t data)
+{
+    assert(page < E1000E_PHY_PAGES);
+    assert(addr < E1000E_PHY_PAGE_SIZE);
+
+    if (e1000e_phyreg_writeops[page][addr]) {
+        e1000e_phyreg_writeops[page][addr](core, addr, data);
+    } else {
+        core->phy[page][addr] = data;
+    }
+}
+
+static void
+e1000e_set_mdic(E1000ECore *core, int index, uint32_t val)
+{
+    uint32_t data = val & E1000_MDIC_DATA_MASK;
+    uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
+    uint8_t page;
+
+    if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) { /* phy # */
+        val = core->mac[MDIC] | E1000_MDIC_ERROR;
+    } else if (val & E1000_MDIC_OP_READ) {
+        if (!e1000e_phy_reg_check_cap(core, addr, PHY_R, &page)) {
+            trace_e1000e_core_mdic_read_unhandled(page, addr);
+            val |= E1000_MDIC_ERROR;
+        } else {
+            val = (val ^ data) | core->phy[page][addr];
+            trace_e1000e_core_mdic_read(page, addr, val);
+        }
+    } else if (val & E1000_MDIC_OP_WRITE) {
+        if (!e1000e_phy_reg_check_cap(core, addr, PHY_W, &page)) {
+            trace_e1000e_core_mdic_write_unhandled(page, addr);
+            val |= E1000_MDIC_ERROR;
+        } else {
+            trace_e1000e_core_mdic_write(page, addr, data);
+            e1000e_phy_reg_write(core, page, addr, data);
+        }
+    }
+    core->mac[MDIC] = val | E1000_MDIC_READY;
+
+    if (val & E1000_MDIC_INT_EN) {
+        e1000e_set_interrupt_cause(core, E1000_ICR_MDAC);
+    }
+}
+
+static void
+e1000e_set_rdt(E1000ECore *core, int index, uint32_t val)
+{
+    core->mac[index] = val & 0xffff;
+    trace_e1000e_rx_set_rdt(e1000e_mq_queue_idx(RDT0, index), val);
+    e1000e_start_recv(core);
+}
+
+static void
+e1000e_set_status(E1000ECore *core, int index, uint32_t val)
+{
+    if ((val & E1000_STATUS_PHYRA) == 0) {
+        core->mac[index] &= ~E1000_STATUS_PHYRA;
+    }
+}
+
+static void
+e1000e_set_ctrlext(E1000ECore *core, int index, uint32_t val)
+{
+    trace_e1000e_link_set_ext_params(!!(val & E1000_CTRL_EXT_ASDCHK),
+                                     !!(val & E1000_CTRL_EXT_SPD_BYPS));
+
+    /* Zero self-clearing bits */
+    val &= ~(E1000_CTRL_EXT_ASDCHK | E1000_CTRL_EXT_EE_RST);
+    core->mac[CTRL_EXT] = val;
+}
+
+static void
+e1000e_set_pbaclr(E1000ECore *core, int index, uint32_t val)
+{
+    int i;
+
+    core->mac[PBACLR] = val & E1000_PBACLR_VALID_MASK;
+
+    if (!msix_enabled(core->owner)) {
+        return;
+    }
+
+    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
+        if (core->mac[PBACLR] & BIT(i)) {
+            msix_clr_pending(core->owner, i);
+        }
+    }
+}
+
+static void
+e1000e_set_fcrth(E1000ECore *core, int index, uint32_t val)
+{
+    core->mac[FCRTH] = val & 0xFFF8;
+}
+
+static void
+e1000e_set_fcrtl(E1000ECore *core, int index, uint32_t val)
+{
+    core->mac[FCRTL] = val & 0x8000FFF8;
+}
+
+#define E1000E_LOW_BITS_SET_FUNC(num)                                \
+    static void                                                      \
+    e1000e_set_##num##bit(E1000ECore *core, int index, uint32_t val) \
+    {                                                                \
+        core->mac[index] = val & (BIT(num) - 1);                     \
+    }
+
+E1000E_LOW_BITS_SET_FUNC(4)
+E1000E_LOW_BITS_SET_FUNC(6)
+E1000E_LOW_BITS_SET_FUNC(11)
+E1000E_LOW_BITS_SET_FUNC(12)
+E1000E_LOW_BITS_SET_FUNC(13)
+E1000E_LOW_BITS_SET_FUNC(16)
+
+static void
+e1000e_set_vet(E1000ECore *core, int index, uint32_t val)
+{
+    core->mac[VET] = val & 0xffff;
+    trace_e1000e_vlan_vet(core->mac[VET]);
+}
+
+static void
+e1000e_set_dlen(E1000ECore *core, int index, uint32_t val)
+{
+    core->mac[index] = val & E1000_XDLEN_MASK;
+}
+
+static void
+e1000e_set_dbal(E1000ECore *core, int index, uint32_t val)
+{
+    core->mac[index] = val & E1000_XDBAL_MASK;
+}
+
+static void
+e1000e_set_tctl(E1000ECore *core, int index, uint32_t val)
+{
+    E1000E_TxRing txr;
+    core->mac[index] = val;
+
+    if (core->mac[TARC0] & E1000_TARC_ENABLE) {
+        e1000e_tx_ring_init(core, &txr, 0);
+        e1000e_start_xmit(core, &txr);
+    }
+
+    if (core->mac[TARC1] & E1000_TARC_ENABLE) {
+        e1000e_tx_ring_init(core, &txr, 1);
+        e1000e_start_xmit(core, &txr);
+    }
+}
+
+static void
+e1000e_set_tdt(E1000ECore *core, int index, uint32_t val)
+{
+    E1000E_TxRing txr;
+    int qidx = e1000e_mq_queue_idx(TDT, index);
+    uint32_t tarc_reg = (qidx == 0) ? TARC0 : TARC1;
+
+    core->mac[index] = val & 0xffff;
+
+    if (core->mac[tarc_reg] & E1000_TARC_ENABLE) {
+        e1000e_tx_ring_init(core, &txr, qidx);
+        e1000e_start_xmit(core, &txr);
+    }
+}
+
+static void
+e1000e_set_ics(E1000ECore *core, int index, uint32_t val)
+{
+    trace_e1000e_irq_write_ics(val);
+    e1000e_set_interrupt_cause(core, val);
+}
+
+static void
+e1000e_set_icr(E1000ECore *core, int index, uint32_t val)
+{
+    uint32_t icr = 0;
+    if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
+        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
+        trace_e1000e_irq_icr_process_iame();
+        e1000e_clear_ims_bits(core, core->mac[IAM]);
+    }
+
+    icr = core->mac[ICR] & ~val;
+    /*
+     * Windows driver expects that the "receive overrun" bit and other
+     * ones to be cleared when the "Other" bit (#24) is cleared.
+     */
+    icr = (val & E1000_ICR_OTHER) ? (icr & ~E1000_ICR_OTHER_CAUSES) : icr;
+    trace_e1000e_irq_icr_write(val, core->mac[ICR], icr);
+    core->mac[ICR] = icr;
+    e1000e_update_interrupt_state(core);
+}
+
+static void
+e1000e_set_imc(E1000ECore *core, int index, uint32_t val)
+{
+    trace_e1000e_irq_ims_clear_set_imc(val);
+    e1000e_clear_ims_bits(core, val);
+    e1000e_update_interrupt_state(core);
+}
+
+static void
+e1000e_set_ims(E1000ECore *core, int index, uint32_t val)
+{
+    static const uint32_t ims_ext_mask =
+        E1000_IMS_RXQ0 | E1000_IMS_RXQ1 |
+        E1000_IMS_TXQ0 | E1000_IMS_TXQ1 |
+        E1000_IMS_OTHER;
+
+    static const uint32_t ims_valid_mask =
+        E1000_IMS_TXDW      | E1000_IMS_TXQE    | E1000_IMS_LSC  |
+        E1000_IMS_RXDMT0    | E1000_IMS_RXO     | E1000_IMS_RXT0 |
+        E1000_IMS_MDAC      | E1000_IMS_TXD_LOW | E1000_IMS_SRPD |
+        E1000_IMS_ACK       | E1000_IMS_MNG     | E1000_IMS_RXQ0 |
+        E1000_IMS_RXQ1      | E1000_IMS_TXQ0    | E1000_IMS_TXQ1 |
+        E1000_IMS_OTHER;
+
+    uint32_t valid_val = val & ims_valid_mask;
+
+    trace_e1000e_irq_set_ims(val, core->mac[IMS], core->mac[IMS] | valid_val);
+    core->mac[IMS] |= valid_val;
+
+    if ((valid_val & ims_ext_mask) &&
+        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_PBA_CLR) &&
+        msix_enabled(core->owner)) {
+        e1000e_msix_clear(core, valid_val);
+    }
+
+    if ((valid_val == ims_valid_mask) &&
+        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_INT_TIMERS_CLEAR_ENA)) {
+        trace_e1000e_irq_fire_all_timers(val);
+        e1000e_intrmgr_fire_all_timers(core);
+    }
+
+    e1000e_update_interrupt_state(core);
+}
+
+static void
+e1000e_set_rdtr(E1000ECore *core, int index, uint32_t val)
+{
+    e1000e_set_16bit(core, index, val);
+
+    if ((val & E1000_RDTR_FPD) && (core->rdtr.running)) {
+        trace_e1000e_irq_rdtr_fpd_running();
+        e1000e_intrmgr_fire_delayed_interrupts(core);
+    } else {
+        trace_e1000e_irq_rdtr_fpd_not_running();
+    }
+}
+
+static void
+e1000e_set_tidv(E1000ECore *core, int index, uint32_t val)
+{
+    e1000e_set_16bit(core, index, val);
+
+    if ((val & E1000_TIDV_FPD) && (core->tidv.running)) {
+        trace_e1000e_irq_tidv_fpd_running();
+        e1000e_intrmgr_fire_delayed_interrupts(core);
+    } else {
+        trace_e1000e_irq_tidv_fpd_not_running();
+    }
+}
+
+static uint32_t
+e1000e_mac_readreg(E1000ECore *core, int index)
+{
+    return core->mac[index];
+}
+
+static uint32_t
+e1000e_mac_ics_read(E1000ECore *core, int index)
+{
+    trace_e1000e_irq_read_ics(core->mac[ICS]);
+    return core->mac[ICS];
+}
+
+static uint32_t
+e1000e_mac_ims_read(E1000ECore *core, int index)
+{
+    trace_e1000e_irq_read_ims(core->mac[IMS]);
+    return core->mac[IMS];
+}
+
+static uint32_t
+e1000e_mac_swsm_read(E1000ECore *core, int index)
+{
+    uint32_t val = core->mac[SWSM];
+    core->mac[SWSM] = val | E1000_SWSM_SMBI;
+    return val;
+}
+
+static uint32_t
+e1000e_mac_itr_read(E1000ECore *core, int index)
+{
+    return core->itr_guest_value;
+}
+
+static uint32_t
+e1000e_mac_eitr_read(E1000ECore *core, int index)
+{
+    return core->eitr_guest_value[index - EITR];
+}
+
+static uint32_t
+e1000e_mac_icr_read(E1000ECore *core, int index)
+{
+    uint32_t ret = core->mac[ICR];
+    trace_e1000e_irq_icr_read_entry(ret);
+
+    if (core->mac[IMS] == 0) {
+        trace_e1000e_irq_icr_clear_zero_ims();
+        core->mac[ICR] = 0;
+    }
+
+    if (!msix_enabled(core->owner)) {
+        trace_e1000e_irq_icr_clear_nonmsix_icr_read();
+        core->mac[ICR] = 0;
+    }
+
+    if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
+        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
+        trace_e1000e_irq_icr_clear_iame();
+        core->mac[ICR] = 0;
+        trace_e1000e_irq_icr_process_iame();
+        e1000e_clear_ims_bits(core, core->mac[IAM]);
+    }
+
+    trace_e1000e_irq_icr_read_exit(core->mac[ICR]);
+    e1000e_update_interrupt_state(core);
+    return ret;
+}
+
+static uint32_t
+e1000e_mac_read_clr4(E1000ECore *core, int index)
+{
+    uint32_t ret = core->mac[index];
+
+    core->mac[index] = 0;
+    return ret;
+}
+
+static uint32_t
+e1000e_mac_read_clr8(E1000ECore *core, int index)
+{
+    uint32_t ret = core->mac[index];
+
+    core->mac[index] = 0;
+    core->mac[index - 1] = 0;
+    return ret;
+}
+
+static uint32_t
+e1000e_get_ctrl(E1000ECore *core, int index)
+{
+    uint32_t val = core->mac[CTRL];
+
+    trace_e1000e_link_read_params(
+        !!(val & E1000_CTRL_ASDE),
+        (val & E1000_CTRL_SPD_SEL) >> E1000_CTRL_SPD_SHIFT,
+        !!(val & E1000_CTRL_FRCSPD),
+        !!(val & E1000_CTRL_FRCDPX),
+        !!(val & E1000_CTRL_RFCE),
+        !!(val & E1000_CTRL_TFCE));
+
+    return val;
+}
+
+static uint32_t
+e1000e_get_status(E1000ECore *core, int index)
+{
+    uint32_t res = core->mac[STATUS];
+
+    if (!(core->mac[CTRL] & E1000_CTRL_GIO_MASTER_DISABLE)) {
+        res |= E1000_STATUS_GIO_MASTER_ENABLE;
+    }
+
+    if (core->mac[CTRL] & E1000_CTRL_FRCDPX) {
+        res |= (core->mac[CTRL] & E1000_CTRL_FD) ? E1000_STATUS_FD : 0;
+    } else {
+        res |= E1000_STATUS_FD;
+    }
+
+    if ((core->mac[CTRL] & E1000_CTRL_FRCSPD) ||
+        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_SPD_BYPS)) {
+        switch (core->mac[CTRL] & E1000_CTRL_SPD_SEL) {
+        case E1000_CTRL_SPD_10:
+            res |= E1000_STATUS_SPEED_10;
+            break;
+        case E1000_CTRL_SPD_100:
+            res |= E1000_STATUS_SPEED_100;
+            break;
+        case E1000_CTRL_SPD_1000:
+        default:
+            res |= E1000_STATUS_SPEED_1000;
+            break;
+        }
+    } else {
+        res |= E1000_STATUS_SPEED_1000;
+    }
+
+    trace_e1000e_link_status(
+        !!(res & E1000_STATUS_LU),
+        !!(res & E1000_STATUS_FD),
+        (res & E1000_STATUS_SPEED_MASK) >> E1000_STATUS_SPEED_SHIFT,
+        (res & E1000_STATUS_ASDV) >> E1000_STATUS_ASDV_SHIFT);
+
+    return res;
+}
+
+static uint32_t
+e1000e_get_tarc(E1000ECore *core, int index)
+{
+    return core->mac[index] & ((BIT(11) - 1) |
+                                BIT(27)      |
+                                BIT(28)      |
+                                BIT(29)      |
+                                BIT(30));
+}
+
+static void
+e1000e_mac_writereg(E1000ECore *core, int index, uint32_t val)
+{
+    core->mac[index] = val;
+}
+
+static void
+e1000e_mac_setmacaddr(E1000ECore *core, int index, uint32_t val)
+{
+    uint32_t macaddr[2];
+
+    core->mac[index] = val;
+
+    macaddr[0] = cpu_to_le32(core->mac[RA]);
+    macaddr[1] = cpu_to_le32(core->mac[RA + 1]);
+    qemu_format_nic_info_str(qemu_get_queue(core->owner_nic),
+        (uint8_t *) macaddr);
+
+    trace_e1000e_mac_set_sw(MAC_ARG(macaddr));
+}
+
+static void
+e1000e_set_eecd(E1000ECore *core, int index, uint32_t val)
+{
+    static const uint32_t ro_bits = E1000_EECD_PRES          |
+                                    E1000_EECD_AUTO_RD       |
+                                    E1000_EECD_SIZE_EX_MASK;
+
+    core->mac[EECD] = (core->mac[EECD] & ro_bits) | (val & ~ro_bits);
+}
+
+static void
+e1000e_set_eerd(E1000ECore *core, int index, uint32_t val)
+{
+    uint32_t addr = (val >> E1000_EERW_ADDR_SHIFT) & E1000_EERW_ADDR_MASK;
+    uint32_t flags = 0;
+    uint32_t data = 0;
+
+    if ((addr < E1000E_EEPROM_SIZE) && (val & E1000_EERW_START)) {
+        data = core->eeprom[addr];
+        flags = E1000_EERW_DONE;
+    }
+
+    core->mac[EERD] = flags                           |
+                      (addr << E1000_EERW_ADDR_SHIFT) |
+                      (data << E1000_EERW_DATA_SHIFT);
+}
+
+static void
+e1000e_set_eewr(E1000ECore *core, int index, uint32_t val)
+{
+    uint32_t addr = (val >> E1000_EERW_ADDR_SHIFT) & E1000_EERW_ADDR_MASK;
+    uint32_t data = (val >> E1000_EERW_DATA_SHIFT) & E1000_EERW_DATA_MASK;
+    uint32_t flags = 0;
+
+    if ((addr < E1000E_EEPROM_SIZE) && (val & E1000_EERW_START)) {
+        core->eeprom[addr] = data;
+        flags = E1000_EERW_DONE;
+    }
+
+    core->mac[EERD] = flags                           |
+                      (addr << E1000_EERW_ADDR_SHIFT) |
+                      (data << E1000_EERW_DATA_SHIFT);
+}
+
+static void
+e1000e_set_rxdctl(E1000ECore *core, int index, uint32_t val)
+{
+    core->mac[RXDCTL] = core->mac[RXDCTL1] = val;
+}
+
+static void
+e1000e_set_itr(E1000ECore *core, int index, uint32_t val)
+{
+    uint32_t interval = val & 0xffff;
+
+    trace_e1000e_irq_itr_set(val);
+
+    core->itr_guest_value = interval;
+    core->mac[index] = MAX(interval, E1000E_MIN_XITR);
+}
+
+static void
+e1000e_set_eitr(E1000ECore *core, int index, uint32_t val)
+{
+    uint32_t interval = val & 0xffff;
+    uint32_t eitr_num = index - EITR;
+
+    trace_e1000e_irq_eitr_set(eitr_num, val);
+
+    core->eitr_guest_value[eitr_num] = interval;
+    core->mac[index] = MAX(interval, E1000E_MIN_XITR);
+}
+
+static void
+e1000e_set_psrctl(E1000ECore *core, int index, uint32_t val)
+{
+    if (core->mac[RCTL] & E1000_RCTL_DTYP_MASK) {
+
+        if ((val & E1000_PSRCTL_BSIZE0_MASK) == 0) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "e1000e: PSRCTL.BSIZE0 cannot be zero");
+            return;
+        }
+
+        if ((val & E1000_PSRCTL_BSIZE1_MASK) == 0) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "e1000e: PSRCTL.BSIZE1 cannot be zero");
+            return;
+        }
+    }
+
+    core->mac[PSRCTL] = val;
+}
+
+static void
+e1000e_update_rx_offloads(E1000ECore *core)
+{
+    int cso_state = e1000e_rx_l4_cso_enabled(core);
+
+    trace_e1000e_rx_set_cso(cso_state);
+
+    if (core->has_vnet) {
+        qemu_set_offload(qemu_get_queue(core->owner_nic)->peer,
+                         cso_state, 0, 0, 0, 0);
+    }
+}
+
+static void
+e1000e_set_rxcsum(E1000ECore *core, int index, uint32_t val)
+{
+    core->mac[RXCSUM] = val;
+    e1000e_update_rx_offloads(core);
+}
+
+static void
+e1000e_set_gcr(E1000ECore *core, int index, uint32_t val)
+{
+    uint32_t ro_bits = core->mac[GCR] & E1000_GCR_RO_BITS;
+    core->mac[GCR] = (val & ~E1000_GCR_RO_BITS) | ro_bits;
+}
+
+#define e1000e_getreg(x)    [x] = e1000e_mac_readreg
+typedef uint32_t (*readops)(E1000ECore *, int);
+static const readops e1000e_macreg_readops[] = {
+    e1000e_getreg(PBA),
+    e1000e_getreg(WUFC),
+    e1000e_getreg(MANC),
+    e1000e_getreg(TOTL),
+    e1000e_getreg(RDT0),
+    e1000e_getreg(RDBAH0),
+    e1000e_getreg(TDBAL1),
+    e1000e_getreg(RDLEN0),
+    e1000e_getreg(RDH1),
+    e1000e_getreg(LATECOL),
+    e1000e_getreg(SEQEC),
+    e1000e_getreg(XONTXC),
+    e1000e_getreg(AIT),
+    e1000e_getreg(TDFH),
+    e1000e_getreg(TDFT),
+    e1000e_getreg(TDFHS),
+    e1000e_getreg(TDFTS),
+    e1000e_getreg(TDFPC),
+    e1000e_getreg(WUS),
+    e1000e_getreg(PBS),
+    e1000e_getreg(RDFH),
+    e1000e_getreg(RDFT),
+    e1000e_getreg(RDFHS),
+    e1000e_getreg(RDFTS),
+    e1000e_getreg(RDFPC),
+    e1000e_getreg(GORCL),
+    e1000e_getreg(MGTPRC),
+    e1000e_getreg(EERD),
+    e1000e_getreg(EIAC),
+    e1000e_getreg(PSRCTL),
+    e1000e_getreg(MANC2H),
+    e1000e_getreg(RXCSUM),
+    e1000e_getreg(GSCL_3),
+    e1000e_getreg(GSCN_2),
+    e1000e_getreg(RSRPD),
+    e1000e_getreg(RDBAL1),
+    e1000e_getreg(FCAH),
+    e1000e_getreg(FCRTH),
+    e1000e_getreg(FLOP),
+    e1000e_getreg(FLASHT),
+    e1000e_getreg(RXSTMPH),
+    e1000e_getreg(TXSTMPL),
+    e1000e_getreg(TIMADJL),
+    e1000e_getreg(TXDCTL),
+    e1000e_getreg(RDH0),
+    e1000e_getreg(TDT1),
+    e1000e_getreg(TNCRS),
+    e1000e_getreg(RJC),
+    e1000e_getreg(IAM),
+    e1000e_getreg(GSCL_2),
+    e1000e_getreg(RDBAH1),
+    e1000e_getreg(FLSWDATA),
+    e1000e_getreg(RXSATRH),
+    e1000e_getreg(TIPG),
+    e1000e_getreg(FLMNGCTL),
+    e1000e_getreg(FLMNGCNT),
+    e1000e_getreg(TSYNCTXCTL),
+    e1000e_getreg(EXTCNF_SIZE),
+    e1000e_getreg(EXTCNF_CTRL),
+    e1000e_getreg(EEMNGDATA),
+    e1000e_getreg(CTRL_EXT),
+    e1000e_getreg(SYSTIMH),
+    e1000e_getreg(EEMNGCTL),
+    e1000e_getreg(FLMNGDATA),
+    e1000e_getreg(TSYNCRXCTL),
+    e1000e_getreg(TDH),
+    e1000e_getreg(LEDCTL),
+    e1000e_getreg(TCTL),
+    e1000e_getreg(TDBAL),
+    e1000e_getreg(TDLEN),
+    e1000e_getreg(TDH1),
+    e1000e_getreg(RADV),
+    e1000e_getreg(ECOL),
+    e1000e_getreg(DC),
+    e1000e_getreg(RLEC),
+    e1000e_getreg(XOFFTXC),
+    e1000e_getreg(RFC),
+    e1000e_getreg(RNBC),
+    e1000e_getreg(MGTPTC),
+    e1000e_getreg(TIMINCA),
+    e1000e_getreg(RXCFGL),
+    e1000e_getreg(MFUTP01),
+    e1000e_getreg(FACTPS),
+    e1000e_getreg(GSCL_1),
+    e1000e_getreg(GSCN_0),
+    e1000e_getreg(GCR2),
+    e1000e_getreg(RDT1),
+    e1000e_getreg(PBACLR),
+    e1000e_getreg(FCTTV),
+    e1000e_getreg(EEWR),
+    e1000e_getreg(FLSWCTL),
+    e1000e_getreg(RXDCTL1),
+    e1000e_getreg(RXSATRL),
+    e1000e_getreg(SYSTIML),
+    e1000e_getreg(RXUDP),
+    e1000e_getreg(TORL),
+    e1000e_getreg(TDLEN1),
+    e1000e_getreg(MCC),
+    e1000e_getreg(WUC),
+    e1000e_getreg(EECD),
+    e1000e_getreg(MFUTP23),
+    e1000e_getreg(RAID),
+    e1000e_getreg(FCRTV),
+    e1000e_getreg(TXDCTL1),
+    e1000e_getreg(RCTL),
+    e1000e_getreg(TDT),
+    e1000e_getreg(MDIC),
+    e1000e_getreg(FCRUC),
+    e1000e_getreg(VET),
+    e1000e_getreg(RDBAL0),
+    e1000e_getreg(TDBAH1),
+    e1000e_getreg(RDTR),
+    e1000e_getreg(SCC),
+    e1000e_getreg(COLC),
+    e1000e_getreg(CEXTERR),
+    e1000e_getreg(XOFFRXC),
+    e1000e_getreg(IPAV),
+    e1000e_getreg(GOTCL),
+    e1000e_getreg(MGTPDC),
+    e1000e_getreg(GCR),
+    e1000e_getreg(IVAR),
+    e1000e_getreg(POEMB),
+    e1000e_getreg(MFVAL),
+    e1000e_getreg(FUNCTAG),
+    e1000e_getreg(GSCL_4),
+    e1000e_getreg(GSCN_3),
+    e1000e_getreg(MRQC),
+    e1000e_getreg(RDLEN1),
+    e1000e_getreg(FCT),
+    e1000e_getreg(FLA),
+    e1000e_getreg(FLOL),
+    e1000e_getreg(RXDCTL),
+    e1000e_getreg(RXSTMPL),
+    e1000e_getreg(TXSTMPH),
+    e1000e_getreg(TIMADJH),
+    e1000e_getreg(FCRTL),
+    e1000e_getreg(TDBAH),
+    e1000e_getreg(TADV),
+    e1000e_getreg(XONRXC),
+    e1000e_getreg(TSCTFC),
+    e1000e_getreg(RFCTL),
+    e1000e_getreg(GSCN_1),
+    e1000e_getreg(FCAL),
+    e1000e_getreg(FLSWCNT),
+
+    [TOTH]    = e1000e_mac_read_clr8,
+    [GOTCH]   = e1000e_mac_read_clr8,
+    [PRC64]   = e1000e_mac_read_clr4,
+    [PRC255]  = e1000e_mac_read_clr4,
+    [PRC1023] = e1000e_mac_read_clr4,
+    [PTC64]   = e1000e_mac_read_clr4,
+    [PTC255]  = e1000e_mac_read_clr4,
+    [PTC1023] = e1000e_mac_read_clr4,
+    [GPRC]    = e1000e_mac_read_clr4,
+    [TPT]     = e1000e_mac_read_clr4,
+    [RUC]     = e1000e_mac_read_clr4,
+    [BPRC]    = e1000e_mac_read_clr4,
+    [MPTC]    = e1000e_mac_read_clr4,
+    [IAC]     = e1000e_mac_read_clr4,
+    [ICR]     = e1000e_mac_icr_read,
+    [STATUS]  = e1000e_get_status,
+    [TARC0]   = e1000e_get_tarc,
+    [ICS]     = e1000e_mac_ics_read,
+    [TORH]    = e1000e_mac_read_clr8,
+    [GORCH]   = e1000e_mac_read_clr8,
+    [PRC127]  = e1000e_mac_read_clr4,
+    [PRC511]  = e1000e_mac_read_clr4,
+    [PRC1522] = e1000e_mac_read_clr4,
+    [PTC127]  = e1000e_mac_read_clr4,
+    [PTC511]  = e1000e_mac_read_clr4,
+    [PTC1522] = e1000e_mac_read_clr4,
+    [GPTC]    = e1000e_mac_read_clr4,
+    [TPR]     = e1000e_mac_read_clr4,
+    [ROC]     = e1000e_mac_read_clr4,
+    [MPRC]    = e1000e_mac_read_clr4,
+    [BPTC]    = e1000e_mac_read_clr4,
+    [TSCTC]   = e1000e_mac_read_clr4,
+    [ITR]     = e1000e_mac_itr_read,
+    [CTRL]    = e1000e_get_ctrl,
+    [TARC1]   = e1000e_get_tarc,
+    [SWSM]    = e1000e_mac_swsm_read,
+    [IMS]     = e1000e_mac_ims_read,
+
+    [CRCERRS ... MPC]      = e1000e_mac_readreg,
+    [IP6AT ... IP6AT + 3]  = e1000e_mac_readreg,
+    [IP4AT ... IP4AT + 6]  = e1000e_mac_readreg,
+    [RA ... RA + 31]       = e1000e_mac_readreg,
+    [WUPM ... WUPM + 31]   = e1000e_mac_readreg,
+    [MTA ... MTA + E1000_MC_TBL_SIZE - 1] = e1000e_mac_readreg,
+    [VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1]  = e1000e_mac_readreg,
+    [FFMT ... FFMT + 254]  = e1000e_mac_readreg,
+    [FFVT ... FFVT + 254]  = e1000e_mac_readreg,
+    [MDEF ... MDEF + 7]    = e1000e_mac_readreg,
+    [FFLT ... FFLT + 10]   = e1000e_mac_readreg,
+    [FTFT ... FTFT + 254]  = e1000e_mac_readreg,
+    [PBM ... PBM + 10239]  = e1000e_mac_readreg,
+    [RETA ... RETA + 31]   = e1000e_mac_readreg,
+    [RSSRK ... RSSRK + 31] = e1000e_mac_readreg,
+    [MAVTV0 ... MAVTV3]    = e1000e_mac_readreg,
+    [EITR...EITR + E1000E_MSIX_VEC_NUM - 1] = e1000e_mac_eitr_read
+};
+enum { E1000E_NREADOPS = ARRAY_SIZE(e1000e_macreg_readops) };
+
+#define e1000e_putreg(x)    [x] = e1000e_mac_writereg
+typedef void (*writeops)(E1000ECore *, int, uint32_t);
+static const writeops e1000e_macreg_writeops[] = {
+    e1000e_putreg(PBA),
+    e1000e_putreg(SWSM),
+    e1000e_putreg(WUFC),
+    e1000e_putreg(RDBAH1),
+    e1000e_putreg(TDBAH),
+    e1000e_putreg(TXDCTL),
+    e1000e_putreg(RDBAH0),
+    e1000e_putreg(LEDCTL),
+    e1000e_putreg(FCAL),
+    e1000e_putreg(FCRUC),
+    e1000e_putreg(WUC),
+    e1000e_putreg(WUS),
+    e1000e_putreg(IPAV),
+    e1000e_putreg(TDBAH1),
+    e1000e_putreg(TIMINCA),
+    e1000e_putreg(IAM),
+    e1000e_putreg(EIAC),
+    e1000e_putreg(IVAR),
+    e1000e_putreg(TARC0),
+    e1000e_putreg(TARC1),
+    e1000e_putreg(FLSWDATA),
+    e1000e_putreg(POEMB),
+    e1000e_putreg(MFUTP01),
+    e1000e_putreg(MFUTP23),
+    e1000e_putreg(MANC),
+    e1000e_putreg(MANC2H),
+    e1000e_putreg(MFVAL),
+    e1000e_putreg(EXTCNF_CTRL),
+    e1000e_putreg(FACTPS),
+    e1000e_putreg(FUNCTAG),
+    e1000e_putreg(GSCL_1),
+    e1000e_putreg(GSCL_2),
+    e1000e_putreg(GSCL_3),
+    e1000e_putreg(GSCL_4),
+    e1000e_putreg(GSCN_0),
+    e1000e_putreg(GSCN_1),
+    e1000e_putreg(GSCN_2),
+    e1000e_putreg(GSCN_3),
+    e1000e_putreg(GCR2),
+    e1000e_putreg(MRQC),
+    e1000e_putreg(FLOP),
+    e1000e_putreg(FLOL),
+    e1000e_putreg(FLSWCTL),
+    e1000e_putreg(FLSWCNT),
+    e1000e_putreg(FLA),
+    e1000e_putreg(RXDCTL1),
+    e1000e_putreg(TXDCTL1),
+    e1000e_putreg(TIPG),
+    e1000e_putreg(RXSTMPH),
+    e1000e_putreg(RXSTMPL),
+    e1000e_putreg(RXSATRL),
+    e1000e_putreg(RXSATRH),
+    e1000e_putreg(TXSTMPL),
+    e1000e_putreg(TXSTMPH),
+    e1000e_putreg(SYSTIML),
+    e1000e_putreg(SYSTIMH),
+    e1000e_putreg(TIMADJL),
+    e1000e_putreg(TIMADJH),
+    e1000e_putreg(RXUDP),
+    e1000e_putreg(RXCFGL),
+    e1000e_putreg(TSYNCRXCTL),
+    e1000e_putreg(TSYNCTXCTL),
+    e1000e_putreg(EXTCNF_SIZE),
+    e1000e_putreg(EEMNGCTL),
+    e1000e_putreg(RA),
+
+    [TDH1]     = e1000e_set_16bit,
+    [TDT1]     = e1000e_set_tdt,
+    [TCTL]     = e1000e_set_tctl,
+    [TDT]      = e1000e_set_tdt,
+    [MDIC]     = e1000e_set_mdic,
+    [ICS]      = e1000e_set_ics,
+    [TDH]      = e1000e_set_16bit,
+    [RDH0]     = e1000e_set_16bit,
+    [RDT0]     = e1000e_set_rdt,
+    [IMC]      = e1000e_set_imc,
+    [IMS]      = e1000e_set_ims,
+    [ICR]      = e1000e_set_icr,
+    [EECD]     = e1000e_set_eecd,
+    [RCTL]     = e1000e_set_rx_control,
+    [CTRL]     = e1000e_set_ctrl,
+    [RDTR]     = e1000e_set_rdtr,
+    [RADV]     = e1000e_set_16bit,
+    [TADV]     = e1000e_set_16bit,
+    [ITR]      = e1000e_set_itr,
+    [EERD]     = e1000e_set_eerd,
+    [AIT]      = e1000e_set_16bit,
+    [TDFH]     = e1000e_set_13bit,
+    [TDFT]     = e1000e_set_13bit,
+    [TDFHS]    = e1000e_set_13bit,
+    [TDFTS]    = e1000e_set_13bit,
+    [TDFPC]    = e1000e_set_13bit,
+    [RDFH]     = e1000e_set_13bit,
+    [RDFHS]    = e1000e_set_13bit,
+    [RDFT]     = e1000e_set_13bit,
+    [RDFTS]    = e1000e_set_13bit,
+    [RDFPC]    = e1000e_set_13bit,
+    [PBS]      = e1000e_set_6bit,
+    [GCR]      = e1000e_set_gcr,
+    [PSRCTL]   = e1000e_set_psrctl,
+    [RXCSUM]   = e1000e_set_rxcsum,
+    [RAID]     = e1000e_set_16bit,
+    [RSRPD]    = e1000e_set_12bit,
+    [TIDV]     = e1000e_set_tidv,
+    [TDLEN1]   = e1000e_set_dlen,
+    [TDLEN]    = e1000e_set_dlen,
+    [RDLEN0]   = e1000e_set_dlen,
+    [RDLEN1]   = e1000e_set_dlen,
+    [TDBAL]    = e1000e_set_dbal,
+    [TDBAL1]   = e1000e_set_dbal,
+    [RDBAL0]   = e1000e_set_dbal,
+    [RDBAL1]   = e1000e_set_dbal,
+    [RDH1]     = e1000e_set_16bit,
+    [RDT1]     = e1000e_set_rdt,
+    [STATUS]   = e1000e_set_status,
+    [PBACLR]   = e1000e_set_pbaclr,
+    [CTRL_EXT] = e1000e_set_ctrlext,
+    [FCAH]     = e1000e_set_16bit,
+    [FCT]      = e1000e_set_16bit,
+    [FCTTV]    = e1000e_set_16bit,
+    [FCRTV]    = e1000e_set_16bit,
+    [FCRTH]    = e1000e_set_fcrth,
+    [FCRTL]    = e1000e_set_fcrtl,
+    [VET]      = e1000e_set_vet,
+    [RXDCTL]   = e1000e_set_rxdctl,
+    [FLASHT]   = e1000e_set_16bit,
+    [EEWR]     = e1000e_set_eewr,
+    [CTRL_DUP] = e1000e_set_ctrl,
+    [RFCTL]    = e1000e_set_rfctl,
+    [RA + 1]   = e1000e_mac_setmacaddr,
+
+    [IP6AT ... IP6AT + 3]    = e1000e_mac_writereg,
+    [IP4AT ... IP4AT + 6]    = e1000e_mac_writereg,
+    [RA + 2 ... RA + 31]     = e1000e_mac_writereg,
+    [WUPM ... WUPM + 31]     = e1000e_mac_writereg,
+    [MTA ... MTA + E1000_MC_TBL_SIZE - 1] = e1000e_mac_writereg,
+    [VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1]    = e1000e_mac_writereg,
+    [FFMT ... FFMT + 254]    = e1000e_set_4bit,
+    [FFVT ... FFVT + 254]    = e1000e_mac_writereg,
+    [PBM ... PBM + 10239]    = e1000e_mac_writereg,
+    [MDEF ... MDEF + 7]      = e1000e_mac_writereg,
+    [FFLT ... FFLT + 10]     = e1000e_set_11bit,
+    [FTFT ... FTFT + 254]    = e1000e_mac_writereg,
+    [RETA ... RETA + 31]     = e1000e_mac_writereg,
+    [RSSRK ... RSSRK + 31]   = e1000e_mac_writereg,
+    [MAVTV0 ... MAVTV3]      = e1000e_mac_writereg,
+    [EITR...EITR + E1000E_MSIX_VEC_NUM - 1] = e1000e_set_eitr
+};
+enum { E1000E_NWRITEOPS = ARRAY_SIZE(e1000e_macreg_writeops) };
+
+enum { MAC_ACCESS_PARTIAL = 1 };
+
+/*
+ * The array below combines alias offsets of the index values for the
+ * MAC registers that have aliases, with the indication of not fully
+ * implemented registers (lowest bit). This combination is possible
+ * because all of the offsets are even.
+ */
+static const uint16_t mac_reg_access[E1000E_MAC_SIZE] = {
+    /* Alias index offsets */
+    [FCRTL_A] = 0x07fe, [FCRTH_A] = 0x0802,
+    [RDH0_A]  = 0x09bc, [RDT0_A]  = 0x09bc, [RDTR_A] = 0x09c6,
+    [RDFH_A]  = 0xe904, [RDFT_A]  = 0xe904,
+    [TDH_A]   = 0x0cf8, [TDT_A]   = 0x0cf8, [TIDV_A] = 0x0cf8,
+    [TDFH_A]  = 0xed00, [TDFT_A]  = 0xed00,
+    [RA_A ... RA_A + 31]      = 0x14f0,
+    [VFTA_A ... VFTA_A + E1000_VLAN_FILTER_TBL_SIZE - 1] = 0x1400,
+    [RDBAL0_A ... RDLEN0_A] = 0x09bc,
+    [TDBAL_A ... TDLEN_A]   = 0x0cf8,
+    /* Access options */
+    [RDFH]  = MAC_ACCESS_PARTIAL,    [RDFT]  = MAC_ACCESS_PARTIAL,
+    [RDFHS] = MAC_ACCESS_PARTIAL,    [RDFTS] = MAC_ACCESS_PARTIAL,
+    [RDFPC] = MAC_ACCESS_PARTIAL,
+    [TDFH]  = MAC_ACCESS_PARTIAL,    [TDFT]  = MAC_ACCESS_PARTIAL,
+    [TDFHS] = MAC_ACCESS_PARTIAL,    [TDFTS] = MAC_ACCESS_PARTIAL,
+    [TDFPC] = MAC_ACCESS_PARTIAL,    [EECD]  = MAC_ACCESS_PARTIAL,
+    [PBM]   = MAC_ACCESS_PARTIAL,    [FLA]   = MAC_ACCESS_PARTIAL,
+    [FCAL]  = MAC_ACCESS_PARTIAL,    [FCAH]  = MAC_ACCESS_PARTIAL,
+    [FCT]   = MAC_ACCESS_PARTIAL,    [FCTTV] = MAC_ACCESS_PARTIAL,
+    [FCRTV] = MAC_ACCESS_PARTIAL,    [FCRTL] = MAC_ACCESS_PARTIAL,
+    [FCRTH] = MAC_ACCESS_PARTIAL,    [TXDCTL] = MAC_ACCESS_PARTIAL,
+    [TXDCTL1] = MAC_ACCESS_PARTIAL,
+    [MAVTV0 ... MAVTV3] = MAC_ACCESS_PARTIAL
+};
+
+void
+e1000e_core_write(E1000ECore *core, hwaddr addr, uint64_t val, unsigned size)
+{
+    uint16_t index = e1000e_get_reg_index_with_offset(mac_reg_access, addr);
+
+    if (index < E1000E_NWRITEOPS && e1000e_macreg_writeops[index]) {
+        if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) {
+            trace_e1000e_wrn_regs_write_trivial(index << 2);
+        }
+        trace_e1000e_core_write(index << 2, size, val);
+        e1000e_macreg_writeops[index](core, index, val);
+    } else if (index < E1000E_NREADOPS && e1000e_macreg_readops[index]) {
+        trace_e1000e_wrn_regs_write_ro(index << 2, size, val);
+    } else {
+        trace_e1000e_wrn_regs_write_unknown(index << 2, size, val);
+    }
+}
+
+uint64_t
+e1000e_core_read(E1000ECore *core, hwaddr addr, unsigned size)
+{
+    uint64_t val;
+    uint16_t index = e1000e_get_reg_index_with_offset(mac_reg_access, addr);
+
+    if (index < E1000E_NREADOPS && e1000e_macreg_readops[index]) {
+        if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) {
+            trace_e1000e_wrn_regs_read_trivial(index << 2);
+        }
+        val = e1000e_macreg_readops[index](core, index);
+        trace_e1000e_core_read(index << 2, size, val);
+        return val;
+    } else {
+        trace_e1000e_wrn_regs_read_unknown(index << 2, size);
+    }
+    return 0;
+}
+
+static inline void
+e1000e_autoneg_pause(E1000ECore *core)
+{
+    timer_del(core->autoneg_timer);
+}
+
+static void
+e1000e_autoneg_resume(E1000ECore *core)
+{
+    if (e1000e_have_autoneg(core) &&
+        !(core->phy[0][MII_BMSR] & MII_BMSR_AN_COMP)) {
+        qemu_get_queue(core->owner_nic)->link_down = false;
+        timer_mod(core->autoneg_timer,
+                  qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
+    }
+}
+
+static void
+e1000e_vm_state_change(void *opaque, bool running, RunState state)
+{
+    E1000ECore *core = opaque;
+
+    if (running) {
+        trace_e1000e_vm_state_running();
+        e1000e_intrmgr_resume(core);
+        e1000e_autoneg_resume(core);
+    } else {
+        trace_e1000e_vm_state_stopped();
+        e1000e_autoneg_pause(core);
+        e1000e_intrmgr_pause(core);
+    }
+}
+
+void
+e1000e_core_pci_realize(E1000ECore     *core,
+                        const uint16_t *eeprom_templ,
+                        uint32_t        eeprom_size,
+                        const uint8_t  *macaddr)
+{
+    int i;
+
+    core->autoneg_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+                                       e1000e_autoneg_timer, core);
+    e1000e_intrmgr_pci_realize(core);
+
+    core->vmstate =
+        qemu_add_vm_change_state_handler(e1000e_vm_state_change, core);
+
+    for (i = 0; i < E1000E_NUM_QUEUES; i++) {
+        net_tx_pkt_init(&core->tx[i].tx_pkt, core->owner,
+                        E1000E_MAX_TX_FRAGS, core->has_vnet);
+    }
+
+    net_rx_pkt_init(&core->rx_pkt, core->has_vnet);
+
+    e1000x_core_prepare_eeprom(core->eeprom,
+                               eeprom_templ,
+                               eeprom_size,
+                               PCI_DEVICE_GET_CLASS(core->owner)->device_id,
+                               macaddr);
+    e1000e_update_rx_offloads(core);
+}
+
+void
+e1000e_core_pci_uninit(E1000ECore *core)
+{
+    int i;
+
+    timer_free(core->autoneg_timer);
+
+    e1000e_intrmgr_pci_unint(core);
+
+    qemu_del_vm_change_state_handler(core->vmstate);
+
+    for (i = 0; i < E1000E_NUM_QUEUES; i++) {
+        net_tx_pkt_reset(core->tx[i].tx_pkt);
+        net_tx_pkt_uninit(core->tx[i].tx_pkt);
+    }
+
+    net_rx_pkt_uninit(core->rx_pkt);
+}
+
+static const uint16_t
+e1000e_phy_reg_init[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE] = {
+    [0] = {
+        [MII_BMCR] = MII_BMCR_SPEED1000 |
+                     MII_BMCR_FD        |
+                     MII_BMCR_AUTOEN,
+
+        [MII_BMSR] = MII_BMSR_EXTCAP    |
+                     MII_BMSR_LINK_ST   |
+                     MII_BMSR_AUTONEG   |
+                     MII_BMSR_MFPS      |
+                     MII_BMSR_EXTSTAT   |
+                     MII_BMSR_10T_HD    |
+                     MII_BMSR_10T_FD    |
+                     MII_BMSR_100TX_HD  |
+                     MII_BMSR_100TX_FD,
+
+        [MII_PHYID1]            = 0x141,
+        [MII_PHYID2]            = E1000_PHY_ID2_82574x,
+        [MII_ANAR]              = MII_ANAR_CSMACD | MII_ANAR_10 |
+                                  MII_ANAR_10FD | MII_ANAR_TX |
+                                  MII_ANAR_TXFD | MII_ANAR_PAUSE |
+                                  MII_ANAR_PAUSE_ASYM,
+        [MII_ANLPAR]            = MII_ANLPAR_10 | MII_ANLPAR_10FD |
+                                  MII_ANLPAR_TX | MII_ANLPAR_TXFD |
+                                  MII_ANLPAR_T4 | MII_ANLPAR_PAUSE,
+        [MII_ANER]              = MII_ANER_NP | MII_ANER_NWAY,
+        [MII_ANNP]              = 1 | MII_ANNP_MP,
+        [MII_CTRL1000]          = MII_CTRL1000_HALF | MII_CTRL1000_FULL |
+                                  MII_CTRL1000_PORT | MII_CTRL1000_MASTER,
+        [MII_STAT1000]          = MII_STAT1000_HALF | MII_STAT1000_FULL |
+                                  MII_STAT1000_ROK | MII_STAT1000_LOK,
+        [MII_EXTSTAT]           = MII_EXTSTAT_1000T_HD | MII_EXTSTAT_1000T_FD,
+
+        [PHY_COPPER_CTRL1]      = BIT(5) | BIT(6) | BIT(8) | BIT(9) |
+                                  BIT(12) | BIT(13),
+        [PHY_COPPER_STAT1]      = BIT(3) | BIT(10) | BIT(11) | BIT(13) | BIT(15)
+    },
+    [2] = {
+        [PHY_MAC_CTRL1]         = BIT(3) | BIT(7),
+        [PHY_MAC_CTRL2]         = BIT(1) | BIT(2) | BIT(6) | BIT(12)
+    },
+    [3] = {
+        [PHY_LED_TIMER_CTRL]    = BIT(0) | BIT(2) | BIT(14)
+    }
+};
+
+static const uint32_t e1000e_mac_reg_init[] = {
+    [PBA]           =     0x00140014,
+    [LEDCTL]        =  BIT(1) | BIT(8) | BIT(9) | BIT(15) | BIT(17) | BIT(18),
+    [EXTCNF_CTRL]   = BIT(3),
+    [EEMNGCTL]      = BIT(31),
+    [FLASHT]        = 0x2,
+    [FLSWCTL]       = BIT(30) | BIT(31),
+    [FLOL]          = BIT(0),
+    [RXDCTL]        = BIT(16),
+    [RXDCTL1]       = BIT(16),
+    [TIPG]          = 0x8 | (0x8 << 10) | (0x6 << 20),
+    [RXCFGL]        = 0x88F7,
+    [RXUDP]         = 0x319,
+    [CTRL]          = E1000_CTRL_FD | E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
+                      E1000_CTRL_SPD_1000 | E1000_CTRL_SLU |
+                      E1000_CTRL_ADVD3WUC,
+    [STATUS]        =  E1000_STATUS_ASDV_1000 | E1000_STATUS_LU,
+    [PSRCTL]        = (2 << E1000_PSRCTL_BSIZE0_SHIFT) |
+                      (4 << E1000_PSRCTL_BSIZE1_SHIFT) |
+                      (4 << E1000_PSRCTL_BSIZE2_SHIFT),
+    [TARC0]         = 0x3 | E1000_TARC_ENABLE,
+    [TARC1]         = 0x3 | E1000_TARC_ENABLE,
+    [EECD]          = E1000_EECD_AUTO_RD | E1000_EECD_PRES,
+    [EERD]          = E1000_EERW_DONE,
+    [EEWR]          = E1000_EERW_DONE,
+    [GCR]           = E1000_L0S_ADJUST |
+                      E1000_L1_ENTRY_LATENCY_MSB |
+                      E1000_L1_ENTRY_LATENCY_LSB,
+    [TDFH]          = 0x600,
+    [TDFT]          = 0x600,
+    [TDFHS]         = 0x600,
+    [TDFTS]         = 0x600,
+    [POEMB]         = 0x30D,
+    [PBS]           = 0x028,
+    [MANC]          = E1000_MANC_DIS_IP_CHK_ARP,
+    [FACTPS]        = E1000_FACTPS_LAN0_ON | 0x20000000,
+    [SWSM]          = 1,
+    [RXCSUM]        = E1000_RXCSUM_IPOFLD | E1000_RXCSUM_TUOFLD,
+    [ITR]           = E1000E_MIN_XITR,
+    [EITR...EITR + E1000E_MSIX_VEC_NUM - 1] = E1000E_MIN_XITR,
+};
+
+static void e1000e_reset(E1000ECore *core, bool sw)
+{
+    int i;
+
+    timer_del(core->autoneg_timer);
+
+    e1000e_intrmgr_reset(core);
+
+    memset(core->phy, 0, sizeof core->phy);
+    memcpy(core->phy, e1000e_phy_reg_init, sizeof e1000e_phy_reg_init);
+
+    for (i = 0; i < E1000E_MAC_SIZE; i++) {
+        if (sw && (i == PBA || i == PBS || i == FLA)) {
+            continue;
+        }
+
+        core->mac[i] = i < ARRAY_SIZE(e1000e_mac_reg_init) ?
+                       e1000e_mac_reg_init[i] : 0;
+    }
+
+    core->rxbuf_min_shift = 1 + E1000_RING_DESC_LEN_SHIFT;
+
+    if (qemu_get_queue(core->owner_nic)->link_down) {
+        e1000e_link_down(core);
+    }
+
+    e1000x_reset_mac_addr(core->owner_nic, core->mac, core->permanent_mac);
+
+    for (i = 0; i < ARRAY_SIZE(core->tx); i++) {
+        net_tx_pkt_reset(core->tx[i].tx_pkt);
+        memset(&core->tx[i].props, 0, sizeof(core->tx[i].props));
+        core->tx[i].skip_cp = false;
+    }
+}
+
+void
+e1000e_core_reset(E1000ECore *core)
+{
+    e1000e_reset(core, false);
+}
+
+void e1000e_core_pre_save(E1000ECore *core)
+{
+    int i;
+    NetClientState *nc = qemu_get_queue(core->owner_nic);
+
+    /*
+     * If link is down and auto-negotiation is supported and ongoing,
+     * complete auto-negotiation immediately. This allows us to look
+     * at MII_BMSR_AN_COMP to infer link status on load.
+     */
+    if (nc->link_down && e1000e_have_autoneg(core)) {
+        core->phy[0][MII_BMSR] |= MII_BMSR_AN_COMP;
+        e1000e_update_flowctl_status(core);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(core->tx); i++) {
+        if (net_tx_pkt_has_fragments(core->tx[i].tx_pkt)) {
+            core->tx[i].skip_cp = true;
+        }
+    }
+}
+
+int
+e1000e_core_post_load(E1000ECore *core)
+{
+    NetClientState *nc = qemu_get_queue(core->owner_nic);
+
+    /*
+     * nc.link_down can't be migrated, so infer link_down according
+     * to link status bit in core.mac[STATUS].
+     */
+    nc->link_down = (core->mac[STATUS] & E1000_STATUS_LU) == 0;
+
+    return 0;
+}
diff --git a/hw/net/igb_core.h b/hw/net/igb_core.h
new file mode 100644
index 0000000000..d0a14b4523
--- /dev/null
+++ b/hw/net/igb_core.h
@@ -0,0 +1,156 @@
+/*
+ * Core code for QEMU e1000e emulation
+ *
+ * Software developer's manuals:
+ * http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
+ *
+ * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Leonid Bloch <leonid@daynix.com>
+ * Yan Vugenfirer <yan@daynix.com>
+ *
+ * Based on work done by:
+ * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
+ * Copyright (c) 2008 Qumranet
+ * Based on work done by:
+ * Copyright (c) 2007 Dan Aloni
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_NET_E1000E_CORE_H
+#define HW_NET_E1000E_CORE_H
+
+#define E1000E_PHY_PAGE_SIZE    (0x20)
+#define E1000E_PHY_PAGES        (0x07)
+#define E1000E_MAC_SIZE         (0x8000)
+#define E1000E_EEPROM_SIZE      (64)
+#define E1000E_MSIX_VEC_NUM     (5)
+#define E1000E_NUM_QUEUES       (2)
+
+typedef struct E1000Core E1000ECore;
+
+enum { PHY_R = BIT(0),
+       PHY_W = BIT(1),
+       PHY_RW = PHY_R | PHY_W,
+       PHY_ANYPAGE = BIT(2) };
+
+typedef struct E1000IntrDelayTimer_st {
+    QEMUTimer *timer;
+    bool running;
+    uint32_t delay_reg;
+    uint32_t delay_resolution_ns;
+    E1000ECore *core;
+} E1000IntrDelayTimer;
+
+struct E1000Core {
+    uint32_t mac[E1000E_MAC_SIZE];
+    uint16_t phy[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE];
+    uint16_t eeprom[E1000E_EEPROM_SIZE];
+
+    uint32_t rxbuf_sizes[E1000_PSRCTL_BUFFS_PER_DESC];
+    uint32_t rx_desc_buf_size;
+    uint32_t rxbuf_min_shift;
+    uint8_t rx_desc_len;
+
+    QEMUTimer *autoneg_timer;
+
+    struct e1000e_tx {
+        e1000x_txd_props props;
+
+        bool skip_cp;
+        unsigned char sum_needed;
+        bool cptse;
+        struct NetTxPkt *tx_pkt;
+    } tx[E1000E_NUM_QUEUES];
+
+    struct NetRxPkt *rx_pkt;
+
+    bool has_vnet;
+    int max_queue_num;
+
+    /* Interrupt moderation management */
+    uint32_t delayed_causes;
+
+    E1000IntrDelayTimer radv;
+    E1000IntrDelayTimer rdtr;
+    E1000IntrDelayTimer raid;
+
+    E1000IntrDelayTimer tadv;
+    E1000IntrDelayTimer tidv;
+
+    E1000IntrDelayTimer itr;
+
+    E1000IntrDelayTimer eitr[E1000E_MSIX_VEC_NUM];
+
+    VMChangeStateEntry *vmstate;
+
+    uint32_t itr_guest_value;
+    uint32_t eitr_guest_value[E1000E_MSIX_VEC_NUM];
+
+    uint16_t vet;
+
+    uint8_t permanent_mac[ETH_ALEN];
+
+    NICState *owner_nic;
+    PCIDevice *owner;
+    void (*owner_start_recv)(PCIDevice *d);
+
+    uint32_t msi_causes_pending;
+};
+
+void
+e1000e_core_write(E1000ECore *core, hwaddr addr, uint64_t val, unsigned size);
+
+uint64_t
+e1000e_core_read(E1000ECore *core, hwaddr addr, unsigned size);
+
+void
+e1000e_core_pci_realize(E1000ECore      *regs,
+                       const uint16_t *eeprom_templ,
+                       uint32_t        eeprom_size,
+                       const uint8_t  *macaddr);
+
+void
+e1000e_core_reset(E1000ECore *core);
+
+void
+e1000e_core_pre_save(E1000ECore *core);
+
+int
+e1000e_core_post_load(E1000ECore *core);
+
+void
+e1000e_core_set_link_status(E1000ECore *core);
+
+void
+e1000e_core_pci_uninit(E1000ECore *core);
+
+bool
+e1000e_can_receive(E1000ECore *core);
+
+ssize_t
+e1000e_receive(E1000ECore *core, const uint8_t *buf, size_t size);
+
+ssize_t
+e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt);
+
+void
+e1000e_start_recv(E1000ECore *core);
+
+#endif
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 05/13] igb: Rename identifiers
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
                   ` (3 preceding siblings ...)
  2023-01-14  4:09 ` [PATCH v2 04/13] igb: Copy e1000e code Akihiko Odaki
@ 2023-01-14  4:09 ` Akihiko Odaki
  2023-01-14  4:09 ` [PATCH v2 06/13] igb: Build igb Akihiko Odaki
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:09 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich, Gal Hammer

Rename identifiers of definitions which will be modified later for igb.
This will also allow to build igb along with e1000e.

Signed-off-by: Gal Hammer <gal.hammer@sap.com>
Signed-off-by: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/net/igb.c        |  368 +++++-----
 hw/net/igb_common.h |    6 +-
 hw/net/igb_core.c   | 1694 +++++++++++++++++++++----------------------
 hw/net/igb_core.h   |   74 +-
 4 files changed, 1062 insertions(+), 1080 deletions(-)

diff --git a/hw/net/igb.c b/hw/net/igb.c
index a0c4693330..edecd9c449 100644
--- a/hw/net/igb.c
+++ b/hw/net/igb.c
@@ -48,18 +48,18 @@
 #include "hw/qdev-properties.h"
 #include "migration/vmstate.h"
 
-#include "e1000_common.h"
+#include "igb_common.h"
 #include "e1000x_common.h"
-#include "e1000e_core.h"
+#include "igb_core.h"
 
 #include "trace.h"
 #include "qapi/error.h"
 #include "qom/object.h"
 
-#define TYPE_E1000E "e1000e"
-OBJECT_DECLARE_SIMPLE_TYPE(E1000EState, E1000E)
+#define TYPE_IGB "igb"
+OBJECT_DECLARE_SIMPLE_TYPE(IGBState, IGB)
 
-struct E1000EState {
+struct IGBState {
     PCIDevice parent_obj;
     NICState *nic;
     NICConf conf;
@@ -79,7 +79,7 @@ struct E1000EState {
 
     bool disable_vnet;
 
-    E1000ECore core;
+    IGBCore core;
     bool init_vet;
 };
 
@@ -97,22 +97,21 @@ struct E1000EState {
 #define E1000E_MSIX_PBA     (0x2000)
 
 static uint64_t
-e1000e_mmio_read(void *opaque, hwaddr addr, unsigned size)
+igb_mmio_read(void *opaque, hwaddr addr, unsigned size)
 {
-    E1000EState *s = opaque;
-    return e1000e_core_read(&s->core, addr, size);
+    IGBState *s = opaque;
+    return igb_core_read(&s->core, addr, size);
 }
 
 static void
-e1000e_mmio_write(void *opaque, hwaddr addr,
-                   uint64_t val, unsigned size)
+igb_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
 {
-    E1000EState *s = opaque;
-    e1000e_core_write(&s->core, addr, val, size);
+    IGBState *s = opaque;
+    igb_core_write(&s->core, addr, val, size);
 }
 
 static bool
-e1000e_io_get_reg_index(E1000EState *s, uint32_t *idx)
+igb_io_get_reg_index(IGBState *s, uint32_t *idx)
 {
     if (s->ioaddr < 0x1FFFF) {
         *idx = s->ioaddr;
@@ -134,9 +133,9 @@ e1000e_io_get_reg_index(E1000EState *s, uint32_t *idx)
 }
 
 static uint64_t
-e1000e_io_read(void *opaque, hwaddr addr, unsigned size)
+igb_io_read(void *opaque, hwaddr addr, unsigned size)
 {
-    E1000EState *s = opaque;
+    IGBState *s = opaque;
     uint32_t idx = 0;
     uint64_t val;
 
@@ -145,8 +144,8 @@ e1000e_io_read(void *opaque, hwaddr addr, unsigned size)
         trace_e1000e_io_read_addr(s->ioaddr);
         return s->ioaddr;
     case E1000_IODATA:
-        if (e1000e_io_get_reg_index(s, &idx)) {
-            val = e1000e_core_read(&s->core, idx, sizeof(val));
+        if (igb_io_get_reg_index(s, &idx)) {
+            val = igb_core_read(&s->core, idx, sizeof(val));
             trace_e1000e_io_read_data(idx, val);
             return val;
         }
@@ -158,10 +157,9 @@ e1000e_io_read(void *opaque, hwaddr addr, unsigned size)
 }
 
 static void
-e1000e_io_write(void *opaque, hwaddr addr,
-                uint64_t val, unsigned size)
+igb_io_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
 {
-    E1000EState *s = opaque;
+    IGBState *s = opaque;
     uint32_t idx = 0;
 
     switch (addr) {
@@ -170,9 +168,9 @@ e1000e_io_write(void *opaque, hwaddr addr,
         s->ioaddr = (uint32_t) val;
         return;
     case E1000_IODATA:
-        if (e1000e_io_get_reg_index(s, &idx)) {
+        if (igb_io_get_reg_index(s, &idx)) {
             trace_e1000e_io_write_data(idx, val);
-            e1000e_core_write(&s->core, idx, val, sizeof(val));
+            igb_core_write(&s->core, idx, val, sizeof(val));
         }
         return;
     default:
@@ -182,8 +180,8 @@ e1000e_io_write(void *opaque, hwaddr addr,
 }
 
 static const MemoryRegionOps mmio_ops = {
-    .read = e1000e_mmio_read,
-    .write = e1000e_mmio_write,
+    .read = igb_mmio_read,
+    .write = igb_mmio_write,
     .endianness = DEVICE_LITTLE_ENDIAN,
     .impl = {
         .min_access_size = 4,
@@ -192,8 +190,8 @@ static const MemoryRegionOps mmio_ops = {
 };
 
 static const MemoryRegionOps io_ops = {
-    .read = e1000e_io_read,
-    .write = e1000e_io_write,
+    .read = igb_io_read,
+    .write = igb_io_write,
     .endianness = DEVICE_LITTLE_ENDIAN,
     .impl = {
         .min_access_size = 4,
@@ -202,47 +200,47 @@ static const MemoryRegionOps io_ops = {
 };
 
 static bool
-e1000e_nc_can_receive(NetClientState *nc)
+igb_nc_can_receive(NetClientState *nc)
 {
-    E1000EState *s = qemu_get_nic_opaque(nc);
-    return e1000e_can_receive(&s->core);
+    IGBState *s = qemu_get_nic_opaque(nc);
+    return igb_can_receive(&s->core);
 }
 
 static ssize_t
-e1000e_nc_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
+igb_nc_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
 {
-    E1000EState *s = qemu_get_nic_opaque(nc);
-    return e1000e_receive_iov(&s->core, iov, iovcnt);
+    IGBState *s = qemu_get_nic_opaque(nc);
+    return igb_receive_iov(&s->core, iov, iovcnt);
 }
 
 static ssize_t
-e1000e_nc_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+igb_nc_receive(NetClientState *nc, const uint8_t *buf, size_t size)
 {
-    E1000EState *s = qemu_get_nic_opaque(nc);
-    return e1000e_receive(&s->core, buf, size);
+    IGBState *s = qemu_get_nic_opaque(nc);
+    return igb_receive(&s->core, buf, size);
 }
 
 static void
-e1000e_set_link_status(NetClientState *nc)
+igb_set_link_status(NetClientState *nc)
 {
-    E1000EState *s = qemu_get_nic_opaque(nc);
-    e1000e_core_set_link_status(&s->core);
+    IGBState *s = qemu_get_nic_opaque(nc);
+    igb_core_set_link_status(&s->core);
 }
 
-static NetClientInfo net_e1000e_info = {
+static NetClientInfo net_igb_info = {
     .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
-    .can_receive = e1000e_nc_can_receive,
-    .receive = e1000e_nc_receive,
-    .receive_iov = e1000e_nc_receive_iov,
-    .link_status_changed = e1000e_set_link_status,
+    .can_receive = igb_nc_can_receive,
+    .receive = igb_nc_receive,
+    .receive_iov = igb_nc_receive_iov,
+    .link_status_changed = igb_set_link_status,
 };
 
 /*
  * EEPROM (NVM) contents documented in Table 36, section 6.1
  * and generally 6.1.2 Software accessed words.
  */
-static const uint16_t e1000e_eeprom_template[64] = {
+static const uint16_t igb_eeprom_template[64] = {
   /*        Address        |    Compat.    | ImVer |   Compat.     */
     0x0000, 0x0000, 0x0000, 0x0420, 0xf746, 0x2010, 0xffff, 0xffff,
   /*      PBA      |ICtrl1 | SSID  | SVID  | DevID |-------|ICtrl2 */
@@ -261,14 +259,14 @@ static const uint16_t e1000e_eeprom_template[64] = {
     0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0120, 0xffff, 0x0000,
 };
 
-static void e1000e_core_realize(E1000EState *s)
+static void igb_core_realize(IGBState *s)
 {
     s->core.owner = &s->parent_obj;
     s->core.owner_nic = s->nic;
 }
 
 static void
-e1000e_unuse_msix_vectors(E1000EState *s, int num_vectors)
+igb_unuse_msix_vectors(IGBState *s, int num_vectors)
 {
     int i;
     for (i = 0; i < num_vectors; i++) {
@@ -277,7 +275,7 @@ e1000e_unuse_msix_vectors(E1000EState *s, int num_vectors)
 }
 
 static void
-e1000e_use_msix_vectors(E1000EState *s, int num_vectors)
+igb_use_msix_vectors(IGBState *s, int num_vectors)
 {
     int i;
     for (i = 0; i < num_vectors; i++) {
@@ -286,9 +284,9 @@ e1000e_use_msix_vectors(E1000EState *s, int num_vectors)
 }
 
 static void
-e1000e_init_msix(E1000EState *s)
+igb_init_msix(IGBState *s)
 {
-    int res = msix_init(PCI_DEVICE(s), E1000E_MSIX_VEC_NUM,
+    int res = msix_init(PCI_DEVICE(s), IGB_MSIX_VEC_NUM,
                         &s->msix,
                         E1000E_MSIX_IDX, E1000E_MSIX_TABLE,
                         &s->msix,
@@ -298,27 +296,27 @@ e1000e_init_msix(E1000EState *s)
     if (res < 0) {
         trace_e1000e_msix_init_fail(res);
     } else {
-        e1000e_use_msix_vectors(s, E1000E_MSIX_VEC_NUM);
+        igb_use_msix_vectors(s, IGB_MSIX_VEC_NUM);
     }
 }
 
 static void
-e1000e_cleanup_msix(E1000EState *s)
+igb_cleanup_msix(IGBState *s)
 {
     if (msix_present(PCI_DEVICE(s))) {
-        e1000e_unuse_msix_vectors(s, E1000E_MSIX_VEC_NUM);
+        igb_unuse_msix_vectors(s, IGB_MSIX_VEC_NUM);
         msix_uninit(PCI_DEVICE(s), &s->msix, &s->msix);
     }
 }
 
 static void
-e1000e_init_net_peer(E1000EState *s, PCIDevice *pci_dev, uint8_t *macaddr)
+igb_init_net_peer(IGBState *s, PCIDevice *pci_dev, uint8_t *macaddr)
 {
     DeviceState *dev = DEVICE(pci_dev);
     NetClientState *nc;
     int i;
 
-    s->nic = qemu_new_nic(&net_e1000e_info, &s->conf,
+    s->nic = qemu_new_nic(&net_igb_info, &s->conf,
         object_get_typename(OBJECT(s)), dev->id, s);
 
     s->core.max_queue_num = s->conf.peers.queues ? s->conf.peers.queues - 1 : 0;
@@ -356,7 +354,7 @@ e1000e_init_net_peer(E1000EState *s, PCIDevice *pci_dev, uint8_t *macaddr)
 }
 
 static inline uint64_t
-e1000e_gen_dsn(uint8_t *mac)
+igb_gen_dsn(uint8_t *mac)
 {
     return (uint64_t)(mac[5])        |
            (uint64_t)(mac[4])  << 8  |
@@ -369,7 +367,7 @@ e1000e_gen_dsn(uint8_t *mac)
 }
 
 static int
-e1000e_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc)
+igb_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc)
 {
     Error *local_err = NULL;
     int ret = pci_add_capability(pdev, PCI_CAP_ID_PM, offset,
@@ -395,32 +393,32 @@ e1000e_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc)
     return ret;
 }
 
-static void e1000e_write_config(PCIDevice *pci_dev, uint32_t address,
-                                uint32_t val, int len)
+static void igb_write_config(PCIDevice *pci_dev, uint32_t address,
+                             uint32_t val, int len)
 {
-    E1000EState *s = E1000E(pci_dev);
+    IGBState *s = IGB(pci_dev);
 
     pci_default_write_config(pci_dev, address, val, len);
 
     if (range_covers_byte(address, len, PCI_COMMAND) &&
         (pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
-        e1000e_start_recv(&s->core);
+        igb_start_recv(&s->core);
     }
 }
 
-static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp)
+static void igb_pci_realize(PCIDevice *pci_dev, Error **errp)
 {
     static const uint16_t e1000e_pmrb_offset = 0x0C8;
     static const uint16_t e1000e_pcie_offset = 0x0E0;
     static const uint16_t e1000e_aer_offset =  0x100;
     static const uint16_t e1000e_dsn_offset =  0x140;
-    E1000EState *s = E1000E(pci_dev);
+    IGBState *s = IGB(pci_dev);
     uint8_t *macaddr;
     int ret;
 
     trace_e1000e_cb_pci_realize();
 
-    pci_dev->config_write = e1000e_write_config;
+    pci_dev->config_write = igb_write_config;
 
     pci_dev->config[PCI_CACHE_LINE_SIZE] = 0x10;
     pci_dev->config[PCI_INTERRUPT_PIN] = 1;
@@ -433,7 +431,7 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp)
 
     /* Define IO/MMIO regions */
     memory_region_init_io(&s->mmio, OBJECT(s), &mmio_ops, s,
-                          "e1000e-mmio", E1000E_MMIO_SIZE);
+                          "igb-mmio", E1000E_MMIO_SIZE);
     pci_register_bar(pci_dev, E1000E_MMIO_IDX,
                      PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
 
@@ -442,16 +440,16 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp)
      * for drivers that may theoretically probe for its presence.
      */
     memory_region_init(&s->flash, OBJECT(s),
-                       "e1000e-flash", E1000E_FLASH_SIZE);
+                       "igb-flash", E1000E_FLASH_SIZE);
     pci_register_bar(pci_dev, E1000E_FLASH_IDX,
                      PCI_BASE_ADDRESS_SPACE_MEMORY, &s->flash);
 
     memory_region_init_io(&s->io, OBJECT(s), &io_ops, s,
-                          "e1000e-io", E1000E_IO_SIZE);
+                          "igb-io", E1000E_IO_SIZE);
     pci_register_bar(pci_dev, E1000E_IO_IDX,
                      PCI_BASE_ADDRESS_SPACE_IO, &s->io);
 
-    memory_region_init(&s->msix, OBJECT(s), "e1000e-msix",
+    memory_region_init(&s->msix, OBJECT(s), "igb-msix",
                        E1000E_MSIX_SIZE);
     pci_register_bar(pci_dev, E1000E_MSIX_IDX,
                      PCI_BASE_ADDRESS_SPACE_MEMORY, &s->msix);
@@ -460,7 +458,7 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp)
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     macaddr = s->conf.macaddr.a;
 
-    e1000e_init_msix(s);
+    igb_init_msix(s);
 
     if (pcie_endpoint_cap_v1_init(pci_dev, e1000e_pcie_offset) < 0) {
         hw_error("Failed to initialize PCIe capability");
@@ -471,8 +469,8 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp)
         trace_e1000e_msi_init_fail(ret);
     }
 
-    if (e1000e_add_pm_capability(pci_dev, e1000e_pmrb_offset,
-                                  PCI_PM_CAP_DSI) < 0) {
+    if (igb_add_pm_capability(pci_dev, e1000e_pmrb_offset,
+                              PCI_PM_CAP_DSI) < 0) {
         hw_error("Failed to initialize PM capability");
     }
 
@@ -481,64 +479,63 @@ static void e1000e_pci_realize(PCIDevice *pci_dev, Error **errp)
         hw_error("Failed to initialize AER capability");
     }
 
-    pcie_dev_ser_num_init(pci_dev, e1000e_dsn_offset,
-                          e1000e_gen_dsn(macaddr));
+    pcie_dev_ser_num_init(pci_dev, e1000e_dsn_offset, igb_gen_dsn(macaddr));
 
-    e1000e_init_net_peer(s, pci_dev, macaddr);
+    igb_init_net_peer(s, pci_dev, macaddr);
 
     /* Initialize core */
-    e1000e_core_realize(s);
+    igb_core_realize(s);
 
-    e1000e_core_pci_realize(&s->core,
-                            e1000e_eeprom_template,
-                            sizeof(e1000e_eeprom_template),
-                            macaddr);
+    igb_core_pci_realize(&s->core,
+                         igb_eeprom_template,
+                         sizeof(igb_eeprom_template),
+                         macaddr);
 }
 
-static void e1000e_pci_uninit(PCIDevice *pci_dev)
+static void igb_pci_uninit(PCIDevice *pci_dev)
 {
-    E1000EState *s = E1000E(pci_dev);
+    IGBState *s = IGB(pci_dev);
 
     trace_e1000e_cb_pci_uninit();
 
-    e1000e_core_pci_uninit(&s->core);
+    igb_core_pci_uninit(&s->core);
 
     pcie_aer_exit(pci_dev);
     pcie_cap_exit(pci_dev);
 
     qemu_del_nic(s->nic);
 
-    e1000e_cleanup_msix(s);
+    igb_cleanup_msix(s);
     msi_uninit(pci_dev);
 }
 
-static void e1000e_qdev_reset_hold(Object *obj)
+static void igb_qdev_reset_hold(Object *obj)
 {
-    E1000EState *s = E1000E(obj);
+    IGBState *s = IGB(obj);
 
     trace_e1000e_cb_qdev_reset_hold();
 
-    e1000e_core_reset(&s->core);
+    igb_core_reset(&s->core);
 
     if (s->init_vet) {
         s->core.mac[VET] = ETH_P_VLAN;
     }
 }
 
-static int e1000e_pre_save(void *opaque)
+static int igb_pre_save(void *opaque)
 {
-    E1000EState *s = opaque;
+    IGBState *s = opaque;
 
     trace_e1000e_cb_pre_save();
 
-    e1000e_core_pre_save(&s->core);
+    igb_core_pre_save(&s->core);
 
     return 0;
 }
 
-static int e1000e_post_load(void *opaque, int version_id)
+static int igb_post_load(void *opaque, int version_id)
 {
-    E1000EState *s = opaque;
+    IGBState *s = opaque;
 
     trace_e1000e_cb_post_load();
 
@@ -550,178 +547,175 @@ static int e1000e_post_load(void *opaque, int version_id)
         return -1;
     }
 
-    return e1000e_core_post_load(&s->core);
+    return igb_core_post_load(&s->core);
 }
 
-static const VMStateDescription e1000e_vmstate_tx = {
-    .name = "e1000e-tx",
+static const VMStateDescription igb_vmstate_tx = {
+    .name = "igb-tx",
     .version_id = 1,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
-        VMSTATE_UINT8(sum_needed, struct e1000e_tx),
-        VMSTATE_UINT8(props.ipcss, struct e1000e_tx),
-        VMSTATE_UINT8(props.ipcso, struct e1000e_tx),
-        VMSTATE_UINT16(props.ipcse, struct e1000e_tx),
-        VMSTATE_UINT8(props.tucss, struct e1000e_tx),
-        VMSTATE_UINT8(props.tucso, struct e1000e_tx),
-        VMSTATE_UINT16(props.tucse, struct e1000e_tx),
-        VMSTATE_UINT8(props.hdr_len, struct e1000e_tx),
-        VMSTATE_UINT16(props.mss, struct e1000e_tx),
-        VMSTATE_UINT32(props.paylen, struct e1000e_tx),
-        VMSTATE_INT8(props.ip, struct e1000e_tx),
-        VMSTATE_INT8(props.tcp, struct e1000e_tx),
-        VMSTATE_BOOL(props.tse, struct e1000e_tx),
-        VMSTATE_BOOL(cptse, struct e1000e_tx),
-        VMSTATE_BOOL(skip_cp, struct e1000e_tx),
+        VMSTATE_UINT8(sum_needed, struct igb_tx),
+        VMSTATE_UINT8(props.ipcss, struct igb_tx),
+        VMSTATE_UINT8(props.ipcso, struct igb_tx),
+        VMSTATE_UINT16(props.ipcse, struct igb_tx),
+        VMSTATE_UINT8(props.tucss, struct igb_tx),
+        VMSTATE_UINT8(props.tucso, struct igb_tx),
+        VMSTATE_UINT16(props.tucse, struct igb_tx),
+        VMSTATE_UINT8(props.hdr_len, struct igb_tx),
+        VMSTATE_UINT16(props.mss, struct igb_tx),
+        VMSTATE_UINT32(props.paylen, struct igb_tx),
+        VMSTATE_INT8(props.ip, struct igb_tx),
+        VMSTATE_INT8(props.tcp, struct igb_tx),
+        VMSTATE_BOOL(props.tse, struct igb_tx),
+        VMSTATE_BOOL(cptse, struct igb_tx),
+        VMSTATE_BOOL(skip_cp, struct igb_tx),
         VMSTATE_END_OF_LIST()
     }
 };
 
-static const VMStateDescription e1000e_vmstate_intr_timer = {
-    .name = "e1000e-intr-timer",
+static const VMStateDescription igb_vmstate_intr_timer = {
+    .name = "igb-intr-timer",
     .version_id = 1,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
-        VMSTATE_TIMER_PTR(timer, E1000IntrDelayTimer),
-        VMSTATE_BOOL(running, E1000IntrDelayTimer),
+        VMSTATE_TIMER_PTR(timer, IGBIntrDelayTimer),
+        VMSTATE_BOOL(running, IGBIntrDelayTimer),
         VMSTATE_END_OF_LIST()
     }
 };
 
-#define VMSTATE_E1000E_INTR_DELAY_TIMER(_f, _s)                     \
+#define VMSTATE_IGB_INTR_DELAY_TIMER(_f, _s)                        \
     VMSTATE_STRUCT(_f, _s, 0,                                       \
-                   e1000e_vmstate_intr_timer, E1000IntrDelayTimer)
+                   igb_vmstate_intr_timer, IGBIntrDelayTimer)
 
-#define VMSTATE_E1000E_INTR_DELAY_TIMER_ARRAY(_f, _s, _num)         \
+#define VMSTATE_IGB_INTR_DELAY_TIMER_ARRAY(_f, _s, _num)            \
     VMSTATE_STRUCT_ARRAY(_f, _s, _num, 0,                           \
-                         e1000e_vmstate_intr_timer, E1000IntrDelayTimer)
+                         igb_vmstate_intr_timer, IGBIntrDelayTimer)
 
-static const VMStateDescription e1000e_vmstate = {
-    .name = "e1000e",
+static const VMStateDescription igb_vmstate = {
+    .name = "igb",
     .version_id = 1,
     .minimum_version_id = 1,
-    .pre_save = e1000e_pre_save,
-    .post_load = e1000e_post_load,
+    .pre_save = igb_pre_save,
+    .post_load = igb_post_load,
     .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(parent_obj, E1000EState),
-        VMSTATE_MSIX(parent_obj, E1000EState),
+        VMSTATE_PCI_DEVICE(parent_obj, IGBState),
+        VMSTATE_MSIX(parent_obj, IGBState),
 
-        VMSTATE_UINT32(ioaddr, E1000EState),
-        VMSTATE_UINT32(core.rxbuf_min_shift, E1000EState),
-        VMSTATE_UINT8(core.rx_desc_len, E1000EState),
-        VMSTATE_UINT32_ARRAY(core.rxbuf_sizes, E1000EState,
+        VMSTATE_UINT32(ioaddr, IGBState),
+        VMSTATE_UINT32(core.rxbuf_min_shift, IGBState),
+        VMSTATE_UINT8(core.rx_desc_len, IGBState),
+        VMSTATE_UINT32_ARRAY(core.rxbuf_sizes, IGBState,
                              E1000_PSRCTL_BUFFS_PER_DESC),
-        VMSTATE_UINT32(core.rx_desc_buf_size, E1000EState),
-        VMSTATE_UINT16_ARRAY(core.eeprom, E1000EState, E1000E_EEPROM_SIZE),
-        VMSTATE_UINT16_2DARRAY(core.phy, E1000EState,
+        VMSTATE_UINT32(core.rx_desc_buf_size, IGBState),
+        VMSTATE_UINT16_ARRAY(core.eeprom, IGBState, IGB_EEPROM_SIZE),
+        VMSTATE_UINT16_2DARRAY(core.phy, IGBState,
                                E1000E_PHY_PAGES, E1000E_PHY_PAGE_SIZE),
-        VMSTATE_UINT32_ARRAY(core.mac, E1000EState, E1000E_MAC_SIZE),
-        VMSTATE_UINT8_ARRAY(core.permanent_mac, E1000EState, ETH_ALEN),
+        VMSTATE_UINT32_ARRAY(core.mac, IGBState, E1000E_MAC_SIZE),
+        VMSTATE_UINT8_ARRAY(core.permanent_mac, IGBState, ETH_ALEN),
 
-        VMSTATE_UINT32(core.delayed_causes, E1000EState),
+        VMSTATE_UINT32(core.delayed_causes, IGBState),
 
-        VMSTATE_UINT16(subsys, E1000EState),
-        VMSTATE_UINT16(subsys_ven, E1000EState),
+        VMSTATE_UINT16(subsys, IGBState),
+        VMSTATE_UINT16(subsys_ven, IGBState),
 
-        VMSTATE_E1000E_INTR_DELAY_TIMER(core.rdtr, E1000EState),
-        VMSTATE_E1000E_INTR_DELAY_TIMER(core.radv, E1000EState),
-        VMSTATE_E1000E_INTR_DELAY_TIMER(core.raid, E1000EState),
-        VMSTATE_E1000E_INTR_DELAY_TIMER(core.tadv, E1000EState),
-        VMSTATE_E1000E_INTR_DELAY_TIMER(core.tidv, E1000EState),
+        VMSTATE_IGB_INTR_DELAY_TIMER(core.rdtr, IGBState),
+        VMSTATE_IGB_INTR_DELAY_TIMER(core.radv, IGBState),
+        VMSTATE_IGB_INTR_DELAY_TIMER(core.raid, IGBState),
+        VMSTATE_IGB_INTR_DELAY_TIMER(core.tadv, IGBState),
+        VMSTATE_IGB_INTR_DELAY_TIMER(core.tidv, IGBState),
 
-        VMSTATE_E1000E_INTR_DELAY_TIMER(core.itr, E1000EState),
-        VMSTATE_UNUSED(1),
+        VMSTATE_IGB_INTR_DELAY_TIMER(core.itr, IGBState),
 
-        VMSTATE_E1000E_INTR_DELAY_TIMER_ARRAY(core.eitr, E1000EState,
-                                              E1000E_MSIX_VEC_NUM),
-        VMSTATE_UNUSED(E1000E_MSIX_VEC_NUM),
+        VMSTATE_IGB_INTR_DELAY_TIMER_ARRAY(core.eitr, IGBState,
+                                           IGB_MSIX_VEC_NUM),
 
-        VMSTATE_UINT32(core.itr_guest_value, E1000EState),
-        VMSTATE_UINT32_ARRAY(core.eitr_guest_value, E1000EState,
-                             E1000E_MSIX_VEC_NUM),
+        VMSTATE_UINT32(core.itr_guest_value, IGBState),
+        VMSTATE_UINT32_ARRAY(core.eitr_guest_value, IGBState, IGB_MSIX_VEC_NUM),
 
-        VMSTATE_UINT16(core.vet, E1000EState),
+        VMSTATE_UINT16(core.vet, IGBState),
 
-        VMSTATE_STRUCT_ARRAY(core.tx, E1000EState, E1000E_NUM_QUEUES, 0,
-                             e1000e_vmstate_tx, struct e1000e_tx),
+        VMSTATE_STRUCT_ARRAY(core.tx, IGBState, IGB_NUM_QUEUES, 0,
+                             igb_vmstate_tx, struct igb_tx),
         VMSTATE_END_OF_LIST()
     }
 };
 
-static PropertyInfo e1000e_prop_disable_vnet,
-                    e1000e_prop_subsys_ven,
-                    e1000e_prop_subsys;
+static PropertyInfo igb_prop_disable_vnet,
+                    igb_prop_subsys_ven,
+                    igb_prop_subsys;
 
-static Property e1000e_properties[] = {
-    DEFINE_NIC_PROPERTIES(E1000EState, conf),
-    DEFINE_PROP_SIGNED("disable_vnet_hdr", E1000EState, disable_vnet, false,
-                        e1000e_prop_disable_vnet, bool),
-    DEFINE_PROP_SIGNED("subsys_ven", E1000EState, subsys_ven,
+static Property igb_properties[] = {
+    DEFINE_NIC_PROPERTIES(IGBState, conf),
+    DEFINE_PROP_SIGNED("disable_vnet_hdr", IGBState, disable_vnet, false,
+                        igb_prop_disable_vnet, bool),
+    DEFINE_PROP_SIGNED("subsys_ven", IGBState, subsys_ven,
                         PCI_VENDOR_ID_INTEL,
-                        e1000e_prop_subsys_ven, uint16_t),
-    DEFINE_PROP_SIGNED("subsys", E1000EState, subsys, 0,
-                        e1000e_prop_subsys, uint16_t),
-    DEFINE_PROP_BOOL("init-vet", E1000EState, init_vet, true),
+                        igb_prop_subsys_ven, uint16_t),
+    DEFINE_PROP_SIGNED("subsys", IGBState, subsys, 0,
+                        igb_prop_subsys, uint16_t),
+    DEFINE_PROP_BOOL("init-vet", IGBState, init_vet, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-static void e1000e_class_init(ObjectClass *class, void *data)
+static void igb_class_init(ObjectClass *class, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(class);
     ResettableClass *rc = RESETTABLE_CLASS(class);
     PCIDeviceClass *c = PCI_DEVICE_CLASS(class);
 
-    c->realize = e1000e_pci_realize;
-    c->exit = e1000e_pci_uninit;
+    c->realize = igb_pci_realize;
+    c->exit = igb_pci_uninit;
     c->vendor_id = PCI_VENDOR_ID_INTEL;
     c->device_id = E1000_DEV_ID_82574L;
     c->revision = 0;
     c->romfile = "efi-e1000e.rom";
     c->class_id = PCI_CLASS_NETWORK_ETHERNET;
 
-    rc->phases.hold = e1000e_qdev_reset_hold;
+    rc->phases.hold = igb_qdev_reset_hold;
 
     dc->desc = "Intel 82574L GbE Controller";
-    dc->vmsd = &e1000e_vmstate;
+    dc->vmsd = &igb_vmstate;
 
-    e1000e_prop_disable_vnet = qdev_prop_uint8;
-    e1000e_prop_disable_vnet.description = "Do not use virtio headers, "
-                                           "perform SW offloads emulation "
-                                           "instead";
+    igb_prop_disable_vnet = qdev_prop_uint8;
+    igb_prop_disable_vnet.description = "Do not use virtio headers, "
+                                        "perform SW offloads emulation "
+                                        "instead";
 
-    e1000e_prop_subsys_ven = qdev_prop_uint16;
-    e1000e_prop_subsys_ven.description = "PCI device Subsystem Vendor ID";
+    igb_prop_subsys_ven = qdev_prop_uint16;
+    igb_prop_subsys_ven.description = "PCI device Subsystem Vendor ID";
 
-    e1000e_prop_subsys = qdev_prop_uint16;
-    e1000e_prop_subsys.description = "PCI device Subsystem ID";
+    igb_prop_subsys = qdev_prop_uint16;
+    igb_prop_subsys.description = "PCI device Subsystem ID";
 
-    device_class_set_props(dc, e1000e_properties);
+    device_class_set_props(dc, igb_properties);
     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
 }
 
-static void e1000e_instance_init(Object *obj)
+static void igb_instance_init(Object *obj)
 {
-    E1000EState *s = E1000E(obj);
+    IGBState *s = IGB(obj);
     device_add_bootindex_property(obj, &s->conf.bootindex,
                                   "bootindex", "/ethernet-phy@0",
                                   DEVICE(obj));
 }
 
-static const TypeInfo e1000e_info = {
-    .name = TYPE_E1000E,
+static const TypeInfo igb_info = {
+    .name = TYPE_IGB,
     .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(E1000EState),
-    .class_init = e1000e_class_init,
-    .instance_init = e1000e_instance_init,
+    .instance_size = sizeof(IGBState),
+    .class_init = igb_class_init,
+    .instance_init = igb_instance_init,
     .interfaces = (InterfaceInfo[]) {
         { INTERFACE_PCIE_DEVICE },
         { }
     },
 };
 
-static void e1000e_register_types(void)
+static void igb_register_types(void)
 {
-    type_register_static(&e1000e_info);
+    type_register_static(&igb_info);
 }
 
-type_init(e1000e_register_types)
+type_init(igb_register_types)
diff --git a/hw/net/igb_common.h b/hw/net/igb_common.h
index 48feda7404..c38d6e8084 100644
--- a/hw/net/igb_common.h
+++ b/hw/net/igb_common.h
@@ -1,5 +1,5 @@
 /*
- * QEMU e1000(e) emulation - shared definitions
+ * QEMU igb emulation - shared definitions
  *
  * Copyright (c) 2008 Qumranet
  *
@@ -22,8 +22,8 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef HW_NET_E1000_COMMON_H
-#define HW_NET_E1000_COMMON_H
+#ifndef HW_NET_IGB_COMMON_H
+#define HW_NET_IGB_COMMON_H
 
 #include "e1000_regs.h"
 
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
index e874d417ed..bf8ed64fbd 100644
--- a/hw/net/igb_core.c
+++ b/hw/net/igb_core.c
@@ -1,5 +1,5 @@
 /*
- * Core code for QEMU e1000e emulation
+ * Core code for QEMU igb emulation
  *
  * Software developer's manuals:
  * http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
@@ -45,9 +45,9 @@
 #include "net_tx_pkt.h"
 #include "net_rx_pkt.h"
 
-#include "e1000_common.h"
+#include "igb_common.h"
 #include "e1000x_common.h"
-#include "e1000e_core.h"
+#include "igb_core.h"
 
 #include "trace.h"
 
@@ -63,12 +63,12 @@ union e1000_rx_desc_union {
 };
 
 static inline void
-e1000e_set_interrupt_cause(E1000ECore *core, uint32_t val);
+igb_set_interrupt_cause(IGBCore *core, uint32_t val);
 
-static void e1000e_reset(E1000ECore *core, bool sw);
+static void igb_reset(IGBCore *core, bool sw);
 
 static inline void
-e1000e_process_ts_option(E1000ECore *core, struct e1000_tx_desc *dp)
+igb_process_ts_option(IGBCore *core, struct e1000_tx_desc *dp)
 {
     if (le32_to_cpu(dp->upper.data) & E1000_TXD_EXTCMD_TSTAMP) {
         trace_e1000e_wrn_no_ts_support();
@@ -76,7 +76,7 @@ e1000e_process_ts_option(E1000ECore *core, struct e1000_tx_desc *dp)
 }
 
 static inline void
-e1000e_process_snap_option(E1000ECore *core, uint32_t cmd_and_length)
+igb_process_snap_option(IGBCore *core, uint32_t cmd_and_length)
 {
     if (cmd_and_length & E1000_TXD_CMD_SNAP) {
         trace_e1000e_wrn_no_snap_support();
@@ -84,7 +84,7 @@ e1000e_process_snap_option(E1000ECore *core, uint32_t cmd_and_length)
 }
 
 static inline void
-e1000e_raise_legacy_irq(E1000ECore *core)
+igb_raise_legacy_irq(IGBCore *core)
 {
     trace_e1000e_irq_legacy_notify(true);
     e1000x_inc_reg_if_not_full(core->mac, IAC);
@@ -92,14 +92,14 @@ e1000e_raise_legacy_irq(E1000ECore *core)
 }
 
 static inline void
-e1000e_lower_legacy_irq(E1000ECore *core)
+igb_lower_legacy_irq(IGBCore *core)
 {
     trace_e1000e_irq_legacy_notify(false);
     pci_set_irq(core->owner, 0);
 }
 
 static inline void
-e1000e_intrmgr_rearm_timer(E1000IntrDelayTimer *timer)
+igb_intrmgr_rearm_timer(IGBIntrDelayTimer *timer)
 {
     int64_t delay_ns = (int64_t) timer->core->mac[timer->delay_reg] *
                                  timer->delay_resolution_ns;
@@ -112,15 +112,15 @@ e1000e_intrmgr_rearm_timer(E1000IntrDelayTimer *timer)
 }
 
 static void
-e1000e_intmgr_timer_resume(E1000IntrDelayTimer *timer)
+igb_intmgr_timer_resume(IGBIntrDelayTimer *timer)
 {
     if (timer->running) {
-        e1000e_intrmgr_rearm_timer(timer);
+        igb_intrmgr_rearm_timer(timer);
     }
 }
 
 static void
-e1000e_intmgr_timer_pause(E1000IntrDelayTimer *timer)
+igb_intmgr_timer_pause(IGBIntrDelayTimer *timer)
 {
     if (timer->running) {
         timer_del(timer->timer);
@@ -128,7 +128,7 @@ e1000e_intmgr_timer_pause(E1000IntrDelayTimer *timer)
 }
 
 static inline void
-e1000e_intrmgr_stop_timer(E1000IntrDelayTimer *timer)
+igb_intrmgr_stop_timer(IGBIntrDelayTimer *timer)
 {
     if (timer->running) {
         timer_del(timer->timer);
@@ -137,27 +137,27 @@ e1000e_intrmgr_stop_timer(E1000IntrDelayTimer *timer)
 }
 
 static inline void
-e1000e_intrmgr_fire_delayed_interrupts(E1000ECore *core)
+igb_intrmgr_fire_delayed_interrupts(IGBCore *core)
 {
     trace_e1000e_irq_fire_delayed_interrupts();
-    e1000e_set_interrupt_cause(core, 0);
+    igb_set_interrupt_cause(core, 0);
 }
 
 static void
-e1000e_intrmgr_on_timer(void *opaque)
+igb_intrmgr_on_timer(void *opaque)
 {
-    E1000IntrDelayTimer *timer = opaque;
+    IGBIntrDelayTimer *timer = opaque;
 
     trace_e1000e_irq_throttling_timer(timer->delay_reg << 2);
 
     timer->running = false;
-    e1000e_intrmgr_fire_delayed_interrupts(timer->core);
+    igb_intrmgr_fire_delayed_interrupts(timer->core);
 }
 
 static void
-e1000e_intrmgr_on_throttling_timer(void *opaque)
+igb_intrmgr_on_throttling_timer(void *opaque)
 {
-    E1000IntrDelayTimer *timer = opaque;
+    IGBIntrDelayTimer *timer = opaque;
 
     assert(!msix_enabled(timer->core->owner));
 
@@ -167,17 +167,17 @@ e1000e_intrmgr_on_throttling_timer(void *opaque)
         trace_e1000e_irq_msi_notify_postponed();
         /* Clear msi_causes_pending to fire MSI eventually */
         timer->core->msi_causes_pending = 0;
-        e1000e_set_interrupt_cause(timer->core, 0);
+        igb_set_interrupt_cause(timer->core, 0);
     } else {
         trace_e1000e_irq_legacy_notify_postponed();
-        e1000e_set_interrupt_cause(timer->core, 0);
+        igb_set_interrupt_cause(timer->core, 0);
     }
 }
 
 static void
-e1000e_intrmgr_on_msix_throttling_timer(void *opaque)
+igb_intrmgr_on_msix_throttling_timer(void *opaque)
 {
-    E1000IntrDelayTimer *timer = opaque;
+    IGBIntrDelayTimer *timer = opaque;
     int idx = timer - &timer->core->eitr[0];
 
     assert(msix_enabled(timer->core->owner));
@@ -189,7 +189,7 @@ e1000e_intrmgr_on_msix_throttling_timer(void *opaque)
 }
 
 static void
-e1000e_intrmgr_initialize_all_timers(E1000ECore *core, bool create)
+igb_intrmgr_initialize_all_timers(IGBCore *core, bool create)
 {
     int i;
 
@@ -215,7 +215,7 @@ e1000e_intrmgr_initialize_all_timers(E1000ECore *core, bool create)
     core->itr.delay_reg = ITR;
     core->itr.delay_resolution_ns = E1000_INTR_THROTTLING_NS_RES;
 
-    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
+    for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
         core->eitr[i].core = core;
         core->eitr[i].delay_reg = EITR + i;
         core->eitr[i].delay_resolution_ns = E1000_INTR_THROTTLING_NS_RES;
@@ -226,41 +226,40 @@ e1000e_intrmgr_initialize_all_timers(E1000ECore *core, bool create)
     }
 
     core->radv.timer =
-        timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->radv);
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, igb_intrmgr_on_timer, &core->radv);
     core->rdtr.timer =
-        timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->rdtr);
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, igb_intrmgr_on_timer, &core->rdtr);
     core->raid.timer =
-        timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->raid);
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, igb_intrmgr_on_timer, &core->raid);
 
     core->tadv.timer =
-        timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->tadv);
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, igb_intrmgr_on_timer, &core->tadv);
     core->tidv.timer =
-        timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000e_intrmgr_on_timer, &core->tidv);
+        timer_new_ns(QEMU_CLOCK_VIRTUAL, igb_intrmgr_on_timer, &core->tidv);
 
     core->itr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
-                                   e1000e_intrmgr_on_throttling_timer,
+                                   igb_intrmgr_on_throttling_timer,
                                    &core->itr);
 
-    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
-        core->eitr[i].timer =
-            timer_new_ns(QEMU_CLOCK_VIRTUAL,
-                         e1000e_intrmgr_on_msix_throttling_timer,
-                         &core->eitr[i]);
+    for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
+        core->eitr[i].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                           igb_intrmgr_on_msix_throttling_timer,
+                                           &core->eitr[i]);
     }
 }
 
 static inline void
-e1000e_intrmgr_stop_delay_timers(E1000ECore *core)
+igb_intrmgr_stop_delay_timers(IGBCore *core)
 {
-    e1000e_intrmgr_stop_timer(&core->radv);
-    e1000e_intrmgr_stop_timer(&core->rdtr);
-    e1000e_intrmgr_stop_timer(&core->raid);
-    e1000e_intrmgr_stop_timer(&core->tidv);
-    e1000e_intrmgr_stop_timer(&core->tadv);
+    igb_intrmgr_stop_timer(&core->radv);
+    igb_intrmgr_stop_timer(&core->rdtr);
+    igb_intrmgr_stop_timer(&core->raid);
+    igb_intrmgr_stop_timer(&core->tidv);
+    igb_intrmgr_stop_timer(&core->tadv);
 }
 
 static bool
-e1000e_intrmgr_delay_rx_causes(E1000ECore *core, uint32_t *causes)
+igb_intrmgr_delay_rx_causes(IGBCore *core, uint32_t *causes)
 {
     uint32_t delayable_causes;
     uint32_t rdtr = core->mac[RDTR];
@@ -300,21 +299,21 @@ e1000e_intrmgr_delay_rx_causes(E1000ECore *core, uint32_t *causes)
     }
 
     /* All causes delayed */
-    e1000e_intrmgr_rearm_timer(&core->rdtr);
+    igb_intrmgr_rearm_timer(&core->rdtr);
 
     if (!core->radv.running && (radv != 0)) {
-        e1000e_intrmgr_rearm_timer(&core->radv);
+        igb_intrmgr_rearm_timer(&core->radv);
     }
 
     if (!core->raid.running && (core->delayed_causes & E1000_ICR_ACK)) {
-        e1000e_intrmgr_rearm_timer(&core->raid);
+        igb_intrmgr_rearm_timer(&core->raid);
     }
 
     return true;
 }
 
 static bool
-e1000e_intrmgr_delay_tx_causes(E1000ECore *core, uint32_t *causes)
+igb_intrmgr_delay_tx_causes(IGBCore *core, uint32_t *causes)
 {
     static const uint32_t delayable_causes = E1000_ICR_TXQ0 |
                                              E1000_ICR_TXQ1 |
@@ -335,17 +334,17 @@ e1000e_intrmgr_delay_tx_causes(E1000ECore *core, uint32_t *causes)
     }
 
     /* All causes delayed */
-    e1000e_intrmgr_rearm_timer(&core->tidv);
+    igb_intrmgr_rearm_timer(&core->tidv);
 
     if (!core->tadv.running && (core->mac[TADV] != 0)) {
-        e1000e_intrmgr_rearm_timer(&core->tadv);
+        igb_intrmgr_rearm_timer(&core->tadv);
     }
 
     return true;
 }
 
 static uint32_t
-e1000e_intmgr_collect_delayed_causes(E1000ECore *core)
+igb_intmgr_collect_delayed_causes(IGBCore *core)
 {
     uint32_t res;
 
@@ -357,87 +356,87 @@ e1000e_intmgr_collect_delayed_causes(E1000ECore *core)
     res = core->delayed_causes;
     core->delayed_causes = 0;
 
-    e1000e_intrmgr_stop_delay_timers(core);
+    igb_intrmgr_stop_delay_timers(core);
 
     return res;
 }
 
 static void
-e1000e_intrmgr_fire_all_timers(E1000ECore *core)
+igb_intrmgr_fire_all_timers(IGBCore *core)
 {
     int i;
-    uint32_t val = e1000e_intmgr_collect_delayed_causes(core);
+    uint32_t val = igb_intmgr_collect_delayed_causes(core);
 
     trace_e1000e_irq_adding_delayed_causes(val, core->mac[ICR]);
     core->mac[ICR] |= val;
 
     if (core->itr.running) {
         timer_del(core->itr.timer);
-        e1000e_intrmgr_on_throttling_timer(&core->itr);
+        igb_intrmgr_on_throttling_timer(&core->itr);
     }
 
-    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
+    for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
         if (core->eitr[i].running) {
             timer_del(core->eitr[i].timer);
-            e1000e_intrmgr_on_msix_throttling_timer(&core->eitr[i]);
+            igb_intrmgr_on_msix_throttling_timer(&core->eitr[i]);
         }
     }
 }
 
 static void
-e1000e_intrmgr_resume(E1000ECore *core)
+igb_intrmgr_resume(IGBCore *core)
 {
     int i;
 
-    e1000e_intmgr_timer_resume(&core->radv);
-    e1000e_intmgr_timer_resume(&core->rdtr);
-    e1000e_intmgr_timer_resume(&core->raid);
-    e1000e_intmgr_timer_resume(&core->tidv);
-    e1000e_intmgr_timer_resume(&core->tadv);
+    igb_intmgr_timer_resume(&core->radv);
+    igb_intmgr_timer_resume(&core->rdtr);
+    igb_intmgr_timer_resume(&core->raid);
+    igb_intmgr_timer_resume(&core->tidv);
+    igb_intmgr_timer_resume(&core->tadv);
 
-    e1000e_intmgr_timer_resume(&core->itr);
+    igb_intmgr_timer_resume(&core->itr);
 
-    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
-        e1000e_intmgr_timer_resume(&core->eitr[i]);
+    for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
+        igb_intmgr_timer_resume(&core->eitr[i]);
     }
 }
 
 static void
-e1000e_intrmgr_pause(E1000ECore *core)
+igb_intrmgr_pause(IGBCore *core)
 {
     int i;
 
-    e1000e_intmgr_timer_pause(&core->radv);
-    e1000e_intmgr_timer_pause(&core->rdtr);
-    e1000e_intmgr_timer_pause(&core->raid);
-    e1000e_intmgr_timer_pause(&core->tidv);
-    e1000e_intmgr_timer_pause(&core->tadv);
+    igb_intmgr_timer_pause(&core->radv);
+    igb_intmgr_timer_pause(&core->rdtr);
+    igb_intmgr_timer_pause(&core->raid);
+    igb_intmgr_timer_pause(&core->tidv);
+    igb_intmgr_timer_pause(&core->tadv);
 
-    e1000e_intmgr_timer_pause(&core->itr);
+    igb_intmgr_timer_pause(&core->itr);
 
-    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
-        e1000e_intmgr_timer_pause(&core->eitr[i]);
+    for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
+        igb_intmgr_timer_pause(&core->eitr[i]);
     }
 }
 
 static void
-e1000e_intrmgr_reset(E1000ECore *core)
+igb_intrmgr_reset(IGBCore *core)
 {
     int i;
 
     core->delayed_causes = 0;
 
-    e1000e_intrmgr_stop_delay_timers(core);
+    igb_intrmgr_stop_delay_timers(core);
 
-    e1000e_intrmgr_stop_timer(&core->itr);
+    igb_intrmgr_stop_timer(&core->itr);
 
-    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
-        e1000e_intrmgr_stop_timer(&core->eitr[i]);
+    for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
+        igb_intrmgr_stop_timer(&core->eitr[i]);
     }
 }
 
 static void
-e1000e_intrmgr_pci_unint(E1000ECore *core)
+igb_intrmgr_pci_unint(IGBCore *core)
 {
     int i;
 
@@ -450,42 +449,42 @@ e1000e_intrmgr_pci_unint(E1000ECore *core)
 
     timer_free(core->itr.timer);
 
-    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
+    for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
         timer_free(core->eitr[i].timer);
     }
 }
 
 static void
-e1000e_intrmgr_pci_realize(E1000ECore *core)
+igb_intrmgr_pci_realize(IGBCore *core)
 {
-    e1000e_intrmgr_initialize_all_timers(core, true);
+    igb_intrmgr_initialize_all_timers(core, true);
 }
 
 static inline bool
-e1000e_rx_csum_enabled(E1000ECore *core)
+igb_rx_csum_enabled(IGBCore *core)
 {
     return (core->mac[RXCSUM] & E1000_RXCSUM_PCSD) ? false : true;
 }
 
 static inline bool
-e1000e_rx_use_legacy_descriptor(E1000ECore *core)
+igb_rx_use_legacy_descriptor(IGBCore *core)
 {
     return (core->mac[RFCTL] & E1000_RFCTL_EXTEN) ? false : true;
 }
 
 static inline bool
-e1000e_rx_use_ps_descriptor(E1000ECore *core)
+igb_rx_use_ps_descriptor(IGBCore *core)
 {
-    return !e1000e_rx_use_legacy_descriptor(core) &&
+    return !igb_rx_use_legacy_descriptor(core) &&
            (core->mac[RCTL] & E1000_RCTL_DTYP_PS);
 }
 
 static inline bool
-e1000e_rss_enabled(E1000ECore *core)
+igb_rss_enabled(IGBCore *core)
 {
     return E1000_MRQC_ENABLED(core->mac[MRQC]) &&
-           !e1000e_rx_csum_enabled(core) &&
-           !e1000e_rx_use_legacy_descriptor(core);
+           !igb_rx_csum_enabled(core) &&
+           !igb_rx_use_legacy_descriptor(core);
 }
 
 typedef struct E1000E_RSSInfo_st {
@@ -496,11 +495,11 @@ typedef struct E1000E_RSSInfo_st {
 } E1000E_RSSInfo;
 
 static uint32_t
-e1000e_rss_get_hash_type(E1000ECore *core, struct NetRxPkt *pkt)
+igb_rss_get_hash_type(IGBCore *core, struct NetRxPkt *pkt)
 {
     bool isip4, isip6, isudp, istcp;
 
-    assert(e1000e_rss_enabled(core));
+    assert(igb_rss_enabled(core));
 
     net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
 
@@ -566,13 +565,11 @@ e1000e_rss_get_hash_type(E1000ECore *core, struct NetRxPkt *pkt)
 }
 
 static uint32_t
-e1000e_rss_calc_hash(E1000ECore *core,
-                     struct NetRxPkt *pkt,
-                     E1000E_RSSInfo *info)
+igb_rss_calc_hash(IGBCore *core, struct NetRxPkt *pkt, E1000E_RSSInfo *info)
 {
     NetRxPktRssType type;
 
-    assert(e1000e_rss_enabled(core));
+    assert(igb_rss_enabled(core));
 
     switch (info->type) {
     case E1000_MRQ_RSS_TYPE_IPV4:
@@ -599,13 +596,11 @@ e1000e_rss_calc_hash(E1000ECore *core,
 }
 
 static void
-e1000e_rss_parse_packet(E1000ECore *core,
-                        struct NetRxPkt *pkt,
-                        E1000E_RSSInfo *info)
+igb_rss_parse_packet(IGBCore *core, struct NetRxPkt *pkt, E1000E_RSSInfo *info)
 {
     trace_e1000e_rx_rss_started();
 
-    if (!e1000e_rss_enabled(core)) {
+    if (!igb_rss_enabled(core)) {
         info->enabled = false;
         info->hash = 0;
         info->queue = 0;
@@ -616,7 +611,7 @@ e1000e_rss_parse_packet(E1000ECore *core,
 
     info->enabled = true;
 
-    info->type = e1000e_rss_get_hash_type(core, pkt);
+    info->type = igb_rss_get_hash_type(core, pkt);
 
     trace_e1000e_rx_rss_type(info->type);
 
@@ -626,12 +621,12 @@ e1000e_rss_parse_packet(E1000ECore *core,
         return;
     }
 
-    info->hash = e1000e_rss_calc_hash(core, pkt, info);
+    info->hash = igb_rss_calc_hash(core, pkt, info);
     info->queue = E1000_RSS_QUEUE(&core->mac[RETA], info->hash);
 }
 
 static void
-e1000e_setup_tx_offloads(E1000ECore *core, struct e1000e_tx *tx)
+igb_setup_tx_offloads(IGBCore *core, struct igb_tx *tx)
 {
     if (tx->props.tse && tx->cptse) {
         net_tx_pkt_build_vheader(tx->tx_pkt, true, true, tx->props.mss);
@@ -650,12 +645,12 @@ e1000e_setup_tx_offloads(E1000ECore *core, struct e1000e_tx *tx)
 }
 
 static bool
-e1000e_tx_pkt_send(E1000ECore *core, struct e1000e_tx *tx, int queue_index)
+igb_tx_pkt_send(IGBCore *core, struct igb_tx *tx, int queue_index)
 {
     int target_queue = MIN(core->max_queue_num, queue_index);
     NetClientState *queue = qemu_get_subqueue(core->owner_nic, target_queue);
 
-    e1000e_setup_tx_offloads(core, tx);
+    igb_setup_tx_offloads(core, tx);
 
     net_tx_pkt_dump(tx->tx_pkt);
 
@@ -668,7 +663,7 @@ e1000e_tx_pkt_send(E1000ECore *core, struct e1000e_tx *tx, int queue_index)
 }
 
 static void
-e1000e_on_tx_done_update_stats(E1000ECore *core, struct NetTxPkt *tx_pkt)
+igb_on_tx_done_update_stats(IGBCore *core, struct NetTxPkt *tx_pkt)
 {
     static const int PTCregs[6] = { PTC64, PTC127, PTC255, PTC511,
                                     PTC1023, PTC1522 };
@@ -698,10 +693,10 @@ e1000e_on_tx_done_update_stats(E1000ECore *core, struct NetTxPkt *tx_pkt)
 }
 
 static void
-e1000e_process_tx_desc(E1000ECore *core,
-                       struct e1000e_tx *tx,
-                       struct e1000_tx_desc *dp,
-                       int queue_index)
+igb_process_tx_desc(IGBCore *core,
+                    struct igb_tx *tx,
+                    struct e1000_tx_desc *dp,
+                    int queue_index)
 {
     uint32_t txd_lower = le32_to_cpu(dp->lower.data);
     uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D);
@@ -712,16 +707,16 @@ e1000e_process_tx_desc(E1000ECore *core,
 
     if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */
         e1000x_read_tx_ctx_descr(xp, &tx->props);
-        e1000e_process_snap_option(core, le32_to_cpu(xp->cmd_and_length));
+        igb_process_snap_option(core, le32_to_cpu(xp->cmd_and_length));
         return;
     } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
         /* data descriptor */
         tx->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
         tx->cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
-        e1000e_process_ts_option(core, dp);
+        igb_process_ts_option(core, dp);
     } else {
         /* legacy descriptor */
-        e1000e_process_ts_option(core, dp);
+        igb_process_ts_option(core, dp);
         tx->cptse = 0;
     }
 
@@ -740,8 +735,8 @@ e1000e_process_tx_desc(E1000ECore *core,
                 net_tx_pkt_setup_vlan_header_ex(tx->tx_pkt,
                     le16_to_cpu(dp->upper.fields.special), core->mac[VET]);
             }
-            if (e1000e_tx_pkt_send(core, tx, queue_index)) {
-                e1000e_on_tx_done_update_stats(core, tx->tx_pkt);
+            if (igb_tx_pkt_send(core, tx, queue_index)) {
+                igb_on_tx_done_update_stats(core, tx->tx_pkt);
             }
         }
 
@@ -754,7 +749,7 @@ e1000e_process_tx_desc(E1000ECore *core,
 }
 
 static inline uint32_t
-e1000e_tx_wb_interrupt_cause(E1000ECore *core, int queue_idx)
+igb_tx_wb_interrupt_cause(IGBCore *core, int queue_idx)
 {
     if (!msix_enabled(core->owner)) {
         return E1000_ICR_TXDW;
@@ -764,7 +759,7 @@ e1000e_tx_wb_interrupt_cause(E1000ECore *core, int queue_idx)
 }
 
 static inline uint32_t
-e1000e_rx_wb_interrupt_cause(E1000ECore *core, int queue_idx,
+igb_rx_wb_interrupt_cause(IGBCore *core, int queue_idx,
                              bool min_threshold_hit)
 {
     if (!msix_enabled(core->owner)) {
@@ -775,8 +770,8 @@ e1000e_rx_wb_interrupt_cause(E1000ECore *core, int queue_idx,
 }
 
 static uint32_t
-e1000e_txdesc_writeback(E1000ECore *core, dma_addr_t base,
-                        struct e1000_tx_desc *dp, bool *ide, int queue_idx)
+igb_txdesc_writeback(IGBCore *core, dma_addr_t base,
+                     struct e1000_tx_desc *dp, bool *ide, int queue_idx)
 {
     uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data);
 
@@ -792,7 +787,7 @@ e1000e_txdesc_writeback(E1000ECore *core, dma_addr_t base,
     dp->upper.data = cpu_to_le32(txd_upper);
     pci_dma_write(core->owner, base + ((char *)&dp->upper - (char *)dp),
                   &dp->upper, sizeof(dp->upper));
-    return e1000e_tx_wb_interrupt_cause(core, queue_idx);
+    return igb_tx_wb_interrupt_cause(core, queue_idx);
 }
 
 typedef struct E1000E_RingInfo_st {
@@ -805,14 +800,14 @@ typedef struct E1000E_RingInfo_st {
 } E1000E_RingInfo;
 
 static inline bool
-e1000e_ring_empty(E1000ECore *core, const E1000E_RingInfo *r)
+igb_ring_empty(IGBCore *core, const E1000E_RingInfo *r)
 {
     return core->mac[r->dh] == core->mac[r->dt] ||
                 core->mac[r->dt] >= core->mac[r->dlen] / E1000_RING_DESC_LEN;
 }
 
 static inline uint64_t
-e1000e_ring_base(E1000ECore *core, const E1000E_RingInfo *r)
+igb_ring_base(IGBCore *core, const E1000E_RingInfo *r)
 {
     uint64_t bah = core->mac[r->dbah];
     uint64_t bal = core->mac[r->dbal];
@@ -821,13 +816,13 @@ e1000e_ring_base(E1000ECore *core, const E1000E_RingInfo *r)
 }
 
 static inline uint64_t
-e1000e_ring_head_descr(E1000ECore *core, const E1000E_RingInfo *r)
+igb_ring_head_descr(IGBCore *core, const E1000E_RingInfo *r)
 {
-    return e1000e_ring_base(core, r) + E1000_RING_DESC_LEN * core->mac[r->dh];
+    return igb_ring_base(core, r) + E1000_RING_DESC_LEN * core->mac[r->dh];
 }
 
 static inline void
-e1000e_ring_advance(E1000ECore *core, const E1000E_RingInfo *r, uint32_t count)
+igb_ring_advance(IGBCore *core, const E1000E_RingInfo *r, uint32_t count)
 {
     core->mac[r->dh] += count;
 
@@ -837,7 +832,7 @@ e1000e_ring_advance(E1000ECore *core, const E1000E_RingInfo *r, uint32_t count)
 }
 
 static inline uint32_t
-e1000e_ring_free_descr_num(E1000ECore *core, const E1000E_RingInfo *r)
+igb_ring_free_descr_num(IGBCore *core, const E1000E_RingInfo *r)
 {
     trace_e1000e_ring_free_space(r->idx, core->mac[r->dlen],
                                  core->mac[r->dh],  core->mac[r->dt]);
@@ -856,32 +851,32 @@ e1000e_ring_free_descr_num(E1000ECore *core, const E1000E_RingInfo *r)
 }
 
 static inline bool
-e1000e_ring_enabled(E1000ECore *core, const E1000E_RingInfo *r)
+igb_ring_enabled(IGBCore *core, const E1000E_RingInfo *r)
 {
     return core->mac[r->dlen] > 0;
 }
 
 static inline uint32_t
-e1000e_ring_len(E1000ECore *core, const E1000E_RingInfo *r)
+igb_ring_len(IGBCore *core, const E1000E_RingInfo *r)
 {
     return core->mac[r->dlen];
 }
 
-typedef struct E1000E_TxRing_st {
+typedef struct IGB_TxRing_st {
     const E1000E_RingInfo *i;
-    struct e1000e_tx *tx;
-} E1000E_TxRing;
+    struct igb_tx *tx;
+} IGB_TxRing;
 
 static inline int
-e1000e_mq_queue_idx(int base_reg_idx, int reg_idx)
+igb_mq_queue_idx(int base_reg_idx, int reg_idx)
 {
     return (reg_idx - base_reg_idx) / (0x100 >> 2);
 }
 
 static inline void
-e1000e_tx_ring_init(E1000ECore *core, E1000E_TxRing *txr, int idx)
+igb_tx_ring_init(IGBCore *core, IGB_TxRing *txr, int idx)
 {
-    static const E1000E_RingInfo i[E1000E_NUM_QUEUES] = {
+    static const E1000E_RingInfo i[IGB_NUM_QUEUES] = {
         { TDBAH,  TDBAL,  TDLEN,  TDH,  TDT, 0 },
         { TDBAH1, TDBAL1, TDLEN1, TDH1, TDT1, 1 }
     };
@@ -897,9 +892,9 @@ typedef struct E1000E_RxRing_st {
 } E1000E_RxRing;
 
 static inline void
-e1000e_rx_ring_init(E1000ECore *core, E1000E_RxRing *rxr, int idx)
+igb_rx_ring_init(IGBCore *core, E1000E_RxRing *rxr, int idx)
 {
-    static const E1000E_RingInfo i[E1000E_NUM_QUEUES] = {
+    static const E1000E_RingInfo i[IGB_NUM_QUEUES] = {
         { RDBAH0, RDBAL0, RDLEN0, RDH0, RDT0, 0 },
         { RDBAH1, RDBAL1, RDLEN1, RDH1, RDT1, 1 }
     };
@@ -910,7 +905,7 @@ e1000e_rx_ring_init(E1000ECore *core, E1000E_RxRing *rxr, int idx)
 }
 
 static void
-e1000e_start_xmit(E1000ECore *core, const E1000E_TxRing *txr)
+igb_start_xmit(IGBCore *core, const IGB_TxRing *txr)
 {
     dma_addr_t base;
     struct e1000_tx_desc desc;
@@ -923,30 +918,29 @@ e1000e_start_xmit(E1000ECore *core, const E1000E_TxRing *txr)
         return;
     }
 
-    while (!e1000e_ring_empty(core, txi)) {
-        base = e1000e_ring_head_descr(core, txi);
+    while (!igb_ring_empty(core, txi)) {
+        base = igb_ring_head_descr(core, txi);
 
         pci_dma_read(core->owner, base, &desc, sizeof(desc));
 
         trace_e1000e_tx_descr((void *)(intptr_t)desc.buffer_addr,
                               desc.lower.data, desc.upper.data);
 
-        e1000e_process_tx_desc(core, txr->tx, &desc, txi->idx);
-        cause |= e1000e_txdesc_writeback(core, base, &desc, &ide, txi->idx);
+        igb_process_tx_desc(core, txr->tx, &desc, txi->idx);
+        cause |= igb_txdesc_writeback(core, base, &desc, &ide, txi->idx);
 
-        e1000e_ring_advance(core, txi, 1);
+        igb_ring_advance(core, txi, 1);
     }
 
-    if (!ide || !e1000e_intrmgr_delay_tx_causes(core, &cause)) {
-        e1000e_set_interrupt_cause(core, cause);
+    if (!ide || !igb_intrmgr_delay_tx_causes(core, &cause)) {
+        igb_set_interrupt_cause(core, cause);
     }
 }
 
 static bool
-e1000e_has_rxbufs(E1000ECore *core, const E1000E_RingInfo *r,
-                  size_t total_size)
+igb_has_rxbufs(IGBCore *core, const E1000E_RingInfo *r, size_t total_size)
 {
-    uint32_t bufs = e1000e_ring_free_descr_num(core, r);
+    uint32_t bufs = igb_ring_free_descr_num(core, r);
 
     trace_e1000e_rx_has_buffers(r->idx, bufs, total_size,
                                 core->rx_desc_buf_size);
@@ -956,7 +950,7 @@ e1000e_has_rxbufs(E1000ECore *core, const E1000E_RingInfo *r,
 }
 
 void
-e1000e_start_recv(E1000ECore *core)
+igb_start_recv(IGBCore *core)
 {
     int i;
 
@@ -968,7 +962,7 @@ e1000e_start_recv(E1000ECore *core)
 }
 
 bool
-e1000e_can_receive(E1000ECore *core)
+igb_can_receive(IGBCore *core)
 {
     int i;
 
@@ -976,12 +970,11 @@ e1000e_can_receive(E1000ECore *core)
         return false;
     }
 
-    for (i = 0; i < E1000E_NUM_QUEUES; i++) {
+    for (i = 0; i < IGB_NUM_QUEUES; i++) {
         E1000E_RxRing rxr;
 
-        e1000e_rx_ring_init(core, &rxr, i);
-        if (e1000e_ring_enabled(core, rxr.i) &&
-            e1000e_has_rxbufs(core, rxr.i, 1)) {
+        igb_rx_ring_init(core, &rxr, i);
+        if (igb_ring_enabled(core, rxr.i) && igb_has_rxbufs(core, rxr.i, 1)) {
             trace_e1000e_rx_can_recv();
             return true;
         }
@@ -992,30 +985,30 @@ e1000e_can_receive(E1000ECore *core)
 }
 
 ssize_t
-e1000e_receive(E1000ECore *core, const uint8_t *buf, size_t size)
+igb_receive(IGBCore *core, const uint8_t *buf, size_t size)
 {
     const struct iovec iov = {
         .iov_base = (uint8_t *)buf,
         .iov_len = size
     };
 
-    return e1000e_receive_iov(core, &iov, 1);
+    return igb_receive_iov(core, &iov, 1);
 }
 
 static inline bool
-e1000e_rx_l3_cso_enabled(E1000ECore *core)
+igb_rx_l3_cso_enabled(IGBCore *core)
 {
     return !!(core->mac[RXCSUM] & E1000_RXCSUM_IPOFLD);
 }
 
 static inline bool
-e1000e_rx_l4_cso_enabled(E1000ECore *core)
+igb_rx_l4_cso_enabled(IGBCore *core)
 {
     return !!(core->mac[RXCSUM] & E1000_RXCSUM_TUOFLD);
 }
 
 static bool
-e1000e_receive_filter(E1000ECore *core, const uint8_t *buf, int size)
+igb_receive_filter(IGBCore *core, const uint8_t *buf, int size)
 {
     uint32_t rctl = core->mac[RCTL];
 
@@ -1060,23 +1053,23 @@ e1000e_receive_filter(E1000ECore *core, const uint8_t *buf, int size)
 }
 
 static inline void
-e1000e_read_lgcy_rx_descr(E1000ECore *core, struct e1000_rx_desc *desc,
-                          hwaddr *buff_addr)
+igb_read_lgcy_rx_descr(IGBCore *core, struct e1000_rx_desc *desc,
+                       hwaddr *buff_addr)
 {
     *buff_addr = le64_to_cpu(desc->buffer_addr);
 }
 
 static inline void
-e1000e_read_ext_rx_descr(E1000ECore *core, union e1000_rx_desc_extended *desc,
-                         hwaddr *buff_addr)
+igb_read_ext_rx_descr(IGBCore *core, union e1000_rx_desc_extended *desc,
+                      hwaddr *buff_addr)
 {
     *buff_addr = le64_to_cpu(desc->read.buffer_addr);
 }
 
 static inline void
-e1000e_read_ps_rx_descr(E1000ECore *core,
-                        union e1000_rx_desc_packet_split *desc,
-                        hwaddr buff_addr[MAX_PS_BUFFERS])
+igb_read_ps_rx_descr(IGBCore *core,
+                     union e1000_rx_desc_packet_split *desc,
+                     hwaddr buff_addr[MAX_PS_BUFFERS])
 {
     int i;
 
@@ -1089,32 +1082,32 @@ e1000e_read_ps_rx_descr(E1000ECore *core,
 }
 
 static inline void
-e1000e_read_rx_descr(E1000ECore *core, union e1000_rx_desc_union *desc,
-                     hwaddr buff_addr[MAX_PS_BUFFERS])
+igb_read_rx_descr(IGBCore *core, union e1000_rx_desc_union *desc,
+                  hwaddr buff_addr[MAX_PS_BUFFERS])
 {
-    if (e1000e_rx_use_legacy_descriptor(core)) {
-        e1000e_read_lgcy_rx_descr(core, &desc->legacy, &buff_addr[0]);
+    if (igb_rx_use_legacy_descriptor(core)) {
+        igb_read_lgcy_rx_descr(core, &desc->legacy, &buff_addr[0]);
         buff_addr[1] = buff_addr[2] = buff_addr[3] = 0;
     } else {
         if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) {
-            e1000e_read_ps_rx_descr(core, &desc->packet_split, buff_addr);
+            igb_read_ps_rx_descr(core, &desc->packet_split, buff_addr);
         } else {
-            e1000e_read_ext_rx_descr(core, &desc->extended, &buff_addr[0]);
+            igb_read_ext_rx_descr(core, &desc->extended, &buff_addr[0]);
             buff_addr[1] = buff_addr[2] = buff_addr[3] = 0;
         }
     }
 }
 
 static void
-e1000e_verify_csum_in_sw(E1000ECore *core,
-                         struct NetRxPkt *pkt,
-                         uint32_t *status_flags,
-                         bool istcp, bool isudp)
+igb_verify_csum_in_sw(IGBCore *core,
+                      struct NetRxPkt *pkt,
+                      uint32_t *status_flags,
+                      bool istcp, bool isudp)
 {
     bool csum_valid;
     uint32_t csum_error;
 
-    if (e1000e_rx_l3_cso_enabled(core)) {
+    if (igb_rx_l3_cso_enabled(core)) {
         if (!net_rx_pkt_validate_l3_csum(pkt, &csum_valid)) {
             trace_e1000e_rx_metadata_l3_csum_validation_failed();
         } else {
@@ -1125,7 +1118,7 @@ e1000e_verify_csum_in_sw(E1000ECore *core,
         trace_e1000e_rx_metadata_l3_cso_disabled();
     }
 
-    if (!e1000e_rx_l4_cso_enabled(core)) {
+    if (!igb_rx_l4_cso_enabled(core)) {
         trace_e1000e_rx_metadata_l4_cso_disabled();
         return;
     }
@@ -1148,7 +1141,7 @@ e1000e_verify_csum_in_sw(E1000ECore *core,
 }
 
 static inline bool
-e1000e_is_tcp_ack(E1000ECore *core, struct NetRxPkt *rx_pkt)
+igb_is_tcp_ack(IGBCore *core, struct NetRxPkt *rx_pkt)
 {
     if (!net_rx_pkt_is_tcp_ack(rx_pkt)) {
         return false;
@@ -1162,14 +1155,14 @@ e1000e_is_tcp_ack(E1000ECore *core, struct NetRxPkt *rx_pkt)
 }
 
 static void
-e1000e_build_rx_metadata(E1000ECore *core,
-                         struct NetRxPkt *pkt,
-                         bool is_eop,
-                         const E1000E_RSSInfo *rss_info,
-                         uint32_t *rss, uint32_t *mrq,
-                         uint32_t *status_flags,
-                         uint16_t *ip_id,
-                         uint16_t *vlan_tag)
+igb_build_rx_metadata(IGBCore *core,
+                      struct NetRxPkt *pkt,
+                      bool is_eop,
+                      const E1000E_RSSInfo *rss_info,
+                      uint32_t *rss, uint32_t *mrq,
+                      uint32_t *status_flags,
+                      uint16_t *ip_id,
+                      uint16_t *vlan_tag)
 {
     struct virtio_net_hdr *vhdr;
     bool isip4, isip6, istcp, isudp;
@@ -1207,7 +1200,7 @@ e1000e_build_rx_metadata(E1000ECore *core,
             trace_e1000e_rx_metadata_ip_id(*ip_id);
     }
 
-    if (istcp && e1000e_is_tcp_ack(core, pkt)) {
+    if (istcp && igb_is_tcp_ack(core, pkt)) {
         *status_flags |= E1000_RXD_STAT_ACK;
         trace_e1000e_rx_metadata_ack();
     }
@@ -1234,7 +1227,7 @@ e1000e_build_rx_metadata(E1000ECore *core,
 
     if (!net_rx_pkt_has_virt_hdr(pkt)) {
         trace_e1000e_rx_metadata_no_virthdr();
-        e1000e_verify_csum_in_sw(core, pkt, status_flags, istcp, isudp);
+        igb_verify_csum_in_sw(core, pkt, status_flags, istcp, isudp);
         goto func_exit;
     }
 
@@ -1243,17 +1236,17 @@ e1000e_build_rx_metadata(E1000ECore *core,
     if (!(vhdr->flags & VIRTIO_NET_HDR_F_DATA_VALID) &&
         !(vhdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) {
         trace_e1000e_rx_metadata_virthdr_no_csum_info();
-        e1000e_verify_csum_in_sw(core, pkt, status_flags, istcp, isudp);
+        igb_verify_csum_in_sw(core, pkt, status_flags, istcp, isudp);
         goto func_exit;
     }
 
-    if (e1000e_rx_l3_cso_enabled(core)) {
+    if (igb_rx_l3_cso_enabled(core)) {
         *status_flags |= isip4 ? E1000_RXD_STAT_IPCS : 0;
     } else {
         trace_e1000e_rx_metadata_l3_cso_disabled();
     }
 
-    if (e1000e_rx_l4_cso_enabled(core)) {
+    if (igb_rx_l4_cso_enabled(core)) {
         if (istcp) {
             *status_flags |= E1000_RXD_STAT_TCPCS;
         } else if (isudp) {
@@ -1270,10 +1263,10 @@ func_exit:
 }
 
 static inline void
-e1000e_write_lgcy_rx_descr(E1000ECore *core, struct e1000_rx_desc *desc,
-                           struct NetRxPkt *pkt,
-                           const E1000E_RSSInfo *rss_info,
-                           uint16_t length)
+igb_write_lgcy_rx_descr(IGBCore *core, struct e1000_rx_desc *desc,
+                        struct NetRxPkt *pkt,
+                        const E1000E_RSSInfo *rss_info,
+                        uint16_t length)
 {
     uint32_t status_flags, rss, mrq;
     uint16_t ip_id;
@@ -1283,7 +1276,7 @@ e1000e_write_lgcy_rx_descr(E1000ECore *core, struct e1000_rx_desc *desc,
     desc->length = cpu_to_le16(length);
     desc->csum = 0;
 
-    e1000e_build_rx_metadata(core, pkt, pkt != NULL,
+    igb_build_rx_metadata(core, pkt, pkt != NULL,
                              rss_info,
                              &rss, &mrq,
                              &status_flags, &ip_id,
@@ -1293,31 +1286,31 @@ e1000e_write_lgcy_rx_descr(E1000ECore *core, struct e1000_rx_desc *desc,
 }
 
 static inline void
-e1000e_write_ext_rx_descr(E1000ECore *core, union e1000_rx_desc_extended *desc,
-                          struct NetRxPkt *pkt,
-                          const E1000E_RSSInfo *rss_info,
-                          uint16_t length)
+igb_write_ext_rx_descr(IGBCore *core, union e1000_rx_desc_extended *desc,
+                       struct NetRxPkt *pkt,
+                       const E1000E_RSSInfo *rss_info,
+                       uint16_t length)
 {
     memset(&desc->wb, 0, sizeof(desc->wb));
 
     desc->wb.upper.length = cpu_to_le16(length);
 
-    e1000e_build_rx_metadata(core, pkt, pkt != NULL,
-                             rss_info,
-                             &desc->wb.lower.hi_dword.rss,
-                             &desc->wb.lower.mrq,
-                             &desc->wb.upper.status_error,
-                             &desc->wb.lower.hi_dword.csum_ip.ip_id,
-                             &desc->wb.upper.vlan);
+    igb_build_rx_metadata(core, pkt, pkt != NULL,
+                          rss_info,
+                          &desc->wb.lower.hi_dword.rss,
+                          &desc->wb.lower.mrq,
+                          &desc->wb.upper.status_error,
+                          &desc->wb.lower.hi_dword.csum_ip.ip_id,
+                          &desc->wb.upper.vlan);
 }
 
 static inline void
-e1000e_write_ps_rx_descr(E1000ECore *core,
-                         union e1000_rx_desc_packet_split *desc,
-                         struct NetRxPkt *pkt,
-                         const E1000E_RSSInfo *rss_info,
-                         size_t ps_hdr_len,
-                         uint16_t(*written)[MAX_PS_BUFFERS])
+igb_write_ps_rx_descr(IGBCore *core,
+                      union e1000_rx_desc_packet_split *desc,
+                      struct NetRxPkt *pkt,
+                      const E1000E_RSSInfo *rss_info,
+                      size_t ps_hdr_len,
+                      uint16_t(*written)[MAX_PS_BUFFERS])
 {
     int i;
 
@@ -1329,13 +1322,13 @@ e1000e_write_ps_rx_descr(E1000ECore *core,
         desc->wb.upper.length[i] = cpu_to_le16((*written)[i + 1]);
     }
 
-    e1000e_build_rx_metadata(core, pkt, pkt != NULL,
-                             rss_info,
-                             &desc->wb.lower.hi_dword.rss,
-                             &desc->wb.lower.mrq,
-                             &desc->wb.middle.status_error,
-                             &desc->wb.lower.hi_dword.csum_ip.ip_id,
-                             &desc->wb.middle.vlan);
+    igb_build_rx_metadata(core, pkt, pkt != NULL,
+                          rss_info,
+                          &desc->wb.lower.hi_dword.rss,
+                          &desc->wb.lower.mrq,
+                          &desc->wb.middle.status_error,
+                          &desc->wb.lower.hi_dword.csum_ip.ip_id,
+                          &desc->wb.middle.vlan);
 
     desc->wb.upper.header_status =
         cpu_to_le16(ps_hdr_len | (ps_hdr_len ? E1000_RXDPS_HDRSTAT_HDRSP : 0));
@@ -1345,33 +1338,33 @@ e1000e_write_ps_rx_descr(E1000ECore *core,
 }
 
 static inline void
-e1000e_write_rx_descr(E1000ECore *core, union e1000_rx_desc_union *desc,
+igb_write_rx_descr(IGBCore *core, union e1000_rx_desc_union *desc,
 struct NetRxPkt *pkt, const E1000E_RSSInfo *rss_info,
     size_t ps_hdr_len, uint16_t(*written)[MAX_PS_BUFFERS])
 {
-    if (e1000e_rx_use_legacy_descriptor(core)) {
+    if (igb_rx_use_legacy_descriptor(core)) {
         assert(ps_hdr_len == 0);
-        e1000e_write_lgcy_rx_descr(core, &desc->legacy, pkt, rss_info,
-                                   (*written)[0]);
+        igb_write_lgcy_rx_descr(core, &desc->legacy, pkt, rss_info,
+                                (*written)[0]);
     } else {
         if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) {
-            e1000e_write_ps_rx_descr(core, &desc->packet_split, pkt, rss_info,
-                                      ps_hdr_len, written);
+            igb_write_ps_rx_descr(core, &desc->packet_split, pkt, rss_info,
+                                  ps_hdr_len, written);
         } else {
             assert(ps_hdr_len == 0);
-            e1000e_write_ext_rx_descr(core, &desc->extended, pkt, rss_info,
-                                       (*written)[0]);
+            igb_write_ext_rx_descr(core, &desc->extended, pkt, rss_info,
+                                   (*written)[0]);
         }
     }
 }
 
 static inline void
-e1000e_pci_dma_write_rx_desc(E1000ECore *core, dma_addr_t addr,
-                             union e1000_rx_desc_union *desc, dma_addr_t len)
+igb_pci_dma_write_rx_desc(IGBCore *core, dma_addr_t addr,
+                          union e1000_rx_desc_union *desc, dma_addr_t len)
 {
     PCIDevice *dev = core->owner;
 
-    if (e1000e_rx_use_legacy_descriptor(core)) {
+    if (igb_rx_use_legacy_descriptor(core)) {
         struct e1000_rx_desc *d = &desc->legacy;
         size_t offset = offsetof(struct e1000_rx_desc, status);
         uint8_t status = d->status;
@@ -1420,11 +1413,11 @@ typedef struct e1000e_ba_state_st {
 } e1000e_ba_state;
 
 static inline void
-e1000e_write_hdr_to_rx_buffers(E1000ECore *core,
-                               hwaddr ba[MAX_PS_BUFFERS],
-                               e1000e_ba_state *bastate,
-                               const char *data,
-                               dma_addr_t data_len)
+igb_write_hdr_to_rx_buffers(IGBCore *core,
+                            hwaddr ba[MAX_PS_BUFFERS],
+                            e1000e_ba_state *bastate,
+                            const char *data,
+                            dma_addr_t data_len)
 {
     assert(data_len <= core->rxbuf_sizes[0] - bastate->written[0]);
 
@@ -1435,11 +1428,11 @@ e1000e_write_hdr_to_rx_buffers(E1000ECore *core,
 }
 
 static void
-e1000e_write_to_rx_buffers(E1000ECore *core,
-                           hwaddr ba[MAX_PS_BUFFERS],
-                           e1000e_ba_state *bastate,
-                           const char *data,
-                           dma_addr_t data_len)
+igb_write_to_rx_buffers(IGBCore *core,
+                        hwaddr ba[MAX_PS_BUFFERS],
+                        e1000e_ba_state *bastate,
+                        const char *data,
+                        dma_addr_t data_len)
 {
     while (data_len > 0) {
         uint32_t cur_buf_len = core->rxbuf_sizes[bastate->cur_idx];
@@ -1470,9 +1463,7 @@ e1000e_write_to_rx_buffers(E1000ECore *core,
 }
 
 static void
-e1000e_update_rx_stats(E1000ECore *core,
-                       size_t data_size,
-                       size_t data_fcs_size)
+igb_update_rx_stats(IGBCore *core, size_t data_size, size_t data_fcs_size)
 {
     e1000x_update_rx_total_stats(core->mac, data_size, data_fcs_size);
 
@@ -1491,19 +1482,19 @@ e1000e_update_rx_stats(E1000ECore *core,
 }
 
 static inline bool
-e1000e_rx_descr_threshold_hit(E1000ECore *core, const E1000E_RingInfo *rxi)
+igb_rx_descr_threshold_hit(IGBCore *core, const E1000E_RingInfo *rxi)
 {
-    return e1000e_ring_free_descr_num(core, rxi) ==
-           e1000e_ring_len(core, rxi) >> core->rxbuf_min_shift;
+    return igb_ring_free_descr_num(core, rxi) ==
+           igb_ring_len(core, rxi) >> core->rxbuf_min_shift;
 }
 
 static bool
-e1000e_do_ps(E1000ECore *core, struct NetRxPkt *pkt, size_t *hdr_len)
+igb_do_ps(IGBCore *core, struct NetRxPkt *pkt, size_t *hdr_len)
 {
     bool isip4, isip6, isudp, istcp;
     bool fragment;
 
-    if (!e1000e_rx_use_ps_descriptor(core)) {
+    if (!igb_rx_use_ps_descriptor(core)) {
         return false;
     }
 
@@ -1536,9 +1527,9 @@ e1000e_do_ps(E1000ECore *core, struct NetRxPkt *pkt, size_t *hdr_len)
 }
 
 static void
-e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
-                             const E1000E_RxRing *rxr,
-                             const E1000E_RSSInfo *rss_info)
+igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
+                          const E1000E_RxRing *rxr,
+                          const E1000E_RSSInfo *rss_info)
 {
     PCIDevice *d = core->owner;
     dma_addr_t base;
@@ -1552,7 +1543,7 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
     size_t total_size = size + e1000x_fcs_len(core->mac);
     const E1000E_RingInfo *rxi;
     size_t ps_hdr_len = 0;
-    bool do_ps = e1000e_do_ps(core, pkt, &ps_hdr_len);
+    bool do_ps = igb_do_ps(core, pkt, &ps_hdr_len);
     bool is_first = true;
 
     rxi = rxr->i;
@@ -1568,17 +1559,17 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
             desc_size = core->rx_desc_buf_size;
         }
 
-        if (e1000e_ring_empty(core, rxi)) {
+        if (igb_ring_empty(core, rxi)) {
             return;
         }
 
-        base = e1000e_ring_head_descr(core, rxi);
+        base = igb_ring_head_descr(core, rxi);
 
         pci_dma_read(d, base, &desc, core->rx_desc_len);
 
         trace_e1000e_rx_descr(rxi->idx, base, core->rx_desc_len);
 
-        e1000e_read_rx_descr(core, &desc, ba);
+        igb_read_rx_descr(core, &desc, ba);
 
         if (ba[0]) {
             if (desc_offset < size) {
@@ -1597,7 +1588,7 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
                             iov_copy = MIN(ps_hdr_len - ps_hdr_copied,
                                            iov->iov_len - iov_ofs);
 
-                            e1000e_write_hdr_to_rx_buffers(core, ba, &bastate,
+                            igb_write_hdr_to_rx_buffers(core, ba, &bastate,
                                                       iov->iov_base, iov_copy);
 
                             copy_size -= iov_copy;
@@ -1614,7 +1605,7 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
                     } else {
                         /* Leave buffer 0 of each descriptor except first */
                         /* empty as per spec 7.1.5.1                      */
-                        e1000e_write_hdr_to_rx_buffers(core, ba, &bastate,
+                        igb_write_hdr_to_rx_buffers(core, ba, &bastate,
                                                        NULL, 0);
                     }
                 }
@@ -1623,7 +1614,7 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
                 while (copy_size) {
                     iov_copy = MIN(copy_size, iov->iov_len - iov_ofs);
 
-                    e1000e_write_to_rx_buffers(core, ba, &bastate,
+                    igb_write_to_rx_buffers(core, ba, &bastate,
                                             iov->iov_base + iov_ofs, iov_copy);
 
                     copy_size -= iov_copy;
@@ -1636,7 +1627,7 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
 
                 if (desc_offset + desc_size >= total_size) {
                     /* Simulate FCS checksum presence in the last descriptor */
-                    e1000e_write_to_rx_buffers(core, ba, &bastate,
+                    igb_write_to_rx_buffers(core, ba, &bastate,
                           (const char *) &fcs_pad, e1000x_fcs_len(core->mac));
                 }
             }
@@ -1648,20 +1639,20 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
             is_last = true;
         }
 
-        e1000e_write_rx_descr(core, &desc, is_last ? core->rx_pkt : NULL,
+        igb_write_rx_descr(core, &desc, is_last ? core->rx_pkt : NULL,
                            rss_info, do_ps ? ps_hdr_len : 0, &bastate.written);
-        e1000e_pci_dma_write_rx_desc(core, base, &desc, core->rx_desc_len);
+        igb_pci_dma_write_rx_desc(core, base, &desc, core->rx_desc_len);
 
-        e1000e_ring_advance(core, rxi,
-                            core->rx_desc_len / E1000_MIN_RX_DESC_LEN);
+        igb_ring_advance(core, rxi,
+                         core->rx_desc_len / E1000_MIN_RX_DESC_LEN);
 
     } while (desc_offset < total_size);
 
-    e1000e_update_rx_stats(core, size, total_size);
+    igb_update_rx_stats(core, size, total_size);
 }
 
 static inline void
-e1000e_rx_fix_l4_csum(E1000ECore *core, struct NetRxPkt *pkt)
+igb_rx_fix_l4_csum(IGBCore *core, struct NetRxPkt *pkt)
 {
     if (net_rx_pkt_has_virt_hdr(pkt)) {
         struct virtio_net_hdr *vhdr = net_rx_pkt_get_vhdr(pkt);
@@ -1673,7 +1664,7 @@ e1000e_rx_fix_l4_csum(E1000ECore *core, struct NetRxPkt *pkt)
 }
 
 ssize_t
-e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt)
+igb_receive_iov(IGBCore *core, const struct iovec *iov, int iovcnt)
 {
     static const int maximum_ethernet_hdr_len = (ETH_HLEN + 4);
 
@@ -1729,7 +1720,7 @@ e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt)
     net_rx_pkt_set_packet_type(core->rx_pkt,
         get_eth_packet_type(PKT_GET_ETH_HDR(filter_buf)));
 
-    if (!e1000e_receive_filter(core, filter_buf, size)) {
+    if (!igb_receive_filter(core, filter_buf, size)) {
         trace_e1000e_rx_flt_dropped();
         return orig_size;
     }
@@ -1737,18 +1728,18 @@ e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt)
     net_rx_pkt_attach_iovec_ex(core->rx_pkt, iov, iovcnt, iov_ofs,
                                e1000x_vlan_enabled(core->mac), core->mac[VET]);
 
-    e1000e_rss_parse_packet(core, core->rx_pkt, &rss_info);
-    e1000e_rx_ring_init(core, &rxr, rss_info.queue);
+    igb_rss_parse_packet(core, core->rx_pkt, &rss_info);
+    igb_rx_ring_init(core, &rxr, rss_info.queue);
 
     trace_e1000e_rx_rss_dispatched_to_queue(rxr.i->idx);
 
     total_size = net_rx_pkt_get_total_len(core->rx_pkt) +
         e1000x_fcs_len(core->mac);
 
-    if (e1000e_has_rxbufs(core, rxr.i, total_size)) {
-        e1000e_rx_fix_l4_csum(core, core->rx_pkt);
+    if (igb_has_rxbufs(core, rxr.i, total_size)) {
+        igb_rx_fix_l4_csum(core, core->rx_pkt);
 
-        e1000e_write_packet_to_guest(core, core->rx_pkt, &rxr, &rss_info);
+        igb_write_packet_to_guest(core, core->rx_pkt, &rxr, &rss_info);
 
         retval = orig_size;
 
@@ -1759,13 +1750,13 @@ e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt)
 
         /* Perform ACK receive detection */
         if  (!(core->mac[RFCTL] & E1000_RFCTL_ACK_DIS) &&
-             (e1000e_is_tcp_ack(core, core->rx_pkt))) {
+             (igb_is_tcp_ack(core, core->rx_pkt))) {
             n |= E1000_ICS_ACK;
         }
 
         /* Check if receive descriptor minimum threshold hit */
-        rdmts_hit = e1000e_rx_descr_threshold_hit(core, rxr.i);
-        n |= e1000e_rx_wb_interrupt_cause(core, rxr.i->idx, rdmts_hit);
+        rdmts_hit = igb_rx_descr_threshold_hit(core, rxr.i);
+        n |= igb_rx_wb_interrupt_cause(core, rxr.i->idx, rdmts_hit);
 
         trace_e1000e_rx_written_to_guest(n);
     } else {
@@ -1775,9 +1766,9 @@ e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt)
         trace_e1000e_rx_not_written_to_guest(n);
     }
 
-    if (!e1000e_intrmgr_delay_rx_causes(core, &n)) {
+    if (!igb_intrmgr_delay_rx_causes(core, &n)) {
         trace_e1000e_rx_interrupt_set(n);
-        e1000e_set_interrupt_cause(core, n);
+        igb_set_interrupt_cause(core, n);
     } else {
         trace_e1000e_rx_interrupt_delayed(n);
     }
@@ -1786,14 +1777,14 @@ e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt)
 }
 
 static inline bool
-e1000e_have_autoneg(E1000ECore *core)
+igb_have_autoneg(IGBCore *core)
 {
     return core->phy[0][MII_BMCR] & MII_BMCR_AUTOEN;
 }
 
-static void e1000e_update_flowctl_status(E1000ECore *core)
+static void igb_update_flowctl_status(IGBCore *core)
 {
-    if (e1000e_have_autoneg(core) &&
+    if (igb_have_autoneg(core) &&
         core->phy[0][MII_BMSR] & MII_BMSR_AN_COMP) {
         trace_e1000e_link_autoneg_flowctl(true);
         core->mac[CTRL] |= E1000_CTRL_TFCE | E1000_CTRL_RFCE;
@@ -1803,14 +1794,14 @@ static void e1000e_update_flowctl_status(E1000ECore *core)
 }
 
 static inline void
-e1000e_link_down(E1000ECore *core)
+igb_link_down(IGBCore *core)
 {
     e1000x_update_regs_on_link_down(core->mac, core->phy[0]);
-    e1000e_update_flowctl_status(core);
+    igb_update_flowctl_status(core);
 }
 
 static inline void
-e1000e_set_phy_ctrl(E1000ECore *core, int index, uint16_t val)
+igb_set_phy_ctrl(IGBCore *core, int index, uint16_t val)
 {
     /* bits 0-5 reserved; MII_BMCR_[ANRESTART,RESET] are self clearing */
     core->phy[0][MII_BMCR] = val & ~(0x3f |
@@ -1818,13 +1809,13 @@ e1000e_set_phy_ctrl(E1000ECore *core, int index, uint16_t val)
                                      MII_BMCR_ANRESTART);
 
     if ((val & MII_BMCR_ANRESTART) &&
-        e1000e_have_autoneg(core)) {
+        igb_have_autoneg(core)) {
         e1000x_restart_autoneg(core->mac, core->phy[0], core->autoneg_timer);
     }
 }
 
 static void
-e1000e_set_phy_oem_bits(E1000ECore *core, int index, uint16_t val)
+igb_set_phy_oem_bits(IGBCore *core, int index, uint16_t val)
 {
     core->phy[0][PHY_OEM_BITS] = val & ~BIT(10);
 
@@ -1834,13 +1825,13 @@ e1000e_set_phy_oem_bits(E1000ECore *core, int index, uint16_t val)
 }
 
 static void
-e1000e_set_phy_page(E1000ECore *core, int index, uint16_t val)
+igb_set_phy_page(IGBCore *core, int index, uint16_t val)
 {
     core->phy[0][PHY_PAGE] = val & PHY_PAGE_RW_MASK;
 }
 
 void
-e1000e_core_set_link_status(E1000ECore *core)
+igb_core_set_link_status(IGBCore *core)
 {
     NetClientState *nc = qemu_get_queue(core->owner_nic);
     uint32_t old_status = core->mac[STATUS];
@@ -1850,23 +1841,23 @@ e1000e_core_set_link_status(E1000ECore *core)
     if (nc->link_down) {
         e1000x_update_regs_on_link_down(core->mac, core->phy[0]);
     } else {
-        if (e1000e_have_autoneg(core) &&
+        if (igb_have_autoneg(core) &&
             !(core->phy[0][MII_BMSR] & MII_BMSR_AN_COMP)) {
             e1000x_restart_autoneg(core->mac, core->phy[0],
                                    core->autoneg_timer);
         } else {
             e1000x_update_regs_on_link_up(core->mac, core->phy[0]);
-            e1000e_start_recv(core);
+            igb_start_recv(core);
         }
     }
 
     if (core->mac[STATUS] != old_status) {
-        e1000e_set_interrupt_cause(core, E1000_ICR_LSC);
+        igb_set_interrupt_cause(core, E1000_ICR_LSC);
     }
 }
 
 static void
-e1000e_set_ctrl(E1000ECore *core, int index, uint32_t val)
+igb_set_ctrl(IGBCore *core, int index, uint32_t val)
 {
     trace_e1000e_core_ctrl_write(index, val);
 
@@ -1884,7 +1875,7 @@ e1000e_set_ctrl(E1000ECore *core, int index, uint32_t val)
 
     if (val & E1000_CTRL_RST) {
         trace_e1000e_core_ctrl_sw_reset();
-        e1000e_reset(core, true);
+        igb_reset(core, true);
     }
 
     if (val & E1000_CTRL_PHY_RST) {
@@ -1894,7 +1885,7 @@ e1000e_set_ctrl(E1000ECore *core, int index, uint32_t val)
 }
 
 static void
-e1000e_set_rfctl(E1000ECore *core, int index, uint32_t val)
+igb_set_rfctl(IGBCore *core, int index, uint32_t val)
 {
     trace_e1000e_rx_set_rfctl(val);
 
@@ -1914,7 +1905,7 @@ e1000e_set_rfctl(E1000ECore *core, int index, uint32_t val)
 }
 
 static void
-e1000e_calc_per_desc_buf_size(E1000ECore *core)
+igb_calc_per_desc_buf_size(IGBCore *core)
 {
     int i;
     core->rx_desc_buf_size = 0;
@@ -1925,7 +1916,7 @@ e1000e_calc_per_desc_buf_size(E1000ECore *core)
 }
 
 static void
-e1000e_parse_rxbufsize(E1000ECore *core)
+igb_parse_rxbufsize(IGBCore *core)
 {
     uint32_t rctl = core->mac[RCTL];
 
@@ -1955,13 +1946,13 @@ e1000e_parse_rxbufsize(E1000ECore *core)
     trace_e1000e_rx_desc_buff_sizes(core->rxbuf_sizes[0], core->rxbuf_sizes[1],
                                     core->rxbuf_sizes[2], core->rxbuf_sizes[3]);
 
-    e1000e_calc_per_desc_buf_size(core);
+    igb_calc_per_desc_buf_size(core);
 }
 
 static void
-e1000e_calc_rxdesclen(E1000ECore *core)
+igb_calc_rxdesclen(IGBCore *core)
 {
-    if (e1000e_rx_use_legacy_descriptor(core)) {
+    if (igb_rx_use_legacy_descriptor(core)) {
         core->rx_desc_len = sizeof(struct e1000_rx_desc);
     } else {
         if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) {
@@ -1974,40 +1965,40 @@ e1000e_calc_rxdesclen(E1000ECore *core)
 }
 
 static void
-e1000e_set_rx_control(E1000ECore *core, int index, uint32_t val)
+igb_set_rx_control(IGBCore *core, int index, uint32_t val)
 {
     core->mac[RCTL] = val;
     trace_e1000e_rx_set_rctl(core->mac[RCTL]);
 
     if (val & E1000_RCTL_EN) {
-        e1000e_parse_rxbufsize(core);
-        e1000e_calc_rxdesclen(core);
+        igb_parse_rxbufsize(core);
+        igb_calc_rxdesclen(core);
         core->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1 +
                                 E1000_RING_DESC_LEN_SHIFT;
 
-        e1000e_start_recv(core);
+        igb_start_recv(core);
     }
 }
 
 static
-void(*e1000e_phyreg_writeops[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE])
-(E1000ECore *, int, uint16_t) = {
+void(*igb_phyreg_writeops[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE])
+(IGBCore *, int, uint16_t) = {
     [0] = {
-        [MII_BMCR]     = e1000e_set_phy_ctrl,
-        [PHY_PAGE]     = e1000e_set_phy_page,
-        [PHY_OEM_BITS] = e1000e_set_phy_oem_bits
+        [MII_BMCR]     = igb_set_phy_ctrl,
+        [PHY_PAGE]     = igb_set_phy_page,
+        [PHY_OEM_BITS] = igb_set_phy_oem_bits
     }
 };
 
 static inline void
-e1000e_clear_ims_bits(E1000ECore *core, uint32_t bits)
+igb_clear_ims_bits(IGBCore *core, uint32_t bits)
 {
     trace_e1000e_irq_clear_ims(bits, core->mac[IMS], core->mac[IMS] & ~bits);
     core->mac[IMS] &= ~bits;
 }
 
 static inline bool
-e1000e_postpone_interrupt(E1000IntrDelayTimer *timer)
+igb_postpone_interrupt(IGBIntrDelayTimer *timer)
 {
     if (timer->running) {
         trace_e1000e_irq_postponed_by_xitr(timer->delay_reg << 2);
@@ -2016,33 +2007,33 @@ e1000e_postpone_interrupt(E1000IntrDelayTimer *timer)
     }
 
     if (timer->core->mac[timer->delay_reg] != 0) {
-        e1000e_intrmgr_rearm_timer(timer);
+        igb_intrmgr_rearm_timer(timer);
     }
 
     return false;
 }
 
 static inline bool
-e1000e_itr_should_postpone(E1000ECore *core)
+igb_itr_should_postpone(IGBCore *core)
 {
-    return e1000e_postpone_interrupt(&core->itr);
+    return igb_postpone_interrupt(&core->itr);
 }
 
 static inline bool
-e1000e_eitr_should_postpone(E1000ECore *core, int idx)
+igb_eitr_should_postpone(IGBCore *core, int idx)
 {
-    return e1000e_postpone_interrupt(&core->eitr[idx]);
+    return igb_postpone_interrupt(&core->eitr[idx]);
 }
 
 static void
-e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg)
+igb_msix_notify_one(IGBCore *core, uint32_t cause, uint32_t int_cfg)
 {
     uint32_t effective_eiac;
 
     if (E1000_IVAR_ENTRY_VALID(int_cfg)) {
         uint32_t vec = E1000_IVAR_ENTRY_VEC(int_cfg);
-        if (vec < E1000E_MSIX_VEC_NUM) {
-            if (!e1000e_eitr_should_postpone(core, vec)) {
+        if (vec < IGB_MSIX_VEC_NUM) {
+            if (!igb_eitr_should_postpone(core, vec)) {
                 trace_e1000e_irq_msix_notify_vec(vec);
                 msix_notify(core->owner, vec);
             }
@@ -2071,40 +2062,40 @@ e1000e_msix_notify_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg)
 }
 
 static void
-e1000e_msix_notify(E1000ECore *core, uint32_t causes)
+igb_msix_notify(IGBCore *core, uint32_t causes)
 {
     if (causes & E1000_ICR_RXQ0) {
-        e1000e_msix_notify_one(core, E1000_ICR_RXQ0,
+        igb_msix_notify_one(core, E1000_ICR_RXQ0,
                                E1000_IVAR_RXQ0(core->mac[IVAR]));
     }
 
     if (causes & E1000_ICR_RXQ1) {
-        e1000e_msix_notify_one(core, E1000_ICR_RXQ1,
+        igb_msix_notify_one(core, E1000_ICR_RXQ1,
                                E1000_IVAR_RXQ1(core->mac[IVAR]));
     }
 
     if (causes & E1000_ICR_TXQ0) {
-        e1000e_msix_notify_one(core, E1000_ICR_TXQ0,
+        igb_msix_notify_one(core, E1000_ICR_TXQ0,
                                E1000_IVAR_TXQ0(core->mac[IVAR]));
     }
 
     if (causes & E1000_ICR_TXQ1) {
-        e1000e_msix_notify_one(core, E1000_ICR_TXQ1,
+        igb_msix_notify_one(core, E1000_ICR_TXQ1,
                                E1000_IVAR_TXQ1(core->mac[IVAR]));
     }
 
     if (causes & E1000_ICR_OTHER) {
-        e1000e_msix_notify_one(core, E1000_ICR_OTHER,
+        igb_msix_notify_one(core, E1000_ICR_OTHER,
                                E1000_IVAR_OTHER(core->mac[IVAR]));
     }
 }
 
 static void
-e1000e_msix_clear_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg)
+igb_msix_clear_one(IGBCore *core, uint32_t cause, uint32_t int_cfg)
 {
     if (E1000_IVAR_ENTRY_VALID(int_cfg)) {
         uint32_t vec = E1000_IVAR_ENTRY_VEC(int_cfg);
-        if (vec < E1000E_MSIX_VEC_NUM) {
+        if (vec < IGB_MSIX_VEC_NUM) {
             trace_e1000e_irq_msix_pending_clearing(cause, int_cfg, vec);
             msix_clr_pending(core->owner, vec);
         } else {
@@ -2116,36 +2107,36 @@ e1000e_msix_clear_one(E1000ECore *core, uint32_t cause, uint32_t int_cfg)
 }
 
 static void
-e1000e_msix_clear(E1000ECore *core, uint32_t causes)
+igb_msix_clear(IGBCore *core, uint32_t causes)
 {
     if (causes & E1000_ICR_RXQ0) {
-        e1000e_msix_clear_one(core, E1000_ICR_RXQ0,
+        igb_msix_clear_one(core, E1000_ICR_RXQ0,
                               E1000_IVAR_RXQ0(core->mac[IVAR]));
     }
 
     if (causes & E1000_ICR_RXQ1) {
-        e1000e_msix_clear_one(core, E1000_ICR_RXQ1,
+        igb_msix_clear_one(core, E1000_ICR_RXQ1,
                               E1000_IVAR_RXQ1(core->mac[IVAR]));
     }
 
     if (causes & E1000_ICR_TXQ0) {
-        e1000e_msix_clear_one(core, E1000_ICR_TXQ0,
+        igb_msix_clear_one(core, E1000_ICR_TXQ0,
                               E1000_IVAR_TXQ0(core->mac[IVAR]));
     }
 
     if (causes & E1000_ICR_TXQ1) {
-        e1000e_msix_clear_one(core, E1000_ICR_TXQ1,
+        igb_msix_clear_one(core, E1000_ICR_TXQ1,
                               E1000_IVAR_TXQ1(core->mac[IVAR]));
     }
 
     if (causes & E1000_ICR_OTHER) {
-        e1000e_msix_clear_one(core, E1000_ICR_OTHER,
+        igb_msix_clear_one(core, E1000_ICR_OTHER,
                               E1000_IVAR_OTHER(core->mac[IVAR]));
     }
 }
 
 static inline void
-e1000e_fix_icr_asserted(E1000ECore *core)
+igb_fix_icr_asserted(IGBCore *core)
 {
     core->mac[ICR] &= ~E1000_ICR_ASSERTED;
     if (core->mac[ICR]) {
@@ -2156,7 +2147,7 @@ e1000e_fix_icr_asserted(E1000ECore *core)
 }
 
 static void
-e1000e_send_msi(E1000ECore *core, bool msix)
+igb_send_msi(IGBCore *core, bool msix)
 {
     uint32_t causes = core->mac[ICR] & core->mac[IMS] & ~E1000_ICR_ASSERTED;
 
@@ -2168,9 +2159,9 @@ e1000e_send_msi(E1000ECore *core, bool msix)
     core->msi_causes_pending |= causes;
 
     if (msix) {
-        e1000e_msix_notify(core, causes);
+        igb_msix_notify(core, causes);
     } else {
-        if (!e1000e_itr_should_postpone(core)) {
+        if (!igb_itr_should_postpone(core)) {
             trace_e1000e_irq_msi_notify(causes);
             msi_notify(core->owner, 0);
         }
@@ -2178,7 +2169,7 @@ e1000e_send_msi(E1000ECore *core, bool msix)
 }
 
 static void
-e1000e_update_interrupt_state(E1000ECore *core)
+igb_update_interrupt_state(IGBCore *core)
 {
     bool interrupts_pending;
     bool is_msix = msix_enabled(core->owner);
@@ -2191,7 +2182,7 @@ e1000e_update_interrupt_state(E1000ECore *core)
         }
     }
 
-    e1000e_fix_icr_asserted(core);
+    igb_fix_icr_asserted(core);
 
     /*
      * Make sure ICR and ICS registers have the same value.
@@ -2213,54 +2204,54 @@ e1000e_update_interrupt_state(E1000ECore *core)
 
     if (is_msix || msi_enabled(core->owner)) {
         if (interrupts_pending) {
-            e1000e_send_msi(core, is_msix);
+            igb_send_msi(core, is_msix);
         }
     } else {
         if (interrupts_pending) {
-            if (!e1000e_itr_should_postpone(core)) {
-                e1000e_raise_legacy_irq(core);
+            if (!igb_itr_should_postpone(core)) {
+                igb_raise_legacy_irq(core);
             }
         } else {
-            e1000e_lower_legacy_irq(core);
+            igb_lower_legacy_irq(core);
         }
     }
 }
 
 static void
-e1000e_set_interrupt_cause(E1000ECore *core, uint32_t val)
+igb_set_interrupt_cause(IGBCore *core, uint32_t val)
 {
     trace_e1000e_irq_set_cause_entry(val, core->mac[ICR]);
 
-    val |= e1000e_intmgr_collect_delayed_causes(core);
+    val |= igb_intmgr_collect_delayed_causes(core);
     core->mac[ICR] |= val;
 
     trace_e1000e_irq_set_cause_exit(val, core->mac[ICR]);
 
-    e1000e_update_interrupt_state(core);
+    igb_update_interrupt_state(core);
 }
 
 static inline void
-e1000e_autoneg_timer(void *opaque)
+igb_autoneg_timer(void *opaque)
 {
-    E1000ECore *core = opaque;
+    IGBCore *core = opaque;
     if (!qemu_get_queue(core->owner_nic)->link_down) {
         e1000x_update_regs_on_autoneg_done(core->mac, core->phy[0]);
-        e1000e_start_recv(core);
+        igb_start_recv(core);
 
-        e1000e_update_flowctl_status(core);
+        igb_update_flowctl_status(core);
         /* signal link status change to the guest */
-        e1000e_set_interrupt_cause(core, E1000_ICR_LSC);
+        igb_set_interrupt_cause(core, E1000_ICR_LSC);
     }
 }
 
 static inline uint16_t
-e1000e_get_reg_index_with_offset(const uint16_t *mac_reg_access, hwaddr addr)
+igb_get_reg_index_with_offset(const uint16_t *mac_reg_access, hwaddr addr)
 {
     uint16_t index = (addr & 0x1ffff) >> 2;
     return index + (mac_reg_access[index] & 0xfffe);
 }
 
-static const char e1000e_phy_regcap[E1000E_PHY_PAGES][0x20] = {
+static const char igb_phy_regcap[E1000E_PHY_PAGES][0x20] = {
     [0] = {
         [MII_BMCR]              = PHY_ANYPAGE | PHY_RW,
         [MII_BMSR]              = PHY_ANYPAGE | PHY_R,
@@ -2309,36 +2300,34 @@ static const char e1000e_phy_regcap[E1000E_PHY_PAGES][0x20] = {
 };
 
 static bool
-e1000e_phy_reg_check_cap(E1000ECore *core, uint32_t addr,
+igb_phy_reg_check_cap(IGBCore *core, uint32_t addr,
                          char cap, uint8_t *page)
 {
-    *page =
-        (e1000e_phy_regcap[0][addr] & PHY_ANYPAGE) ? 0
+    *page = (igb_phy_regcap[0][addr] & PHY_ANYPAGE) ? 0
                                                     : core->phy[0][PHY_PAGE];
 
     if (*page >= E1000E_PHY_PAGES) {
         return false;
     }
 
-    return e1000e_phy_regcap[*page][addr] & cap;
+    return igb_phy_regcap[*page][addr] & cap;
 }
 
 static void
-e1000e_phy_reg_write(E1000ECore *core, uint8_t page,
-                     uint32_t addr, uint16_t data)
+igb_phy_reg_write(IGBCore *core, uint8_t page, uint32_t addr, uint16_t data)
 {
     assert(page < E1000E_PHY_PAGES);
     assert(addr < E1000E_PHY_PAGE_SIZE);
 
-    if (e1000e_phyreg_writeops[page][addr]) {
-        e1000e_phyreg_writeops[page][addr](core, addr, data);
+    if (igb_phyreg_writeops[page][addr]) {
+        igb_phyreg_writeops[page][addr](core, addr, data);
     } else {
         core->phy[page][addr] = data;
     }
 }
 
 static void
-e1000e_set_mdic(E1000ECore *core, int index, uint32_t val)
+igb_set_mdic(IGBCore *core, int index, uint32_t val)
 {
     uint32_t data = val & E1000_MDIC_DATA_MASK;
     uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
@@ -2347,7 +2336,7 @@ e1000e_set_mdic(E1000ECore *core, int index, uint32_t val)
     if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) { /* phy # */
         val = core->mac[MDIC] | E1000_MDIC_ERROR;
     } else if (val & E1000_MDIC_OP_READ) {
-        if (!e1000e_phy_reg_check_cap(core, addr, PHY_R, &page)) {
+        if (!igb_phy_reg_check_cap(core, addr, PHY_R, &page)) {
             trace_e1000e_core_mdic_read_unhandled(page, addr);
             val |= E1000_MDIC_ERROR;
         } else {
@@ -2355,31 +2344,31 @@ e1000e_set_mdic(E1000ECore *core, int index, uint32_t val)
             trace_e1000e_core_mdic_read(page, addr, val);
         }
     } else if (val & E1000_MDIC_OP_WRITE) {
-        if (!e1000e_phy_reg_check_cap(core, addr, PHY_W, &page)) {
+        if (!igb_phy_reg_check_cap(core, addr, PHY_W, &page)) {
             trace_e1000e_core_mdic_write_unhandled(page, addr);
             val |= E1000_MDIC_ERROR;
         } else {
             trace_e1000e_core_mdic_write(page, addr, data);
-            e1000e_phy_reg_write(core, page, addr, data);
+            igb_phy_reg_write(core, page, addr, data);
         }
     }
     core->mac[MDIC] = val | E1000_MDIC_READY;
 
     if (val & E1000_MDIC_INT_EN) {
-        e1000e_set_interrupt_cause(core, E1000_ICR_MDAC);
+        igb_set_interrupt_cause(core, E1000_ICR_MDAC);
     }
 }
 
 static void
-e1000e_set_rdt(E1000ECore *core, int index, uint32_t val)
+igb_set_rdt(IGBCore *core, int index, uint32_t val)
 {
     core->mac[index] = val & 0xffff;
-    trace_e1000e_rx_set_rdt(e1000e_mq_queue_idx(RDT0, index), val);
-    e1000e_start_recv(core);
+    trace_e1000e_rx_set_rdt(igb_mq_queue_idx(RDT0, index), val);
+    igb_start_recv(core);
 }
 
 static void
-e1000e_set_status(E1000ECore *core, int index, uint32_t val)
+igb_set_status(IGBCore *core, int index, uint32_t val)
 {
     if ((val & E1000_STATUS_PHYRA) == 0) {
         core->mac[index] &= ~E1000_STATUS_PHYRA;
@@ -2387,7 +2376,7 @@ e1000e_set_status(E1000ECore *core, int index, uint32_t val)
 }
 
 static void
-e1000e_set_ctrlext(E1000ECore *core, int index, uint32_t val)
+igb_set_ctrlext(IGBCore *core, int index, uint32_t val)
 {
     trace_e1000e_link_set_ext_params(!!(val & E1000_CTRL_EXT_ASDCHK),
                                      !!(val & E1000_CTRL_EXT_SPD_BYPS));
@@ -2398,7 +2387,7 @@ e1000e_set_ctrlext(E1000ECore *core, int index, uint32_t val)
 }
 
 static void
-e1000e_set_pbaclr(E1000ECore *core, int index, uint32_t val)
+igb_set_pbaclr(IGBCore *core, int index, uint32_t val)
 {
     int i;
 
@@ -2408,7 +2397,7 @@ e1000e_set_pbaclr(E1000ECore *core, int index, uint32_t val)
         return;
     }
 
-    for (i = 0; i < E1000E_MSIX_VEC_NUM; i++) {
+    for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
         if (core->mac[PBACLR] & BIT(i)) {
             msix_clr_pending(core->owner, i);
         }
@@ -2416,97 +2405,97 @@ e1000e_set_pbaclr(E1000ECore *core, int index, uint32_t val)
 }
 
 static void
-e1000e_set_fcrth(E1000ECore *core, int index, uint32_t val)
+igb_set_fcrth(IGBCore *core, int index, uint32_t val)
 {
     core->mac[FCRTH] = val & 0xFFF8;
 }
 
 static void
-e1000e_set_fcrtl(E1000ECore *core, int index, uint32_t val)
+igb_set_fcrtl(IGBCore *core, int index, uint32_t val)
 {
     core->mac[FCRTL] = val & 0x8000FFF8;
 }
 
-#define E1000E_LOW_BITS_SET_FUNC(num)                                \
-    static void                                                      \
-    e1000e_set_##num##bit(E1000ECore *core, int index, uint32_t val) \
-    {                                                                \
-        core->mac[index] = val & (BIT(num) - 1);                     \
+#define IGB_LOW_BITS_SET_FUNC(num)                             \
+    static void                                                \
+    igb_set_##num##bit(IGBCore *core, int index, uint32_t val) \
+    {                                                          \
+        core->mac[index] = val & (BIT(num) - 1);               \
     }
 
-E1000E_LOW_BITS_SET_FUNC(4)
-E1000E_LOW_BITS_SET_FUNC(6)
-E1000E_LOW_BITS_SET_FUNC(11)
-E1000E_LOW_BITS_SET_FUNC(12)
-E1000E_LOW_BITS_SET_FUNC(13)
-E1000E_LOW_BITS_SET_FUNC(16)
+IGB_LOW_BITS_SET_FUNC(4)
+IGB_LOW_BITS_SET_FUNC(6)
+IGB_LOW_BITS_SET_FUNC(11)
+IGB_LOW_BITS_SET_FUNC(12)
+IGB_LOW_BITS_SET_FUNC(13)
+IGB_LOW_BITS_SET_FUNC(16)
 
 static void
-e1000e_set_vet(E1000ECore *core, int index, uint32_t val)
+igb_set_vet(IGBCore *core, int index, uint32_t val)
 {
     core->mac[VET] = val & 0xffff;
     trace_e1000e_vlan_vet(core->mac[VET]);
 }
 
 static void
-e1000e_set_dlen(E1000ECore *core, int index, uint32_t val)
+igb_set_dlen(IGBCore *core, int index, uint32_t val)
 {
     core->mac[index] = val & E1000_XDLEN_MASK;
 }
 
 static void
-e1000e_set_dbal(E1000ECore *core, int index, uint32_t val)
+igb_set_dbal(IGBCore *core, int index, uint32_t val)
 {
     core->mac[index] = val & E1000_XDBAL_MASK;
 }
 
 static void
-e1000e_set_tctl(E1000ECore *core, int index, uint32_t val)
+igb_set_tctl(IGBCore *core, int index, uint32_t val)
 {
-    E1000E_TxRing txr;
+    IGB_TxRing txr;
     core->mac[index] = val;
 
     if (core->mac[TARC0] & E1000_TARC_ENABLE) {
-        e1000e_tx_ring_init(core, &txr, 0);
-        e1000e_start_xmit(core, &txr);
+        igb_tx_ring_init(core, &txr, 0);
+        igb_start_xmit(core, &txr);
     }
 
     if (core->mac[TARC1] & E1000_TARC_ENABLE) {
-        e1000e_tx_ring_init(core, &txr, 1);
-        e1000e_start_xmit(core, &txr);
+        igb_tx_ring_init(core, &txr, 1);
+        igb_start_xmit(core, &txr);
     }
 }
 
 static void
-e1000e_set_tdt(E1000ECore *core, int index, uint32_t val)
+igb_set_tdt(IGBCore *core, int index, uint32_t val)
 {
-    E1000E_TxRing txr;
-    int qidx = e1000e_mq_queue_idx(TDT, index);
+    IGB_TxRing txr;
+    int qidx = igb_mq_queue_idx(TDT, index);
     uint32_t tarc_reg = (qidx == 0) ? TARC0 : TARC1;
 
     core->mac[index] = val & 0xffff;
 
     if (core->mac[tarc_reg] & E1000_TARC_ENABLE) {
-        e1000e_tx_ring_init(core, &txr, qidx);
-        e1000e_start_xmit(core, &txr);
+        igb_tx_ring_init(core, &txr, qidx);
+        igb_start_xmit(core, &txr);
     }
 }
 
 static void
-e1000e_set_ics(E1000ECore *core, int index, uint32_t val)
+igb_set_ics(IGBCore *core, int index, uint32_t val)
 {
     trace_e1000e_irq_write_ics(val);
-    e1000e_set_interrupt_cause(core, val);
+    igb_set_interrupt_cause(core, val);
 }
 
 static void
-e1000e_set_icr(E1000ECore *core, int index, uint32_t val)
+igb_set_icr(IGBCore *core, int index, uint32_t val)
 {
     uint32_t icr = 0;
     if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
         (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
         trace_e1000e_irq_icr_process_iame();
-        e1000e_clear_ims_bits(core, core->mac[IAM]);
+        igb_clear_ims_bits(core, core->mac[IAM]);
     }
 
     icr = core->mac[ICR] & ~val;
@@ -2517,19 +2506,19 @@ e1000e_set_icr(E1000ECore *core, int index, uint32_t val)
     icr = (val & E1000_ICR_OTHER) ? (icr & ~E1000_ICR_OTHER_CAUSES) : icr;
     trace_e1000e_irq_icr_write(val, core->mac[ICR], icr);
     core->mac[ICR] = icr;
-    e1000e_update_interrupt_state(core);
+    igb_update_interrupt_state(core);
 }
 
 static void
-e1000e_set_imc(E1000ECore *core, int index, uint32_t val)
+igb_set_imc(IGBCore *core, int index, uint32_t val)
 {
     trace_e1000e_irq_ims_clear_set_imc(val);
-    e1000e_clear_ims_bits(core, val);
-    e1000e_update_interrupt_state(core);
+    igb_clear_ims_bits(core, val);
+    igb_update_interrupt_state(core);
 }
 
 static void
-e1000e_set_ims(E1000ECore *core, int index, uint32_t val)
+igb_set_ims(IGBCore *core, int index, uint32_t val)
 {
     static const uint32_t ims_ext_mask =
         E1000_IMS_RXQ0 | E1000_IMS_RXQ1 |
@@ -2552,66 +2541,66 @@ e1000e_set_ims(E1000ECore *core, int index, uint32_t val)
     if ((valid_val & ims_ext_mask) &&
         (core->mac[CTRL_EXT] & E1000_CTRL_EXT_PBA_CLR) &&
         msix_enabled(core->owner)) {
-        e1000e_msix_clear(core, valid_val);
+        igb_msix_clear(core, valid_val);
     }
 
     if ((valid_val == ims_valid_mask) &&
         (core->mac[CTRL_EXT] & E1000_CTRL_EXT_INT_TIMERS_CLEAR_ENA)) {
         trace_e1000e_irq_fire_all_timers(val);
-        e1000e_intrmgr_fire_all_timers(core);
+        igb_intrmgr_fire_all_timers(core);
     }
 
-    e1000e_update_interrupt_state(core);
+    igb_update_interrupt_state(core);
 }
 
 static void
-e1000e_set_rdtr(E1000ECore *core, int index, uint32_t val)
+igb_set_rdtr(IGBCore *core, int index, uint32_t val)
 {
-    e1000e_set_16bit(core, index, val);
+    igb_set_16bit(core, index, val);
 
     if ((val & E1000_RDTR_FPD) && (core->rdtr.running)) {
         trace_e1000e_irq_rdtr_fpd_running();
-        e1000e_intrmgr_fire_delayed_interrupts(core);
+        igb_intrmgr_fire_delayed_interrupts(core);
     } else {
         trace_e1000e_irq_rdtr_fpd_not_running();
     }
 }
 
 static void
-e1000e_set_tidv(E1000ECore *core, int index, uint32_t val)
+igb_set_tidv(IGBCore *core, int index, uint32_t val)
 {
-    e1000e_set_16bit(core, index, val);
+    igb_set_16bit(core, index, val);
 
     if ((val & E1000_TIDV_FPD) && (core->tidv.running)) {
         trace_e1000e_irq_tidv_fpd_running();
-        e1000e_intrmgr_fire_delayed_interrupts(core);
+        igb_intrmgr_fire_delayed_interrupts(core);
     } else {
         trace_e1000e_irq_tidv_fpd_not_running();
     }
 }
 
 static uint32_t
-e1000e_mac_readreg(E1000ECore *core, int index)
+igb_mac_readreg(IGBCore *core, int index)
 {
     return core->mac[index];
 }
 
 static uint32_t
-e1000e_mac_ics_read(E1000ECore *core, int index)
+igb_mac_ics_read(IGBCore *core, int index)
 {
     trace_e1000e_irq_read_ics(core->mac[ICS]);
     return core->mac[ICS];
 }
 
 static uint32_t
-e1000e_mac_ims_read(E1000ECore *core, int index)
+igb_mac_ims_read(IGBCore *core, int index)
 {
     trace_e1000e_irq_read_ims(core->mac[IMS]);
     return core->mac[IMS];
 }
 
 static uint32_t
-e1000e_mac_swsm_read(E1000ECore *core, int index)
+igb_mac_swsm_read(IGBCore *core, int index)
 {
     uint32_t val = core->mac[SWSM];
     core->mac[SWSM] = val | E1000_SWSM_SMBI;
@@ -2619,19 +2608,19 @@ e1000e_mac_swsm_read(E1000ECore *core, int index)
 }
 
 static uint32_t
-e1000e_mac_itr_read(E1000ECore *core, int index)
+igb_mac_itr_read(IGBCore *core, int index)
 {
     return core->itr_guest_value;
 }
 
 static uint32_t
-e1000e_mac_eitr_read(E1000ECore *core, int index)
+igb_mac_eitr_read(IGBCore *core, int index)
 {
     return core->eitr_guest_value[index - EITR];
 }
 
 static uint32_t
-e1000e_mac_icr_read(E1000ECore *core, int index)
+igb_mac_icr_read(IGBCore *core, int index)
 {
     uint32_t ret = core->mac[ICR];
     trace_e1000e_irq_icr_read_entry(ret);
@@ -2651,16 +2640,16 @@ e1000e_mac_icr_read(E1000ECore *core, int index)
         trace_e1000e_irq_icr_clear_iame();
         core->mac[ICR] = 0;
         trace_e1000e_irq_icr_process_iame();
-        e1000e_clear_ims_bits(core, core->mac[IAM]);
+        igb_clear_ims_bits(core, core->mac[IAM]);
     }
 
     trace_e1000e_irq_icr_read_exit(core->mac[ICR]);
-    e1000e_update_interrupt_state(core);
+    igb_update_interrupt_state(core);
     return ret;
 }
 
 static uint32_t
-e1000e_mac_read_clr4(E1000ECore *core, int index)
+igb_mac_read_clr4(IGBCore *core, int index)
 {
     uint32_t ret = core->mac[index];
 
@@ -2669,7 +2658,7 @@ e1000e_mac_read_clr4(E1000ECore *core, int index)
 }
 
 static uint32_t
-e1000e_mac_read_clr8(E1000ECore *core, int index)
+igb_mac_read_clr8(IGBCore *core, int index)
 {
     uint32_t ret = core->mac[index];
 
@@ -2679,7 +2668,7 @@ e1000e_mac_read_clr8(E1000ECore *core, int index)
 }
 
 static uint32_t
-e1000e_get_ctrl(E1000ECore *core, int index)
+igb_get_ctrl(IGBCore *core, int index)
 {
     uint32_t val = core->mac[CTRL];
 
@@ -2695,7 +2684,7 @@ e1000e_get_ctrl(E1000ECore *core, int index)
 }
 
 static uint32_t
-e1000e_get_status(E1000ECore *core, int index)
+igb_get_status(IGBCore *core, int index)
 {
     uint32_t res = core->mac[STATUS];
 
@@ -2737,7 +2726,7 @@ e1000e_get_status(E1000ECore *core, int index)
 }
 
 static uint32_t
-e1000e_get_tarc(E1000ECore *core, int index)
+igb_get_tarc(IGBCore *core, int index)
 {
     return core->mac[index] & ((BIT(11) - 1) |
                                 BIT(27)      |
@@ -2747,13 +2736,13 @@ e1000e_get_tarc(E1000ECore *core, int index)
 }
 
 static void
-e1000e_mac_writereg(E1000ECore *core, int index, uint32_t val)
+igb_mac_writereg(IGBCore *core, int index, uint32_t val)
 {
     core->mac[index] = val;
 }
 
 static void
-e1000e_mac_setmacaddr(E1000ECore *core, int index, uint32_t val)
+igb_mac_setmacaddr(IGBCore *core, int index, uint32_t val)
 {
     uint32_t macaddr[2];
 
@@ -2768,7 +2757,7 @@ e1000e_mac_setmacaddr(E1000ECore *core, int index, uint32_t val)
 }
 
 static void
-e1000e_set_eecd(E1000ECore *core, int index, uint32_t val)
+igb_set_eecd(IGBCore *core, int index, uint32_t val)
 {
     static const uint32_t ro_bits = E1000_EECD_PRES          |
                                     E1000_EECD_AUTO_RD       |
@@ -2778,13 +2767,13 @@ e1000e_set_eecd(E1000ECore *core, int index, uint32_t val)
 }
 
 static void
-e1000e_set_eerd(E1000ECore *core, int index, uint32_t val)
+igb_set_eerd(IGBCore *core, int index, uint32_t val)
 {
     uint32_t addr = (val >> E1000_EERW_ADDR_SHIFT) & E1000_EERW_ADDR_MASK;
     uint32_t flags = 0;
     uint32_t data = 0;
 
-    if ((addr < E1000E_EEPROM_SIZE) && (val & E1000_EERW_START)) {
+    if ((addr < IGB_EEPROM_SIZE) && (val & E1000_EERW_START)) {
         data = core->eeprom[addr];
         flags = E1000_EERW_DONE;
     }
@@ -2795,13 +2784,13 @@ e1000e_set_eerd(E1000ECore *core, int index, uint32_t val)
 }
 
 static void
-e1000e_set_eewr(E1000ECore *core, int index, uint32_t val)
+igb_set_eewr(IGBCore *core, int index, uint32_t val)
 {
     uint32_t addr = (val >> E1000_EERW_ADDR_SHIFT) & E1000_EERW_ADDR_MASK;
     uint32_t data = (val >> E1000_EERW_DATA_SHIFT) & E1000_EERW_DATA_MASK;
     uint32_t flags = 0;
 
-    if ((addr < E1000E_EEPROM_SIZE) && (val & E1000_EERW_START)) {
+    if ((addr < IGB_EEPROM_SIZE) && (val & E1000_EERW_START)) {
         core->eeprom[addr] = data;
         flags = E1000_EERW_DONE;
     }
@@ -2812,13 +2801,13 @@ e1000e_set_eewr(E1000ECore *core, int index, uint32_t val)
 }
 
 static void
-e1000e_set_rxdctl(E1000ECore *core, int index, uint32_t val)
+igb_set_rxdctl(IGBCore *core, int index, uint32_t val)
 {
     core->mac[RXDCTL] = core->mac[RXDCTL1] = val;
 }
 
 static void
-e1000e_set_itr(E1000ECore *core, int index, uint32_t val)
+igb_set_itr(IGBCore *core, int index, uint32_t val)
 {
     uint32_t interval = val & 0xffff;
 
@@ -2829,7 +2818,7 @@ e1000e_set_itr(E1000ECore *core, int index, uint32_t val)
 }
 
 static void
-e1000e_set_eitr(E1000ECore *core, int index, uint32_t val)
+igb_set_eitr(IGBCore *core, int index, uint32_t val)
 {
     uint32_t interval = val & 0xffff;
     uint32_t eitr_num = index - EITR;
@@ -2841,19 +2830,19 @@ e1000e_set_eitr(E1000ECore *core, int index, uint32_t val)
 }
 
 static void
-e1000e_set_psrctl(E1000ECore *core, int index, uint32_t val)
+igb_set_psrctl(IGBCore *core, int index, uint32_t val)
 {
     if (core->mac[RCTL] & E1000_RCTL_DTYP_MASK) {
 
         if ((val & E1000_PSRCTL_BSIZE0_MASK) == 0) {
             qemu_log_mask(LOG_GUEST_ERROR,
-                          "e1000e: PSRCTL.BSIZE0 cannot be zero");
+                          "igb: PSRCTL.BSIZE0 cannot be zero");
             return;
         }
 
         if ((val & E1000_PSRCTL_BSIZE1_MASK) == 0) {
             qemu_log_mask(LOG_GUEST_ERROR,
-                          "e1000e: PSRCTL.BSIZE1 cannot be zero");
+                          "igb: PSRCTL.BSIZE1 cannot be zero");
             return;
         }
     }
@@ -2862,9 +2851,9 @@ e1000e_set_psrctl(E1000ECore *core, int index, uint32_t val)
 }
 
 static void
-e1000e_update_rx_offloads(E1000ECore *core)
+igb_update_rx_offloads(IGBCore *core)
 {
-    int cso_state = e1000e_rx_l4_cso_enabled(core);
+    int cso_state = igb_rx_l4_cso_enabled(core);
 
     trace_e1000e_rx_set_cso(cso_state);
 
@@ -2875,377 +2864,377 @@ e1000e_update_rx_offloads(E1000ECore *core)
 }
 
 static void
-e1000e_set_rxcsum(E1000ECore *core, int index, uint32_t val)
+igb_set_rxcsum(IGBCore *core, int index, uint32_t val)
 {
     core->mac[RXCSUM] = val;
-    e1000e_update_rx_offloads(core);
+    igb_update_rx_offloads(core);
 }
 
 static void
-e1000e_set_gcr(E1000ECore *core, int index, uint32_t val)
+igb_set_gcr(IGBCore *core, int index, uint32_t val)
 {
     uint32_t ro_bits = core->mac[GCR] & E1000_GCR_RO_BITS;
     core->mac[GCR] = (val & ~E1000_GCR_RO_BITS) | ro_bits;
 }
 
-#define e1000e_getreg(x)    [x] = e1000e_mac_readreg
-typedef uint32_t (*readops)(E1000ECore *, int);
-static const readops e1000e_macreg_readops[] = {
-    e1000e_getreg(PBA),
-    e1000e_getreg(WUFC),
-    e1000e_getreg(MANC),
-    e1000e_getreg(TOTL),
-    e1000e_getreg(RDT0),
-    e1000e_getreg(RDBAH0),
-    e1000e_getreg(TDBAL1),
-    e1000e_getreg(RDLEN0),
-    e1000e_getreg(RDH1),
-    e1000e_getreg(LATECOL),
-    e1000e_getreg(SEQEC),
-    e1000e_getreg(XONTXC),
-    e1000e_getreg(AIT),
-    e1000e_getreg(TDFH),
-    e1000e_getreg(TDFT),
-    e1000e_getreg(TDFHS),
-    e1000e_getreg(TDFTS),
-    e1000e_getreg(TDFPC),
-    e1000e_getreg(WUS),
-    e1000e_getreg(PBS),
-    e1000e_getreg(RDFH),
-    e1000e_getreg(RDFT),
-    e1000e_getreg(RDFHS),
-    e1000e_getreg(RDFTS),
-    e1000e_getreg(RDFPC),
-    e1000e_getreg(GORCL),
-    e1000e_getreg(MGTPRC),
-    e1000e_getreg(EERD),
-    e1000e_getreg(EIAC),
-    e1000e_getreg(PSRCTL),
-    e1000e_getreg(MANC2H),
-    e1000e_getreg(RXCSUM),
-    e1000e_getreg(GSCL_3),
-    e1000e_getreg(GSCN_2),
-    e1000e_getreg(RSRPD),
-    e1000e_getreg(RDBAL1),
-    e1000e_getreg(FCAH),
-    e1000e_getreg(FCRTH),
-    e1000e_getreg(FLOP),
-    e1000e_getreg(FLASHT),
-    e1000e_getreg(RXSTMPH),
-    e1000e_getreg(TXSTMPL),
-    e1000e_getreg(TIMADJL),
-    e1000e_getreg(TXDCTL),
-    e1000e_getreg(RDH0),
-    e1000e_getreg(TDT1),
-    e1000e_getreg(TNCRS),
-    e1000e_getreg(RJC),
-    e1000e_getreg(IAM),
-    e1000e_getreg(GSCL_2),
-    e1000e_getreg(RDBAH1),
-    e1000e_getreg(FLSWDATA),
-    e1000e_getreg(RXSATRH),
-    e1000e_getreg(TIPG),
-    e1000e_getreg(FLMNGCTL),
-    e1000e_getreg(FLMNGCNT),
-    e1000e_getreg(TSYNCTXCTL),
-    e1000e_getreg(EXTCNF_SIZE),
-    e1000e_getreg(EXTCNF_CTRL),
-    e1000e_getreg(EEMNGDATA),
-    e1000e_getreg(CTRL_EXT),
-    e1000e_getreg(SYSTIMH),
-    e1000e_getreg(EEMNGCTL),
-    e1000e_getreg(FLMNGDATA),
-    e1000e_getreg(TSYNCRXCTL),
-    e1000e_getreg(TDH),
-    e1000e_getreg(LEDCTL),
-    e1000e_getreg(TCTL),
-    e1000e_getreg(TDBAL),
-    e1000e_getreg(TDLEN),
-    e1000e_getreg(TDH1),
-    e1000e_getreg(RADV),
-    e1000e_getreg(ECOL),
-    e1000e_getreg(DC),
-    e1000e_getreg(RLEC),
-    e1000e_getreg(XOFFTXC),
-    e1000e_getreg(RFC),
-    e1000e_getreg(RNBC),
-    e1000e_getreg(MGTPTC),
-    e1000e_getreg(TIMINCA),
-    e1000e_getreg(RXCFGL),
-    e1000e_getreg(MFUTP01),
-    e1000e_getreg(FACTPS),
-    e1000e_getreg(GSCL_1),
-    e1000e_getreg(GSCN_0),
-    e1000e_getreg(GCR2),
-    e1000e_getreg(RDT1),
-    e1000e_getreg(PBACLR),
-    e1000e_getreg(FCTTV),
-    e1000e_getreg(EEWR),
-    e1000e_getreg(FLSWCTL),
-    e1000e_getreg(RXDCTL1),
-    e1000e_getreg(RXSATRL),
-    e1000e_getreg(SYSTIML),
-    e1000e_getreg(RXUDP),
-    e1000e_getreg(TORL),
-    e1000e_getreg(TDLEN1),
-    e1000e_getreg(MCC),
-    e1000e_getreg(WUC),
-    e1000e_getreg(EECD),
-    e1000e_getreg(MFUTP23),
-    e1000e_getreg(RAID),
-    e1000e_getreg(FCRTV),
-    e1000e_getreg(TXDCTL1),
-    e1000e_getreg(RCTL),
-    e1000e_getreg(TDT),
-    e1000e_getreg(MDIC),
-    e1000e_getreg(FCRUC),
-    e1000e_getreg(VET),
-    e1000e_getreg(RDBAL0),
-    e1000e_getreg(TDBAH1),
-    e1000e_getreg(RDTR),
-    e1000e_getreg(SCC),
-    e1000e_getreg(COLC),
-    e1000e_getreg(CEXTERR),
-    e1000e_getreg(XOFFRXC),
-    e1000e_getreg(IPAV),
-    e1000e_getreg(GOTCL),
-    e1000e_getreg(MGTPDC),
-    e1000e_getreg(GCR),
-    e1000e_getreg(IVAR),
-    e1000e_getreg(POEMB),
-    e1000e_getreg(MFVAL),
-    e1000e_getreg(FUNCTAG),
-    e1000e_getreg(GSCL_4),
-    e1000e_getreg(GSCN_3),
-    e1000e_getreg(MRQC),
-    e1000e_getreg(RDLEN1),
-    e1000e_getreg(FCT),
-    e1000e_getreg(FLA),
-    e1000e_getreg(FLOL),
-    e1000e_getreg(RXDCTL),
-    e1000e_getreg(RXSTMPL),
-    e1000e_getreg(TXSTMPH),
-    e1000e_getreg(TIMADJH),
-    e1000e_getreg(FCRTL),
-    e1000e_getreg(TDBAH),
-    e1000e_getreg(TADV),
-    e1000e_getreg(XONRXC),
-    e1000e_getreg(TSCTFC),
-    e1000e_getreg(RFCTL),
-    e1000e_getreg(GSCN_1),
-    e1000e_getreg(FCAL),
-    e1000e_getreg(FLSWCNT),
-
-    [TOTH]    = e1000e_mac_read_clr8,
-    [GOTCH]   = e1000e_mac_read_clr8,
-    [PRC64]   = e1000e_mac_read_clr4,
-    [PRC255]  = e1000e_mac_read_clr4,
-    [PRC1023] = e1000e_mac_read_clr4,
-    [PTC64]   = e1000e_mac_read_clr4,
-    [PTC255]  = e1000e_mac_read_clr4,
-    [PTC1023] = e1000e_mac_read_clr4,
-    [GPRC]    = e1000e_mac_read_clr4,
-    [TPT]     = e1000e_mac_read_clr4,
-    [RUC]     = e1000e_mac_read_clr4,
-    [BPRC]    = e1000e_mac_read_clr4,
-    [MPTC]    = e1000e_mac_read_clr4,
-    [IAC]     = e1000e_mac_read_clr4,
-    [ICR]     = e1000e_mac_icr_read,
-    [STATUS]  = e1000e_get_status,
-    [TARC0]   = e1000e_get_tarc,
-    [ICS]     = e1000e_mac_ics_read,
-    [TORH]    = e1000e_mac_read_clr8,
-    [GORCH]   = e1000e_mac_read_clr8,
-    [PRC127]  = e1000e_mac_read_clr4,
-    [PRC511]  = e1000e_mac_read_clr4,
-    [PRC1522] = e1000e_mac_read_clr4,
-    [PTC127]  = e1000e_mac_read_clr4,
-    [PTC511]  = e1000e_mac_read_clr4,
-    [PTC1522] = e1000e_mac_read_clr4,
-    [GPTC]    = e1000e_mac_read_clr4,
-    [TPR]     = e1000e_mac_read_clr4,
-    [ROC]     = e1000e_mac_read_clr4,
-    [MPRC]    = e1000e_mac_read_clr4,
-    [BPTC]    = e1000e_mac_read_clr4,
-    [TSCTC]   = e1000e_mac_read_clr4,
-    [ITR]     = e1000e_mac_itr_read,
-    [CTRL]    = e1000e_get_ctrl,
-    [TARC1]   = e1000e_get_tarc,
-    [SWSM]    = e1000e_mac_swsm_read,
-    [IMS]     = e1000e_mac_ims_read,
-
-    [CRCERRS ... MPC]      = e1000e_mac_readreg,
-    [IP6AT ... IP6AT + 3]  = e1000e_mac_readreg,
-    [IP4AT ... IP4AT + 6]  = e1000e_mac_readreg,
-    [RA ... RA + 31]       = e1000e_mac_readreg,
-    [WUPM ... WUPM + 31]   = e1000e_mac_readreg,
-    [MTA ... MTA + E1000_MC_TBL_SIZE - 1] = e1000e_mac_readreg,
-    [VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1]  = e1000e_mac_readreg,
-    [FFMT ... FFMT + 254]  = e1000e_mac_readreg,
-    [FFVT ... FFVT + 254]  = e1000e_mac_readreg,
-    [MDEF ... MDEF + 7]    = e1000e_mac_readreg,
-    [FFLT ... FFLT + 10]   = e1000e_mac_readreg,
-    [FTFT ... FTFT + 254]  = e1000e_mac_readreg,
-    [PBM ... PBM + 10239]  = e1000e_mac_readreg,
-    [RETA ... RETA + 31]   = e1000e_mac_readreg,
-    [RSSRK ... RSSRK + 31] = e1000e_mac_readreg,
-    [MAVTV0 ... MAVTV3]    = e1000e_mac_readreg,
-    [EITR...EITR + E1000E_MSIX_VEC_NUM - 1] = e1000e_mac_eitr_read
+#define igb_getreg(x)    [x] = igb_mac_readreg
+typedef uint32_t (*readops)(IGBCore *, int);
+static const readops igb_macreg_readops[] = {
+    igb_getreg(PBA),
+    igb_getreg(WUFC),
+    igb_getreg(MANC),
+    igb_getreg(TOTL),
+    igb_getreg(RDT0),
+    igb_getreg(RDBAH0),
+    igb_getreg(TDBAL1),
+    igb_getreg(RDLEN0),
+    igb_getreg(RDH1),
+    igb_getreg(LATECOL),
+    igb_getreg(SEQEC),
+    igb_getreg(XONTXC),
+    igb_getreg(AIT),
+    igb_getreg(TDFH),
+    igb_getreg(TDFT),
+    igb_getreg(TDFHS),
+    igb_getreg(TDFTS),
+    igb_getreg(TDFPC),
+    igb_getreg(WUS),
+    igb_getreg(PBS),
+    igb_getreg(RDFH),
+    igb_getreg(RDFT),
+    igb_getreg(RDFHS),
+    igb_getreg(RDFTS),
+    igb_getreg(RDFPC),
+    igb_getreg(GORCL),
+    igb_getreg(MGTPRC),
+    igb_getreg(EERD),
+    igb_getreg(EIAC),
+    igb_getreg(PSRCTL),
+    igb_getreg(MANC2H),
+    igb_getreg(RXCSUM),
+    igb_getreg(GSCL_3),
+    igb_getreg(GSCN_2),
+    igb_getreg(RSRPD),
+    igb_getreg(RDBAL1),
+    igb_getreg(FCAH),
+    igb_getreg(FCRTH),
+    igb_getreg(FLOP),
+    igb_getreg(FLASHT),
+    igb_getreg(RXSTMPH),
+    igb_getreg(TXSTMPL),
+    igb_getreg(TIMADJL),
+    igb_getreg(TXDCTL),
+    igb_getreg(RDH0),
+    igb_getreg(TDT1),
+    igb_getreg(TNCRS),
+    igb_getreg(RJC),
+    igb_getreg(IAM),
+    igb_getreg(GSCL_2),
+    igb_getreg(RDBAH1),
+    igb_getreg(FLSWDATA),
+    igb_getreg(RXSATRH),
+    igb_getreg(TIPG),
+    igb_getreg(FLMNGCTL),
+    igb_getreg(FLMNGCNT),
+    igb_getreg(TSYNCTXCTL),
+    igb_getreg(EXTCNF_SIZE),
+    igb_getreg(EXTCNF_CTRL),
+    igb_getreg(EEMNGDATA),
+    igb_getreg(CTRL_EXT),
+    igb_getreg(SYSTIMH),
+    igb_getreg(EEMNGCTL),
+    igb_getreg(FLMNGDATA),
+    igb_getreg(TSYNCRXCTL),
+    igb_getreg(TDH),
+    igb_getreg(LEDCTL),
+    igb_getreg(TCTL),
+    igb_getreg(TDBAL),
+    igb_getreg(TDLEN),
+    igb_getreg(TDH1),
+    igb_getreg(RADV),
+    igb_getreg(ECOL),
+    igb_getreg(DC),
+    igb_getreg(RLEC),
+    igb_getreg(XOFFTXC),
+    igb_getreg(RFC),
+    igb_getreg(RNBC),
+    igb_getreg(MGTPTC),
+    igb_getreg(TIMINCA),
+    igb_getreg(RXCFGL),
+    igb_getreg(MFUTP01),
+    igb_getreg(FACTPS),
+    igb_getreg(GSCL_1),
+    igb_getreg(GSCN_0),
+    igb_getreg(GCR2),
+    igb_getreg(RDT1),
+    igb_getreg(PBACLR),
+    igb_getreg(FCTTV),
+    igb_getreg(EEWR),
+    igb_getreg(FLSWCTL),
+    igb_getreg(RXDCTL1),
+    igb_getreg(RXSATRL),
+    igb_getreg(SYSTIML),
+    igb_getreg(RXUDP),
+    igb_getreg(TORL),
+    igb_getreg(TDLEN1),
+    igb_getreg(MCC),
+    igb_getreg(WUC),
+    igb_getreg(EECD),
+    igb_getreg(MFUTP23),
+    igb_getreg(RAID),
+    igb_getreg(FCRTV),
+    igb_getreg(TXDCTL1),
+    igb_getreg(RCTL),
+    igb_getreg(TDT),
+    igb_getreg(MDIC),
+    igb_getreg(FCRUC),
+    igb_getreg(VET),
+    igb_getreg(RDBAL0),
+    igb_getreg(TDBAH1),
+    igb_getreg(RDTR),
+    igb_getreg(SCC),
+    igb_getreg(COLC),
+    igb_getreg(CEXTERR),
+    igb_getreg(XOFFRXC),
+    igb_getreg(IPAV),
+    igb_getreg(GOTCL),
+    igb_getreg(MGTPDC),
+    igb_getreg(GCR),
+    igb_getreg(IVAR),
+    igb_getreg(POEMB),
+    igb_getreg(MFVAL),
+    igb_getreg(FUNCTAG),
+    igb_getreg(GSCL_4),
+    igb_getreg(GSCN_3),
+    igb_getreg(MRQC),
+    igb_getreg(RDLEN1),
+    igb_getreg(FCT),
+    igb_getreg(FLA),
+    igb_getreg(FLOL),
+    igb_getreg(RXDCTL),
+    igb_getreg(RXSTMPL),
+    igb_getreg(TXSTMPH),
+    igb_getreg(TIMADJH),
+    igb_getreg(FCRTL),
+    igb_getreg(TDBAH),
+    igb_getreg(TADV),
+    igb_getreg(XONRXC),
+    igb_getreg(TSCTFC),
+    igb_getreg(RFCTL),
+    igb_getreg(GSCN_1),
+    igb_getreg(FCAL),
+    igb_getreg(FLSWCNT),
+
+    [TOTH]    = igb_mac_read_clr8,
+    [GOTCH]   = igb_mac_read_clr8,
+    [PRC64]   = igb_mac_read_clr4,
+    [PRC255]  = igb_mac_read_clr4,
+    [PRC1023] = igb_mac_read_clr4,
+    [PTC64]   = igb_mac_read_clr4,
+    [PTC255]  = igb_mac_read_clr4,
+    [PTC1023] = igb_mac_read_clr4,
+    [GPRC]    = igb_mac_read_clr4,
+    [TPT]     = igb_mac_read_clr4,
+    [RUC]     = igb_mac_read_clr4,
+    [BPRC]    = igb_mac_read_clr4,
+    [MPTC]    = igb_mac_read_clr4,
+    [IAC]     = igb_mac_read_clr4,
+    [ICR]     = igb_mac_icr_read,
+    [STATUS]  = igb_get_status,
+    [TARC0]   = igb_get_tarc,
+    [ICS]     = igb_mac_ics_read,
+    [TORH]    = igb_mac_read_clr8,
+    [GORCH]   = igb_mac_read_clr8,
+    [PRC127]  = igb_mac_read_clr4,
+    [PRC511]  = igb_mac_read_clr4,
+    [PRC1522] = igb_mac_read_clr4,
+    [PTC127]  = igb_mac_read_clr4,
+    [PTC511]  = igb_mac_read_clr4,
+    [PTC1522] = igb_mac_read_clr4,
+    [GPTC]    = igb_mac_read_clr4,
+    [TPR]     = igb_mac_read_clr4,
+    [ROC]     = igb_mac_read_clr4,
+    [MPRC]    = igb_mac_read_clr4,
+    [BPTC]    = igb_mac_read_clr4,
+    [TSCTC]   = igb_mac_read_clr4,
+    [ITR]     = igb_mac_itr_read,
+    [CTRL]    = igb_get_ctrl,
+    [TARC1]   = igb_get_tarc,
+    [SWSM]    = igb_mac_swsm_read,
+    [IMS]     = igb_mac_ims_read,
+
+    [CRCERRS ... MPC]      = igb_mac_readreg,
+    [IP6AT ... IP6AT + 3]  = igb_mac_readreg,
+    [IP4AT ... IP4AT + 6]  = igb_mac_readreg,
+    [RA ... RA + 31]       = igb_mac_readreg,
+    [WUPM ... WUPM + 31]   = igb_mac_readreg,
+    [MTA ... MTA + E1000_MC_TBL_SIZE - 1] = igb_mac_readreg,
+    [VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1]  = igb_mac_readreg,
+    [FFMT ... FFMT + 254]  = igb_mac_readreg,
+    [FFVT ... FFVT + 254]  = igb_mac_readreg,
+    [MDEF ... MDEF + 7]    = igb_mac_readreg,
+    [FFLT ... FFLT + 10]   = igb_mac_readreg,
+    [FTFT ... FTFT + 254]  = igb_mac_readreg,
+    [PBM ... PBM + 10239]  = igb_mac_readreg,
+    [RETA ... RETA + 31]   = igb_mac_readreg,
+    [RSSRK ... RSSRK + 31] = igb_mac_readreg,
+    [MAVTV0 ... MAVTV3]    = igb_mac_readreg,
+    [EITR...EITR + IGB_MSIX_VEC_NUM - 1] = igb_mac_eitr_read
 };
-enum { E1000E_NREADOPS = ARRAY_SIZE(e1000e_macreg_readops) };
-
-#define e1000e_putreg(x)    [x] = e1000e_mac_writereg
-typedef void (*writeops)(E1000ECore *, int, uint32_t);
-static const writeops e1000e_macreg_writeops[] = {
-    e1000e_putreg(PBA),
-    e1000e_putreg(SWSM),
-    e1000e_putreg(WUFC),
-    e1000e_putreg(RDBAH1),
-    e1000e_putreg(TDBAH),
-    e1000e_putreg(TXDCTL),
-    e1000e_putreg(RDBAH0),
-    e1000e_putreg(LEDCTL),
-    e1000e_putreg(FCAL),
-    e1000e_putreg(FCRUC),
-    e1000e_putreg(WUC),
-    e1000e_putreg(WUS),
-    e1000e_putreg(IPAV),
-    e1000e_putreg(TDBAH1),
-    e1000e_putreg(TIMINCA),
-    e1000e_putreg(IAM),
-    e1000e_putreg(EIAC),
-    e1000e_putreg(IVAR),
-    e1000e_putreg(TARC0),
-    e1000e_putreg(TARC1),
-    e1000e_putreg(FLSWDATA),
-    e1000e_putreg(POEMB),
-    e1000e_putreg(MFUTP01),
-    e1000e_putreg(MFUTP23),
-    e1000e_putreg(MANC),
-    e1000e_putreg(MANC2H),
-    e1000e_putreg(MFVAL),
-    e1000e_putreg(EXTCNF_CTRL),
-    e1000e_putreg(FACTPS),
-    e1000e_putreg(FUNCTAG),
-    e1000e_putreg(GSCL_1),
-    e1000e_putreg(GSCL_2),
-    e1000e_putreg(GSCL_3),
-    e1000e_putreg(GSCL_4),
-    e1000e_putreg(GSCN_0),
-    e1000e_putreg(GSCN_1),
-    e1000e_putreg(GSCN_2),
-    e1000e_putreg(GSCN_3),
-    e1000e_putreg(GCR2),
-    e1000e_putreg(MRQC),
-    e1000e_putreg(FLOP),
-    e1000e_putreg(FLOL),
-    e1000e_putreg(FLSWCTL),
-    e1000e_putreg(FLSWCNT),
-    e1000e_putreg(FLA),
-    e1000e_putreg(RXDCTL1),
-    e1000e_putreg(TXDCTL1),
-    e1000e_putreg(TIPG),
-    e1000e_putreg(RXSTMPH),
-    e1000e_putreg(RXSTMPL),
-    e1000e_putreg(RXSATRL),
-    e1000e_putreg(RXSATRH),
-    e1000e_putreg(TXSTMPL),
-    e1000e_putreg(TXSTMPH),
-    e1000e_putreg(SYSTIML),
-    e1000e_putreg(SYSTIMH),
-    e1000e_putreg(TIMADJL),
-    e1000e_putreg(TIMADJH),
-    e1000e_putreg(RXUDP),
-    e1000e_putreg(RXCFGL),
-    e1000e_putreg(TSYNCRXCTL),
-    e1000e_putreg(TSYNCTXCTL),
-    e1000e_putreg(EXTCNF_SIZE),
-    e1000e_putreg(EEMNGCTL),
-    e1000e_putreg(RA),
-
-    [TDH1]     = e1000e_set_16bit,
-    [TDT1]     = e1000e_set_tdt,
-    [TCTL]     = e1000e_set_tctl,
-    [TDT]      = e1000e_set_tdt,
-    [MDIC]     = e1000e_set_mdic,
-    [ICS]      = e1000e_set_ics,
-    [TDH]      = e1000e_set_16bit,
-    [RDH0]     = e1000e_set_16bit,
-    [RDT0]     = e1000e_set_rdt,
-    [IMC]      = e1000e_set_imc,
-    [IMS]      = e1000e_set_ims,
-    [ICR]      = e1000e_set_icr,
-    [EECD]     = e1000e_set_eecd,
-    [RCTL]     = e1000e_set_rx_control,
-    [CTRL]     = e1000e_set_ctrl,
-    [RDTR]     = e1000e_set_rdtr,
-    [RADV]     = e1000e_set_16bit,
-    [TADV]     = e1000e_set_16bit,
-    [ITR]      = e1000e_set_itr,
-    [EERD]     = e1000e_set_eerd,
-    [AIT]      = e1000e_set_16bit,
-    [TDFH]     = e1000e_set_13bit,
-    [TDFT]     = e1000e_set_13bit,
-    [TDFHS]    = e1000e_set_13bit,
-    [TDFTS]    = e1000e_set_13bit,
-    [TDFPC]    = e1000e_set_13bit,
-    [RDFH]     = e1000e_set_13bit,
-    [RDFHS]    = e1000e_set_13bit,
-    [RDFT]     = e1000e_set_13bit,
-    [RDFTS]    = e1000e_set_13bit,
-    [RDFPC]    = e1000e_set_13bit,
-    [PBS]      = e1000e_set_6bit,
-    [GCR]      = e1000e_set_gcr,
-    [PSRCTL]   = e1000e_set_psrctl,
-    [RXCSUM]   = e1000e_set_rxcsum,
-    [RAID]     = e1000e_set_16bit,
-    [RSRPD]    = e1000e_set_12bit,
-    [TIDV]     = e1000e_set_tidv,
-    [TDLEN1]   = e1000e_set_dlen,
-    [TDLEN]    = e1000e_set_dlen,
-    [RDLEN0]   = e1000e_set_dlen,
-    [RDLEN1]   = e1000e_set_dlen,
-    [TDBAL]    = e1000e_set_dbal,
-    [TDBAL1]   = e1000e_set_dbal,
-    [RDBAL0]   = e1000e_set_dbal,
-    [RDBAL1]   = e1000e_set_dbal,
-    [RDH1]     = e1000e_set_16bit,
-    [RDT1]     = e1000e_set_rdt,
-    [STATUS]   = e1000e_set_status,
-    [PBACLR]   = e1000e_set_pbaclr,
-    [CTRL_EXT] = e1000e_set_ctrlext,
-    [FCAH]     = e1000e_set_16bit,
-    [FCT]      = e1000e_set_16bit,
-    [FCTTV]    = e1000e_set_16bit,
-    [FCRTV]    = e1000e_set_16bit,
-    [FCRTH]    = e1000e_set_fcrth,
-    [FCRTL]    = e1000e_set_fcrtl,
-    [VET]      = e1000e_set_vet,
-    [RXDCTL]   = e1000e_set_rxdctl,
-    [FLASHT]   = e1000e_set_16bit,
-    [EEWR]     = e1000e_set_eewr,
-    [CTRL_DUP] = e1000e_set_ctrl,
-    [RFCTL]    = e1000e_set_rfctl,
-    [RA + 1]   = e1000e_mac_setmacaddr,
-
-    [IP6AT ... IP6AT + 3]    = e1000e_mac_writereg,
-    [IP4AT ... IP4AT + 6]    = e1000e_mac_writereg,
-    [RA + 2 ... RA + 31]     = e1000e_mac_writereg,
-    [WUPM ... WUPM + 31]     = e1000e_mac_writereg,
-    [MTA ... MTA + E1000_MC_TBL_SIZE - 1] = e1000e_mac_writereg,
-    [VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1]    = e1000e_mac_writereg,
-    [FFMT ... FFMT + 254]    = e1000e_set_4bit,
-    [FFVT ... FFVT + 254]    = e1000e_mac_writereg,
-    [PBM ... PBM + 10239]    = e1000e_mac_writereg,
-    [MDEF ... MDEF + 7]      = e1000e_mac_writereg,
-    [FFLT ... FFLT + 10]     = e1000e_set_11bit,
-    [FTFT ... FTFT + 254]    = e1000e_mac_writereg,
-    [RETA ... RETA + 31]     = e1000e_mac_writereg,
-    [RSSRK ... RSSRK + 31]   = e1000e_mac_writereg,
-    [MAVTV0 ... MAVTV3]      = e1000e_mac_writereg,
-    [EITR...EITR + E1000E_MSIX_VEC_NUM - 1] = e1000e_set_eitr
+enum { IGB_NREADOPS = ARRAY_SIZE(igb_macreg_readops) };
+
+#define igb_putreg(x)    [x] = igb_mac_writereg
+typedef void (*writeops)(IGBCore *, int, uint32_t);
+static const writeops igb_macreg_writeops[] = {
+    igb_putreg(PBA),
+    igb_putreg(SWSM),
+    igb_putreg(WUFC),
+    igb_putreg(RDBAH1),
+    igb_putreg(TDBAH),
+    igb_putreg(TXDCTL),
+    igb_putreg(RDBAH0),
+    igb_putreg(LEDCTL),
+    igb_putreg(FCAL),
+    igb_putreg(FCRUC),
+    igb_putreg(WUC),
+    igb_putreg(WUS),
+    igb_putreg(IPAV),
+    igb_putreg(TDBAH1),
+    igb_putreg(TIMINCA),
+    igb_putreg(IAM),
+    igb_putreg(EIAC),
+    igb_putreg(IVAR),
+    igb_putreg(TARC0),
+    igb_putreg(TARC1),
+    igb_putreg(FLSWDATA),
+    igb_putreg(POEMB),
+    igb_putreg(MFUTP01),
+    igb_putreg(MFUTP23),
+    igb_putreg(MANC),
+    igb_putreg(MANC2H),
+    igb_putreg(MFVAL),
+    igb_putreg(EXTCNF_CTRL),
+    igb_putreg(FACTPS),
+    igb_putreg(FUNCTAG),
+    igb_putreg(GSCL_1),
+    igb_putreg(GSCL_2),
+    igb_putreg(GSCL_3),
+    igb_putreg(GSCL_4),
+    igb_putreg(GSCN_0),
+    igb_putreg(GSCN_1),
+    igb_putreg(GSCN_2),
+    igb_putreg(GSCN_3),
+    igb_putreg(GCR2),
+    igb_putreg(MRQC),
+    igb_putreg(FLOP),
+    igb_putreg(FLOL),
+    igb_putreg(FLSWCTL),
+    igb_putreg(FLSWCNT),
+    igb_putreg(FLA),
+    igb_putreg(RXDCTL1),
+    igb_putreg(TXDCTL1),
+    igb_putreg(TIPG),
+    igb_putreg(RXSTMPH),
+    igb_putreg(RXSTMPL),
+    igb_putreg(RXSATRL),
+    igb_putreg(RXSATRH),
+    igb_putreg(TXSTMPL),
+    igb_putreg(TXSTMPH),
+    igb_putreg(SYSTIML),
+    igb_putreg(SYSTIMH),
+    igb_putreg(TIMADJL),
+    igb_putreg(TIMADJH),
+    igb_putreg(RXUDP),
+    igb_putreg(RXCFGL),
+    igb_putreg(TSYNCRXCTL),
+    igb_putreg(TSYNCTXCTL),
+    igb_putreg(EXTCNF_SIZE),
+    igb_putreg(EEMNGCTL),
+    igb_putreg(RA),
+
+    [TDH1]     = igb_set_16bit,
+    [TDT1]     = igb_set_tdt,
+    [TCTL]     = igb_set_tctl,
+    [TDT]      = igb_set_tdt,
+    [MDIC]     = igb_set_mdic,
+    [ICS]      = igb_set_ics,
+    [TDH]      = igb_set_16bit,
+    [RDH0]     = igb_set_16bit,
+    [RDT0]     = igb_set_rdt,
+    [IMC]      = igb_set_imc,
+    [IMS]      = igb_set_ims,
+    [ICR]      = igb_set_icr,
+    [EECD]     = igb_set_eecd,
+    [RCTL]     = igb_set_rx_control,
+    [CTRL]     = igb_set_ctrl,
+    [RDTR]     = igb_set_rdtr,
+    [RADV]     = igb_set_16bit,
+    [TADV]     = igb_set_16bit,
+    [ITR]      = igb_set_itr,
+    [EERD]     = igb_set_eerd,
+    [AIT]      = igb_set_16bit,
+    [TDFH]     = igb_set_13bit,
+    [TDFT]     = igb_set_13bit,
+    [TDFHS]    = igb_set_13bit,
+    [TDFTS]    = igb_set_13bit,
+    [TDFPC]    = igb_set_13bit,
+    [RDFH]     = igb_set_13bit,
+    [RDFHS]    = igb_set_13bit,
+    [RDFT]     = igb_set_13bit,
+    [RDFTS]    = igb_set_13bit,
+    [RDFPC]    = igb_set_13bit,
+    [PBS]      = igb_set_6bit,
+    [GCR]      = igb_set_gcr,
+    [PSRCTL]   = igb_set_psrctl,
+    [RXCSUM]   = igb_set_rxcsum,
+    [RAID]     = igb_set_16bit,
+    [RSRPD]    = igb_set_12bit,
+    [TIDV]     = igb_set_tidv,
+    [TDLEN1]   = igb_set_dlen,
+    [TDLEN]    = igb_set_dlen,
+    [RDLEN0]   = igb_set_dlen,
+    [RDLEN1]   = igb_set_dlen,
+    [TDBAL]    = igb_set_dbal,
+    [TDBAL1]   = igb_set_dbal,
+    [RDBAL0]   = igb_set_dbal,
+    [RDBAL1]   = igb_set_dbal,
+    [RDH1]     = igb_set_16bit,
+    [RDT1]     = igb_set_rdt,
+    [STATUS]   = igb_set_status,
+    [PBACLR]   = igb_set_pbaclr,
+    [CTRL_EXT] = igb_set_ctrlext,
+    [FCAH]     = igb_set_16bit,
+    [FCT]      = igb_set_16bit,
+    [FCTTV]    = igb_set_16bit,
+    [FCRTV]    = igb_set_16bit,
+    [FCRTH]    = igb_set_fcrth,
+    [FCRTL]    = igb_set_fcrtl,
+    [VET]      = igb_set_vet,
+    [RXDCTL]   = igb_set_rxdctl,
+    [FLASHT]   = igb_set_16bit,
+    [EEWR]     = igb_set_eewr,
+    [CTRL_DUP] = igb_set_ctrl,
+    [RFCTL]    = igb_set_rfctl,
+    [RA + 1]   = igb_mac_setmacaddr,
+
+    [IP6AT ... IP6AT + 3]    = igb_mac_writereg,
+    [IP4AT ... IP4AT + 6]    = igb_mac_writereg,
+    [RA + 2 ... RA + 31]     = igb_mac_writereg,
+    [WUPM ... WUPM + 31]     = igb_mac_writereg,
+    [MTA ... MTA + E1000_MC_TBL_SIZE - 1] = igb_mac_writereg,
+    [VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1]    = igb_mac_writereg,
+    [FFMT ... FFMT + 254]    = igb_set_4bit,
+    [FFVT ... FFVT + 254]    = igb_mac_writereg,
+    [PBM ... PBM + 10239]    = igb_mac_writereg,
+    [MDEF ... MDEF + 7]      = igb_mac_writereg,
+    [FFLT ... FFLT + 10]     = igb_set_11bit,
+    [FTFT ... FTFT + 254]    = igb_mac_writereg,
+    [RETA ... RETA + 31]     = igb_mac_writereg,
+    [RSSRK ... RSSRK + 31]   = igb_mac_writereg,
+    [MAVTV0 ... MAVTV3]      = igb_mac_writereg,
+    [EITR...EITR + IGB_MSIX_VEC_NUM - 1] = igb_set_eitr
 };
-enum { E1000E_NWRITEOPS = ARRAY_SIZE(e1000e_macreg_writeops) };
+enum { IGB_NWRITEOPS = ARRAY_SIZE(igb_macreg_writeops) };
 
 enum { MAC_ACCESS_PARTIAL = 1 };
 
@@ -3283,17 +3272,17 @@ static const uint16_t mac_reg_access[E1000E_MAC_SIZE] = {
 };
 
 void
-e1000e_core_write(E1000ECore *core, hwaddr addr, uint64_t val, unsigned size)
+igb_core_write(IGBCore *core, hwaddr addr, uint64_t val, unsigned size)
 {
-    uint16_t index = e1000e_get_reg_index_with_offset(mac_reg_access, addr);
+    uint16_t index = igb_get_reg_index_with_offset(mac_reg_access, addr);
 
-    if (index < E1000E_NWRITEOPS && e1000e_macreg_writeops[index]) {
+    if (index < IGB_NWRITEOPS && igb_macreg_writeops[index]) {
         if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) {
             trace_e1000e_wrn_regs_write_trivial(index << 2);
         }
         trace_e1000e_core_write(index << 2, size, val);
-        e1000e_macreg_writeops[index](core, index, val);
-    } else if (index < E1000E_NREADOPS && e1000e_macreg_readops[index]) {
+        igb_macreg_writeops[index](core, index, val);
+    } else if (index < IGB_NREADOPS && igb_macreg_readops[index]) {
         trace_e1000e_wrn_regs_write_ro(index << 2, size, val);
     } else {
         trace_e1000e_wrn_regs_write_unknown(index << 2, size, val);
@@ -3301,16 +3290,16 @@ e1000e_core_write(E1000ECore *core, hwaddr addr, uint64_t val, unsigned size)
 }
 
 uint64_t
-e1000e_core_read(E1000ECore *core, hwaddr addr, unsigned size)
+igb_core_read(IGBCore *core, hwaddr addr, unsigned size)
 {
     uint64_t val;
-    uint16_t index = e1000e_get_reg_index_with_offset(mac_reg_access, addr);
+    uint16_t index = igb_get_reg_index_with_offset(mac_reg_access, addr);
 
-    if (index < E1000E_NREADOPS && e1000e_macreg_readops[index]) {
+    if (index < IGB_NREADOPS && igb_macreg_readops[index]) {
         if (mac_reg_access[index] & MAC_ACCESS_PARTIAL) {
             trace_e1000e_wrn_regs_read_trivial(index << 2);
         }
-        val = e1000e_macreg_readops[index](core, index);
+        val = igb_macreg_readops[index](core, index);
         trace_e1000e_core_read(index << 2, size, val);
         return val;
     } else {
@@ -3320,15 +3309,15 @@ e1000e_core_read(E1000ECore *core, hwaddr addr, unsigned size)
 }
 
 static inline void
-e1000e_autoneg_pause(E1000ECore *core)
+igb_autoneg_pause(IGBCore *core)
 {
     timer_del(core->autoneg_timer);
 }
 
 static void
-e1000e_autoneg_resume(E1000ECore *core)
+igb_autoneg_resume(IGBCore *core)
 {
-    if (e1000e_have_autoneg(core) &&
+    if (igb_have_autoneg(core) &&
         !(core->phy[0][MII_BMSR] & MII_BMSR_AN_COMP)) {
         qemu_get_queue(core->owner_nic)->link_down = false;
         timer_mod(core->autoneg_timer,
@@ -3337,37 +3326,36 @@ e1000e_autoneg_resume(E1000ECore *core)
 }
 
 static void
-e1000e_vm_state_change(void *opaque, bool running, RunState state)
+igb_vm_state_change(void *opaque, bool running, RunState state)
 {
-    E1000ECore *core = opaque;
+    IGBCore *core = opaque;
 
     if (running) {
         trace_e1000e_vm_state_running();
-        e1000e_intrmgr_resume(core);
-        e1000e_autoneg_resume(core);
+        igb_intrmgr_resume(core);
+        igb_autoneg_resume(core);
     } else {
         trace_e1000e_vm_state_stopped();
-        e1000e_autoneg_pause(core);
-        e1000e_intrmgr_pause(core);
+        igb_autoneg_pause(core);
+        igb_intrmgr_pause(core);
     }
 }
 
 void
-e1000e_core_pci_realize(E1000ECore     *core,
-                        const uint16_t *eeprom_templ,
-                        uint32_t        eeprom_size,
-                        const uint8_t  *macaddr)
+igb_core_pci_realize(IGBCore        *core,
+                     const uint16_t *eeprom_templ,
+                     uint32_t        eeprom_size,
+                     const uint8_t  *macaddr)
 {
     int i;
 
     core->autoneg_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
-                                       e1000e_autoneg_timer, core);
-    e1000e_intrmgr_pci_realize(core);
+                                       igb_autoneg_timer, core);
+    igb_intrmgr_pci_realize(core);
 
-    core->vmstate =
-        qemu_add_vm_change_state_handler(e1000e_vm_state_change, core);
+    core->vmstate = qemu_add_vm_change_state_handler(igb_vm_state_change, core);
 
-    for (i = 0; i < E1000E_NUM_QUEUES; i++) {
+    for (i = 0; i < IGB_NUM_QUEUES; i++) {
         net_tx_pkt_init(&core->tx[i].tx_pkt, core->owner,
                         E1000E_MAX_TX_FRAGS, core->has_vnet);
     }
@@ -3379,21 +3367,21 @@ e1000e_core_pci_realize(E1000ECore     *core,
                                eeprom_size,
                                PCI_DEVICE_GET_CLASS(core->owner)->device_id,
                                macaddr);
-    e1000e_update_rx_offloads(core);
+    igb_update_rx_offloads(core);
 }
 
 void
-e1000e_core_pci_uninit(E1000ECore *core)
+igb_core_pci_uninit(IGBCore *core)
 {
     int i;
 
     timer_free(core->autoneg_timer);
 
-    e1000e_intrmgr_pci_unint(core);
+    igb_intrmgr_pci_unint(core);
 
     qemu_del_vm_change_state_handler(core->vmstate);
 
-    for (i = 0; i < E1000E_NUM_QUEUES; i++) {
+    for (i = 0; i < IGB_NUM_QUEUES; i++) {
         net_tx_pkt_reset(core->tx[i].tx_pkt);
         net_tx_pkt_uninit(core->tx[i].tx_pkt);
     }
@@ -3402,7 +3390,7 @@ e1000e_core_pci_uninit(E1000ECore *core)
 }
 
 static const uint16_t
-e1000e_phy_reg_init[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE] = {
+igb_phy_reg_init[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE] = {
     [0] = {
         [MII_BMCR] = MII_BMCR_SPEED1000 |
                      MII_BMCR_FD        |
@@ -3448,7 +3436,7 @@ e1000e_phy_reg_init[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE] = {
     }
 };
 
-static const uint32_t e1000e_mac_reg_init[] = {
+static const uint32_t igb_mac_reg_init[] = {
     [PBA]           =     0x00140014,
     [LEDCTL]        =  BIT(1) | BIT(8) | BIT(9) | BIT(15) | BIT(17) | BIT(18),
     [EXTCNF_CTRL]   = BIT(3),
@@ -3487,33 +3475,33 @@ static const uint32_t e1000e_mac_reg_init[] = {
     [SWSM]          = 1,
     [RXCSUM]        = E1000_RXCSUM_IPOFLD | E1000_RXCSUM_TUOFLD,
     [ITR]           = E1000E_MIN_XITR,
-    [EITR...EITR + E1000E_MSIX_VEC_NUM - 1] = E1000E_MIN_XITR,
+    [EITR...EITR + IGB_MSIX_VEC_NUM - 1] = E1000E_MIN_XITR,
 };
 
-static void e1000e_reset(E1000ECore *core, bool sw)
+static void igb_reset(IGBCore *core, bool sw)
 {
     int i;
 
     timer_del(core->autoneg_timer);
 
-    e1000e_intrmgr_reset(core);
+    igb_intrmgr_reset(core);
 
     memset(core->phy, 0, sizeof core->phy);
-    memcpy(core->phy, e1000e_phy_reg_init, sizeof e1000e_phy_reg_init);
+    memcpy(core->phy, igb_phy_reg_init, sizeof igb_phy_reg_init);
 
     for (i = 0; i < E1000E_MAC_SIZE; i++) {
         if (sw && (i == PBA || i == PBS || i == FLA)) {
             continue;
         }
 
-        core->mac[i] = i < ARRAY_SIZE(e1000e_mac_reg_init) ?
-                       e1000e_mac_reg_init[i] : 0;
+        core->mac[i] = i < ARRAY_SIZE(igb_mac_reg_init) ?
+                       igb_mac_reg_init[i] : 0;
     }
 
     core->rxbuf_min_shift = 1 + E1000_RING_DESC_LEN_SHIFT;
 
     if (qemu_get_queue(core->owner_nic)->link_down) {
-        e1000e_link_down(core);
+        igb_link_down(core);
     }
 
     e1000x_reset_mac_addr(core->owner_nic, core->mac, core->permanent_mac);
@@ -3526,12 +3514,12 @@ static void e1000e_reset(E1000ECore *core, bool sw)
 }
 
 void
-e1000e_core_reset(E1000ECore *core)
+igb_core_reset(IGBCore *core)
 {
-    e1000e_reset(core, false);
+    igb_reset(core, false);
 }
 
-void e1000e_core_pre_save(E1000ECore *core)
+void igb_core_pre_save(IGBCore *core)
 {
     int i;
     NetClientState *nc = qemu_get_queue(core->owner_nic);
@@ -3541,9 +3529,9 @@ void e1000e_core_pre_save(E1000ECore *core)
      * complete auto-negotiation immediately. This allows us to look
      * at MII_BMSR_AN_COMP to infer link status on load.
      */
-    if (nc->link_down && e1000e_have_autoneg(core)) {
+    if (nc->link_down && igb_have_autoneg(core)) {
         core->phy[0][MII_BMSR] |= MII_BMSR_AN_COMP;
-        e1000e_update_flowctl_status(core);
+        igb_update_flowctl_status(core);
     }
 
     for (i = 0; i < ARRAY_SIZE(core->tx); i++) {
@@ -3554,7 +3542,7 @@ void e1000e_core_pre_save(E1000ECore *core)
 }
 
 int
-e1000e_core_post_load(E1000ECore *core)
+igb_core_post_load(IGBCore *core)
 {
     NetClientState *nc = qemu_get_queue(core->owner_nic);
 
diff --git a/hw/net/igb_core.h b/hw/net/igb_core.h
index d0a14b4523..4f70e45cb1 100644
--- a/hw/net/igb_core.h
+++ b/hw/net/igb_core.h
@@ -1,5 +1,5 @@
 /*
- * Core code for QEMU e1000e emulation
+ * Core code for QEMU igb emulation
  *
  * Software developer's manuals:
  * http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
@@ -33,35 +33,35 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef HW_NET_E1000E_CORE_H
-#define HW_NET_E1000E_CORE_H
+#ifndef HW_NET_IGB_CORE_H
+#define HW_NET_IGB_CORE_H
 
 #define E1000E_PHY_PAGE_SIZE    (0x20)
 #define E1000E_PHY_PAGES        (0x07)
 #define E1000E_MAC_SIZE         (0x8000)
-#define E1000E_EEPROM_SIZE      (64)
-#define E1000E_MSIX_VEC_NUM     (5)
-#define E1000E_NUM_QUEUES       (2)
+#define IGB_EEPROM_SIZE         (64)
+#define IGB_MSIX_VEC_NUM        (5)
+#define IGB_NUM_QUEUES          (2)
 
-typedef struct E1000Core E1000ECore;
+typedef struct IGBCore IGBCore;
 
 enum { PHY_R = BIT(0),
        PHY_W = BIT(1),
        PHY_RW = PHY_R | PHY_W,
        PHY_ANYPAGE = BIT(2) };
 
-typedef struct E1000IntrDelayTimer_st {
+typedef struct IGBIntrDelayTimer_st {
     QEMUTimer *timer;
     bool running;
     uint32_t delay_reg;
     uint32_t delay_resolution_ns;
-    E1000ECore *core;
-} E1000IntrDelayTimer;
+    IGBCore *core;
+} IGBIntrDelayTimer;
 
-struct E1000Core {
+struct IGBCore {
     uint32_t mac[E1000E_MAC_SIZE];
     uint16_t phy[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE];
-    uint16_t eeprom[E1000E_EEPROM_SIZE];
+    uint16_t eeprom[IGB_EEPROM_SIZE];
 
     uint32_t rxbuf_sizes[E1000_PSRCTL_BUFFS_PER_DESC];
     uint32_t rx_desc_buf_size;
@@ -70,14 +70,14 @@ struct E1000Core {
 
     QEMUTimer *autoneg_timer;
 
-    struct e1000e_tx {
+    struct igb_tx {
         e1000x_txd_props props;
 
         bool skip_cp;
         unsigned char sum_needed;
         bool cptse;
         struct NetTxPkt *tx_pkt;
-    } tx[E1000E_NUM_QUEUES];
+    } tx[IGB_NUM_QUEUES];
 
     struct NetRxPkt *rx_pkt;
 
@@ -87,21 +87,21 @@ struct E1000Core {
     /* Interrupt moderation management */
     uint32_t delayed_causes;
 
-    E1000IntrDelayTimer radv;
-    E1000IntrDelayTimer rdtr;
-    E1000IntrDelayTimer raid;
+    IGBIntrDelayTimer radv;
+    IGBIntrDelayTimer rdtr;
+    IGBIntrDelayTimer raid;
 
-    E1000IntrDelayTimer tadv;
-    E1000IntrDelayTimer tidv;
+    IGBIntrDelayTimer tadv;
+    IGBIntrDelayTimer tidv;
 
-    E1000IntrDelayTimer itr;
+    IGBIntrDelayTimer itr;
 
-    E1000IntrDelayTimer eitr[E1000E_MSIX_VEC_NUM];
+    IGBIntrDelayTimer eitr[IGB_MSIX_VEC_NUM];
 
     VMChangeStateEntry *vmstate;
 
     uint32_t itr_guest_value;
-    uint32_t eitr_guest_value[E1000E_MSIX_VEC_NUM];
+    uint32_t eitr_guest_value[IGB_MSIX_VEC_NUM];
 
     uint16_t vet;
 
@@ -115,42 +115,42 @@ struct E1000Core {
 };
 
 void
-e1000e_core_write(E1000ECore *core, hwaddr addr, uint64_t val, unsigned size);
+igb_core_write(IGBCore *core, hwaddr addr, uint64_t val, unsigned size);
 
 uint64_t
-e1000e_core_read(E1000ECore *core, hwaddr addr, unsigned size);
+igb_core_read(IGBCore *core, hwaddr addr, unsigned size);
 
 void
-e1000e_core_pci_realize(E1000ECore      *regs,
-                       const uint16_t *eeprom_templ,
-                       uint32_t        eeprom_size,
-                       const uint8_t  *macaddr);
+igb_core_pci_realize(IGBCore        *regs,
+                     const uint16_t *eeprom_templ,
+                     uint32_t        eeprom_size,
+                     const uint8_t  *macaddr);
 
 void
-e1000e_core_reset(E1000ECore *core);
+igb_core_reset(IGBCore *core);
 
 void
-e1000e_core_pre_save(E1000ECore *core);
+igb_core_pre_save(IGBCore *core);
 
 int
-e1000e_core_post_load(E1000ECore *core);
+igb_core_post_load(IGBCore *core);
 
 void
-e1000e_core_set_link_status(E1000ECore *core);
+igb_core_set_link_status(IGBCore *core);
 
 void
-e1000e_core_pci_uninit(E1000ECore *core);
+igb_core_pci_uninit(IGBCore *core);
 
 bool
-e1000e_can_receive(E1000ECore *core);
+igb_can_receive(IGBCore *core);
 
 ssize_t
-e1000e_receive(E1000ECore *core, const uint8_t *buf, size_t size);
+igb_receive(IGBCore *core, const uint8_t *buf, size_t size);
 
 ssize_t
-e1000e_receive_iov(E1000ECore *core, const struct iovec *iov, int iovcnt);
+igb_receive_iov(IGBCore *core, const struct iovec *iov, int iovcnt);
 
 void
-e1000e_start_recv(E1000ECore *core);
+igb_start_recv(IGBCore *core);
 
 #endif
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 06/13] igb: Build igb
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
                   ` (4 preceding siblings ...)
  2023-01-14  4:09 ` [PATCH v2 05/13] igb: Rename identifiers Akihiko Odaki
@ 2023-01-14  4:09 ` Akihiko Odaki
  2023-01-14  4:09 ` [PATCH v2 07/13] igb: Transform to 82576 implementation Akihiko Odaki
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:09 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich, Gal Hammer

Currently igb functions identically with e1000e.

Signed-off-by: Gal Hammer <gal.hammer@sap.com>
Signed-off-by: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/net/Kconfig     | 5 +++++
 hw/net/meson.build | 2 ++
 2 files changed, 7 insertions(+)

diff --git a/hw/net/Kconfig b/hw/net/Kconfig
index 1cc1c5775e..18c7851efe 100644
--- a/hw/net/Kconfig
+++ b/hw/net/Kconfig
@@ -44,6 +44,11 @@ config E1000E_PCI_EXPRESS
     default y if PCI_DEVICES
     depends on PCI_EXPRESS && MSI_NONBROKEN
 
+config IGB_PCI_EXPRESS
+    bool
+    default y if PCI_DEVICES
+    depends on PCI_EXPRESS && MSI_NONBROKEN
+
 config RTL8139_PCI
     bool
     default y if PCI_DEVICES
diff --git a/hw/net/meson.build b/hw/net/meson.build
index ebac261542..4974ad6bd2 100644
--- a/hw/net/meson.build
+++ b/hw/net/meson.build
@@ -10,6 +10,8 @@ softmmu_ss.add(when: 'CONFIG_PCNET_COMMON', if_true: files('pcnet.c'))
 softmmu_ss.add(when: 'CONFIG_E1000_PCI', if_true: files('e1000.c', 'e1000x_common.c'))
 softmmu_ss.add(when: 'CONFIG_E1000E_PCI_EXPRESS', if_true: files('net_tx_pkt.c', 'net_rx_pkt.c'))
 softmmu_ss.add(when: 'CONFIG_E1000E_PCI_EXPRESS', if_true: files('e1000e.c', 'e1000e_core.c', 'e1000x_common.c'))
+softmmu_ss.add(when: 'CONFIG_IGB_PCI_EXPRESS', if_true: files('net_tx_pkt.c', 'net_rx_pkt.c'))
+softmmu_ss.add(when: 'CONFIG_IGB_PCI_EXPRESS', if_true: files('igb.c', 'igb_core.c'))
 softmmu_ss.add(when: 'CONFIG_RTL8139_PCI', if_true: files('rtl8139.c'))
 softmmu_ss.add(when: 'CONFIG_TULIP', if_true: files('tulip.c'))
 softmmu_ss.add(when: 'CONFIG_VMXNET3_PCI', if_true: files('net_tx_pkt.c', 'net_rx_pkt.c'))
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 07/13] igb: Transform to 82576 implementation
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
                   ` (5 preceding siblings ...)
  2023-01-14  4:09 ` [PATCH v2 06/13] igb: Build igb Akihiko Odaki
@ 2023-01-14  4:09 ` Akihiko Odaki
  2023-01-14  4:09 ` [PATCH v2 08/13] tests/qtest/e1000e-test: Fabricate ethernet header Akihiko Odaki
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:09 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich, Gal Hammer

This is the change that transforms e1000e implementation to the real
igb implementation.

Signed-off-by: Gal Hammer <gal.hammer@sap.com>
Signed-off-by: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 hw/net/igb.c        |  298 ++--
 hw/net/igb_common.h |  114 +-
 hw/net/igb_core.c   | 3176 ++++++++++++++++++++++++-------------------
 hw/net/igb_core.h   |   55 +-
 hw/net/igb_regs.h   |  624 +++++++++
 hw/net/igbvf.c      |  327 +++++
 hw/net/meson.build  |    2 +-
 hw/net/trace-events |   32 +
 8 files changed, 2964 insertions(+), 1664 deletions(-)
 create mode 100644 hw/net/igb_regs.h
 create mode 100644 hw/net/igbvf.c

diff --git a/hw/net/igb.c b/hw/net/igb.c
index edecd9c449..dabfa6a1c4 100644
--- a/hw/net/igb.c
+++ b/hw/net/igb.c
@@ -1,13 +1,17 @@
 /*
- * QEMU INTEL 82574 GbE NIC emulation
+ * QEMU Intel 82576 SR/IOV Ethernet Controller Emulation
  *
- * Software developer's manuals:
- * http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
+ * Datasheet:
+ * https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eg-gbe-datasheet.pdf
  *
+ * Copyright (c) 2020-2023 Red Hat, Inc.
  * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
  * Developed by Daynix Computing LTD (http://www.daynix.com)
  *
  * Authors:
+ * Akihiko Odaki <akihiko.odaki@daynix.com>
+ * Gal Hammmer <gal.hammer@sap.com>
+ * Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
  * Dmitry Fleytman <dmitry@daynix.com>
  * Leonid Bloch <leonid@daynix.com>
  * Yan Vugenfirer <yan@daynix.com>
@@ -43,13 +47,15 @@
 #include "sysemu/sysemu.h"
 #include "hw/hw.h"
 #include "hw/net/mii.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pcie.h"
+#include "hw/pci/pcie_sriov.h"
 #include "hw/pci/msi.h"
 #include "hw/pci/msix.h"
 #include "hw/qdev-properties.h"
 #include "migration/vmstate.h"
 
 #include "igb_common.h"
-#include "e1000x_common.h"
 #include "igb_core.h"
 
 #include "trace.h"
@@ -71,18 +77,15 @@ struct IGBState {
 
     uint32_t ioaddr;
 
-    uint16_t subsys_ven;
-    uint16_t subsys;
-
-    uint16_t subsys_ven_used;
-    uint16_t subsys_used;
-
-    bool disable_vnet;
-
     IGBCore core;
-    bool init_vet;
 };
 
+#define IGB_MSIX_VECTORS    (10)
+
+#define IGB_CAP_SRIOV_OFFSET    (0x160)
+#define IGB_VF_OFFSET           (0x80)
+#define IGB_VF_STRIDE           (2)
+
 #define E1000E_MMIO_IDX     0
 #define E1000E_FLASH_IDX    1
 #define E1000E_IO_IDX       2
@@ -93,17 +96,28 @@ struct IGBState {
 #define E1000E_IO_SIZE      (32)
 #define E1000E_MSIX_SIZE    (16 * KiB)
 
-#define E1000E_MSIX_TABLE   (0x0000)
-#define E1000E_MSIX_PBA     (0x2000)
+static void igb_write_config(PCIDevice *dev, uint32_t addr,
+    uint32_t val, int len)
+{
+    IGBState *s = IGB(dev);
+
+    trace_igb_write_config(addr, val, len);
+    pci_default_write_config(dev, addr, val, len);
 
-static uint64_t
+    if (range_covers_byte(addr, len, PCI_COMMAND) &&
+        (dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
+        igb_start_recv(&s->core);
+    }
+}
+
+uint64_t
 igb_mmio_read(void *opaque, hwaddr addr, unsigned size)
 {
     IGBState *s = opaque;
     return igb_core_read(&s->core, addr, size);
 }
 
-static void
+void
 igb_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
 {
     IGBState *s = opaque;
@@ -237,26 +251,28 @@ static NetClientInfo net_igb_info = {
 };
 
 /*
- * EEPROM (NVM) contents documented in Table 36, section 6.1
- * and generally 6.1.2 Software accessed words.
+ * EEPROM (NVM) contents documented in section 6.1, table 6-1:
+ * and in 6.10 Software accessed words.
  */
-static const uint16_t igb_eeprom_template[64] = {
-  /*        Address        |    Compat.    | ImVer |   Compat.     */
-    0x0000, 0x0000, 0x0000, 0x0420, 0xf746, 0x2010, 0xffff, 0xffff,
+static const uint16_t igb_eeprom_template[] = {
+  /*        Address        |Compat.|OEM sp.| ImRev |    OEM sp.    */
+    0x0000, 0x0000, 0x0000, 0x0d34, 0xffff, 0x2010, 0xffff, 0xffff,
   /*      PBA      |ICtrl1 | SSID  | SVID  | DevID |-------|ICtrl2 */
-    0x0000, 0x0000, 0x026b, 0x0000, 0x8086, 0x0000, 0x0000, 0x8058,
-  /*    NVM words 1,2,3    |-------------------------------|PCI-EID*/
-    0x0000, 0x2001, 0x7e7c, 0xffff, 0x1000, 0x00c8, 0x0000, 0x2704,
-  /* PCIe Init. Conf 1,2,3 |PCICtrl|PHY|LD1|-------| RevID | LD0,2 */
-    0x6cc9, 0x3150, 0x070e, 0x460b, 0x2d84, 0x0100, 0xf000, 0x0706,
-  /* FLPAR |FLANADD|LAN-PWR|FlVndr |ICtrl3 |APTSMBA|APTRxEP|APTSMBC*/
-    0x6000, 0x0080, 0x0f04, 0x7fff, 0x4f01, 0xc600, 0x0000, 0x20ff,
-  /* APTIF | APTMC |APTuCP |LSWFWID|MSWFWID|NC-SIMC|NC-SIC | VPDP  */
-    0x0028, 0x0003, 0x0000, 0x0000, 0x0000, 0x0003, 0x0000, 0xffff,
-  /*                            SW Section                         */
-    0x0100, 0xc000, 0x121c, 0xc007, 0xffff, 0xffff, 0xffff, 0xffff,
-  /*                      SW Section                       |CHKSUM */
-    0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0x0120, 0xffff, 0x0000,
+    0x1040, 0xffff, 0x002b, 0x0000, 0x8086, 0x10c9, 0x0000, 0x70c3,
+  /* SwPin0| DevID | EESZ  |-------|ICtrl3 |PCI-tc | MSIX  | APtr  */
+    0x0004, 0x10c9, 0x5c00, 0x0000, 0x2880, 0x0014, 0x4a40, 0x0060,
+  /* PCIe Init. Conf 1,2,3 |PCICtrl| LD1,3 |DDevID |DevRev | LD0,2 */
+    0x6cfb, 0xc7b0, 0x0abe, 0x0403, 0x0783, 0x10a6, 0x0001, 0x0602,
+  /* SwPin1| FunC  |LAN-PWR|ManHwC |ICtrl3 | IOVct |VDevID |-------*/
+    0x0004, 0x0020, 0x0000, 0x004a, 0x2080, 0x00f5, 0x10ca, 0x0000,
+  /*---------------| LD1,3 | LD0,2 | ROEnd | ROSta | Wdog  | VPD   */
+    0x0000, 0x0000, 0x4784, 0x4602, 0x0000, 0x0000, 0x1000, 0xffff,
+  /* PCSet0| Ccfg0 |PXEver |IBAcap |PCSet1 | Ccfg1 |iSCVer | ??    */
+    0x0100, 0x4000, 0x131f, 0x4013, 0x0100, 0x4000, 0xffff, 0xffff,
+  /* PCSet2| Ccfg2 |PCSet3 | Ccfg3 | ??    |AltMacP| ??    |CHKSUM */
+    0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00e0, 0xffff, 0x0000,
+  /* NC-SIC */
+    0x0003,
 };
 
 static void igb_core_realize(IGBState *s)
@@ -266,47 +282,27 @@ static void igb_core_realize(IGBState *s)
 }
 
 static void
-igb_unuse_msix_vectors(IGBState *s, int num_vectors)
+igb_init_msix(IGBState *s)
 {
     int i;
-    for (i = 0; i < num_vectors; i++) {
-        msix_vector_unuse(PCI_DEVICE(s), i);
-    }
-}
 
-static void
-igb_use_msix_vectors(IGBState *s, int num_vectors)
-{
-    int i;
-    for (i = 0; i < num_vectors; i++) {
-        msix_vector_use(PCI_DEVICE(s), i);
-    }
-}
+    msix_init(PCI_DEVICE(s), IGB_MSIX_VECTORS,
+              &s->msix,
+              E1000E_MSIX_IDX, 0,
+              &s->msix,
+              E1000E_MSIX_IDX, 0x2000,
+              0x70, &error_abort);
 
-static void
-igb_init_msix(IGBState *s)
-{
-    int res = msix_init(PCI_DEVICE(s), IGB_MSIX_VEC_NUM,
-                        &s->msix,
-                        E1000E_MSIX_IDX, E1000E_MSIX_TABLE,
-                        &s->msix,
-                        E1000E_MSIX_IDX, E1000E_MSIX_PBA,
-                        0xA0, NULL);
-
-    if (res < 0) {
-        trace_e1000e_msix_init_fail(res);
-    } else {
-        igb_use_msix_vectors(s, IGB_MSIX_VEC_NUM);
+    for (i = 0; i < IGB_MSIX_VECTORS; i++) {
+        msix_vector_use(PCI_DEVICE(s), i);
     }
 }
 
 static void
 igb_cleanup_msix(IGBState *s)
 {
-    if (msix_present(PCI_DEVICE(s))) {
-        igb_unuse_msix_vectors(s, IGB_MSIX_VEC_NUM);
-        msix_uninit(PCI_DEVICE(s), &s->msix, &s->msix);
-    }
+    msix_unuse_all_vectors(PCI_DEVICE(s));
+    msix_uninit(PCI_DEVICE(s), &s->msix, &s->msix);
 }
 
 static void
@@ -327,24 +323,16 @@ igb_init_net_peer(IGBState *s, PCIDevice *pci_dev, uint8_t *macaddr)
     qemu_format_nic_info_str(qemu_get_queue(s->nic), macaddr);
 
     /* Setup virtio headers */
-    if (s->disable_vnet) {
-        s->core.has_vnet = false;
-        trace_e1000e_cfg_support_virtio(false);
-        return;
-    } else {
-        s->core.has_vnet = true;
-    }
-
     for (i = 0; i < s->conf.peers.queues; i++) {
         nc = qemu_get_subqueue(s->nic, i);
         if (!nc->peer || !qemu_has_vnet_hdr(nc->peer)) {
-            s->core.has_vnet = false;
             trace_e1000e_cfg_support_virtio(false);
             return;
         }
     }
 
     trace_e1000e_cfg_support_virtio(true);
+    s->core.has_vnet = true;
 
     for (i = 0; i < s->conf.peers.queues; i++) {
         nc = qemu_get_subqueue(s->nic, i);
@@ -353,19 +341,6 @@ igb_init_net_peer(IGBState *s, PCIDevice *pci_dev, uint8_t *macaddr)
     }
 }
 
-static inline uint64_t
-igb_gen_dsn(uint8_t *mac)
-{
-    return (uint64_t)(mac[5])        |
-           (uint64_t)(mac[4])  << 8  |
-           (uint64_t)(mac[3])  << 16 |
-           (uint64_t)(0x00FF)  << 24 |
-           (uint64_t)(0x00FF)  << 32 |
-           (uint64_t)(mac[2])  << 40 |
-           (uint64_t)(mac[1])  << 48 |
-           (uint64_t)(mac[0])  << 56;
-}
-
 static int
 igb_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc)
 {
@@ -393,28 +368,10 @@ igb_add_pm_capability(PCIDevice *pdev, uint8_t offset, uint16_t pmc)
     return ret;
 }
 
-static void igb_write_config(PCIDevice *pci_dev, uint32_t address,
-                             uint32_t val, int len)
-{
-    IGBState *s = IGB(pci_dev);
-
-    pci_default_write_config(pci_dev, address, val, len);
-
-    if (range_covers_byte(address, len, PCI_COMMAND) &&
-        (pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
-        igb_start_recv(&s->core);
-    }
-}
-
 static void igb_pci_realize(PCIDevice *pci_dev, Error **errp)
 {
-    static const uint16_t e1000e_pmrb_offset = 0x0C8;
-    static const uint16_t e1000e_pcie_offset = 0x0E0;
-    static const uint16_t e1000e_aer_offset =  0x100;
-    static const uint16_t e1000e_dsn_offset =  0x140;
     IGBState *s = IGB(pci_dev);
     uint8_t *macaddr;
-    int ret;
 
     trace_e1000e_cb_pci_realize();
 
@@ -423,12 +380,6 @@ static void igb_pci_realize(PCIDevice *pci_dev, Error **errp)
     pci_dev->config[PCI_CACHE_LINE_SIZE] = 0x10;
     pci_dev->config[PCI_INTERRUPT_PIN] = 1;
 
-    pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, s->subsys_ven);
-    pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, s->subsys);
-
-    s->subsys_ven_used = s->subsys_ven;
-    s->subsys_used = s->subsys;
-
     /* Define IO/MMIO regions */
     memory_region_init_io(&s->mmio, OBJECT(s), &mmio_ops, s,
                           "igb-mmio", E1000E_MMIO_SIZE);
@@ -452,34 +403,40 @@ static void igb_pci_realize(PCIDevice *pci_dev, Error **errp)
     memory_region_init(&s->msix, OBJECT(s), "igb-msix",
                        E1000E_MSIX_SIZE);
     pci_register_bar(pci_dev, E1000E_MSIX_IDX,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, &s->msix);
+                     PCI_BASE_ADDRESS_MEM_TYPE_64, &s->msix);
 
     /* Create networking backend */
     qemu_macaddr_default_if_unset(&s->conf.macaddr);
     macaddr = s->conf.macaddr.a;
 
-    igb_init_msix(s);
+    /* Add PCI capabilities in reverse order */
+    assert(pcie_endpoint_cap_init(pci_dev, 0xa0) > 0);
 
-    if (pcie_endpoint_cap_v1_init(pci_dev, e1000e_pcie_offset) < 0) {
-        hw_error("Failed to initialize PCIe capability");
-    }
+    igb_init_msix(s);
 
-    ret = msi_init(PCI_DEVICE(s), 0xD0, 1, true, false, NULL);
-    if (ret) {
-        trace_e1000e_msi_init_fail(ret);
-    }
+    msi_init(pci_dev, 0x50, 1, true, true, &error_abort);
 
-    if (igb_add_pm_capability(pci_dev, e1000e_pmrb_offset,
-                              PCI_PM_CAP_DSI) < 0) {
+    if (igb_add_pm_capability(pci_dev, 0x40, PCI_PM_CAP_DSI) < 0) {
         hw_error("Failed to initialize PM capability");
     }
 
-    if (pcie_aer_init(pci_dev, PCI_ERR_VER, e1000e_aer_offset,
-                      PCI_ERR_SIZEOF, NULL) < 0) {
+    /* PCIe extended capabilities (in order) */
+    if (pcie_aer_init(pci_dev, 1, 0x100, 0x40, errp) < 0) {
         hw_error("Failed to initialize AER capability");
     }
 
-    pcie_dev_ser_num_init(pci_dev, e1000e_dsn_offset, igb_gen_dsn(macaddr));
+    pcie_ari_init(pci_dev, 0x150, 1);
+
+    pcie_sriov_pf_init(pci_dev, IGB_CAP_SRIOV_OFFSET, "igbvf",
+        IGB_82576_VF_DEV_ID, IGB_MAX_VF_FUNCTIONS, IGB_MAX_VF_FUNCTIONS,
+        IGB_VF_OFFSET, IGB_VF_STRIDE);
+
+    pcie_sriov_pf_init_vf_bar(pci_dev, 0,
+        PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH,
+        16 * KiB);
+    pcie_sriov_pf_init_vf_bar(pci_dev, 3,
+        PCI_BASE_ADDRESS_MEM_TYPE_64 | PCI_BASE_ADDRESS_MEM_PREFETCH,
+        16 * KiB);
 
     igb_init_net_peer(s, pci_dev, macaddr);
 
@@ -500,7 +457,7 @@ static void igb_pci_uninit(PCIDevice *pci_dev)
 
     igb_core_pci_uninit(&s->core);
 
-    pcie_aer_exit(pci_dev);
+    pcie_sriov_pf_exit(pci_dev);
     pcie_cap_exit(pci_dev);
 
     qemu_del_nic(s->nic);
@@ -511,15 +468,13 @@ static void igb_pci_uninit(PCIDevice *pci_dev)
 
 static void igb_qdev_reset_hold(Object *obj)
 {
+    PCIDevice *d = PCI_DEVICE(obj);
     IGBState *s = IGB(obj);
 
     trace_e1000e_cb_qdev_reset_hold();
 
+    pcie_sriov_pf_disable_vfs(d);
     igb_core_reset(&s->core);
-
-    if (s->init_vet) {
-        s->core.mac[VET] = ETH_P_VLAN;
-    }
 }
 
 static int igb_pre_save(void *opaque)
@@ -538,15 +493,6 @@ static int igb_post_load(void *opaque, int version_id)
     IGBState *s = opaque;
 
     trace_e1000e_cb_post_load();
-
-    if ((s->subsys != s->subsys_used) ||
-        (s->subsys_ven != s->subsys_ven_used)) {
-        fprintf(stderr,
-            "ERROR: Cannot migrate while device properties "
-            "(subsys/subsys_ven) differ");
-        return -1;
-    }
-
     return igb_core_post_load(&s->core);
 }
 
@@ -555,20 +501,12 @@ static const VMStateDescription igb_vmstate_tx = {
     .version_id = 1,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
-        VMSTATE_UINT8(sum_needed, struct igb_tx),
-        VMSTATE_UINT8(props.ipcss, struct igb_tx),
-        VMSTATE_UINT8(props.ipcso, struct igb_tx),
-        VMSTATE_UINT16(props.ipcse, struct igb_tx),
-        VMSTATE_UINT8(props.tucss, struct igb_tx),
-        VMSTATE_UINT8(props.tucso, struct igb_tx),
-        VMSTATE_UINT16(props.tucse, struct igb_tx),
-        VMSTATE_UINT8(props.hdr_len, struct igb_tx),
-        VMSTATE_UINT16(props.mss, struct igb_tx),
-        VMSTATE_UINT32(props.paylen, struct igb_tx),
-        VMSTATE_INT8(props.ip, struct igb_tx),
-        VMSTATE_INT8(props.tcp, struct igb_tx),
-        VMSTATE_BOOL(props.tse, struct igb_tx),
-        VMSTATE_BOOL(cptse, struct igb_tx),
+        VMSTATE_UINT16(vlan, struct igb_tx),
+        VMSTATE_UINT16(mss, struct igb_tx),
+        VMSTATE_BOOL(tse, struct igb_tx),
+        VMSTATE_BOOL(ixsm, struct igb_tx),
+        VMSTATE_BOOL(txsm, struct igb_tx),
+        VMSTATE_BOOL(first, struct igb_tx),
         VMSTATE_BOOL(skip_cp, struct igb_tx),
         VMSTATE_END_OF_LIST()
     }
@@ -604,58 +542,26 @@ static const VMStateDescription igb_vmstate = {
         VMSTATE_MSIX(parent_obj, IGBState),
 
         VMSTATE_UINT32(ioaddr, IGBState),
-        VMSTATE_UINT32(core.rxbuf_min_shift, IGBState),
         VMSTATE_UINT8(core.rx_desc_len, IGBState),
-        VMSTATE_UINT32_ARRAY(core.rxbuf_sizes, IGBState,
-                             E1000_PSRCTL_BUFFS_PER_DESC),
         VMSTATE_UINT32(core.rx_desc_buf_size, IGBState),
         VMSTATE_UINT16_ARRAY(core.eeprom, IGBState, IGB_EEPROM_SIZE),
-        VMSTATE_UINT16_2DARRAY(core.phy, IGBState,
-                               E1000E_PHY_PAGES, E1000E_PHY_PAGE_SIZE),
+        VMSTATE_UINT16_ARRAY(core.phy, IGBState, MAX_PHY_REG_ADDRESS + 1),
         VMSTATE_UINT32_ARRAY(core.mac, IGBState, E1000E_MAC_SIZE),
         VMSTATE_UINT8_ARRAY(core.permanent_mac, IGBState, ETH_ALEN),
 
-        VMSTATE_UINT32(core.delayed_causes, IGBState),
-
-        VMSTATE_UINT16(subsys, IGBState),
-        VMSTATE_UINT16(subsys_ven, IGBState),
-
-        VMSTATE_IGB_INTR_DELAY_TIMER(core.rdtr, IGBState),
-        VMSTATE_IGB_INTR_DELAY_TIMER(core.radv, IGBState),
-        VMSTATE_IGB_INTR_DELAY_TIMER(core.raid, IGBState),
-        VMSTATE_IGB_INTR_DELAY_TIMER(core.tadv, IGBState),
-        VMSTATE_IGB_INTR_DELAY_TIMER(core.tidv, IGBState),
-
-        VMSTATE_IGB_INTR_DELAY_TIMER(core.itr, IGBState),
-
         VMSTATE_IGB_INTR_DELAY_TIMER_ARRAY(core.eitr, IGBState,
                                            IGB_MSIX_VEC_NUM),
 
-        VMSTATE_UINT32(core.itr_guest_value, IGBState),
         VMSTATE_UINT32_ARRAY(core.eitr_guest_value, IGBState, IGB_MSIX_VEC_NUM),
 
-        VMSTATE_UINT16(core.vet, IGBState),
-
         VMSTATE_STRUCT_ARRAY(core.tx, IGBState, IGB_NUM_QUEUES, 0,
                              igb_vmstate_tx, struct igb_tx),
         VMSTATE_END_OF_LIST()
     }
 };
 
-static PropertyInfo igb_prop_disable_vnet,
-                    igb_prop_subsys_ven,
-                    igb_prop_subsys;
-
 static Property igb_properties[] = {
     DEFINE_NIC_PROPERTIES(IGBState, conf),
-    DEFINE_PROP_SIGNED("disable_vnet_hdr", IGBState, disable_vnet, false,
-                        igb_prop_disable_vnet, bool),
-    DEFINE_PROP_SIGNED("subsys_ven", IGBState, subsys_ven,
-                        PCI_VENDOR_ID_INTEL,
-                        igb_prop_subsys_ven, uint16_t),
-    DEFINE_PROP_SIGNED("subsys", IGBState, subsys, 0,
-                        igb_prop_subsys, uint16_t),
-    DEFINE_PROP_BOOL("init-vet", IGBState, init_vet, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -668,27 +574,15 @@ static void igb_class_init(ObjectClass *class, void *data)
     c->realize = igb_pci_realize;
     c->exit = igb_pci_uninit;
     c->vendor_id = PCI_VENDOR_ID_INTEL;
-    c->device_id = E1000_DEV_ID_82574L;
-    c->revision = 0;
-    c->romfile = "efi-e1000e.rom";
+    c->device_id = E1000_DEV_ID_82576;
+    c->revision = 1;
     c->class_id = PCI_CLASS_NETWORK_ETHERNET;
 
     rc->phases.hold = igb_qdev_reset_hold;
 
-    dc->desc = "Intel 82574L GbE Controller";
+    dc->desc = "Intel 82576 Gigabit Ethernet Controller";
     dc->vmsd = &igb_vmstate;
 
-    igb_prop_disable_vnet = qdev_prop_uint8;
-    igb_prop_disable_vnet.description = "Do not use virtio headers, "
-                                        "perform SW offloads emulation "
-                                        "instead";
-
-    igb_prop_subsys_ven = qdev_prop_uint16;
-    igb_prop_subsys_ven.description = "PCI device Subsystem Vendor ID";
-
-    igb_prop_subsys = qdev_prop_uint16;
-    igb_prop_subsys.description = "PCI device Subsystem ID";
-
     device_class_set_props(dc, igb_properties);
     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
 }
diff --git a/hw/net/igb_common.h b/hw/net/igb_common.h
index c38d6e8084..f1b2457a0a 100644
--- a/hw/net/igb_common.h
+++ b/hw/net/igb_common.h
@@ -1,6 +1,7 @@
 /*
  * QEMU igb emulation - shared definitions
  *
+ * Copyright (c) 2020-2023 Red Hat, Inc.
  * Copyright (c) 2008 Qumranet
  *
  * Based on work done by:
@@ -25,35 +26,51 @@
 #ifndef HW_NET_IGB_COMMON_H
 #define HW_NET_IGB_COMMON_H
 
-#include "e1000_regs.h"
+#include "igb_regs.h"
+
+#define defreg(x) x = (E1000_##x >> 2)
+#define defreg_indexed(x, i) x##i = (E1000_##x(i) >> 2)
+#define defreg_indexeda(x, i) x##i##_A = (E1000_##x##_A(i) >> 2)
+
+#define defregd(x) defreg_indexed(x, 0),  defreg_indexed(x, 1),  \
+                   defreg_indexed(x, 2),  defreg_indexed(x, 3),  \
+                   defreg_indexed(x, 4),  defreg_indexed(x, 5),  \
+                   defreg_indexed(x, 6),  defreg_indexed(x, 7),  \
+                   defreg_indexed(x, 8),  defreg_indexed(x, 9),  \
+                   defreg_indexed(x, 10), defreg_indexed(x, 11), \
+                   defreg_indexed(x, 12), defreg_indexed(x, 13), \
+                   defreg_indexed(x, 14), defreg_indexed(x, 15), \
+                   defreg_indexeda(x, 0), defreg_indexeda(x, 1), \
+                   defreg_indexeda(x, 2), defreg_indexeda(x, 3)
+
+#define defregv(x) defreg_indexed(x, 0), defreg_indexed(x, 1),   \
+                   defreg_indexed(x, 2), defreg_indexed(x, 3),   \
+                   defreg_indexed(x, 4), defreg_indexed(x, 5),   \
+                   defreg_indexed(x, 6), defreg_indexed(x, 7)
 
-#define defreg(x)   x = (E1000_##x >> 2)
 enum {
     defreg(CTRL),    defreg(EECD),    defreg(EERD),    defreg(GPRC),
     defreg(GPTC),    defreg(ICR),     defreg(ICS),     defreg(IMC),
     defreg(IMS),     defreg(LEDCTL),  defreg(MANC),    defreg(MDIC),
-    defreg(MPC),     defreg(PBA),     defreg(RCTL),    defreg(RDBAH0),
-    defreg(RDBAL0),  defreg(RDH0),    defreg(RDLEN0),  defreg(RDT0),
-    defreg(STATUS),  defreg(SWSM),    defreg(TCTL),    defreg(TDBAH),
-    defreg(TDBAL),   defreg(TDH),     defreg(TDLEN),   defreg(TDT),
-    defreg(TDLEN1),  defreg(TDBAL1),  defreg(TDBAH1),  defreg(TDH1),
-    defreg(TDT1),    defreg(TORH),    defreg(TORL),    defreg(TOTH),
-    defreg(TOTL),    defreg(TPR),     defreg(TPT),     defreg(TXDCTL),
+    defreg(MPC),     defreg(RCTL),
+    defreg(STATUS),  defreg(SWSM),    defreg(TCTL),
+    defreg(TORH),    defreg(TORL),    defreg(TOTH),
+    defreg(TOTL),    defreg(TPR),     defreg(TPT),
     defreg(WUFC),    defreg(RA),      defreg(MTA),     defreg(CRCERRS),
-    defreg(VFTA),    defreg(VET),     defreg(RDTR),    defreg(RADV),
-    defreg(TADV),    defreg(ITR),     defreg(SCC),     defreg(ECOL),
+    defreg(VFTA),    defreg(VET),
+    defreg(SCC),     defreg(ECOL),
     defreg(MCC),     defreg(LATECOL), defreg(COLC),    defreg(DC),
-    defreg(TNCRS),   defreg(SEQEC),   defreg(CEXTERR), defreg(RLEC),
+    defreg(TNCRS),   defreg(RLEC),
     defreg(XONRXC),  defreg(XONTXC),  defreg(XOFFRXC), defreg(XOFFTXC),
-    defreg(FCRUC),   defreg(AIT),     defreg(TDFH),    defreg(TDFT),
+    defreg(FCRUC),   defreg(TDFH),    defreg(TDFT),
     defreg(TDFHS),   defreg(TDFTS),   defreg(TDFPC),   defreg(WUC),
-    defreg(WUS),     defreg(POEMB),   defreg(PBS),     defreg(RDFH),
+    defreg(WUS),     defreg(RDFH),
     defreg(RDFT),    defreg(RDFHS),   defreg(RDFTS),   defreg(RDFPC),
-    defreg(PBM),     defreg(IPAV),    defreg(IP4AT),   defreg(IP6AT),
-    defreg(WUPM),    defreg(FFLT),    defreg(FFMT),    defreg(FFVT),
-    defreg(TARC0),   defreg(TARC1),   defreg(IAM),     defreg(EXTCNF_CTRL),
+    defreg(IPAV),    defreg(IP4AT),   defreg(IP6AT),
+    defreg(WUPM),    defreg(FFMT),
+    defreg(IAM),
     defreg(GCR),     defreg(TIMINCA), defreg(EIAC),    defreg(CTRL_EXT),
-    defreg(IVAR),    defreg(MFUTP01), defreg(MFUTP23), defreg(MANC2H),
+    defreg(IVAR0),   defreg(MANC2H),
     defreg(MFVAL),   defreg(MDEF),    defreg(FACTPS),  defreg(FTFT),
     defreg(RUC),     defreg(ROC),     defreg(RFC),     defreg(RJC),
     defreg(PRC64),   defreg(PRC127),  defreg(PRC255),  defreg(PRC511),
@@ -61,28 +78,22 @@ enum {
     defreg(PTC255),  defreg(PTC511),  defreg(PTC1023), defreg(PTC1522),
     defreg(GORCL),   defreg(GORCH),   defreg(GOTCL),   defreg(GOTCH),
     defreg(RNBC),    defreg(BPRC),    defreg(MPRC),    defreg(RFCTL),
-    defreg(PSRCTL),  defreg(MPTC),    defreg(BPTC),    defreg(TSCTFC),
+    defreg(MPTC),    defreg(BPTC),
     defreg(IAC),     defreg(MGTPRC),  defreg(MGTPDC),  defreg(MGTPTC),
     defreg(TSCTC),   defreg(RXCSUM),  defreg(FUNCTAG), defreg(GSCL_1),
     defreg(GSCL_2),  defreg(GSCL_3),  defreg(GSCL_4),  defreg(GSCN_0),
-    defreg(GSCN_1),  defreg(GSCN_2),  defreg(GSCN_3),  defreg(GCR2),
-    defreg(RAID),    defreg(RSRPD),   defreg(TIDV),    defreg(EITR),
-    defreg(MRQC),    defreg(RETA),    defreg(RSSRK),   defreg(RDBAH1),
-    defreg(RDBAL1),  defreg(RDLEN1),  defreg(RDH1),    defreg(RDT1),
+    defreg(GSCN_1),  defreg(GSCN_2),  defreg(GSCN_3),
+    defreg_indexed(EITR, 0),
+    defreg(MRQC),    defreg(RETA),    defreg(RSSRK),
     defreg(PBACLR),  defreg(FCAL),    defreg(FCAH),    defreg(FCT),
     defreg(FCRTH),   defreg(FCRTL),   defreg(FCTTV),   defreg(FCRTV),
-    defreg(FLA),     defreg(EEWR),    defreg(FLOP),    defreg(FLOL),
-    defreg(FLSWCTL), defreg(FLSWCNT), defreg(RXDCTL),  defreg(RXDCTL1),
+    defreg(FLA),     defreg(FLOP),
     defreg(MAVTV0),  defreg(MAVTV1),  defreg(MAVTV2),  defreg(MAVTV3),
     defreg(TXSTMPL), defreg(TXSTMPH), defreg(SYSTIML), defreg(SYSTIMH),
-    defreg(RXCFGL),  defreg(RXUDP),   defreg(TIMADJL), defreg(TIMADJH),
+    defreg(TIMADJL), defreg(TIMADJH),
     defreg(RXSTMPH), defreg(RXSTMPL), defreg(RXSATRL), defreg(RXSATRH),
-    defreg(FLASHT),  defreg(TIPG),    defreg(RDH),     defreg(RDT),
-    defreg(RDLEN),   defreg(RDBAH),   defreg(RDBAL),
-    defreg(TXDCTL1),
-    defreg(FLSWDATA),
+    defreg(TIPG),
     defreg(CTRL_DUP),
-    defreg(EXTCNF_SIZE),
     defreg(EEMNGCTL),
     defreg(EEMNGDATA),
     defreg(FLMNGCTL),
@@ -90,13 +101,44 @@ enum {
     defreg(FLMNGCNT),
     defreg(TSYNCRXCTL),
     defreg(TSYNCTXCTL),
+    defreg(RLPML),
+    defreg(UTA),
 
     /* Aliases */
-    defreg(RDH0_A),  defreg(RDT0_A),  defreg(RDTR_A),  defreg(RDFH_A),
-    defreg(RDFT_A),  defreg(TDH_A),   defreg(TDT_A),   defreg(TIDV_A),
-    defreg(TDFH_A),  defreg(TDFT_A),  defreg(RA_A),    defreg(RDBAL0_A),
-    defreg(TDBAL_A), defreg(TDLEN_A), defreg(VFTA_A),  defreg(RDLEN0_A),
-    defreg(FCRTL_A), defreg(FCRTH_A)
+    defreg(RDFH_A),      defreg(RDFT_A),     defreg(TDFH_A),     defreg(TDFT_A),
+    defreg(RA_A),        defreg(VFTA_A),     defreg(FCRTL_A),
+
+    /* Additional regs used by IGB */
+    defreg(FWSM),        defreg(SW_FW_SYNC),
+
+    defreg(EICS),        defreg(EIMS),        defreg(EIMC),       defreg(EIAM),
+    defreg(EICR),        defreg(IVAR_MISC),   defreg(GPIE),
+
+    defreg(RXPBS),      defregd(RDBAL),       defregd(RDBAH),     defregd(RDLEN),
+    defregd(SRRCTL),    defregd(RDH),         defregd(RDT),
+    defregd(RXDCTL),    defregd(RXCTL),       defregd(RQDPC),     defreg(RA2),
+
+    defreg(TXPBS),       defreg(TCTL_EXT),    defreg(DTXCTL),     defreg(HTCBDPC),
+    defregd(TDBAL),      defregd(TDBAH),      defregd(TDLEN),     defregd(TDH),
+    defregd(TDT),        defregd(TXDCTL),     defregd(TXCTL),
+    defregd(TDWBAL),     defregd(TDWBAH),
+
+    defregv(P2VMAILBOX), defregv(V2PMAILBOX), defreg(MBVFICR),    defreg(MBVFIMR),
+    defreg(VFLRE),       defreg(VFRE),        defreg(VFTE),       defreg(WVBR),
+    defreg(QDE),         defreg(DTXSWC),      defreg_indexed(VLVF, 0),
+    defregv(VMOLR),      defreg(RPLOLR),      defregv(VMBMEM),    defregv(VMVIR),
+
+    defregv(PVTCTRL),    defregv(PVTEICS),    defregv(PVTEIMS),   defregv(PVTEIMC),
+    defregv(PVTEIAC),    defregv(PVTEIAM),    defregv(PVTEICR),   defregv(PVFGPRC),
+    defregv(PVFGPTC),    defregv(PVFGORC),    defregv(PVFGOTC),   defregv(PVFMPRC),
+    defregv(PVFGPRLBC),  defregv(PVFGPTLBC),  defregv(PVFGORLBC), defregv(PVFGOTLBC),
+
+    defreg(MTA_A),
+
+    defreg(VTIVAR), defreg(VTIVAR_MISC),
 };
 
+uint64_t igb_mmio_read(void *opaque, hwaddr addr, unsigned size);
+void igb_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size);
+
 #endif
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
index bf8ed64fbd..acee9d4fb6 100644
--- a/hw/net/igb_core.c
+++ b/hw/net/igb_core.c
@@ -1,13 +1,17 @@
 /*
  * Core code for QEMU igb emulation
  *
- * Software developer's manuals:
- * http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
+ * Datasheet:
+ * https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eg-gbe-datasheet.pdf
  *
+ * Copyright (c) 2020-2023 Red Hat, Inc.
  * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
  * Developed by Daynix Computing LTD (http://www.daynix.com)
  *
  * Authors:
+ * Akihiko Odaki <akihiko.odaki@daynix.com>
+ * Gal Hammmer <gal.hammer@sap.com>
+ * Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
  * Dmitry Fleytman <dmitry@daynix.com>
  * Leonid Bloch <leonid@daynix.com>
  * Yan Vugenfirer <yan@daynix.com>
@@ -51,38 +55,19 @@
 
 #include "trace.h"
 
-/* No more then 7813 interrupts per second according to spec 10.2.4.2 */
-#define E1000E_MIN_XITR     (500)
-
 #define E1000E_MAX_TX_FRAGS (64)
 
 union e1000_rx_desc_union {
     struct e1000_rx_desc legacy;
-    union e1000_rx_desc_extended extended;
-    union e1000_rx_desc_packet_split packet_split;
+    union e1000_adv_rx_desc adv;
 };
 
 static inline void
 igb_set_interrupt_cause(IGBCore *core, uint32_t val);
 
+static void igb_update_interrupt_state(IGBCore *core);
 static void igb_reset(IGBCore *core, bool sw);
 
-static inline void
-igb_process_ts_option(IGBCore *core, struct e1000_tx_desc *dp)
-{
-    if (le32_to_cpu(dp->upper.data) & E1000_TXD_EXTCMD_TSTAMP) {
-        trace_e1000e_wrn_no_ts_support();
-    }
-}
-
-static inline void
-igb_process_snap_option(IGBCore *core, uint32_t cmd_and_length)
-{
-    if (cmd_and_length & E1000_TXD_CMD_SNAP) {
-        trace_e1000e_wrn_no_snap_support();
-    }
-}
-
 static inline void
 igb_raise_legacy_irq(IGBCore *core)
 {
@@ -98,6 +83,21 @@ igb_lower_legacy_irq(IGBCore *core)
     pci_set_irq(core->owner, 0);
 }
 
+static void igb_msix_notify(IGBCore *core, unsigned int vector)
+{
+    PCIDevice *dev = core->owner;
+    uint16_t vfn;
+
+    vfn = 8 - (vector + 2) / 3;
+    if (vfn < pcie_sriov_num_vfs(core->owner)) {
+        dev = pcie_sriov_get_vf_at_index(core->owner, vfn);
+        assert(dev);
+        vector = (vector + 2) % 3;
+    }
+
+    msix_notify(dev, vector);
+}
+
 static inline void
 igb_intrmgr_rearm_timer(IGBIntrDelayTimer *timer)
 {
@@ -127,53 +127,6 @@ igb_intmgr_timer_pause(IGBIntrDelayTimer *timer)
     }
 }
 
-static inline void
-igb_intrmgr_stop_timer(IGBIntrDelayTimer *timer)
-{
-    if (timer->running) {
-        timer_del(timer->timer);
-        timer->running = false;
-    }
-}
-
-static inline void
-igb_intrmgr_fire_delayed_interrupts(IGBCore *core)
-{
-    trace_e1000e_irq_fire_delayed_interrupts();
-    igb_set_interrupt_cause(core, 0);
-}
-
-static void
-igb_intrmgr_on_timer(void *opaque)
-{
-    IGBIntrDelayTimer *timer = opaque;
-
-    trace_e1000e_irq_throttling_timer(timer->delay_reg << 2);
-
-    timer->running = false;
-    igb_intrmgr_fire_delayed_interrupts(timer->core);
-}
-
-static void
-igb_intrmgr_on_throttling_timer(void *opaque)
-{
-    IGBIntrDelayTimer *timer = opaque;
-
-    assert(!msix_enabled(timer->core->owner));
-
-    timer->running = false;
-
-    if (msi_enabled(timer->core->owner)) {
-        trace_e1000e_irq_msi_notify_postponed();
-        /* Clear msi_causes_pending to fire MSI eventually */
-        timer->core->msi_causes_pending = 0;
-        igb_set_interrupt_cause(timer->core, 0);
-    } else {
-        trace_e1000e_irq_legacy_notify_postponed();
-        igb_set_interrupt_cause(timer->core, 0);
-    }
-}
-
 static void
 igb_intrmgr_on_msix_throttling_timer(void *opaque)
 {
@@ -185,7 +138,7 @@ igb_intrmgr_on_msix_throttling_timer(void *opaque)
     timer->running = false;
 
     trace_e1000e_irq_msix_notify_postponed_vec(idx);
-    msix_notify(timer->core->owner, idx);
+    igb_msix_notify(timer->core, idx);
 }
 
 static void
@@ -193,54 +146,16 @@ igb_intrmgr_initialize_all_timers(IGBCore *core, bool create)
 {
     int i;
 
-    core->radv.delay_reg = RADV;
-    core->rdtr.delay_reg = RDTR;
-    core->raid.delay_reg = RAID;
-    core->tadv.delay_reg = TADV;
-    core->tidv.delay_reg = TIDV;
-
-    core->radv.delay_resolution_ns = E1000_INTR_DELAY_NS_RES;
-    core->rdtr.delay_resolution_ns = E1000_INTR_DELAY_NS_RES;
-    core->raid.delay_resolution_ns = E1000_INTR_DELAY_NS_RES;
-    core->tadv.delay_resolution_ns = E1000_INTR_DELAY_NS_RES;
-    core->tidv.delay_resolution_ns = E1000_INTR_DELAY_NS_RES;
-
-    core->radv.core = core;
-    core->rdtr.core = core;
-    core->raid.core = core;
-    core->tadv.core = core;
-    core->tidv.core = core;
-
-    core->itr.core = core;
-    core->itr.delay_reg = ITR;
-    core->itr.delay_resolution_ns = E1000_INTR_THROTTLING_NS_RES;
-
     for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
         core->eitr[i].core = core;
-        core->eitr[i].delay_reg = EITR + i;
-        core->eitr[i].delay_resolution_ns = E1000_INTR_THROTTLING_NS_RES;
+        core->eitr[i].delay_reg = EITR0 + i;
+        core->eitr[i].delay_resolution_ns = E1000_INTR_DELAY_NS_RES;
     }
 
     if (!create) {
         return;
     }
 
-    core->radv.timer =
-        timer_new_ns(QEMU_CLOCK_VIRTUAL, igb_intrmgr_on_timer, &core->radv);
-    core->rdtr.timer =
-        timer_new_ns(QEMU_CLOCK_VIRTUAL, igb_intrmgr_on_timer, &core->rdtr);
-    core->raid.timer =
-        timer_new_ns(QEMU_CLOCK_VIRTUAL, igb_intrmgr_on_timer, &core->raid);
-
-    core->tadv.timer =
-        timer_new_ns(QEMU_CLOCK_VIRTUAL, igb_intrmgr_on_timer, &core->tadv);
-    core->tidv.timer =
-        timer_new_ns(QEMU_CLOCK_VIRTUAL, igb_intrmgr_on_timer, &core->tidv);
-
-    core->itr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
-                                   igb_intrmgr_on_throttling_timer,
-                                   &core->itr);
-
     for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
         core->eitr[i].timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
                                            igb_intrmgr_on_msix_throttling_timer,
@@ -248,154 +163,11 @@ igb_intrmgr_initialize_all_timers(IGBCore *core, bool create)
     }
 }
 
-static inline void
-igb_intrmgr_stop_delay_timers(IGBCore *core)
-{
-    igb_intrmgr_stop_timer(&core->radv);
-    igb_intrmgr_stop_timer(&core->rdtr);
-    igb_intrmgr_stop_timer(&core->raid);
-    igb_intrmgr_stop_timer(&core->tidv);
-    igb_intrmgr_stop_timer(&core->tadv);
-}
-
-static bool
-igb_intrmgr_delay_rx_causes(IGBCore *core, uint32_t *causes)
-{
-    uint32_t delayable_causes;
-    uint32_t rdtr = core->mac[RDTR];
-    uint32_t radv = core->mac[RADV];
-    uint32_t raid = core->mac[RAID];
-
-    if (msix_enabled(core->owner)) {
-        return false;
-    }
-
-    delayable_causes = E1000_ICR_RXQ0 |
-                       E1000_ICR_RXQ1 |
-                       E1000_ICR_RXT0;
-
-    if (!(core->mac[RFCTL] & E1000_RFCTL_ACK_DIS)) {
-        delayable_causes |= E1000_ICR_ACK;
-    }
-
-    /* Clean up all causes that may be delayed */
-    core->delayed_causes |= *causes & delayable_causes;
-    *causes &= ~delayable_causes;
-
-    /*
-     * Check if delayed RX interrupts disabled by client
-     * or if there are causes that cannot be delayed
-     */
-    if ((rdtr == 0) || (*causes != 0)) {
-        return false;
-    }
-
-    /*
-     * Check if delayed RX ACK interrupts disabled by client
-     * and there is an ACK packet received
-     */
-    if ((raid == 0) && (core->delayed_causes & E1000_ICR_ACK)) {
-        return false;
-    }
-
-    /* All causes delayed */
-    igb_intrmgr_rearm_timer(&core->rdtr);
-
-    if (!core->radv.running && (radv != 0)) {
-        igb_intrmgr_rearm_timer(&core->radv);
-    }
-
-    if (!core->raid.running && (core->delayed_causes & E1000_ICR_ACK)) {
-        igb_intrmgr_rearm_timer(&core->raid);
-    }
-
-    return true;
-}
-
-static bool
-igb_intrmgr_delay_tx_causes(IGBCore *core, uint32_t *causes)
-{
-    static const uint32_t delayable_causes = E1000_ICR_TXQ0 |
-                                             E1000_ICR_TXQ1 |
-                                             E1000_ICR_TXQE |
-                                             E1000_ICR_TXDW;
-
-    if (msix_enabled(core->owner)) {
-        return false;
-    }
-
-    /* Clean up all causes that may be delayed */
-    core->delayed_causes |= *causes & delayable_causes;
-    *causes &= ~delayable_causes;
-
-    /* If there are causes that cannot be delayed */
-    if (*causes != 0) {
-        return false;
-    }
-
-    /* All causes delayed */
-    igb_intrmgr_rearm_timer(&core->tidv);
-
-    if (!core->tadv.running && (core->mac[TADV] != 0)) {
-        igb_intrmgr_rearm_timer(&core->tadv);
-    }
-
-    return true;
-}
-
-static uint32_t
-igb_intmgr_collect_delayed_causes(IGBCore *core)
-{
-    uint32_t res;
-
-    if (msix_enabled(core->owner)) {
-        assert(core->delayed_causes == 0);
-        return 0;
-    }
-
-    res = core->delayed_causes;
-    core->delayed_causes = 0;
-
-    igb_intrmgr_stop_delay_timers(core);
-
-    return res;
-}
-
-static void
-igb_intrmgr_fire_all_timers(IGBCore *core)
-{
-    int i;
-    uint32_t val = igb_intmgr_collect_delayed_causes(core);
-
-    trace_e1000e_irq_adding_delayed_causes(val, core->mac[ICR]);
-    core->mac[ICR] |= val;
-
-    if (core->itr.running) {
-        timer_del(core->itr.timer);
-        igb_intrmgr_on_throttling_timer(&core->itr);
-    }
-
-    for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
-        if (core->eitr[i].running) {
-            timer_del(core->eitr[i].timer);
-            igb_intrmgr_on_msix_throttling_timer(&core->eitr[i]);
-        }
-    }
-}
-
 static void
 igb_intrmgr_resume(IGBCore *core)
 {
     int i;
 
-    igb_intmgr_timer_resume(&core->radv);
-    igb_intmgr_timer_resume(&core->rdtr);
-    igb_intmgr_timer_resume(&core->raid);
-    igb_intmgr_timer_resume(&core->tidv);
-    igb_intmgr_timer_resume(&core->tadv);
-
-    igb_intmgr_timer_resume(&core->itr);
-
     for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
         igb_intmgr_timer_resume(&core->eitr[i]);
     }
@@ -406,14 +178,6 @@ igb_intrmgr_pause(IGBCore *core)
 {
     int i;
 
-    igb_intmgr_timer_pause(&core->radv);
-    igb_intmgr_timer_pause(&core->rdtr);
-    igb_intmgr_timer_pause(&core->raid);
-    igb_intmgr_timer_pause(&core->tidv);
-    igb_intmgr_timer_pause(&core->tadv);
-
-    igb_intmgr_timer_pause(&core->itr);
-
     for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
         igb_intmgr_timer_pause(&core->eitr[i]);
     }
@@ -424,14 +188,11 @@ igb_intrmgr_reset(IGBCore *core)
 {
     int i;
 
-    core->delayed_causes = 0;
-
-    igb_intrmgr_stop_delay_timers(core);
-
-    igb_intrmgr_stop_timer(&core->itr);
-
     for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
-        igb_intrmgr_stop_timer(&core->eitr[i]);
+        if (core->eitr[i].running) {
+            timer_del(core->eitr[i].timer);
+            igb_intrmgr_on_msix_throttling_timer(&core->eitr[i]);
+        }
     }
 }
 
@@ -440,15 +201,6 @@ igb_intrmgr_pci_unint(IGBCore *core)
 {
     int i;
 
-    timer_free(core->radv.timer);
-    timer_free(core->rdtr.timer);
-    timer_free(core->raid.timer);
-
-    timer_free(core->tadv.timer);
-    timer_free(core->tidv.timer);
-
-    timer_free(core->itr.timer);
-
     for (i = 0; i < IGB_MSIX_VEC_NUM; i++) {
         timer_free(core->eitr[i].timer);
     }
@@ -469,20 +221,17 @@ igb_rx_csum_enabled(IGBCore *core)
 static inline bool
 igb_rx_use_legacy_descriptor(IGBCore *core)
 {
-    return (core->mac[RFCTL] & E1000_RFCTL_EXTEN) ? false : true;
-}
-
-static inline bool
-igb_rx_use_ps_descriptor(IGBCore *core)
-{
-    return !igb_rx_use_legacy_descriptor(core) &&
-           (core->mac[RCTL] & E1000_RCTL_DTYP_PS);
+    /*
+     * TODO: If SRRCTL[n],DESCTYPE = 000b, the 82576 uses the legacy Rx
+     * descriptor.
+     */
+    return false;
 }
 
 static inline bool
 igb_rss_enabled(IGBCore *core)
 {
-    return E1000_MRQC_ENABLED(core->mac[MRQC]) &&
+    return (core->mac[MRQC] & 3) == E1000_MRQC_ENABLE_RSS_MQ &&
            !igb_rx_csum_enabled(core) &&
            !igb_rx_use_legacy_descriptor(core);
 }
@@ -628,22 +377,47 @@ igb_rss_parse_packet(IGBCore *core, struct NetRxPkt *pkt, E1000E_RSSInfo *info)
 static void
 igb_setup_tx_offloads(IGBCore *core, struct igb_tx *tx)
 {
-    if (tx->props.tse && tx->cptse) {
-        net_tx_pkt_build_vheader(tx->tx_pkt, true, true, tx->props.mss);
+    if (tx->tse) {
+        net_tx_pkt_build_vheader(tx->tx_pkt, true, true, tx->mss);
         net_tx_pkt_update_ip_checksums(tx->tx_pkt);
         e1000x_inc_reg_if_not_full(core->mac, TSCTC);
         return;
     }
 
-    if (tx->sum_needed & E1000_TXD_POPTS_TXSM) {
+    if (tx->txsm) {
         net_tx_pkt_build_vheader(tx->tx_pkt, false, true, 0);
     }
 
-    if (tx->sum_needed & E1000_TXD_POPTS_IXSM) {
+    if (tx->ixsm) {
         net_tx_pkt_update_ip_hdr_checksum(tx->tx_pkt);
     }
 }
 
+/* TX Packets Switching (7.10.3.6) */
+static bool igb_tx_pkt_switch(IGBCore *core, struct igb_tx *tx,
+                              NetClientState *nc)
+{
+    bool ret;
+
+    /* TX switching is only used to serve VM to VM traffic. */
+    if (!pcie_sriov_num_vfs(core->owner)) {
+        goto send_out;
+    }
+
+    /* TX switching requires DTXSWC.Loopback_en bit enabled. */
+    if (!(core->mac[DTXSWC] & E1000_DTXSWC_VMDQ_LOOPBACK_EN)) {
+        goto send_out;
+    }
+
+    ret = net_tx_pkt_send_loopback(tx->tx_pkt, nc);
+    if (!ret) {
+        return ret;
+    }
+
+send_out:
+    return net_tx_pkt_send(tx->tx_pkt, nc);
+}
+
 static bool
 igb_tx_pkt_send(IGBCore *core, struct igb_tx *tx, int queue_index)
 {
@@ -654,11 +428,11 @@ igb_tx_pkt_send(IGBCore *core, struct igb_tx *tx, int queue_index)
 
     net_tx_pkt_dump(tx->tx_pkt);
 
-    if ((core->phy[0][MII_BMCR] & MII_BMCR_LOOPBACK) ||
+    if ((core->phy[MII_BMCR] & MII_BMCR_LOOPBACK) ||
         ((core->mac[RCTL] & E1000_RCTL_LBM_MAC) == E1000_RCTL_LBM_MAC)) {
         return net_tx_pkt_send_loopback(tx->tx_pkt, queue);
     } else {
-        return net_tx_pkt_send(tx->tx_pkt, queue);
+        return igb_tx_pkt_switch(core, tx, queue);
     }
 }
 
@@ -695,99 +469,91 @@ igb_on_tx_done_update_stats(IGBCore *core, struct NetTxPkt *tx_pkt)
 static void
 igb_process_tx_desc(IGBCore *core,
                     struct igb_tx *tx,
-                    struct e1000_tx_desc *dp,
+                    union e1000_adv_tx_desc *tx_desc,
                     int queue_index)
 {
-    uint32_t txd_lower = le32_to_cpu(dp->lower.data);
-    uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D);
-    unsigned int split_size = txd_lower & 0xffff;
-    uint64_t addr;
-    struct e1000_context_desc *xp = (struct e1000_context_desc *)dp;
-    bool eop = txd_lower & E1000_TXD_CMD_EOP;
+    struct e1000_adv_tx_context_desc *tx_ctx_desc;
+    uint32_t cmd_type_len;
+    uint32_t olinfo_status;
+    uint64_t buffer_addr;
+    uint16_t length;
 
-    if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */
-        e1000x_read_tx_ctx_descr(xp, &tx->props);
-        igb_process_snap_option(core, le32_to_cpu(xp->cmd_and_length));
-        return;
-    } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
-        /* data descriptor */
-        tx->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
-        tx->cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
-        igb_process_ts_option(core, dp);
+    cmd_type_len = le32_to_cpu(tx_desc->read.cmd_type_len);
+
+    if (cmd_type_len & E1000_ADVTXD_DCMD_DEXT) {
+        if ((cmd_type_len & E1000_ADVTXD_DTYP_DATA) ==
+            E1000_ADVTXD_DTYP_DATA) {
+            /* advanced transmit data descriptor */
+            if (tx->first) {
+                olinfo_status = le32_to_cpu(tx_desc->read.olinfo_status);
+
+                tx->tse = !!(cmd_type_len & E1000_ADVTXD_DCMD_TSE);
+                tx->ixsm = !!(olinfo_status & E1000_ADVTXD_POTS_IXSM);
+                tx->txsm = !!(olinfo_status & E1000_ADVTXD_POTS_TXSM);
+
+                tx->first = false;
+            }
+        } else if ((cmd_type_len & E1000_ADVTXD_DTYP_CTXT) ==
+                   E1000_ADVTXD_DTYP_CTXT) {
+            /* advanced transmit context descriptor */
+            tx_ctx_desc = (struct e1000_adv_tx_context_desc *)tx_desc;
+            tx->vlan = le32_to_cpu(tx_ctx_desc->vlan_macip_lens) >> 16;
+            tx->mss = le32_to_cpu(tx_ctx_desc->mss_l4len_idx) >> 16;
+            return;
+        } else {
+            /* unknown descriptor type */
+            return;
+        }
     } else {
         /* legacy descriptor */
-        igb_process_ts_option(core, dp);
-        tx->cptse = 0;
+
+        /* TODO: Implement a support for legacy descriptors (7.2.2.1). */
     }
 
-    addr = le64_to_cpu(dp->buffer_addr);
+    buffer_addr = le64_to_cpu(tx_desc->read.buffer_addr);
+    length = cmd_type_len & 0xFFFF;
 
     if (!tx->skip_cp) {
-        if (!net_tx_pkt_add_raw_fragment(tx->tx_pkt, addr, split_size)) {
+        if (!net_tx_pkt_add_raw_fragment(tx->tx_pkt, buffer_addr, length)) {
             tx->skip_cp = true;
         }
     }
 
-    if (eop) {
+    if (cmd_type_len & E1000_TXD_CMD_EOP) {
         if (!tx->skip_cp && net_tx_pkt_parse(tx->tx_pkt)) {
-            if (e1000x_vlan_enabled(core->mac) &&
-                e1000x_is_vlan_txd(txd_lower)) {
-                net_tx_pkt_setup_vlan_header_ex(tx->tx_pkt,
-                    le16_to_cpu(dp->upper.fields.special), core->mac[VET]);
+            if (cmd_type_len & E1000_TXD_CMD_VLE) {
+                net_tx_pkt_setup_vlan_header_ex(tx->tx_pkt, tx->vlan,
+                    core->mac[VET] & 0xffff);
             }
             if (igb_tx_pkt_send(core, tx, queue_index)) {
                 igb_on_tx_done_update_stats(core, tx->tx_pkt);
             }
         }
 
+        tx->first = true;
         tx->skip_cp = false;
         net_tx_pkt_reset(tx->tx_pkt);
-
-        tx->sum_needed = 0;
-        tx->cptse = 0;
     }
 }
 
-static inline uint32_t
-igb_tx_wb_interrupt_cause(IGBCore *core, int queue_idx)
+static uint32_t igb_tx_wb_eic(IGBCore *core, int queue_idx)
 {
-    if (!msix_enabled(core->owner)) {
-        return E1000_ICR_TXDW;
-    }
+    uint32_t n, ent = 0;
 
-    return (queue_idx == 0) ? E1000_ICR_TXQ0 : E1000_ICR_TXQ1;
-}
+    n = igb_ivar_entry_tx(queue_idx);
+    ent = (core->mac[IVAR0 + n / 4] >> (8 * (n % 4))) & 0xff;
 
-static inline uint32_t
-igb_rx_wb_interrupt_cause(IGBCore *core, int queue_idx,
-                             bool min_threshold_hit)
-{
-    if (!msix_enabled(core->owner)) {
-        return E1000_ICS_RXT0 | (min_threshold_hit ? E1000_ICS_RXDMT0 : 0);
-    }
-
-    return (queue_idx == 0) ? E1000_ICR_RXQ0 : E1000_ICR_RXQ1;
+    return (ent & E1000_IVAR_VALID) ? BIT(ent & 0x1f) : 0;
 }
 
-static uint32_t
-igb_txdesc_writeback(IGBCore *core, dma_addr_t base,
-                     struct e1000_tx_desc *dp, bool *ide, int queue_idx)
+static uint32_t igb_rx_wb_eic(IGBCore *core, int queue_idx)
 {
-    uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data);
-
-    if (!(txd_lower & E1000_TXD_CMD_RS) &&
-        !(core->mac[IVAR] & E1000_IVAR_TX_INT_EVERY_WB)) {
-        return 0;
-    }
-
-    *ide = (txd_lower & E1000_TXD_CMD_IDE) ? true : false;
+    uint32_t n, ent = 0;
 
-    txd_upper = le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD;
+    n = igb_ivar_entry_rx(queue_idx);
+    ent = (core->mac[IVAR0 + n / 4] >> (8 * (n % 4))) & 0xff;
 
-    dp->upper.data = cpu_to_le32(txd_upper);
-    pci_dma_write(core->owner, base + ((char *)&dp->upper - (char *)dp),
-                  &dp->upper, sizeof(dp->upper));
-    return igb_tx_wb_interrupt_cause(core, queue_idx);
+    return (ent & E1000_IVAR_VALID) ? BIT(ent & 0x1f) : 0;
 }
 
 typedef struct E1000E_RingInfo_st {
@@ -856,12 +622,6 @@ igb_ring_enabled(IGBCore *core, const E1000E_RingInfo *r)
     return core->mac[r->dlen] > 0;
 }
 
-static inline uint32_t
-igb_ring_len(IGBCore *core, const E1000E_RingInfo *r)
-{
-    return core->mac[r->dlen];
-}
-
 typedef struct IGB_TxRing_st {
     const E1000E_RingInfo *i;
     struct igb_tx *tx;
@@ -870,15 +630,29 @@ typedef struct IGB_TxRing_st {
 static inline int
 igb_mq_queue_idx(int base_reg_idx, int reg_idx)
 {
-    return (reg_idx - base_reg_idx) / (0x100 >> 2);
+    return (reg_idx - base_reg_idx) / 16;
 }
 
 static inline void
 igb_tx_ring_init(IGBCore *core, IGB_TxRing *txr, int idx)
 {
     static const E1000E_RingInfo i[IGB_NUM_QUEUES] = {
-        { TDBAH,  TDBAL,  TDLEN,  TDH,  TDT, 0 },
-        { TDBAH1, TDBAL1, TDLEN1, TDH1, TDT1, 1 }
+        { TDBAH0, TDBAL0, TDLEN0, TDH0, TDT0, 0 },
+        { TDBAH1, TDBAL1, TDLEN1, TDH1, TDT1, 1 },
+        { TDBAH2, TDBAL2, TDLEN2, TDH2, TDT2, 2 },
+        { TDBAH3, TDBAL3, TDLEN3, TDH3, TDT3, 3 },
+        { TDBAH4, TDBAL4, TDLEN4, TDH4, TDT4, 4 },
+        { TDBAH5, TDBAL5, TDLEN5, TDH5, TDT5, 5 },
+        { TDBAH6, TDBAL6, TDLEN6, TDH6, TDT6, 6 },
+        { TDBAH7, TDBAL7, TDLEN7, TDH7, TDT7, 7 },
+        { TDBAH8, TDBAL8, TDLEN8, TDH8, TDT8, 8 },
+        { TDBAH9, TDBAL9, TDLEN9, TDH9, TDT9, 9 },
+        { TDBAH10, TDBAL10, TDLEN10, TDH10, TDT10, 10 },
+        { TDBAH11, TDBAL11, TDLEN11, TDH11, TDT11, 11 },
+        { TDBAH12, TDBAL12, TDLEN12, TDH12, TDT12, 12 },
+        { TDBAH13, TDBAL13, TDLEN13, TDH13, TDT13, 13 },
+        { TDBAH14, TDBAL14, TDLEN14, TDH14, TDT14, 14 },
+        { TDBAH15, TDBAL15, TDLEN15, TDH15, TDT15, 15 }
     };
 
     assert(idx < ARRAY_SIZE(i));
@@ -896,7 +670,21 @@ igb_rx_ring_init(IGBCore *core, E1000E_RxRing *rxr, int idx)
 {
     static const E1000E_RingInfo i[IGB_NUM_QUEUES] = {
         { RDBAH0, RDBAL0, RDLEN0, RDH0, RDT0, 0 },
-        { RDBAH1, RDBAL1, RDLEN1, RDH1, RDT1, 1 }
+        { RDBAH1, RDBAL1, RDLEN1, RDH1, RDT1, 1 },
+        { RDBAH2, RDBAL2, RDLEN2, RDH2, RDT2, 2 },
+        { RDBAH3, RDBAL3, RDLEN3, RDH3, RDT3, 3 },
+        { RDBAH4, RDBAL4, RDLEN4, RDH4, RDT4, 4 },
+        { RDBAH5, RDBAL5, RDLEN5, RDH5, RDT5, 5 },
+        { RDBAH6, RDBAL6, RDLEN6, RDH6, RDT6, 6 },
+        { RDBAH7, RDBAL7, RDLEN7, RDH7, RDT7, 7 },
+        { RDBAH8, RDBAL8, RDLEN8, RDH8, RDT8, 8 },
+        { RDBAH9, RDBAL9, RDLEN9, RDH9, RDT9, 9 },
+        { RDBAH10, RDBAL10, RDLEN10, RDH10, RDT10, 10 },
+        { RDBAH11, RDBAL11, RDLEN11, RDH11, RDT11, 11 },
+        { RDBAH12, RDBAL12, RDLEN12, RDH12, RDT12, 12 },
+        { RDBAH13, RDBAL13, RDLEN13, RDH13, RDT13, 13 },
+        { RDBAH14, RDBAL14, RDLEN14, RDH14, RDT14, 14 },
+        { RDBAH15, RDBAL15, RDLEN15, RDH15, RDT15, 15 }
     };
 
     assert(idx < ARRAY_SIZE(i));
@@ -904,15 +692,44 @@ igb_rx_ring_init(IGBCore *core, E1000E_RxRing *rxr, int idx)
     rxr->i      = &i[idx];
 }
 
+static uint32_t
+igb_txdesc_writeback(IGBCore *core, dma_addr_t base,
+                     union e1000_adv_tx_desc *tx_desc,
+                     const E1000E_RingInfo *txi)
+{
+    uint32_t cmd_type_len = le32_to_cpu(tx_desc->read.cmd_type_len);
+    uint64_t tdwba;
+
+    tdwba = core->mac[E1000_TDWBAL(txi->idx) >> 2];
+    tdwba |= (uint64_t)core->mac[E1000_TDWBAH(txi->idx) >> 2] << 32;
+
+    if (!(cmd_type_len & E1000_TXD_CMD_RS)) {
+        return 0;
+    }
+
+    if (tdwba & 1) {
+        uint32_t buffer = cpu_to_le32(core->mac[txi->dh]);
+        pci_dma_write(core->owner, tdwba & ~3, &buffer, sizeof(buffer));
+    } else {
+        uint32_t status = le32_to_cpu(tx_desc->wb.status) | E1000_TXD_STAT_DD;
+
+        tx_desc->wb.status = cpu_to_le32(status);
+        pci_dma_write(core->owner, base + offsetof(union e1000_adv_tx_desc, wb),
+            &tx_desc->wb, sizeof(tx_desc->wb));
+    }
+
+    return igb_tx_wb_eic(core, txi->idx);
+}
+
 static void
 igb_start_xmit(IGBCore *core, const IGB_TxRing *txr)
 {
     dma_addr_t base;
-    struct e1000_tx_desc desc;
-    bool ide = false;
+    union e1000_adv_tx_desc desc;
     const E1000E_RingInfo *txi = txr->i;
-    uint32_t cause = E1000_ICS_TXQE;
+    uint32_t eic = 0;
 
+    /* TODO: check if the queue itself is enabled too. */
     if (!(core->mac[TCTL] & E1000_TCTL_EN)) {
         trace_e1000e_tx_disabled();
         return;
@@ -923,17 +740,17 @@ igb_start_xmit(IGBCore *core, const IGB_TxRing *txr)
 
         pci_dma_read(core->owner, base, &desc, sizeof(desc));
 
-        trace_e1000e_tx_descr((void *)(intptr_t)desc.buffer_addr,
-                              desc.lower.data, desc.upper.data);
+        trace_e1000e_tx_descr((void *)(intptr_t)desc.read.buffer_addr,
+                              desc.read.cmd_type_len, desc.wb.status);
 
         igb_process_tx_desc(core, txr->tx, &desc, txi->idx);
-        cause |= igb_txdesc_writeback(core, base, &desc, &ide, txi->idx);
-
         igb_ring_advance(core, txi, 1);
+        eic |= igb_txdesc_writeback(core, base, &desc, txi);
     }
 
-    if (!ide || !igb_intrmgr_delay_tx_causes(core, &cause)) {
-        igb_set_interrupt_cause(core, cause);
+    if (eic) {
+        core->mac[EICR] |= eic;
+        igb_set_interrupt_cause(core, E1000_ICR_TXDW);
     }
 }
 
@@ -1007,49 +824,137 @@ igb_rx_l4_cso_enabled(IGBCore *core)
     return !!(core->mac[RXCSUM] & E1000_RXCSUM_TUOFLD);
 }
 
-static bool
-igb_receive_filter(IGBCore *core, const uint8_t *buf, int size)
+static uint16_t igb_receive_assign(IGBCore *core, const struct eth_header *ehdr,
+                                   E1000E_RSSInfo *rss_info)
 {
-    uint32_t rctl = core->mac[RCTL];
+    static const int ta_shift[] = { 4, 3, 2, 0 };
+    uint32_t f, ra[2], *macp, rctl = core->mac[RCTL];
+    uint16_t queues = 0;
+    bool accepted = false;
+    int i;
 
-    if (e1000x_is_vlan_packet(buf, core->mac[VET]) &&
+    memset(rss_info, 0, sizeof(E1000E_RSSInfo));
+
+    if (e1000x_is_vlan_packet(ehdr->h_dest, core->mac[VET] & 0xffff) &&
         e1000x_vlan_rx_filter_enabled(core->mac)) {
-        uint16_t vid = lduw_be_p(&PKT_GET_VLAN_HDR(buf)->h_tci);
+        uint16_t vid = lduw_be_p(&PKT_GET_VLAN_HDR(ehdr)->h_tci);
         uint32_t vfta =
             ldl_le_p((uint32_t *)(core->mac + VFTA) +
                      ((vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK));
         if ((vfta & (1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK))) == 0) {
             trace_e1000e_rx_flt_vlan_mismatch(vid);
-            return false;
+            return queues;
         } else {
             trace_e1000e_rx_flt_vlan_match(vid);
         }
     }
 
-    switch (net_rx_pkt_get_packet_type(core->rx_pkt)) {
-    case ETH_PKT_UCAST:
-        if (rctl & E1000_RCTL_UPE) {
-            return true; /* promiscuous ucast */
+    if (pcie_sriov_num_vfs(core->owner)) {
+        if (is_broadcast_ether_addr(ehdr->h_dest)) {
+            for (i = 0; i < IGB_MAX_VF_FUNCTIONS; i++) {
+                if (core->mac[VMOLR0 + i] & E1000_VMOLR_BAM) {
+                    queues |= BIT(i);
+                }
+            }
+
+            return queues;
         }
-        break;
 
-    case ETH_PKT_BCAST:
-        if (rctl & E1000_RCTL_BAM) {
-            return true; /* broadcast enabled */
+        for (macp = core->mac + RA; macp < core->mac + RA + 32; macp += 2) {
+            if (!(macp[1] & E1000_RAH_AV)) {
+                continue;
+            }
+            ra[0] = cpu_to_le32(macp[0]);
+            ra[1] = cpu_to_le32(macp[1]);
+            if (!memcmp(ehdr->h_dest, (uint8_t *)ra, ETH_ALEN)) {
+                queues |= (macp[1] & E1000_RAH_POOL_MASK) / E1000_RAH_POOL_1;
+            }
         }
-        break;
 
-    case ETH_PKT_MCAST:
-        if (rctl & E1000_RCTL_MPE) {
-            return true; /* promiscuous mcast */
+        for (macp = core->mac + RA2; macp < core->mac + RA2 + 16; macp += 2) {
+            if (!(macp[1] & E1000_RAH_AV)) {
+                continue;
+            }
+            ra[0] = cpu_to_le32(macp[0]);
+            ra[1] = cpu_to_le32(macp[1]);
+            if (!memcmp(ehdr->h_dest, (uint8_t *)ra, ETH_ALEN)) {
+                queues |= (macp[1] & E1000_RAH_POOL_MASK) / E1000_RAH_POOL_1;
+            }
         }
-        break;
 
-    default:
-        g_assert_not_reached();
+        if (queues) {
+            return queues;
+        }
+
+        macp = core->mac + (is_multicast_ether_addr(ehdr->h_dest) ? MTA : UTA);
+
+        f = ta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
+        f = (((ehdr->h_dest[5] << 8) | ehdr->h_dest[4]) >> f) & 0xfff;
+        if (macp[f >> 5] & (1 << (f & 0x1f))) {
+            for (i = 0; i < IGB_MAX_VF_FUNCTIONS; i++) {
+                if (core->mac[VMOLR0 + i] & E1000_VMOLR_ROMPE) {
+                        queues |= BIT(i);
+                }
+            }
+        }
+
+        if (queues) {
+            return queues;
+        }
+    } else {
+        switch (net_rx_pkt_get_packet_type(core->rx_pkt)) {
+        case ETH_PKT_UCAST:
+            if (rctl & E1000_RCTL_UPE) {
+                accepted = true; /* promiscuous ucast */
+            }
+            break;
+
+        case ETH_PKT_BCAST:
+            if (rctl & E1000_RCTL_BAM) {
+                accepted = true; /* broadcast enabled */
+            }
+            break;
+
+        case ETH_PKT_MCAST:
+            if (rctl & E1000_RCTL_MPE) {
+                accepted = true; /* promiscuous mcast */
+            }
+            break;
+
+        default:
+            g_assert_not_reached();
+        }
+
+        if (!accepted) {
+            accepted = e1000x_rx_group_filter(core->mac, ehdr->h_dest);
+        }
+
+        if (!accepted) {
+            for (macp = core->mac + RA2; macp < core->mac + RA2 + 16; macp += 2) {
+                if (!(macp[1] & E1000_RAH_AV)) {
+                    continue;
+                }
+                ra[0] = cpu_to_le32(macp[0]);
+                ra[1] = cpu_to_le32(macp[1]);
+                if (!memcmp(ehdr->h_dest, (uint8_t *)ra, ETH_ALEN)) {
+                    trace_e1000x_rx_flt_ucast_match((int)(macp - core->mac - RA2) / 2,
+                                                    MAC_ARG(ehdr->h_dest));
+
+                    accepted = true;
+                    break;
+                }
+            }
+        }
+
+        if (accepted) {
+            igb_rss_parse_packet(core, core->rx_pkt, rss_info);
+            queues = BIT(rss_info->queue);
+
+            return queues;
+        }
     }
 
-    return e1000x_rx_group_filter(core->mac, buf);
+    return queues;
 }
 
 static inline void
@@ -1060,41 +965,20 @@ igb_read_lgcy_rx_descr(IGBCore *core, struct e1000_rx_desc *desc,
 }
 
 static inline void
-igb_read_ext_rx_descr(IGBCore *core, union e1000_rx_desc_extended *desc,
+igb_read_adv_rx_descr(IGBCore *core, union e1000_adv_rx_desc *desc,
                       hwaddr *buff_addr)
 {
-    *buff_addr = le64_to_cpu(desc->read.buffer_addr);
-}
-
-static inline void
-igb_read_ps_rx_descr(IGBCore *core,
-                     union e1000_rx_desc_packet_split *desc,
-                     hwaddr buff_addr[MAX_PS_BUFFERS])
-{
-    int i;
-
-    for (i = 0; i < MAX_PS_BUFFERS; i++) {
-        buff_addr[i] = le64_to_cpu(desc->read.buffer_addr[i]);
-    }
-
-    trace_e1000e_rx_desc_ps_read(buff_addr[0], buff_addr[1],
-                                 buff_addr[2], buff_addr[3]);
+    *buff_addr = le64_to_cpu(desc->read.pkt_addr);
 }
 
 static inline void
 igb_read_rx_descr(IGBCore *core, union e1000_rx_desc_union *desc,
-                  hwaddr buff_addr[MAX_PS_BUFFERS])
+                  hwaddr *buff_addr)
 {
     if (igb_rx_use_legacy_descriptor(core)) {
-        igb_read_lgcy_rx_descr(core, &desc->legacy, &buff_addr[0]);
-        buff_addr[1] = buff_addr[2] = buff_addr[3] = 0;
+        igb_read_lgcy_rx_descr(core, &desc->legacy, buff_addr);
     } else {
-        if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) {
-            igb_read_ps_rx_descr(core, &desc->packet_split, buff_addr);
-        } else {
-            igb_read_ext_rx_descr(core, &desc->extended, &buff_addr[0]);
-            buff_addr[1] = buff_addr[2] = buff_addr[3] = 0;
-        }
+        igb_read_adv_rx_descr(core, &desc->adv, buff_addr);
     }
 }
 
@@ -1140,26 +1024,13 @@ igb_verify_csum_in_sw(IGBCore *core,
     }
 }
 
-static inline bool
-igb_is_tcp_ack(IGBCore *core, struct NetRxPkt *rx_pkt)
-{
-    if (!net_rx_pkt_is_tcp_ack(rx_pkt)) {
-        return false;
-    }
-
-    if (core->mac[RFCTL] & E1000_RFCTL_ACK_DATA_DIS) {
-        return !net_rx_pkt_has_tcp_data(rx_pkt);
-    }
-
-    return true;
-}
-
 static void
 igb_build_rx_metadata(IGBCore *core,
                       struct NetRxPkt *pkt,
                       bool is_eop,
                       const E1000E_RSSInfo *rss_info,
-                      uint32_t *rss, uint32_t *mrq,
+                      uint16_t *pkt_info, uint16_t *hdr_info,
+                      uint32_t *rss,
                       uint32_t *status_flags,
                       uint16_t *ip_id,
                       uint16_t *vlan_tag)
@@ -1171,6 +1042,7 @@ igb_build_rx_metadata(IGBCore *core,
     *status_flags = E1000_RXD_STAT_DD;
 
     /* No additional metadata needed for non-EOP descriptors */
+    /* TODO: EOP apply only to status so don't skip whole function. */
     if (!is_eop) {
         goto func_exit;
     }
@@ -1191,8 +1063,7 @@ igb_build_rx_metadata(IGBCore *core,
     if ((core->mac[RXCSUM] & E1000_RXCSUM_PCSD) != 0) {
         if (rss_info->enabled) {
             *rss = cpu_to_le32(rss_info->hash);
-            *mrq = cpu_to_le32(rss_info->type | (rss_info->queue << 8));
-            trace_e1000e_rx_metadata_rss(*rss, *mrq);
+            trace_igb_rx_metadata_rss(*rss);
         }
     } else if (isip4) {
             *status_flags |= E1000_RXD_STAT_IPIDV;
@@ -1200,7 +1071,7 @@ igb_build_rx_metadata(IGBCore *core,
             trace_e1000e_rx_metadata_ip_id(*ip_id);
     }
 
-    if (istcp && igb_is_tcp_ack(core, pkt)) {
+    if (istcp && net_rx_pkt_is_tcp_ack(pkt)) {
         *status_flags |= E1000_RXD_STAT_ACK;
         trace_e1000e_rx_metadata_ack();
     }
@@ -1216,9 +1087,22 @@ igb_build_rx_metadata(IGBCore *core,
         pkt_type = E1000_RXD_PKT_MAC;
     }
 
-    *status_flags |= E1000_RXD_PKT_TYPE(pkt_type);
     trace_e1000e_rx_metadata_pkt_type(pkt_type);
 
+    if (pkt_info) {
+        if (rss_info->enabled) {
+            *pkt_info = rss_info->type;
+        }
+
+        *pkt_info |= (pkt_type << 4);
+    } else {
+        *status_flags |= E1000_RXD_PKT_TYPE(pkt_type);
+    }
+
+    if (hdr_info) {
+        *hdr_info = 0;
+    }
+
     /* RX CSO information */
     if (isip6 && (core->mac[RFCTL] & E1000_RFCTL_IPV6_XSUM_DIS)) {
         trace_e1000e_rx_metadata_ipv6_sum_disabled();
@@ -1268,25 +1152,24 @@ igb_write_lgcy_rx_descr(IGBCore *core, struct e1000_rx_desc *desc,
                         const E1000E_RSSInfo *rss_info,
                         uint16_t length)
 {
-    uint32_t status_flags, rss, mrq;
+    uint32_t status_flags, rss;
     uint16_t ip_id;
 
     assert(!rss_info->enabled);
-
     desc->length = cpu_to_le16(length);
     desc->csum = 0;
 
     igb_build_rx_metadata(core, pkt, pkt != NULL,
-                             rss_info,
-                             &rss, &mrq,
-                             &status_flags, &ip_id,
-                             &desc->special);
+                          rss_info,
+                          NULL, NULL, &rss,
+                          &status_flags, &ip_id,
+                          &desc->special);
     desc->errors = (uint8_t) (le32_to_cpu(status_flags) >> 24);
     desc->status = (uint8_t) le32_to_cpu(status_flags);
 }
 
 static inline void
-igb_write_ext_rx_descr(IGBCore *core, union e1000_rx_desc_extended *desc,
+igb_write_adv_rx_descr(IGBCore *core, union e1000_adv_rx_desc *desc,
                        struct NetRxPkt *pkt,
                        const E1000E_RSSInfo *rss_info,
                        uint16_t length)
@@ -1297,64 +1180,22 @@ igb_write_ext_rx_descr(IGBCore *core, union e1000_rx_desc_extended *desc,
 
     igb_build_rx_metadata(core, pkt, pkt != NULL,
                           rss_info,
+                          &desc->wb.lower.lo_dword.pkt_info,
+                          &desc->wb.lower.lo_dword.hdr_info,
                           &desc->wb.lower.hi_dword.rss,
-                          &desc->wb.lower.mrq,
                           &desc->wb.upper.status_error,
                           &desc->wb.lower.hi_dword.csum_ip.ip_id,
                           &desc->wb.upper.vlan);
 }
 
-static inline void
-igb_write_ps_rx_descr(IGBCore *core,
-                      union e1000_rx_desc_packet_split *desc,
-                      struct NetRxPkt *pkt,
-                      const E1000E_RSSInfo *rss_info,
-                      size_t ps_hdr_len,
-                      uint16_t(*written)[MAX_PS_BUFFERS])
-{
-    int i;
-
-    memset(&desc->wb, 0, sizeof(desc->wb));
-
-    desc->wb.middle.length0 = cpu_to_le16((*written)[0]);
-
-    for (i = 0; i < PS_PAGE_BUFFERS; i++) {
-        desc->wb.upper.length[i] = cpu_to_le16((*written)[i + 1]);
-    }
-
-    igb_build_rx_metadata(core, pkt, pkt != NULL,
-                          rss_info,
-                          &desc->wb.lower.hi_dword.rss,
-                          &desc->wb.lower.mrq,
-                          &desc->wb.middle.status_error,
-                          &desc->wb.lower.hi_dword.csum_ip.ip_id,
-                          &desc->wb.middle.vlan);
-
-    desc->wb.upper.header_status =
-        cpu_to_le16(ps_hdr_len | (ps_hdr_len ? E1000_RXDPS_HDRSTAT_HDRSP : 0));
-
-    trace_e1000e_rx_desc_ps_write((*written)[0], (*written)[1],
-                                  (*written)[2], (*written)[3]);
-}
-
 static inline void
 igb_write_rx_descr(IGBCore *core, union e1000_rx_desc_union *desc,
-struct NetRxPkt *pkt, const E1000E_RSSInfo *rss_info,
-    size_t ps_hdr_len, uint16_t(*written)[MAX_PS_BUFFERS])
+struct NetRxPkt *pkt, const E1000E_RSSInfo *rss_info, uint16_t length)
 {
     if (igb_rx_use_legacy_descriptor(core)) {
-        assert(ps_hdr_len == 0);
-        igb_write_lgcy_rx_descr(core, &desc->legacy, pkt, rss_info,
-                                (*written)[0]);
+        igb_write_lgcy_rx_descr(core, &desc->legacy, pkt, rss_info, length);
     } else {
-        if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) {
-            igb_write_ps_rx_descr(core, &desc->packet_split, pkt, rss_info,
-                                  ps_hdr_len, written);
-        } else {
-            assert(ps_hdr_len == 0);
-            igb_write_ext_rx_descr(core, &desc->extended, pkt, rss_info,
-                                   (*written)[0]);
-        }
+        igb_write_adv_rx_descr(core, &desc->adv, pkt, rss_info, length);
     }
 }
 
@@ -1377,89 +1218,45 @@ igb_pci_dma_write_rx_desc(IGBCore *core, dma_addr_t addr,
             pci_dma_write(dev, addr + offset, &status, sizeof(status));
         }
     } else {
-        if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) {
-            union e1000_rx_desc_packet_split *d = &desc->packet_split;
-            size_t offset = offsetof(union e1000_rx_desc_packet_split,
-                wb.middle.status_error);
-            uint32_t status = d->wb.middle.status_error;
-
-            d->wb.middle.status_error &= ~E1000_RXD_STAT_DD;
-            pci_dma_write(dev, addr, desc, len);
-
-            if (status & E1000_RXD_STAT_DD) {
-                d->wb.middle.status_error = status;
-                pci_dma_write(dev, addr + offset, &status, sizeof(status));
-            }
-        } else {
-            union e1000_rx_desc_extended *d = &desc->extended;
-            size_t offset = offsetof(union e1000_rx_desc_extended,
-                wb.upper.status_error);
-            uint32_t status = d->wb.upper.status_error;
+        union e1000_adv_rx_desc *d = &desc->adv;
+        size_t offset =
+            offsetof(union e1000_adv_rx_desc, wb.upper.status_error);
+        uint32_t status = d->wb.upper.status_error;
 
-            d->wb.upper.status_error &= ~E1000_RXD_STAT_DD;
-            pci_dma_write(dev, addr, desc, len);
+        d->wb.upper.status_error &= ~E1000_RXD_STAT_DD;
+        pci_dma_write(dev, addr, desc, len);
 
-            if (status & E1000_RXD_STAT_DD) {
-                d->wb.upper.status_error = status;
-                pci_dma_write(dev, addr + offset, &status, sizeof(status));
-            }
+        if (status & E1000_RXD_STAT_DD) {
+            d->wb.upper.status_error = status;
+            pci_dma_write(dev, addr + offset, &status, sizeof(status));
         }
     }
 }
 
-typedef struct e1000e_ba_state_st {
-    uint16_t written[MAX_PS_BUFFERS];
-    uint8_t cur_idx;
-} e1000e_ba_state;
-
 static inline void
 igb_write_hdr_to_rx_buffers(IGBCore *core,
-                            hwaddr ba[MAX_PS_BUFFERS],
-                            e1000e_ba_state *bastate,
+                            hwaddr ba,
+                            uint16_t *written,
                             const char *data,
                             dma_addr_t data_len)
 {
-    assert(data_len <= core->rxbuf_sizes[0] - bastate->written[0]);
-
-    pci_dma_write(core->owner, ba[0] + bastate->written[0], data, data_len);
-    bastate->written[0] += data_len;
+    assert(data_len <= core->rx_desc_buf_size - *written);
 
-    bastate->cur_idx = 1;
+    pci_dma_write(core->owner, ba + *written, data, data_len);
+    *written += data_len;
 }
 
 static void
 igb_write_to_rx_buffers(IGBCore *core,
-                        hwaddr ba[MAX_PS_BUFFERS],
-                        e1000e_ba_state *bastate,
+                        hwaddr ba,
+                        uint16_t *written,
                         const char *data,
                         dma_addr_t data_len)
 {
-    while (data_len > 0) {
-        uint32_t cur_buf_len = core->rxbuf_sizes[bastate->cur_idx];
-        uint32_t cur_buf_bytes_left = cur_buf_len -
-                                      bastate->written[bastate->cur_idx];
-        uint32_t bytes_to_write = MIN(data_len, cur_buf_bytes_left);
-
-        trace_e1000e_rx_desc_buff_write(bastate->cur_idx,
-                                        ba[bastate->cur_idx],
-                                        bastate->written[bastate->cur_idx],
-                                        data,
-                                        bytes_to_write);
-
-        pci_dma_write(core->owner,
-            ba[bastate->cur_idx] + bastate->written[bastate->cur_idx],
-            data, bytes_to_write);
-
-        bastate->written[bastate->cur_idx] += bytes_to_write;
-        data += bytes_to_write;
-        data_len -= bytes_to_write;
-
-        if (bastate->written[bastate->cur_idx] == cur_buf_len) {
-            bastate->cur_idx++;
-        }
-
-        assert(bastate->cur_idx < MAX_PS_BUFFERS);
-    }
+    assert(data_len <= core->rx_desc_buf_size - *written);
+    trace_igb_rx_desc_buff_write(ba, *written, data, data_len);
+    pci_dma_write(core->owner, ba + *written, data, data_len);
+    *written += data_len;
 }
 
 static void
@@ -1485,45 +1282,7 @@ static inline bool
 igb_rx_descr_threshold_hit(IGBCore *core, const E1000E_RingInfo *rxi)
 {
     return igb_ring_free_descr_num(core, rxi) ==
-           igb_ring_len(core, rxi) >> core->rxbuf_min_shift;
-}
-
-static bool
-igb_do_ps(IGBCore *core, struct NetRxPkt *pkt, size_t *hdr_len)
-{
-    bool isip4, isip6, isudp, istcp;
-    bool fragment;
-
-    if (!igb_rx_use_ps_descriptor(core)) {
-        return false;
-    }
-
-    net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
-
-    if (isip4) {
-        fragment = net_rx_pkt_get_ip4_info(pkt)->fragment;
-    } else if (isip6) {
-        fragment = net_rx_pkt_get_ip6_info(pkt)->fragment;
-    } else {
-        return false;
-    }
-
-    if (fragment && (core->mac[RFCTL] & E1000_RFCTL_IPFRSP_DIS)) {
-        return false;
-    }
-
-    if (!fragment && (isudp || istcp)) {
-        *hdr_len = net_rx_pkt_get_l5_hdr_offset(pkt);
-    } else {
-        *hdr_len = net_rx_pkt_get_l4_hdr_offset(pkt);
-    }
-
-    if ((*hdr_len > core->rxbuf_sizes[0]) ||
-        (*hdr_len > net_rx_pkt_get_total_len(pkt))) {
-        return false;
-    }
-
-    return true;
+           ((core->mac[E1000_SRRCTL(rxi->idx) >> 2] >> 20) & 31) * 16;
 }
 
 static void
@@ -1542,15 +1301,12 @@ igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
     size_t size = net_rx_pkt_get_total_len(pkt);
     size_t total_size = size + e1000x_fcs_len(core->mac);
     const E1000E_RingInfo *rxi;
-    size_t ps_hdr_len = 0;
-    bool do_ps = igb_do_ps(core, pkt, &ps_hdr_len);
-    bool is_first = true;
 
     rxi = rxr->i;
 
     do {
-        hwaddr ba[MAX_PS_BUFFERS];
-        e1000e_ba_state bastate = { { 0 } };
+        hwaddr ba;
+        uint16_t written = 0;
         bool is_last = false;
 
         desc_size = total_size - desc_offset;
@@ -1569,9 +1325,9 @@ igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
 
         trace_e1000e_rx_descr(rxi->idx, base, core->rx_desc_len);
 
-        igb_read_rx_descr(core, &desc, ba);
+        igb_read_rx_descr(core, &desc, &ba);
 
-        if (ba[0]) {
+        if (ba) {
             if (desc_offset < size) {
                 static const uint32_t fcs_pad;
                 size_t iov_copy;
@@ -1580,41 +1336,11 @@ igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
                     copy_size = core->rx_desc_buf_size;
                 }
 
-                /* For PS mode copy the packet header first */
-                if (do_ps) {
-                    if (is_first) {
-                        size_t ps_hdr_copied = 0;
-                        do {
-                            iov_copy = MIN(ps_hdr_len - ps_hdr_copied,
-                                           iov->iov_len - iov_ofs);
-
-                            igb_write_hdr_to_rx_buffers(core, ba, &bastate,
-                                                      iov->iov_base, iov_copy);
-
-                            copy_size -= iov_copy;
-                            ps_hdr_copied += iov_copy;
-
-                            iov_ofs += iov_copy;
-                            if (iov_ofs == iov->iov_len) {
-                                iov++;
-                                iov_ofs = 0;
-                            }
-                        } while (ps_hdr_copied < ps_hdr_len);
-
-                        is_first = false;
-                    } else {
-                        /* Leave buffer 0 of each descriptor except first */
-                        /* empty as per spec 7.1.5.1                      */
-                        igb_write_hdr_to_rx_buffers(core, ba, &bastate,
-                                                       NULL, 0);
-                    }
-                }
-
                 /* Copy packet payload */
                 while (copy_size) {
                     iov_copy = MIN(copy_size, iov->iov_len - iov_ofs);
 
-                    igb_write_to_rx_buffers(core, ba, &bastate,
+                    igb_write_to_rx_buffers(core, ba, &written,
                                             iov->iov_base + iov_ofs, iov_copy);
 
                     copy_size -= iov_copy;
@@ -1627,7 +1353,7 @@ igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
 
                 if (desc_offset + desc_size >= total_size) {
                     /* Simulate FCS checksum presence in the last descriptor */
-                    igb_write_to_rx_buffers(core, ba, &bastate,
+                    igb_write_to_rx_buffers(core, ba, &written,
                           (const char *) &fcs_pad, e1000x_fcs_len(core->mac));
                 }
             }
@@ -1640,37 +1366,26 @@ igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
         }
 
         igb_write_rx_descr(core, &desc, is_last ? core->rx_pkt : NULL,
-                           rss_info, do_ps ? ps_hdr_len : 0, &bastate.written);
+                           rss_info, written);
         igb_pci_dma_write_rx_desc(core, base, &desc, core->rx_desc_len);
 
-        igb_ring_advance(core, rxi,
-                         core->rx_desc_len / E1000_MIN_RX_DESC_LEN);
+        igb_ring_advance(core, rxi, core->rx_desc_len / E1000_MIN_RX_DESC_LEN);
 
     } while (desc_offset < total_size);
 
     igb_update_rx_stats(core, size, total_size);
 }
 
-static inline void
-igb_rx_fix_l4_csum(IGBCore *core, struct NetRxPkt *pkt)
-{
-    if (net_rx_pkt_has_virt_hdr(pkt)) {
-        struct virtio_net_hdr *vhdr = net_rx_pkt_get_vhdr(pkt);
-
-        if (vhdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
-            net_rx_pkt_fix_l4_csum(pkt);
-        }
-    }
-}
-
 ssize_t
 igb_receive_iov(IGBCore *core, const struct iovec *iov, int iovcnt)
 {
     static const int maximum_ethernet_hdr_len = (ETH_HLEN + 4);
 
-    uint32_t n = 0;
+    uint16_t queues = 0;
+    uint32_t n;
     uint8_t min_buf[ETH_ZLEN];
     struct iovec min_iov;
+    struct eth_header *ehdr;
     uint8_t *filter_buf;
     size_t size, orig_size;
     size_t iov_ofs = 0;
@@ -1678,7 +1393,7 @@ igb_receive_iov(IGBCore *core, const struct iovec *iov, int iovcnt)
     E1000E_RSSInfo rss_info;
     size_t total_size;
     ssize_t retval;
-    bool rdmts_hit;
+    int i;
 
     trace_e1000e_rx_receive_iov(iovcnt);
 
@@ -1717,61 +1432,66 @@ igb_receive_iov(IGBCore *core, const struct iovec *iov, int iovcnt)
         return orig_size;
     }
 
-    net_rx_pkt_set_packet_type(core->rx_pkt,
-        get_eth_packet_type(PKT_GET_ETH_HDR(filter_buf)));
+    ehdr = PKT_GET_ETH_HDR(filter_buf);
+    net_rx_pkt_set_packet_type(core->rx_pkt, get_eth_packet_type(ehdr));
 
-    if (!igb_receive_filter(core, filter_buf, size)) {
+    net_rx_pkt_attach_iovec_ex(core->rx_pkt, iov, iovcnt, iov_ofs,
+                               e1000x_vlan_enabled(core->mac),
+                               core->mac[VET] & 0xffff);
+
+    queues = igb_receive_assign(core, ehdr, &rss_info);
+    if (!queues) {
         trace_e1000e_rx_flt_dropped();
         return orig_size;
     }
 
-    net_rx_pkt_attach_iovec_ex(core->rx_pkt, iov, iovcnt, iov_ofs,
-                               e1000x_vlan_enabled(core->mac), core->mac[VET]);
-
-    igb_rss_parse_packet(core, core->rx_pkt, &rss_info);
-    igb_rx_ring_init(core, &rxr, rss_info.queue);
-
-    trace_e1000e_rx_rss_dispatched_to_queue(rxr.i->idx);
-
     total_size = net_rx_pkt_get_total_len(core->rx_pkt) +
         e1000x_fcs_len(core->mac);
 
-    if (igb_has_rxbufs(core, rxr.i, total_size)) {
-        igb_rx_fix_l4_csum(core, core->rx_pkt);
+    retval = orig_size;
 
-        igb_write_packet_to_guest(core, core->rx_pkt, &rxr, &rss_info);
+    for (i = 0; i < IGB_NUM_QUEUES; i++) {
+        if (!(queues & BIT(i))) {
+            continue;
+        }
 
-        retval = orig_size;
+        igb_rx_ring_init(core, &rxr, i);
 
-        /* Perform small receive detection (RSRPD) */
-        if (total_size < core->mac[RSRPD]) {
-            n |= E1000_ICS_SRPD;
-        }
+        trace_e1000e_rx_rss_dispatched_to_queue(rxr.i->idx);
 
-        /* Perform ACK receive detection */
-        if  (!(core->mac[RFCTL] & E1000_RFCTL_ACK_DIS) &&
-             (igb_is_tcp_ack(core, core->rx_pkt))) {
-            n |= E1000_ICS_ACK;
+        if (!igb_has_rxbufs(core, rxr.i, total_size)) {
+            retval = 0;
         }
+    }
+
+    if (retval) {
+        n = E1000_ICR_RXT0;
+
+        for (i = 0; i < IGB_NUM_QUEUES; i++) {
+            if (!(queues & BIT(i))) {
+                continue;
+            }
+
+            igb_rx_ring_init(core, &rxr, i);
 
-        /* Check if receive descriptor minimum threshold hit */
-        rdmts_hit = igb_rx_descr_threshold_hit(core, rxr.i);
-        n |= igb_rx_wb_interrupt_cause(core, rxr.i->idx, rdmts_hit);
+            igb_write_packet_to_guest(core, core->rx_pkt, &rxr, &rss_info);
+
+            /* Check if receive descriptor minimum threshold hit */
+            if (igb_rx_descr_threshold_hit(core, rxr.i)) {
+                n |= E1000_ICS_RXDMT0;
+            }
+
+            core->mac[EICR] |= igb_rx_wb_eic(core, rxr.i->idx);
+        }
 
         trace_e1000e_rx_written_to_guest(n);
     } else {
-        n |= E1000_ICS_RXO;
-        retval = 0;
-
+        n = E1000_ICS_RXO;
         trace_e1000e_rx_not_written_to_guest(n);
     }
 
-    if (!igb_intrmgr_delay_rx_causes(core, &n)) {
-        trace_e1000e_rx_interrupt_set(n);
-        igb_set_interrupt_cause(core, n);
-    } else {
-        trace_e1000e_rx_interrupt_delayed(n);
-    }
+    trace_e1000e_rx_interrupt_set(n);
+    igb_set_interrupt_cause(core, n);
 
     return retval;
 }
@@ -1779,13 +1499,12 @@ igb_receive_iov(IGBCore *core, const struct iovec *iov, int iovcnt)
 static inline bool
 igb_have_autoneg(IGBCore *core)
 {
-    return core->phy[0][MII_BMCR] & MII_BMCR_AUTOEN;
+    return core->phy[MII_BMCR] & MII_BMCR_AUTOEN;
 }
 
 static void igb_update_flowctl_status(IGBCore *core)
 {
-    if (igb_have_autoneg(core) &&
-        core->phy[0][MII_BMSR] & MII_BMSR_AN_COMP) {
+    if (igb_have_autoneg(core) && core->phy[MII_BMSR] & MII_BMSR_AN_COMP) {
         trace_e1000e_link_autoneg_flowctl(true);
         core->mac[CTRL] |= E1000_CTRL_TFCE | E1000_CTRL_RFCE;
     } else {
@@ -1796,42 +1515,22 @@ static void igb_update_flowctl_status(IGBCore *core)
 static inline void
 igb_link_down(IGBCore *core)
 {
-    e1000x_update_regs_on_link_down(core->mac, core->phy[0]);
+    e1000x_update_regs_on_link_down(core->mac, core->phy);
     igb_update_flowctl_status(core);
 }
 
 static inline void
-igb_set_phy_ctrl(IGBCore *core, int index, uint16_t val)
+igb_set_phy_ctrl(IGBCore *core, uint16_t val)
 {
     /* bits 0-5 reserved; MII_BMCR_[ANRESTART,RESET] are self clearing */
-    core->phy[0][MII_BMCR] = val & ~(0x3f |
-                                     MII_BMCR_RESET |
-                                     MII_BMCR_ANRESTART);
+    core->phy[MII_BMCR] = val & ~(0x3f | MII_BMCR_RESET | MII_BMCR_ANRESTART);
 
-    if ((val & MII_BMCR_ANRESTART) &&
-        igb_have_autoneg(core)) {
-        e1000x_restart_autoneg(core->mac, core->phy[0], core->autoneg_timer);
+    if ((val & MII_BMCR_ANRESTART) && igb_have_autoneg(core)) {
+        e1000x_restart_autoneg(core->mac, core->phy, core->autoneg_timer);
     }
 }
 
-static void
-igb_set_phy_oem_bits(IGBCore *core, int index, uint16_t val)
-{
-    core->phy[0][PHY_OEM_BITS] = val & ~BIT(10);
-
-    if (val & BIT(10)) {
-        e1000x_restart_autoneg(core->mac, core->phy[0], core->autoneg_timer);
-    }
-}
-
-static void
-igb_set_phy_page(IGBCore *core, int index, uint16_t val)
-{
-    core->phy[0][PHY_PAGE] = val & PHY_PAGE_RW_MASK;
-}
-
-void
-igb_core_set_link_status(IGBCore *core)
+void igb_core_set_link_status(IGBCore *core)
 {
     NetClientState *nc = qemu_get_queue(core->owner_nic);
     uint32_t old_status = core->mac[STATUS];
@@ -1839,14 +1538,14 @@ igb_core_set_link_status(IGBCore *core)
     trace_e1000e_link_status_changed(nc->link_down ? false : true);
 
     if (nc->link_down) {
-        e1000x_update_regs_on_link_down(core->mac, core->phy[0]);
+        e1000x_update_regs_on_link_down(core->mac, core->phy);
     } else {
         if (igb_have_autoneg(core) &&
-            !(core->phy[0][MII_BMSR] & MII_BMSR_AN_COMP)) {
-            e1000x_restart_autoneg(core->mac, core->phy[0],
+            !(core->phy[MII_BMSR] & MII_BMSR_AN_COMP)) {
+            e1000x_restart_autoneg(core->mac, core->phy,
                                    core->autoneg_timer);
         } else {
-            e1000x_update_regs_on_link_up(core->mac, core->phy[0]);
+            e1000x_update_regs_on_link_up(core->mac, core->phy);
             igb_start_recv(core);
         }
     }
@@ -1904,49 +1603,19 @@ igb_set_rfctl(IGBCore *core, int index, uint32_t val)
     core->mac[RFCTL] = val;
 }
 
-static void
-igb_calc_per_desc_buf_size(IGBCore *core)
-{
-    int i;
-    core->rx_desc_buf_size = 0;
-
-    for (i = 0; i < ARRAY_SIZE(core->rxbuf_sizes); i++) {
-        core->rx_desc_buf_size += core->rxbuf_sizes[i];
-    }
-}
-
 static void
 igb_parse_rxbufsize(IGBCore *core)
 {
     uint32_t rctl = core->mac[RCTL];
 
-    memset(core->rxbuf_sizes, 0, sizeof(core->rxbuf_sizes));
-
-    if (rctl & E1000_RCTL_DTYP_MASK) {
-        uint32_t bsize;
-
-        bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE0_MASK;
-        core->rxbuf_sizes[0] = (bsize >> E1000_PSRCTL_BSIZE0_SHIFT) * 128;
-
-        bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE1_MASK;
-        core->rxbuf_sizes[1] = (bsize >> E1000_PSRCTL_BSIZE1_SHIFT) * 1024;
-
-        bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE2_MASK;
-        core->rxbuf_sizes[2] = (bsize >> E1000_PSRCTL_BSIZE2_SHIFT) * 1024;
-
-        bsize = core->mac[PSRCTL] & E1000_PSRCTL_BSIZE3_MASK;
-        core->rxbuf_sizes[3] = (bsize >> E1000_PSRCTL_BSIZE3_SHIFT) * 1024;
-    } else if (rctl & E1000_RCTL_FLXBUF_MASK) {
+    if (rctl & E1000_RCTL_FLXBUF_MASK) {
         int flxbuf = rctl & E1000_RCTL_FLXBUF_MASK;
-        core->rxbuf_sizes[0] = (flxbuf >> E1000_RCTL_FLXBUF_SHIFT) * 1024;
+        core->rx_desc_buf_size = (flxbuf >> E1000_RCTL_FLXBUF_SHIFT) * 1024;
     } else {
-        core->rxbuf_sizes[0] = e1000x_rxbufsize(rctl);
+        core->rx_desc_buf_size = e1000x_rxbufsize(rctl);
     }
 
-    trace_e1000e_rx_desc_buff_sizes(core->rxbuf_sizes[0], core->rxbuf_sizes[1],
-                                    core->rxbuf_sizes[2], core->rxbuf_sizes[3]);
-
-    igb_calc_per_desc_buf_size(core);
+    trace_igb_rx_desc_buff_size(core->rx_desc_buf_size);
 }
 
 static void
@@ -1955,11 +1624,7 @@ igb_calc_rxdesclen(IGBCore *core)
     if (igb_rx_use_legacy_descriptor(core)) {
         core->rx_desc_len = sizeof(struct e1000_rx_desc);
     } else {
-        if (core->mac[RCTL] & E1000_RCTL_DTYP_PS) {
-            core->rx_desc_len = sizeof(union e1000_rx_desc_packet_split);
-        } else {
-            core->rx_desc_len = sizeof(union e1000_rx_desc_extended);
-        }
+        core->rx_desc_len = sizeof(union e1000_adv_rx_desc);
     }
     trace_e1000e_rx_desc_len(core->rx_desc_len);
 }
@@ -1970,26 +1635,18 @@ igb_set_rx_control(IGBCore *core, int index, uint32_t val)
     core->mac[RCTL] = val;
     trace_e1000e_rx_set_rctl(core->mac[RCTL]);
 
+    if (val & E1000_RCTL_DTYP_MASK) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "igb: RCTL.DTYP must be zero for compatibility");
+    }
+
     if (val & E1000_RCTL_EN) {
         igb_parse_rxbufsize(core);
         igb_calc_rxdesclen(core);
-        core->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1 +
-                                E1000_RING_DESC_LEN_SHIFT;
-
         igb_start_recv(core);
     }
 }
 
-static
-void(*igb_phyreg_writeops[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE])
-(IGBCore *, int, uint16_t) = {
-    [0] = {
-        [MII_BMCR]     = igb_set_phy_ctrl,
-        [PHY_PAGE]     = igb_set_phy_page,
-        [PHY_OEM_BITS] = igb_set_phy_oem_bits
-    }
-};
-
 static inline void
 igb_clear_ims_bits(IGBCore *core, uint32_t bits)
 {
@@ -2014,220 +1671,372 @@ igb_postpone_interrupt(IGBIntrDelayTimer *timer)
 }
 
 static inline bool
-igb_itr_should_postpone(IGBCore *core)
+igb_eitr_should_postpone(IGBCore *core, int idx)
+{
+    return igb_postpone_interrupt(&core->eitr[idx]);
+}
+
+static void igb_send_msix(IGBCore *core)
+{
+    uint32_t causes = core->mac[EICR] & core->mac[EIMS];
+    uint32_t effective_eiac;
+    int vector;
+
+    for (vector = 0; vector < IGB_MSIX_VEC_NUM; ++vector) {
+        if ((causes & BIT(vector)) && !igb_eitr_should_postpone(core, vector)) {
+
+            trace_e1000e_irq_msix_notify_vec(vector);
+            igb_msix_notify(core, vector);
+
+            trace_e1000e_irq_icr_clear_eiac(core->mac[EICR], core->mac[EIAC]);
+            effective_eiac = core->mac[EIAC] & BIT(vector);
+            core->mac[EICR] &= ~effective_eiac;
+        }
+    }
+}
+
+static inline void
+igb_fix_icr_asserted(IGBCore *core)
+{
+    core->mac[ICR] &= ~E1000_ICR_ASSERTED;
+    if (core->mac[ICR]) {
+        core->mac[ICR] |= E1000_ICR_ASSERTED;
+    }
+
+    trace_e1000e_irq_fix_icr_asserted(core->mac[ICR]);
+}
+
+static void
+igb_update_interrupt_state(IGBCore *core)
+{
+    uint32_t icr;
+    uint32_t causes;
+    uint32_t int_alloc;
+
+    icr = core->mac[ICR] & core->mac[IMS];
+
+    if (msix_enabled(core->owner)) {
+        if (icr) {
+            causes = 0;
+            if (icr & E1000_ICR_DRSTA) {
+                int_alloc = core->mac[IVAR_MISC] & 0xff;
+                if (int_alloc & E1000_IVAR_VALID) {
+                    causes |= BIT(int_alloc & 0x1f);
+                }
+            }
+            /* Check if other bits (excluding the TCP Timer) are enabled. */
+            if (icr & ~E1000_ICR_DRSTA) {
+                int_alloc = (core->mac[IVAR_MISC] >> 8) & 0xff;
+                if (int_alloc & E1000_IVAR_VALID) {
+                    causes |= BIT(int_alloc & 0x1f);
+                }
+                trace_e1000e_irq_add_msi_other(core->mac[EICR]);
+            }
+            core->mac[EICR] |= causes;
+        }
+
+        if ((core->mac[EICR] & core->mac[EIMS])) {
+            igb_send_msix(core);
+        }
+    } else {
+        igb_fix_icr_asserted(core);
+
+        if (icr) {
+            core->mac[EICR] |= (icr & E1000_ICR_DRSTA) | E1000_EICR_OTHER;
+        } else {
+            core->mac[EICR] &= ~E1000_EICR_OTHER;
+        }
+
+        trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS],
+                                            core->mac[ICR], core->mac[IMS]);
+
+        if (msi_enabled(core->owner)) {
+            if (icr) {
+                msi_notify(core->owner, 0);
+            }
+        } else {
+            if (icr) {
+                igb_raise_legacy_irq(core);
+            } else {
+                igb_lower_legacy_irq(core);
+            }
+        }
+    }
+}
+
+static void
+igb_set_interrupt_cause(IGBCore *core, uint32_t val)
+{
+    trace_e1000e_irq_set_cause_entry(val, core->mac[ICR]);
+
+    core->mac[ICR] |= val;
+
+    trace_e1000e_irq_set_cause_exit(val, core->mac[ICR]);
+
+    igb_update_interrupt_state(core);
+}
+
+static void igb_set_eics(IGBCore *core, int index, uint32_t val)
+{
+    bool msix = !!(core->mac[GPIE] & E1000_GPIE_MSIX_MODE);
+
+    trace_igb_irq_write_eics(val, msix);
+
+    core->mac[EICS] |=
+        val & (msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK);
+
+    /*
+     * TODO: Move to igb_update_interrupt_state if EICS is modified in other
+     * places.
+     */
+    core->mac[EICR] = core->mac[EICS];
+
+    igb_update_interrupt_state(core);
+}
+
+static void igb_set_eims(IGBCore *core, int index, uint32_t val)
+{
+    bool msix = !!(core->mac[GPIE] & E1000_GPIE_MSIX_MODE);
+
+    trace_igb_irq_write_eims(val, msix);
+
+    core->mac[EIMS] |=
+        val & (msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK);
+
+    igb_update_interrupt_state(core);
+}
+
+static void igb_vf_reset(IGBCore *core, uint16_t vfn)
+{
+    /* TODO: Reset of the queue enable and the interrupt registers of the VF. */
+
+    core->mac[V2PMAILBOX0 + vfn] &= ~E1000_V2PMAILBOX_RSTI;
+    core->mac[V2PMAILBOX0 + vfn] = E1000_V2PMAILBOX_RSTD;
+}
+
+static void mailbox_interrupt_to_vf(IGBCore *core, uint16_t vfn)
 {
-    return igb_postpone_interrupt(&core->itr);
+    uint32_t ent = core->mac[VTIVAR_MISC + vfn];
+
+    if ((ent & E1000_IVAR_VALID)) {
+        core->mac[EICR] |= (ent & 0x3) << (22 - vfn * 3);
+        igb_update_interrupt_state(core);
+    }
 }
 
-static inline bool
-igb_eitr_should_postpone(IGBCore *core, int idx)
+static void mailbox_interrupt_to_pf(IGBCore *core)
 {
-    return igb_postpone_interrupt(&core->eitr[idx]);
+    igb_set_interrupt_cause(core, E1000_ICR_VMMB);
 }
 
-static void
-igb_msix_notify_one(IGBCore *core, uint32_t cause, uint32_t int_cfg)
+static void igb_set_pfmailbox(IGBCore *core, int index, uint32_t val)
 {
-    uint32_t effective_eiac;
+    uint16_t vfn = index - P2VMAILBOX0;
 
-    if (E1000_IVAR_ENTRY_VALID(int_cfg)) {
-        uint32_t vec = E1000_IVAR_ENTRY_VEC(int_cfg);
-        if (vec < IGB_MSIX_VEC_NUM) {
-            if (!igb_eitr_should_postpone(core, vec)) {
-                trace_e1000e_irq_msix_notify_vec(vec);
-                msix_notify(core->owner, vec);
-            }
-        } else {
-            trace_e1000e_wrn_msix_vec_wrong(cause, int_cfg);
-        }
-    } else {
-        trace_e1000e_wrn_msix_invalid(cause, int_cfg);
-    }
+    trace_igb_set_pfmailbox(vfn, val);
 
-    if (core->mac[CTRL_EXT] & E1000_CTRL_EXT_EIAME) {
-        trace_e1000e_irq_iam_clear_eiame(core->mac[IAM], cause);
-        core->mac[IAM] &= ~cause;
+    if (val & E1000_P2VMAILBOX_STS) {
+        core->mac[V2PMAILBOX0 + vfn] |= E1000_V2PMAILBOX_PFSTS;
+        mailbox_interrupt_to_vf(core, vfn);
     }
 
-    trace_e1000e_irq_icr_clear_eiac(core->mac[ICR], core->mac[EIAC]);
-
-    effective_eiac = core->mac[EIAC] & cause;
+    if (val & E1000_P2VMAILBOX_ACK) {
+        core->mac[V2PMAILBOX0 + vfn] |= E1000_V2PMAILBOX_PFACK;
+        mailbox_interrupt_to_vf(core, vfn);
+    }
 
-    core->mac[ICR] &= ~effective_eiac;
-    core->msi_causes_pending &= ~effective_eiac;
+    /* Buffer Taken by PF (can be set only if the VFU is cleared). */
+    if (val & E1000_P2VMAILBOX_PFU) {
+        if (!(core->mac[index] & E1000_P2VMAILBOX_VFU)) {
+            core->mac[index] |= E1000_P2VMAILBOX_PFU;
+            core->mac[V2PMAILBOX0 + vfn] |= E1000_V2PMAILBOX_PFU;
+        }
+    } else {
+        core->mac[index] &= ~E1000_P2VMAILBOX_PFU;
+        core->mac[V2PMAILBOX0 + vfn] &= ~E1000_V2PMAILBOX_PFU;
+    }
 
-    if (!(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
-        core->mac[IMS] &= ~effective_eiac;
+    if (val & E1000_P2VMAILBOX_RVFU) {
+        core->mac[V2PMAILBOX0 + vfn] &= ~E1000_V2PMAILBOX_VFU;
+        core->mac[MBVFICR] &= ~((E1000_MBVFICR_VFACK_VF1 << vfn) |
+                                (E1000_MBVFICR_VFREQ_VF1 << vfn));
     }
 }
 
-static void
-igb_msix_notify(IGBCore *core, uint32_t causes)
+static void igb_set_vfmailbox(IGBCore *core, int index, uint32_t val)
 {
-    if (causes & E1000_ICR_RXQ0) {
-        igb_msix_notify_one(core, E1000_ICR_RXQ0,
-                               E1000_IVAR_RXQ0(core->mac[IVAR]));
-    }
+    uint16_t vfn = index - V2PMAILBOX0;
 
-    if (causes & E1000_ICR_RXQ1) {
-        igb_msix_notify_one(core, E1000_ICR_RXQ1,
-                               E1000_IVAR_RXQ1(core->mac[IVAR]));
-    }
+    trace_igb_set_vfmailbox(vfn, val);
 
-    if (causes & E1000_ICR_TXQ0) {
-        igb_msix_notify_one(core, E1000_ICR_TXQ0,
-                               E1000_IVAR_TXQ0(core->mac[IVAR]));
+    if (val & E1000_V2PMAILBOX_REQ) {
+        core->mac[MBVFICR] |= E1000_MBVFICR_VFREQ_VF1 << vfn;
+        mailbox_interrupt_to_pf(core);
     }
 
-    if (causes & E1000_ICR_TXQ1) {
-        igb_msix_notify_one(core, E1000_ICR_TXQ1,
-                               E1000_IVAR_TXQ1(core->mac[IVAR]));
+    if (val & E1000_V2PMAILBOX_ACK) {
+        core->mac[MBVFICR] |= E1000_MBVFICR_VFACK_VF1 << vfn;
+        mailbox_interrupt_to_pf(core);
     }
 
-    if (causes & E1000_ICR_OTHER) {
-        igb_msix_notify_one(core, E1000_ICR_OTHER,
-                               E1000_IVAR_OTHER(core->mac[IVAR]));
+    /* Buffer Taken by VF (can be set only if the PFU is cleared). */
+    if (val & E1000_V2PMAILBOX_VFU) {
+        if (!(core->mac[index] & E1000_V2PMAILBOX_PFU)) {
+            core->mac[index] |= E1000_V2PMAILBOX_VFU;
+            core->mac[P2VMAILBOX0 + vfn] |= E1000_P2VMAILBOX_VFU;
+        }
+    } else {
+        core->mac[index] &= ~E1000_V2PMAILBOX_VFU;
+        core->mac[P2VMAILBOX0 + vfn] &= ~E1000_P2VMAILBOX_VFU;
     }
 }
 
-static void
-igb_msix_clear_one(IGBCore *core, uint32_t cause, uint32_t int_cfg)
+static void igb_w1c(IGBCore *core, int index, uint32_t val)
 {
-    if (E1000_IVAR_ENTRY_VALID(int_cfg)) {
-        uint32_t vec = E1000_IVAR_ENTRY_VEC(int_cfg);
-        if (vec < IGB_MSIX_VEC_NUM) {
-            trace_e1000e_irq_msix_pending_clearing(cause, int_cfg, vec);
-            msix_clr_pending(core->owner, vec);
-        } else {
-            trace_e1000e_wrn_msix_vec_wrong(cause, int_cfg);
-        }
-    } else {
-        trace_e1000e_wrn_msix_invalid(cause, int_cfg);
-    }
+    core->mac[index] &= ~val;
 }
 
-static void
-igb_msix_clear(IGBCore *core, uint32_t causes)
+static void igb_set_eimc(IGBCore *core, int index, uint32_t val)
 {
-    if (causes & E1000_ICR_RXQ0) {
-        igb_msix_clear_one(core, E1000_ICR_RXQ0,
-                              E1000_IVAR_RXQ0(core->mac[IVAR]));
-    }
+    bool msix = !!(core->mac[GPIE] & E1000_GPIE_MSIX_MODE);
 
-    if (causes & E1000_ICR_RXQ1) {
-        igb_msix_clear_one(core, E1000_ICR_RXQ1,
-                              E1000_IVAR_RXQ1(core->mac[IVAR]));
-    }
+    /* Interrupts are disabled via a write to EIMC and reflected in EIMS. */
+    core->mac[EIMS] &=
+        ~(val & (msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK));
 
-    if (causes & E1000_ICR_TXQ0) {
-        igb_msix_clear_one(core, E1000_ICR_TXQ0,
-                              E1000_IVAR_TXQ0(core->mac[IVAR]));
-    }
+    trace_igb_irq_write_eimc(val, core->mac[EIMS], msix);
+    igb_update_interrupt_state(core);
+}
 
-    if (causes & E1000_ICR_TXQ1) {
-        igb_msix_clear_one(core, E1000_ICR_TXQ1,
-                              E1000_IVAR_TXQ1(core->mac[IVAR]));
-    }
+static void igb_set_eiac(IGBCore *core, int index, uint32_t val)
+{
+    bool msix = !!(core->mac[GPIE] & E1000_GPIE_MSIX_MODE);
+
+    if (msix) {
+        trace_igb_irq_write_eiac(val);
 
-    if (causes & E1000_ICR_OTHER) {
-        igb_msix_clear_one(core, E1000_ICR_OTHER,
-                              E1000_IVAR_OTHER(core->mac[IVAR]));
+        /*
+         * TODO: When using IOV, the bits that correspond to MSI-X vectors
+         * that are assigned to a VF are read-only.
+         */
+        core->mac[EIAC] |= (val & E1000_EICR_MSIX_MASK);
     }
 }
 
-static inline void
-igb_fix_icr_asserted(IGBCore *core)
+static void igb_set_eiam(IGBCore *core, int index, uint32_t val)
 {
-    core->mac[ICR] &= ~E1000_ICR_ASSERTED;
-    if (core->mac[ICR]) {
-        core->mac[ICR] |= E1000_ICR_ASSERTED;
-    }
+    bool msix = !!(core->mac[GPIE] & E1000_GPIE_MSIX_MODE);
 
-    trace_e1000e_irq_fix_icr_asserted(core->mac[ICR]);
+    /*
+     * TODO: When using IOV, the bits that correspond to MSI-X vectors that
+     * are assigned to a VF are read-only.
+     */
+    core->mac[EIAM] |=
+        ~(val & (msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK));
+
+    trace_igb_irq_write_eiam(val, msix);
 }
 
-static void
-igb_send_msi(IGBCore *core, bool msix)
+static void igb_set_eicr(IGBCore *core, int index, uint32_t val)
 {
-    uint32_t causes = core->mac[ICR] & core->mac[IMS] & ~E1000_ICR_ASSERTED;
+    bool msix = !!(core->mac[GPIE] & E1000_GPIE_MSIX_MODE);
 
-    core->msi_causes_pending &= causes;
-    causes ^= core->msi_causes_pending;
-    if (causes == 0) {
-        return;
-    }
-    core->msi_causes_pending |= causes;
+    /*
+     * TODO: In IOV mode, only bit zero of this vector is available for the PF
+     * function.
+     */
+    core->mac[EICR] &=
+        ~(val & (msix ? E1000_EICR_MSIX_MASK : E1000_EICR_LEGACY_MASK));
 
-    if (msix) {
-        igb_msix_notify(core, causes);
-    } else {
-        if (!igb_itr_should_postpone(core)) {
-            trace_e1000e_irq_msi_notify(causes);
-            msi_notify(core->owner, 0);
-        }
-    }
+    trace_igb_irq_write_eicr(val, msix);
+    igb_update_interrupt_state(core);
 }
 
-static void
-igb_update_interrupt_state(IGBCore *core)
+static void igb_set_vtctrl(IGBCore *core, int index, uint32_t val)
 {
-    bool interrupts_pending;
-    bool is_msix = msix_enabled(core->owner);
+    uint16_t vfn;
 
-    /* Set ICR[OTHER] for MSI-X */
-    if (is_msix) {
-        if (core->mac[ICR] & E1000_ICR_OTHER_CAUSES) {
-            core->mac[ICR] |= E1000_ICR_OTHER;
-            trace_e1000e_irq_add_msi_other(core->mac[ICR]);
-        }
+    if (val & E1000_CTRL_RST) {
+        vfn = (index - PVTCTRL0) / 0x40;
+        igb_vf_reset(core, vfn);
     }
+}
 
-    igb_fix_icr_asserted(core);
+static void igb_set_vteics(IGBCore *core, int index, uint32_t val)
+{
+    uint16_t vfn = (index - PVTEICS0) / 0x40;
 
-    /*
-     * Make sure ICR and ICS registers have the same value.
-     * The spec says that the ICS register is write-only.  However in practice,
-     * on real hardware ICS is readable, and for reads it has the same value as
-     * ICR (except that ICS does not have the clear on read behaviour of ICR).
-     *
-     * The VxWorks PRO/1000 driver uses this behaviour.
-     */
-    core->mac[ICS] = core->mac[ICR];
+    core->mac[index] = val;
+    igb_set_eics(core, EICS, (val & 0x7) << (22 - vfn * 3));
+}
 
-    interrupts_pending = (core->mac[IMS] & core->mac[ICR]) ? true : false;
-    if (!interrupts_pending) {
-        core->msi_causes_pending = 0;
-    }
+static void igb_set_vteims(IGBCore *core, int index, uint32_t val)
+{
+    uint16_t vfn = (index - PVTEIMS0) / 0x40;
 
-    trace_e1000e_irq_pending_interrupts(core->mac[ICR] & core->mac[IMS],
-                                        core->mac[ICR], core->mac[IMS]);
+    core->mac[index] = val;
+    igb_set_eims(core, EIMS, (val & 0x7) << (22 - vfn * 3));
+}
 
-    if (is_msix || msi_enabled(core->owner)) {
-        if (interrupts_pending) {
-            igb_send_msi(core, is_msix);
-        }
-    } else {
-        if (interrupts_pending) {
-            if (!igb_itr_should_postpone(core)) {
-                igb_raise_legacy_irq(core);
-            }
-        } else {
-            igb_lower_legacy_irq(core);
-        }
-    }
+static void igb_set_vteimc(IGBCore *core, int index, uint32_t val)
+{
+    uint16_t vfn = (index - PVTEIMC0) / 0x40;
+
+    core->mac[index] = val;
+    igb_set_eimc(core, EIMC, (val & 0x7) << (22 - vfn * 3));
 }
 
-static void
-igb_set_interrupt_cause(IGBCore *core, uint32_t val)
+static void igb_set_vteiac(IGBCore *core, int index, uint32_t val)
 {
-    trace_e1000e_irq_set_cause_entry(val, core->mac[ICR]);
+    uint16_t vfn = (index - PVTEIAC0) / 0x40;
 
-    val |= igb_intmgr_collect_delayed_causes(core);
-    core->mac[ICR] |= val;
+    core->mac[index] = val;
+    igb_set_eiac(core, EIAC, (val & 0x7) << (22 - vfn * 3));
+}
 
-    trace_e1000e_irq_set_cause_exit(val, core->mac[ICR]);
+static void igb_set_vteiam(IGBCore *core, int index, uint32_t val)
+{
+    uint16_t vfn = (index - PVTEIAM0) / 0x40;
 
-    igb_update_interrupt_state(core);
+    core->mac[index] = val;
+    igb_set_eiam(core, EIAM, (val & 0x7) << (22 - vfn * 3));
+}
+
+static void igb_set_vteicr(IGBCore *core, int index, uint32_t val)
+{
+    uint16_t vfn = (index - PVTEICR0) / 0x40;
+
+    core->mac[index] = val;
+    igb_set_eicr(core, EICR, (val & 0x7) << (22 - vfn * 3));
+}
+
+static void igb_set_vtivar(IGBCore *core, int index, uint32_t val)
+{
+    uint16_t vfn = (index - VTIVAR);
+    uint16_t qn = vfn;
+    uint8_t ent;
+    int n;
+
+    core->mac[index] = val;
+
+    /* Get assigned vector associated with queue Rx#0. */
+    if ((val & E1000_IVAR_VALID)) {
+        n = igb_ivar_entry_rx(qn);
+        ent = E1000_IVAR_VALID | (24 - vfn * 3 - (2 - (val & 0x7)));
+        core->mac[IVAR0 + n / 4] |= ent << 8 * (n % 4);
+    }
+
+    /* Get assigned vector associated with queue Tx#0 */
+    ent = val >> 8;
+    if ((ent & E1000_IVAR_VALID)) {
+        n = igb_ivar_entry_tx(qn);
+        ent = E1000_IVAR_VALID | (24 - vfn * 3 - (2 - (ent & 0x7)));
+        core->mac[IVAR0 + n / 4] |= ent << 8 * (n % 4);
+    }
+
+    /*
+     * Ignoring assigned vectors associated with queues Rx#1 and Tx#1 for now.
+     */
 }
 
 static inline void
@@ -2235,7 +2044,7 @@ igb_autoneg_timer(void *opaque)
 {
     IGBCore *core = opaque;
     if (!qemu_get_queue(core->owner_nic)->link_down) {
-        e1000x_update_regs_on_autoneg_done(core->mac, core->phy[0]);
+        e1000x_update_regs_on_autoneg_done(core->mac, core->phy);
         igb_start_recv(core);
 
         igb_update_flowctl_status(core);
@@ -2251,78 +2060,37 @@ igb_get_reg_index_with_offset(const uint16_t *mac_reg_access, hwaddr addr)
     return index + (mac_reg_access[index] & 0xfffe);
 }
 
-static const char igb_phy_regcap[E1000E_PHY_PAGES][0x20] = {
-    [0] = {
-        [MII_BMCR]              = PHY_ANYPAGE | PHY_RW,
-        [MII_BMSR]              = PHY_ANYPAGE | PHY_R,
-        [MII_PHYID1]            = PHY_ANYPAGE | PHY_R,
-        [MII_PHYID2]            = PHY_ANYPAGE | PHY_R,
-        [MII_ANAR]              = PHY_ANYPAGE | PHY_RW,
-        [MII_ANLPAR]            = PHY_ANYPAGE | PHY_R,
-        [MII_ANER]              = PHY_ANYPAGE | PHY_R,
-        [MII_ANNP]              = PHY_ANYPAGE | PHY_RW,
-        [MII_ANLPRNP]           = PHY_ANYPAGE | PHY_R,
-        [MII_CTRL1000]          = PHY_ANYPAGE | PHY_RW,
-        [MII_STAT1000]          = PHY_ANYPAGE | PHY_R,
-        [MII_EXTSTAT]           = PHY_ANYPAGE | PHY_R,
-        [PHY_PAGE]              = PHY_ANYPAGE | PHY_RW,
-
-        [PHY_COPPER_CTRL1]      = PHY_RW,
-        [PHY_COPPER_STAT1]      = PHY_R,
-        [PHY_COPPER_CTRL3]      = PHY_RW,
-        [PHY_RX_ERR_CNTR]       = PHY_R,
-        [PHY_OEM_BITS]          = PHY_RW,
-        [PHY_BIAS_1]            = PHY_RW,
-        [PHY_BIAS_2]            = PHY_RW,
-        [PHY_COPPER_INT_ENABLE] = PHY_RW,
-        [PHY_COPPER_STAT2]      = PHY_R,
-        [PHY_COPPER_CTRL2]      = PHY_RW
-    },
-    [2] = {
-        [PHY_MAC_CTRL1]         = PHY_RW,
-        [PHY_MAC_INT_ENABLE]    = PHY_RW,
-        [PHY_MAC_STAT]          = PHY_R,
-        [PHY_MAC_CTRL2]         = PHY_RW
-    },
-    [3] = {
-        [PHY_LED_03_FUNC_CTRL1] = PHY_RW,
-        [PHY_LED_03_POL_CTRL]   = PHY_RW,
-        [PHY_LED_TIMER_CTRL]    = PHY_RW,
-        [PHY_LED_45_CTRL]       = PHY_RW
-    },
-    [5] = {
-        [PHY_1000T_SKEW]        = PHY_R,
-        [PHY_1000T_SWAP]        = PHY_R
-    },
-    [6] = {
-        [PHY_CRC_COUNTERS]      = PHY_R
-    }
+static const char igb_phy_regcap[MAX_PHY_REG_ADDRESS + 1] = {
+    [MII_BMCR]                   = PHY_RW,
+    [MII_BMSR]                   = PHY_R,
+    [MII_PHYID1]                 = PHY_R,
+    [MII_PHYID2]                 = PHY_R,
+    [MII_ANAR]                   = PHY_RW,
+    [MII_ANLPAR]                 = PHY_R,
+    [MII_ANER]                   = PHY_R,
+    [MII_ANNP]                   = PHY_RW,
+    [MII_ANLPRNP]                = PHY_R,
+    [MII_CTRL1000]               = PHY_RW,
+    [MII_STAT1000]               = PHY_R,
+    [MII_EXTSTAT]                = PHY_R,
+
+    [IGP01E1000_PHY_PORT_CONFIG] = PHY_RW,
+    [IGP01E1000_PHY_PORT_STATUS] = PHY_R,
+    [IGP01E1000_PHY_PORT_CTRL]   = PHY_RW,
+    [IGP01E1000_PHY_LINK_HEALTH] = PHY_R,
+    [IGP02E1000_PHY_POWER_MGMT]  = PHY_RW,
+    [IGP01E1000_PHY_PAGE_SELECT] = PHY_W
 };
 
-static bool
-igb_phy_reg_check_cap(IGBCore *core, uint32_t addr,
-                         char cap, uint8_t *page)
-{
-    *page = (igb_phy_regcap[0][addr] & PHY_ANYPAGE) ? 0
-                                                    : core->phy[0][PHY_PAGE];
-
-    if (*page >= E1000E_PHY_PAGES) {
-        return false;
-    }
-
-    return igb_phy_regcap[*page][addr] & cap;
-}
-
 static void
-igb_phy_reg_write(IGBCore *core, uint8_t page, uint32_t addr, uint16_t data)
+igb_phy_reg_write(IGBCore *core, uint32_t addr, uint16_t data)
 {
-    assert(page < E1000E_PHY_PAGES);
-    assert(addr < E1000E_PHY_PAGE_SIZE);
+    assert(addr <= MAX_PHY_REG_ADDRESS);
 
-    if (igb_phyreg_writeops[page][addr]) {
-        igb_phyreg_writeops[page][addr](core, addr, data);
+    if (addr == MII_BMCR) {
+        igb_set_phy_ctrl(core, data);
     } else {
-        core->phy[page][addr] = data;
+        core->phy[addr] = data;
     }
 }
 
@@ -2331,25 +2099,24 @@ igb_set_mdic(IGBCore *core, int index, uint32_t val)
 {
     uint32_t data = val & E1000_MDIC_DATA_MASK;
     uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
-    uint8_t page;
 
     if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) { /* phy # */
         val = core->mac[MDIC] | E1000_MDIC_ERROR;
     } else if (val & E1000_MDIC_OP_READ) {
-        if (!igb_phy_reg_check_cap(core, addr, PHY_R, &page)) {
-            trace_e1000e_core_mdic_read_unhandled(page, addr);
+        if (!(igb_phy_regcap[addr] & PHY_R)) {
+            trace_igb_core_mdic_read_unhandled(addr);
             val |= E1000_MDIC_ERROR;
         } else {
-            val = (val ^ data) | core->phy[page][addr];
-            trace_e1000e_core_mdic_read(page, addr, val);
+            val = (val ^ data) | core->phy[addr];
+            trace_igb_core_mdic_read(addr, val);
         }
     } else if (val & E1000_MDIC_OP_WRITE) {
-        if (!igb_phy_reg_check_cap(core, addr, PHY_W, &page)) {
-            trace_e1000e_core_mdic_write_unhandled(page, addr);
+        if (!(igb_phy_regcap[addr] & PHY_W)) {
+            trace_igb_core_mdic_write_unhandled(addr);
             val |= E1000_MDIC_ERROR;
         } else {
-            trace_e1000e_core_mdic_write(page, addr, data);
-            igb_phy_reg_write(core, page, addr, data);
+            trace_igb_core_mdic_write(addr, data);
+            igb_phy_reg_write(core, addr, data);
         }
     }
     core->mac[MDIC] = val | E1000_MDIC_READY;
@@ -2381,6 +2148,8 @@ igb_set_ctrlext(IGBCore *core, int index, uint32_t val)
     trace_e1000e_link_set_ext_params(!!(val & E1000_CTRL_EXT_ASDCHK),
                                      !!(val & E1000_CTRL_EXT_SPD_BYPS));
 
+    /* TODO: PFRSTD */
+
     /* Zero self-clearing bits */
     val &= ~(E1000_CTRL_EXT_ASDCHK | E1000_CTRL_EXT_EE_RST);
     core->mac[CTRL_EXT] = val;
@@ -2424,23 +2193,13 @@ igb_set_fcrtl(IGBCore *core, int index, uint32_t val)
     }
 
 IGB_LOW_BITS_SET_FUNC(4)
-IGB_LOW_BITS_SET_FUNC(6)
-IGB_LOW_BITS_SET_FUNC(11)
-IGB_LOW_BITS_SET_FUNC(12)
 IGB_LOW_BITS_SET_FUNC(13)
 IGB_LOW_BITS_SET_FUNC(16)
 
-static void
-igb_set_vet(IGBCore *core, int index, uint32_t val)
-{
-    core->mac[VET] = val & 0xffff;
-    trace_e1000e_vlan_vet(core->mac[VET]);
-}
-
 static void
 igb_set_dlen(IGBCore *core, int index, uint32_t val)
 {
-    core->mac[index] = val & E1000_XDLEN_MASK;
+    core->mac[index] = val & 0xffff0;
 }
 
 static void
@@ -2449,36 +2208,16 @@ igb_set_dbal(IGBCore *core, int index, uint32_t val)
     core->mac[index] = val & E1000_XDBAL_MASK;
 }
 
-static void
-igb_set_tctl(IGBCore *core, int index, uint32_t val)
-{
-    IGB_TxRing txr;
-    core->mac[index] = val;
-
-    if (core->mac[TARC0] & E1000_TARC_ENABLE) {
-        igb_tx_ring_init(core, &txr, 0);
-        igb_start_xmit(core, &txr);
-    }
-
-    if (core->mac[TARC1] & E1000_TARC_ENABLE) {
-        igb_tx_ring_init(core, &txr, 1);
-        igb_start_xmit(core, &txr);
-    }
-}
-
 static void
 igb_set_tdt(IGBCore *core, int index, uint32_t val)
 {
     IGB_TxRing txr;
-    int qidx = igb_mq_queue_idx(TDT, index);
-    uint32_t tarc_reg = (qidx == 0) ? TARC0 : TARC1;
+    int qn = igb_mq_queue_idx(TDT0, index);
 
     core->mac[index] = val & 0xffff;
 
-    if (core->mac[tarc_reg] & E1000_TARC_ENABLE) {
-        igb_tx_ring_init(core, &txr, qidx);
-        igb_start_xmit(core, &txr);
-    }
+    igb_tx_ring_init(core, &txr, qn);
+    igb_start_xmit(core, &txr);
 }
 
 static void
@@ -2488,27 +2227,6 @@ igb_set_ics(IGBCore *core, int index, uint32_t val)
     igb_set_interrupt_cause(core, val);
 }
 
-static void
-igb_set_icr(IGBCore *core, int index, uint32_t val)
-{
-    uint32_t icr = 0;
-    if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
-        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
-        trace_e1000e_irq_icr_process_iame();
-        igb_clear_ims_bits(core, core->mac[IAM]);
-    }
-
-    icr = core->mac[ICR] & ~val;
-    /*
-     * Windows driver expects that the "receive overrun" bit and other
-     * ones to be cleared when the "Other" bit (#24) is cleared.
-     */
-    icr = (val & E1000_ICR_OTHER) ? (icr & ~E1000_ICR_OTHER_CAUSES) : icr;
-    trace_e1000e_irq_icr_write(val, core->mac[ICR], icr);
-    core->mac[ICR] = icr;
-    igb_update_interrupt_state(core);
-}
-
 static void
 igb_set_imc(IGBCore *core, int index, uint32_t val)
 {
@@ -2520,63 +2238,35 @@ igb_set_imc(IGBCore *core, int index, uint32_t val)
 static void
 igb_set_ims(IGBCore *core, int index, uint32_t val)
 {
-    static const uint32_t ims_ext_mask =
-        E1000_IMS_RXQ0 | E1000_IMS_RXQ1 |
-        E1000_IMS_TXQ0 | E1000_IMS_TXQ1 |
-        E1000_IMS_OTHER;
-
-    static const uint32_t ims_valid_mask =
-        E1000_IMS_TXDW      | E1000_IMS_TXQE    | E1000_IMS_LSC  |
-        E1000_IMS_RXDMT0    | E1000_IMS_RXO     | E1000_IMS_RXT0 |
-        E1000_IMS_MDAC      | E1000_IMS_TXD_LOW | E1000_IMS_SRPD |
-        E1000_IMS_ACK       | E1000_IMS_MNG     | E1000_IMS_RXQ0 |
-        E1000_IMS_RXQ1      | E1000_IMS_TXQ0    | E1000_IMS_TXQ1 |
-        E1000_IMS_OTHER;
-
-    uint32_t valid_val = val & ims_valid_mask;
+    uint32_t valid_val = val & 0x77D4FBFD;
 
     trace_e1000e_irq_set_ims(val, core->mac[IMS], core->mac[IMS] | valid_val);
     core->mac[IMS] |= valid_val;
-
-    if ((valid_val & ims_ext_mask) &&
-        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_PBA_CLR) &&
-        msix_enabled(core->owner)) {
-        igb_msix_clear(core, valid_val);
-    }
-
-    if ((valid_val == ims_valid_mask) &&
-        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_INT_TIMERS_CLEAR_ENA)) {
-        trace_e1000e_irq_fire_all_timers(val);
-        igb_intrmgr_fire_all_timers(core);
-    }
-
     igb_update_interrupt_state(core);
 }
 
-static void
-igb_set_rdtr(IGBCore *core, int index, uint32_t val)
+static void igb_commit_icr(IGBCore *core)
 {
-    igb_set_16bit(core, index, val);
-
-    if ((val & E1000_RDTR_FPD) && (core->rdtr.running)) {
-        trace_e1000e_irq_rdtr_fpd_running();
-        igb_intrmgr_fire_delayed_interrupts(core);
+    /*
+     * If GPIE.NSICR = 0, then the copy of IAM to IMS will occur only if at
+     * least one bit is set in the IMS and there is a true interrupt as
+     * reflected in ICR.INTA.
+     */
+    if ((core->mac[GPIE] & E1000_GPIE_NSICR) ||
+        (core->mac[IMS] && (core->mac[ICR] & E1000_ICR_INT_ASSERTED))) {
+        igb_set_ims(core, IMS, core->mac[IAM]);
     } else {
-        trace_e1000e_irq_rdtr_fpd_not_running();
+        igb_update_interrupt_state(core);
     }
 }
 
-static void
-igb_set_tidv(IGBCore *core, int index, uint32_t val)
+static void igb_set_icr(IGBCore *core, int index, uint32_t val)
 {
-    igb_set_16bit(core, index, val);
+    uint32_t icr = core->mac[ICR] & ~val;
 
-    if ((val & E1000_TIDV_FPD) && (core->tidv.running)) {
-        trace_e1000e_irq_tidv_fpd_running();
-        igb_intrmgr_fire_delayed_interrupts(core);
-    } else {
-        trace_e1000e_irq_tidv_fpd_not_running();
-    }
+    trace_igb_irq_icr_write(val, core->mac[ICR], icr);
+    core->mac[ICR] = icr;
+    igb_commit_icr(core);
 }
 
 static uint32_t
@@ -2608,15 +2298,19 @@ igb_mac_swsm_read(IGBCore *core, int index)
 }
 
 static uint32_t
-igb_mac_itr_read(IGBCore *core, int index)
+igb_mac_eitr_read(IGBCore *core, int index)
 {
-    return core->itr_guest_value;
+    return core->eitr_guest_value[index - EITR0];
 }
 
-static uint32_t
-igb_mac_eitr_read(IGBCore *core, int index)
+static uint32_t igb_mac_vfmailbox_read(IGBCore *core, int index)
 {
-    return core->eitr_guest_value[index - EITR];
+    uint32_t val = core->mac[index];
+
+    core->mac[index] &= ~(E1000_V2PMAILBOX_PFSTS | E1000_V2PMAILBOX_PFACK |
+                          E1000_V2PMAILBOX_RSTD);
+
+    return val;
 }
 
 static uint32_t
@@ -2625,26 +2319,19 @@ igb_mac_icr_read(IGBCore *core, int index)
     uint32_t ret = core->mac[ICR];
     trace_e1000e_irq_icr_read_entry(ret);
 
-    if (core->mac[IMS] == 0) {
+    if (core->mac[GPIE] & E1000_GPIE_NSICR) {
+        trace_igb_irq_icr_clear_gpie_nsicr();
+        core->mac[ICR] = 0;
+    } else if (core->mac[IMS] == 0) {
         trace_e1000e_irq_icr_clear_zero_ims();
         core->mac[ICR] = 0;
-    }
-
-    if (!msix_enabled(core->owner)) {
+    } else if (!msix_enabled(core->owner)) {
         trace_e1000e_irq_icr_clear_nonmsix_icr_read();
         core->mac[ICR] = 0;
     }
 
-    if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
-        (core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
-        trace_e1000e_irq_icr_clear_iame();
-        core->mac[ICR] = 0;
-        trace_e1000e_irq_icr_process_iame();
-        igb_clear_ims_bits(core, core->mac[IAM]);
-    }
-
     trace_e1000e_irq_icr_read_exit(core->mac[ICR]);
-    igb_update_interrupt_state(core);
+    igb_commit_icr(core);
     return ret;
 }
 
@@ -2683,14 +2370,10 @@ igb_get_ctrl(IGBCore *core, int index)
     return val;
 }
 
-static uint32_t
-igb_get_status(IGBCore *core, int index)
+static uint32_t igb_get_status(IGBCore *core, int index)
 {
     uint32_t res = core->mac[STATUS];
-
-    if (!(core->mac[CTRL] & E1000_CTRL_GIO_MASTER_DISABLE)) {
-        res |= E1000_STATUS_GIO_MASTER_ENABLE;
-    }
+    uint16_t num_vfs = pcie_sriov_num_vfs(core->owner);
 
     if (core->mac[CTRL] & E1000_CTRL_FRCDPX) {
         res |= (core->mac[CTRL] & E1000_CTRL_FD) ? E1000_STATUS_FD : 0;
@@ -2716,23 +2399,21 @@ igb_get_status(IGBCore *core, int index)
         res |= E1000_STATUS_SPEED_1000;
     }
 
-    trace_e1000e_link_status(
-        !!(res & E1000_STATUS_LU),
-        !!(res & E1000_STATUS_FD),
-        (res & E1000_STATUS_SPEED_MASK) >> E1000_STATUS_SPEED_SHIFT,
-        (res & E1000_STATUS_ASDV) >> E1000_STATUS_ASDV_SHIFT);
+    if (num_vfs) {
+        res |= num_vfs << E1000_STATUS_NUM_VFS_SHIFT;
+        res |= E1000_STATUS_IOV_MODE;
+    }
 
-    return res;
-}
+    /*
+     * Windows driver 12.18.9.23 resets if E1000_STATUS_GIO_MASTER_ENABLE is
+     * left set after E1000_CTRL_LRST is set.
+     */
+    if (!(core->mac[CTRL] & E1000_CTRL_GIO_MASTER_DISABLE) &&
+        !(core->mac[CTRL] & E1000_CTRL_LRST)) {
+        res |= E1000_STATUS_GIO_MASTER_ENABLE;
+    }
 
-static uint32_t
-igb_get_tarc(IGBCore *core, int index)
-{
-    return core->mac[index] & ((BIT(11) - 1) |
-                                BIT(27)      |
-                                BIT(28)      |
-                                BIT(29)      |
-                                BIT(30));
+    return res;
 }
 
 static void
@@ -2783,71 +2464,15 @@ igb_set_eerd(IGBCore *core, int index, uint32_t val)
                       (data << E1000_EERW_DATA_SHIFT);
 }
 
-static void
-igb_set_eewr(IGBCore *core, int index, uint32_t val)
-{
-    uint32_t addr = (val >> E1000_EERW_ADDR_SHIFT) & E1000_EERW_ADDR_MASK;
-    uint32_t data = (val >> E1000_EERW_DATA_SHIFT) & E1000_EERW_DATA_MASK;
-    uint32_t flags = 0;
-
-    if ((addr < IGB_EEPROM_SIZE) && (val & E1000_EERW_START)) {
-        core->eeprom[addr] = data;
-        flags = E1000_EERW_DONE;
-    }
-
-    core->mac[EERD] = flags                           |
-                      (addr << E1000_EERW_ADDR_SHIFT) |
-                      (data << E1000_EERW_DATA_SHIFT);
-}
-
-static void
-igb_set_rxdctl(IGBCore *core, int index, uint32_t val)
-{
-    core->mac[RXDCTL] = core->mac[RXDCTL1] = val;
-}
-
-static void
-igb_set_itr(IGBCore *core, int index, uint32_t val)
-{
-    uint32_t interval = val & 0xffff;
-
-    trace_e1000e_irq_itr_set(val);
-
-    core->itr_guest_value = interval;
-    core->mac[index] = MAX(interval, E1000E_MIN_XITR);
-}
-
 static void
 igb_set_eitr(IGBCore *core, int index, uint32_t val)
 {
-    uint32_t interval = val & 0xffff;
-    uint32_t eitr_num = index - EITR;
-
-    trace_e1000e_irq_eitr_set(eitr_num, val);
-
-    core->eitr_guest_value[eitr_num] = interval;
-    core->mac[index] = MAX(interval, E1000E_MIN_XITR);
-}
-
-static void
-igb_set_psrctl(IGBCore *core, int index, uint32_t val)
-{
-    if (core->mac[RCTL] & E1000_RCTL_DTYP_MASK) {
-
-        if ((val & E1000_PSRCTL_BSIZE0_MASK) == 0) {
-            qemu_log_mask(LOG_GUEST_ERROR,
-                          "igb: PSRCTL.BSIZE0 cannot be zero");
-            return;
-        }
+    uint32_t eitr_num = index - EITR0;
 
-        if ((val & E1000_PSRCTL_BSIZE1_MASK) == 0) {
-            qemu_log_mask(LOG_GUEST_ERROR,
-                          "igb: PSRCTL.BSIZE1 cannot be zero");
-            return;
-        }
-    }
+    trace_igb_irq_eitr_set(eitr_num, val);
 
-    core->mac[PSRCTL] = val;
+    core->eitr_guest_value[eitr_num] = val & ~E1000_EITR_CNT_IGNR;
+    core->mac[index] = val & 0x7FFE;
 }
 
 static void
@@ -2880,26 +2505,97 @@ igb_set_gcr(IGBCore *core, int index, uint32_t val)
 #define igb_getreg(x)    [x] = igb_mac_readreg
 typedef uint32_t (*readops)(IGBCore *, int);
 static const readops igb_macreg_readops[] = {
-    igb_getreg(PBA),
     igb_getreg(WUFC),
     igb_getreg(MANC),
     igb_getreg(TOTL),
     igb_getreg(RDT0),
+    igb_getreg(RDT1),
+    igb_getreg(RDT2),
+    igb_getreg(RDT3),
+    igb_getreg(RDT4),
+    igb_getreg(RDT5),
+    igb_getreg(RDT6),
+    igb_getreg(RDT7),
+    igb_getreg(RDT8),
+    igb_getreg(RDT9),
+    igb_getreg(RDT10),
+    igb_getreg(RDT11),
+    igb_getreg(RDT12),
+    igb_getreg(RDT13),
+    igb_getreg(RDT14),
+    igb_getreg(RDT15),
     igb_getreg(RDBAH0),
+    igb_getreg(RDBAH1),
+    igb_getreg(RDBAH2),
+    igb_getreg(RDBAH3),
+    igb_getreg(RDBAH4),
+    igb_getreg(RDBAH5),
+    igb_getreg(RDBAH6),
+    igb_getreg(RDBAH7),
+    igb_getreg(RDBAH8),
+    igb_getreg(RDBAH9),
+    igb_getreg(RDBAH10),
+    igb_getreg(RDBAH11),
+    igb_getreg(RDBAH12),
+    igb_getreg(RDBAH13),
+    igb_getreg(RDBAH14),
+    igb_getreg(RDBAH15),
+    igb_getreg(TDBAL0),
     igb_getreg(TDBAL1),
+    igb_getreg(TDBAL2),
+    igb_getreg(TDBAL3),
+    igb_getreg(TDBAL4),
+    igb_getreg(TDBAL5),
+    igb_getreg(TDBAL6),
+    igb_getreg(TDBAL7),
+    igb_getreg(TDBAL8),
+    igb_getreg(TDBAL9),
+    igb_getreg(TDBAL10),
+    igb_getreg(TDBAL11),
+    igb_getreg(TDBAL12),
+    igb_getreg(TDBAL13),
+    igb_getreg(TDBAL14),
+    igb_getreg(TDBAL15),
     igb_getreg(RDLEN0),
-    igb_getreg(RDH1),
+    igb_getreg(RDLEN1),
+    igb_getreg(RDLEN2),
+    igb_getreg(RDLEN3),
+    igb_getreg(RDLEN4),
+    igb_getreg(RDLEN5),
+    igb_getreg(RDLEN6),
+    igb_getreg(RDLEN7),
+    igb_getreg(RDLEN8),
+    igb_getreg(RDLEN9),
+    igb_getreg(RDLEN10),
+    igb_getreg(RDLEN11),
+    igb_getreg(RDLEN12),
+    igb_getreg(RDLEN13),
+    igb_getreg(RDLEN14),
+    igb_getreg(RDLEN15),
+    igb_getreg(SRRCTL0),
+    igb_getreg(SRRCTL1),
+    igb_getreg(SRRCTL2),
+    igb_getreg(SRRCTL3),
+    igb_getreg(SRRCTL4),
+    igb_getreg(SRRCTL5),
+    igb_getreg(SRRCTL6),
+    igb_getreg(SRRCTL7),
+    igb_getreg(SRRCTL8),
+    igb_getreg(SRRCTL9),
+    igb_getreg(SRRCTL10),
+    igb_getreg(SRRCTL11),
+    igb_getreg(SRRCTL12),
+    igb_getreg(SRRCTL13),
+    igb_getreg(SRRCTL14),
+    igb_getreg(SRRCTL15),
     igb_getreg(LATECOL),
-    igb_getreg(SEQEC),
     igb_getreg(XONTXC),
-    igb_getreg(AIT),
     igb_getreg(TDFH),
     igb_getreg(TDFT),
     igb_getreg(TDFHS),
     igb_getreg(TDFTS),
     igb_getreg(TDFPC),
     igb_getreg(WUS),
-    igb_getreg(PBS),
     igb_getreg(RDFH),
     igb_getreg(RDFT),
     igb_getreg(RDFHS),
@@ -2909,49 +2605,84 @@ static const readops igb_macreg_readops[] = {
     igb_getreg(MGTPRC),
     igb_getreg(EERD),
     igb_getreg(EIAC),
-    igb_getreg(PSRCTL),
     igb_getreg(MANC2H),
     igb_getreg(RXCSUM),
     igb_getreg(GSCL_3),
     igb_getreg(GSCN_2),
-    igb_getreg(RSRPD),
-    igb_getreg(RDBAL1),
     igb_getreg(FCAH),
     igb_getreg(FCRTH),
     igb_getreg(FLOP),
-    igb_getreg(FLASHT),
     igb_getreg(RXSTMPH),
     igb_getreg(TXSTMPL),
     igb_getreg(TIMADJL),
-    igb_getreg(TXDCTL),
     igb_getreg(RDH0),
+    igb_getreg(RDH1),
+    igb_getreg(RDH2),
+    igb_getreg(RDH3),
+    igb_getreg(RDH4),
+    igb_getreg(RDH5),
+    igb_getreg(RDH6),
+    igb_getreg(RDH7),
+    igb_getreg(RDH8),
+    igb_getreg(RDH9),
+    igb_getreg(RDH10),
+    igb_getreg(RDH11),
+    igb_getreg(RDH12),
+    igb_getreg(RDH13),
+    igb_getreg(RDH14),
+    igb_getreg(RDH15),
+    igb_getreg(TDT0),
     igb_getreg(TDT1),
+    igb_getreg(TDT2),
+    igb_getreg(TDT3),
+    igb_getreg(TDT4),
+    igb_getreg(TDT5),
+    igb_getreg(TDT6),
+    igb_getreg(TDT7),
+    igb_getreg(TDT8),
+    igb_getreg(TDT9),
+    igb_getreg(TDT10),
+    igb_getreg(TDT11),
+    igb_getreg(TDT12),
+    igb_getreg(TDT13),
+    igb_getreg(TDT14),
+    igb_getreg(TDT15),
     igb_getreg(TNCRS),
     igb_getreg(RJC),
     igb_getreg(IAM),
     igb_getreg(GSCL_2),
-    igb_getreg(RDBAH1),
-    igb_getreg(FLSWDATA),
     igb_getreg(RXSATRH),
     igb_getreg(TIPG),
     igb_getreg(FLMNGCTL),
     igb_getreg(FLMNGCNT),
     igb_getreg(TSYNCTXCTL),
-    igb_getreg(EXTCNF_SIZE),
-    igb_getreg(EXTCNF_CTRL),
     igb_getreg(EEMNGDATA),
     igb_getreg(CTRL_EXT),
     igb_getreg(SYSTIMH),
     igb_getreg(EEMNGCTL),
     igb_getreg(FLMNGDATA),
     igb_getreg(TSYNCRXCTL),
-    igb_getreg(TDH),
     igb_getreg(LEDCTL),
     igb_getreg(TCTL),
-    igb_getreg(TDBAL),
-    igb_getreg(TDLEN),
+    igb_getreg(TCTL_EXT),
+    igb_getreg(DTXCTL),
+    igb_getreg(RXPBS),
+    igb_getreg(TDH0),
     igb_getreg(TDH1),
-    igb_getreg(RADV),
+    igb_getreg(TDH2),
+    igb_getreg(TDH3),
+    igb_getreg(TDH4),
+    igb_getreg(TDH5),
+    igb_getreg(TDH6),
+    igb_getreg(TDH7),
+    igb_getreg(TDH8),
+    igb_getreg(TDH9),
+    igb_getreg(TDH10),
+    igb_getreg(TDH11),
+    igb_getreg(TDH12),
+    igb_getreg(TDH13),
+    igb_getreg(TDH14),
+    igb_getreg(TDH15),
     igb_getreg(ECOL),
     igb_getreg(DC),
     igb_getreg(RLEC),
@@ -2960,70 +2691,279 @@ static const readops igb_macreg_readops[] = {
     igb_getreg(RNBC),
     igb_getreg(MGTPTC),
     igb_getreg(TIMINCA),
-    igb_getreg(RXCFGL),
-    igb_getreg(MFUTP01),
     igb_getreg(FACTPS),
     igb_getreg(GSCL_1),
     igb_getreg(GSCN_0),
-    igb_getreg(GCR2),
-    igb_getreg(RDT1),
     igb_getreg(PBACLR),
     igb_getreg(FCTTV),
-    igb_getreg(EEWR),
-    igb_getreg(FLSWCTL),
-    igb_getreg(RXDCTL1),
     igb_getreg(RXSATRL),
     igb_getreg(SYSTIML),
-    igb_getreg(RXUDP),
     igb_getreg(TORL),
+    igb_getreg(TDLEN0),
     igb_getreg(TDLEN1),
+    igb_getreg(TDLEN2),
+    igb_getreg(TDLEN3),
+    igb_getreg(TDLEN4),
+    igb_getreg(TDLEN5),
+    igb_getreg(TDLEN6),
+    igb_getreg(TDLEN7),
+    igb_getreg(TDLEN8),
+    igb_getreg(TDLEN9),
+    igb_getreg(TDLEN10),
+    igb_getreg(TDLEN11),
+    igb_getreg(TDLEN12),
+    igb_getreg(TDLEN13),
+    igb_getreg(TDLEN14),
+    igb_getreg(TDLEN15),
     igb_getreg(MCC),
     igb_getreg(WUC),
     igb_getreg(EECD),
-    igb_getreg(MFUTP23),
-    igb_getreg(RAID),
     igb_getreg(FCRTV),
+    igb_getreg(TXDCTL0),
     igb_getreg(TXDCTL1),
+    igb_getreg(TXDCTL2),
+    igb_getreg(TXDCTL3),
+    igb_getreg(TXDCTL4),
+    igb_getreg(TXDCTL5),
+    igb_getreg(TXDCTL6),
+    igb_getreg(TXDCTL7),
+    igb_getreg(TXDCTL8),
+    igb_getreg(TXDCTL9),
+    igb_getreg(TXDCTL10),
+    igb_getreg(TXDCTL11),
+    igb_getreg(TXDCTL12),
+    igb_getreg(TXDCTL13),
+    igb_getreg(TXDCTL14),
+    igb_getreg(TXDCTL15),
+    igb_getreg(TXCTL0),
+    igb_getreg(TXCTL1),
+    igb_getreg(TXCTL2),
+    igb_getreg(TXCTL3),
+    igb_getreg(TXCTL4),
+    igb_getreg(TXCTL5),
+    igb_getreg(TXCTL6),
+    igb_getreg(TXCTL7),
+    igb_getreg(TXCTL8),
+    igb_getreg(TXCTL9),
+    igb_getreg(TXCTL10),
+    igb_getreg(TXCTL11),
+    igb_getreg(TXCTL12),
+    igb_getreg(TXCTL13),
+    igb_getreg(TXCTL14),
+    igb_getreg(TXCTL15),
+    igb_getreg(TDWBAL0),
+    igb_getreg(TDWBAL1),
+    igb_getreg(TDWBAL2),
+    igb_getreg(TDWBAL3),
+    igb_getreg(TDWBAL4),
+    igb_getreg(TDWBAL5),
+    igb_getreg(TDWBAL6),
+    igb_getreg(TDWBAL7),
+    igb_getreg(TDWBAL8),
+    igb_getreg(TDWBAL9),
+    igb_getreg(TDWBAL10),
+    igb_getreg(TDWBAL11),
+    igb_getreg(TDWBAL12),
+    igb_getreg(TDWBAL13),
+    igb_getreg(TDWBAL14),
+    igb_getreg(TDWBAL15),
+    igb_getreg(TDWBAH0),
+    igb_getreg(TDWBAH1),
+    igb_getreg(TDWBAH2),
+    igb_getreg(TDWBAH3),
+    igb_getreg(TDWBAH4),
+    igb_getreg(TDWBAH5),
+    igb_getreg(TDWBAH6),
+    igb_getreg(TDWBAH7),
+    igb_getreg(TDWBAH8),
+    igb_getreg(TDWBAH9),
+    igb_getreg(TDWBAH10),
+    igb_getreg(TDWBAH11),
+    igb_getreg(TDWBAH12),
+    igb_getreg(TDWBAH13),
+    igb_getreg(TDWBAH14),
+    igb_getreg(TDWBAH15),
+    igb_getreg(PVTCTRL0),
+    igb_getreg(PVTCTRL1),
+    igb_getreg(PVTCTRL2),
+    igb_getreg(PVTCTRL3),
+    igb_getreg(PVTCTRL4),
+    igb_getreg(PVTCTRL5),
+    igb_getreg(PVTCTRL6),
+    igb_getreg(PVTCTRL7),
+    igb_getreg(PVTEIMS0),
+    igb_getreg(PVTEIMS1),
+    igb_getreg(PVTEIMS2),
+    igb_getreg(PVTEIMS3),
+    igb_getreg(PVTEIMS4),
+    igb_getreg(PVTEIMS5),
+    igb_getreg(PVTEIMS6),
+    igb_getreg(PVTEIMS7),
+    igb_getreg(PVTEIAC0),
+    igb_getreg(PVTEIAC1),
+    igb_getreg(PVTEIAC2),
+    igb_getreg(PVTEIAC3),
+    igb_getreg(PVTEIAC4),
+    igb_getreg(PVTEIAC5),
+    igb_getreg(PVTEIAC6),
+    igb_getreg(PVTEIAC7),
+    igb_getreg(PVTEIAM0),
+    igb_getreg(PVTEIAM1),
+    igb_getreg(PVTEIAM2),
+    igb_getreg(PVTEIAM3),
+    igb_getreg(PVTEIAM4),
+    igb_getreg(PVTEIAM5),
+    igb_getreg(PVTEIAM6),
+    igb_getreg(PVTEIAM7),
+    igb_getreg(PVFGPRC0),
+    igb_getreg(PVFGPRC1),
+    igb_getreg(PVFGPRC2),
+    igb_getreg(PVFGPRC3),
+    igb_getreg(PVFGPRC4),
+    igb_getreg(PVFGPRC5),
+    igb_getreg(PVFGPRC6),
+    igb_getreg(PVFGPRC7),
+    igb_getreg(PVFGPTC0),
+    igb_getreg(PVFGPTC1),
+    igb_getreg(PVFGPTC2),
+    igb_getreg(PVFGPTC3),
+    igb_getreg(PVFGPTC4),
+    igb_getreg(PVFGPTC5),
+    igb_getreg(PVFGPTC6),
+    igb_getreg(PVFGPTC7),
+    igb_getreg(PVFGORC0),
+    igb_getreg(PVFGORC1),
+    igb_getreg(PVFGORC2),
+    igb_getreg(PVFGORC3),
+    igb_getreg(PVFGORC4),
+    igb_getreg(PVFGORC5),
+    igb_getreg(PVFGORC6),
+    igb_getreg(PVFGORC7),
+    igb_getreg(PVFGOTC0),
+    igb_getreg(PVFGOTC1),
+    igb_getreg(PVFGOTC2),
+    igb_getreg(PVFGOTC3),
+    igb_getreg(PVFGOTC4),
+    igb_getreg(PVFGOTC5),
+    igb_getreg(PVFGOTC6),
+    igb_getreg(PVFGOTC7),
+    igb_getreg(PVFMPRC0),
+    igb_getreg(PVFMPRC1),
+    igb_getreg(PVFMPRC2),
+    igb_getreg(PVFMPRC3),
+    igb_getreg(PVFMPRC4),
+    igb_getreg(PVFMPRC5),
+    igb_getreg(PVFMPRC6),
+    igb_getreg(PVFMPRC7),
+    igb_getreg(PVFGPRLBC0),
+    igb_getreg(PVFGPRLBC1),
+    igb_getreg(PVFGPRLBC2),
+    igb_getreg(PVFGPRLBC3),
+    igb_getreg(PVFGPRLBC4),
+    igb_getreg(PVFGPRLBC5),
+    igb_getreg(PVFGPRLBC6),
+    igb_getreg(PVFGPRLBC7),
+    igb_getreg(PVFGPTLBC0),
+    igb_getreg(PVFGPTLBC1),
+    igb_getreg(PVFGPTLBC2),
+    igb_getreg(PVFGPTLBC3),
+    igb_getreg(PVFGPTLBC4),
+    igb_getreg(PVFGPTLBC5),
+    igb_getreg(PVFGPTLBC6),
+    igb_getreg(PVFGPTLBC7),
+    igb_getreg(PVFGORLBC0),
+    igb_getreg(PVFGORLBC1),
+    igb_getreg(PVFGORLBC2),
+    igb_getreg(PVFGORLBC3),
+    igb_getreg(PVFGORLBC4),
+    igb_getreg(PVFGORLBC5),
+    igb_getreg(PVFGORLBC6),
+    igb_getreg(PVFGORLBC7),
+    igb_getreg(PVFGOTLBC0),
+    igb_getreg(PVFGOTLBC1),
+    igb_getreg(PVFGOTLBC2),
+    igb_getreg(PVFGOTLBC3),
+    igb_getreg(PVFGOTLBC4),
+    igb_getreg(PVFGOTLBC5),
+    igb_getreg(PVFGOTLBC6),
+    igb_getreg(PVFGOTLBC7),
     igb_getreg(RCTL),
-    igb_getreg(TDT),
     igb_getreg(MDIC),
     igb_getreg(FCRUC),
     igb_getreg(VET),
     igb_getreg(RDBAL0),
+    igb_getreg(RDBAL1),
+    igb_getreg(RDBAL2),
+    igb_getreg(RDBAL3),
+    igb_getreg(RDBAL4),
+    igb_getreg(RDBAL5),
+    igb_getreg(RDBAL6),
+    igb_getreg(RDBAL7),
+    igb_getreg(RDBAL8),
+    igb_getreg(RDBAL9),
+    igb_getreg(RDBAL10),
+    igb_getreg(RDBAL11),
+    igb_getreg(RDBAL12),
+    igb_getreg(RDBAL13),
+    igb_getreg(RDBAL14),
+    igb_getreg(RDBAL15),
+    igb_getreg(TDBAH0),
     igb_getreg(TDBAH1),
-    igb_getreg(RDTR),
+    igb_getreg(TDBAH2),
+    igb_getreg(TDBAH3),
+    igb_getreg(TDBAH4),
+    igb_getreg(TDBAH5),
+    igb_getreg(TDBAH6),
+    igb_getreg(TDBAH7),
+    igb_getreg(TDBAH8),
+    igb_getreg(TDBAH9),
+    igb_getreg(TDBAH10),
+    igb_getreg(TDBAH11),
+    igb_getreg(TDBAH12),
+    igb_getreg(TDBAH13),
+    igb_getreg(TDBAH14),
+    igb_getreg(TDBAH15),
     igb_getreg(SCC),
     igb_getreg(COLC),
-    igb_getreg(CEXTERR),
     igb_getreg(XOFFRXC),
     igb_getreg(IPAV),
     igb_getreg(GOTCL),
     igb_getreg(MGTPDC),
     igb_getreg(GCR),
-    igb_getreg(IVAR),
-    igb_getreg(POEMB),
     igb_getreg(MFVAL),
     igb_getreg(FUNCTAG),
     igb_getreg(GSCL_4),
     igb_getreg(GSCN_3),
     igb_getreg(MRQC),
-    igb_getreg(RDLEN1),
     igb_getreg(FCT),
     igb_getreg(FLA),
-    igb_getreg(FLOL),
-    igb_getreg(RXDCTL),
+    igb_getreg(RXDCTL0),
+    igb_getreg(RXDCTL1),
+    igb_getreg(RXDCTL2),
+    igb_getreg(RXDCTL3),
+    igb_getreg(RXDCTL4),
+    igb_getreg(RXDCTL5),
+    igb_getreg(RXDCTL6),
+    igb_getreg(RXDCTL7),
+    igb_getreg(RXDCTL8),
+    igb_getreg(RXDCTL9),
+    igb_getreg(RXDCTL10),
+    igb_getreg(RXDCTL11),
+    igb_getreg(RXDCTL12),
+    igb_getreg(RXDCTL13),
+    igb_getreg(RXDCTL14),
+    igb_getreg(RXDCTL15),
     igb_getreg(RXSTMPL),
     igb_getreg(TXSTMPH),
     igb_getreg(TIMADJH),
     igb_getreg(FCRTL),
-    igb_getreg(TDBAH),
-    igb_getreg(TADV),
     igb_getreg(XONRXC),
-    igb_getreg(TSCTFC),
     igb_getreg(RFCTL),
     igb_getreg(GSCN_1),
     igb_getreg(FCAL),
-    igb_getreg(FLSWCNT),
+    igb_getreg(GPIE),
+    igb_getreg(TXPBS),
+    igb_getreg(RLPML),
 
     [TOTH]    = igb_mac_read_clr8,
     [GOTCH]   = igb_mac_read_clr8,
@@ -3041,8 +2981,11 @@ static const readops igb_macreg_readops[] = {
     [IAC]     = igb_mac_read_clr4,
     [ICR]     = igb_mac_icr_read,
     [STATUS]  = igb_get_status,
-    [TARC0]   = igb_get_tarc,
     [ICS]     = igb_mac_ics_read,
+    /*
+     * 8.8.10: Reading the IMC register returns the value of the IMS register.
+     */
+    [IMC]     = igb_mac_ims_read,
     [TORH]    = igb_mac_read_clr8,
     [GORCH]   = igb_mac_read_clr8,
     [PRC127]  = igb_mac_read_clr4,
@@ -3057,9 +3000,7 @@ static const readops igb_macreg_readops[] = {
     [MPRC]    = igb_mac_read_clr4,
     [BPTC]    = igb_mac_read_clr4,
     [TSCTC]   = igb_mac_read_clr4,
-    [ITR]     = igb_mac_itr_read,
     [CTRL]    = igb_get_ctrl,
-    [TARC1]   = igb_get_tarc,
     [SWSM]    = igb_mac_swsm_read,
     [IMS]     = igb_mac_ims_read,
 
@@ -3067,53 +3008,141 @@ static const readops igb_macreg_readops[] = {
     [IP6AT ... IP6AT + 3]  = igb_mac_readreg,
     [IP4AT ... IP4AT + 6]  = igb_mac_readreg,
     [RA ... RA + 31]       = igb_mac_readreg,
+    [RA2 ... RA2 + 31]     = igb_mac_readreg,
     [WUPM ... WUPM + 31]   = igb_mac_readreg,
-    [MTA ... MTA + E1000_MC_TBL_SIZE - 1] = igb_mac_readreg,
+    [MTA ... MTA + E1000_MC_TBL_SIZE - 1]    = igb_mac_readreg,
     [VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1]  = igb_mac_readreg,
     [FFMT ... FFMT + 254]  = igb_mac_readreg,
-    [FFVT ... FFVT + 254]  = igb_mac_readreg,
     [MDEF ... MDEF + 7]    = igb_mac_readreg,
-    [FFLT ... FFLT + 10]   = igb_mac_readreg,
     [FTFT ... FTFT + 254]  = igb_mac_readreg,
-    [PBM ... PBM + 10239]  = igb_mac_readreg,
     [RETA ... RETA + 31]   = igb_mac_readreg,
-    [RSSRK ... RSSRK + 31] = igb_mac_readreg,
+    [RSSRK ... RSSRK + 9]  = igb_mac_readreg,
     [MAVTV0 ... MAVTV3]    = igb_mac_readreg,
-    [EITR...EITR + IGB_MSIX_VEC_NUM - 1] = igb_mac_eitr_read
+    [EITR0 ... EITR0 + IGB_MSIX_VEC_NUM - 1] = igb_mac_eitr_read,
+    [PVTEICR0] = igb_mac_read_clr4,
+    [PVTEICR1] = igb_mac_read_clr4,
+    [PVTEICR2] = igb_mac_read_clr4,
+    [PVTEICR3] = igb_mac_read_clr4,
+    [PVTEICR4] = igb_mac_read_clr4,
+    [PVTEICR5] = igb_mac_read_clr4,
+    [PVTEICR6] = igb_mac_read_clr4,
+    [PVTEICR7] = igb_mac_read_clr4,
+
+    /* IGB specific: */
+    [FWSM]       = igb_mac_readreg,
+    [SW_FW_SYNC] = igb_mac_readreg,
+    [HTCBDPC]    = igb_mac_read_clr4,
+    [EICR]       = igb_mac_read_clr4,
+    [EIMS]       = igb_mac_readreg,
+    [EIAM]       = igb_mac_readreg,
+    [IVAR0 ... IVAR0 + 7] = igb_mac_readreg,
+    igb_getreg(IVAR_MISC),
+    [P2VMAILBOX0 ... P2VMAILBOX7] = igb_mac_readreg,
+    [V2PMAILBOX0 ... V2PMAILBOX7] = igb_mac_vfmailbox_read,
+    igb_getreg(MBVFICR),
+    [VMBMEM0 ... VMBMEM0 + 127] = igb_mac_readreg,
+    igb_getreg(MBVFIMR),
+    igb_getreg(VFLRE),
+    igb_getreg(VFRE),
+    igb_getreg(VFTE),
+    igb_getreg(QDE),
+    igb_getreg(DTXSWC),
+    igb_getreg(RPLOLR),
+    [VLVF0 ... VLVF0 + E1000_VLVF_ARRAY_SIZE - 1] = igb_mac_readreg,
+    [VMVIR0 ... VMVIR7] = igb_mac_readreg,
+    [VMOLR0 ... VMOLR7] = igb_mac_readreg,
+    [WVBR] = igb_mac_read_clr4,
+    [RQDPC0 ... RQDPC0 + IGB_NUM_QUEUES - 1] = igb_mac_read_clr4,
+    [VTIVAR ... VTIVAR + 7] = igb_mac_readreg,
+    [VTIVAR_MISC ... VTIVAR_MISC + 7] = igb_mac_readreg,
 };
 enum { IGB_NREADOPS = ARRAY_SIZE(igb_macreg_readops) };
 
 #define igb_putreg(x)    [x] = igb_mac_writereg
 typedef void (*writeops)(IGBCore *, int, uint32_t);
 static const writeops igb_macreg_writeops[] = {
-    igb_putreg(PBA),
     igb_putreg(SWSM),
     igb_putreg(WUFC),
-    igb_putreg(RDBAH1),
-    igb_putreg(TDBAH),
-    igb_putreg(TXDCTL),
     igb_putreg(RDBAH0),
+    igb_putreg(RDBAH1),
+    igb_putreg(RDBAH2),
+    igb_putreg(RDBAH3),
+    igb_putreg(RDBAH4),
+    igb_putreg(RDBAH5),
+    igb_putreg(RDBAH6),
+    igb_putreg(RDBAH7),
+    igb_putreg(RDBAH8),
+    igb_putreg(RDBAH9),
+    igb_putreg(RDBAH10),
+    igb_putreg(RDBAH11),
+    igb_putreg(RDBAH12),
+    igb_putreg(RDBAH13),
+    igb_putreg(RDBAH14),
+    igb_putreg(RDBAH15),
+    igb_putreg(SRRCTL0),
+    igb_putreg(SRRCTL1),
+    igb_putreg(SRRCTL2),
+    igb_putreg(SRRCTL3),
+    igb_putreg(SRRCTL4),
+    igb_putreg(SRRCTL5),
+    igb_putreg(SRRCTL6),
+    igb_putreg(SRRCTL7),
+    igb_putreg(SRRCTL8),
+    igb_putreg(SRRCTL9),
+    igb_putreg(SRRCTL10),
+    igb_putreg(SRRCTL11),
+    igb_putreg(SRRCTL12),
+    igb_putreg(SRRCTL13),
+    igb_putreg(SRRCTL14),
+    igb_putreg(SRRCTL15),
+    igb_putreg(RXDCTL0),
+    igb_putreg(RXDCTL1),
+    igb_putreg(RXDCTL2),
+    igb_putreg(RXDCTL3),
+    igb_putreg(RXDCTL4),
+    igb_putreg(RXDCTL5),
+    igb_putreg(RXDCTL6),
+    igb_putreg(RXDCTL7),
+    igb_putreg(RXDCTL8),
+    igb_putreg(RXDCTL9),
+    igb_putreg(RXDCTL10),
+    igb_putreg(RXDCTL11),
+    igb_putreg(RXDCTL12),
+    igb_putreg(RXDCTL13),
+    igb_putreg(RXDCTL14),
+    igb_putreg(RXDCTL15),
     igb_putreg(LEDCTL),
+    igb_putreg(TCTL),
+    igb_putreg(TCTL_EXT),
+    igb_putreg(DTXCTL),
+    igb_putreg(RXPBS),
+    igb_putreg(RQDPC0),
     igb_putreg(FCAL),
     igb_putreg(FCRUC),
     igb_putreg(WUC),
     igb_putreg(WUS),
     igb_putreg(IPAV),
+    igb_putreg(TDBAH0),
     igb_putreg(TDBAH1),
+    igb_putreg(TDBAH2),
+    igb_putreg(TDBAH3),
+    igb_putreg(TDBAH4),
+    igb_putreg(TDBAH5),
+    igb_putreg(TDBAH6),
+    igb_putreg(TDBAH7),
+    igb_putreg(TDBAH8),
+    igb_putreg(TDBAH9),
+    igb_putreg(TDBAH10),
+    igb_putreg(TDBAH11),
+    igb_putreg(TDBAH12),
+    igb_putreg(TDBAH13),
+    igb_putreg(TDBAH14),
+    igb_putreg(TDBAH15),
     igb_putreg(TIMINCA),
     igb_putreg(IAM),
-    igb_putreg(EIAC),
-    igb_putreg(IVAR),
-    igb_putreg(TARC0),
-    igb_putreg(TARC1),
-    igb_putreg(FLSWDATA),
-    igb_putreg(POEMB),
-    igb_putreg(MFUTP01),
-    igb_putreg(MFUTP23),
     igb_putreg(MANC),
     igb_putreg(MANC2H),
     igb_putreg(MFVAL),
-    igb_putreg(EXTCNF_CTRL),
     igb_putreg(FACTPS),
     igb_putreg(FUNCTAG),
     igb_putreg(GSCL_1),
@@ -3124,15 +3153,73 @@ static const writeops igb_macreg_writeops[] = {
     igb_putreg(GSCN_1),
     igb_putreg(GSCN_2),
     igb_putreg(GSCN_3),
-    igb_putreg(GCR2),
     igb_putreg(MRQC),
     igb_putreg(FLOP),
-    igb_putreg(FLOL),
-    igb_putreg(FLSWCTL),
-    igb_putreg(FLSWCNT),
     igb_putreg(FLA),
-    igb_putreg(RXDCTL1),
+    igb_putreg(TXDCTL0),
     igb_putreg(TXDCTL1),
+    igb_putreg(TXDCTL2),
+    igb_putreg(TXDCTL3),
+    igb_putreg(TXDCTL4),
+    igb_putreg(TXDCTL5),
+    igb_putreg(TXDCTL6),
+    igb_putreg(TXDCTL7),
+    igb_putreg(TXDCTL8),
+    igb_putreg(TXDCTL9),
+    igb_putreg(TXDCTL10),
+    igb_putreg(TXDCTL11),
+    igb_putreg(TXDCTL12),
+    igb_putreg(TXDCTL13),
+    igb_putreg(TXDCTL14),
+    igb_putreg(TXDCTL15),
+    igb_putreg(TXCTL0),
+    igb_putreg(TXCTL1),
+    igb_putreg(TXCTL2),
+    igb_putreg(TXCTL3),
+    igb_putreg(TXCTL4),
+    igb_putreg(TXCTL5),
+    igb_putreg(TXCTL6),
+    igb_putreg(TXCTL7),
+    igb_putreg(TXCTL8),
+    igb_putreg(TXCTL9),
+    igb_putreg(TXCTL10),
+    igb_putreg(TXCTL11),
+    igb_putreg(TXCTL12),
+    igb_putreg(TXCTL13),
+    igb_putreg(TXCTL14),
+    igb_putreg(TXCTL15),
+    igb_putreg(TDWBAL0),
+    igb_putreg(TDWBAL1),
+    igb_putreg(TDWBAL2),
+    igb_putreg(TDWBAL3),
+    igb_putreg(TDWBAL4),
+    igb_putreg(TDWBAL5),
+    igb_putreg(TDWBAL6),
+    igb_putreg(TDWBAL7),
+    igb_putreg(TDWBAL8),
+    igb_putreg(TDWBAL9),
+    igb_putreg(TDWBAL10),
+    igb_putreg(TDWBAL11),
+    igb_putreg(TDWBAL12),
+    igb_putreg(TDWBAL13),
+    igb_putreg(TDWBAL14),
+    igb_putreg(TDWBAL15),
+    igb_putreg(TDWBAH0),
+    igb_putreg(TDWBAH1),
+    igb_putreg(TDWBAH2),
+    igb_putreg(TDWBAH3),
+    igb_putreg(TDWBAH4),
+    igb_putreg(TDWBAH5),
+    igb_putreg(TDWBAH6),
+    igb_putreg(TDWBAH7),
+    igb_putreg(TDWBAH8),
+    igb_putreg(TDWBAH9),
+    igb_putreg(TDWBAH10),
+    igb_putreg(TDWBAH11),
+    igb_putreg(TDWBAH12),
+    igb_putreg(TDWBAH13),
+    igb_putreg(TDWBAH14),
+    igb_putreg(TDWBAH15),
     igb_putreg(TIPG),
     igb_putreg(RXSTMPH),
     igb_putreg(RXSTMPL),
@@ -3144,62 +3231,163 @@ static const writeops igb_macreg_writeops[] = {
     igb_putreg(SYSTIMH),
     igb_putreg(TIMADJL),
     igb_putreg(TIMADJH),
-    igb_putreg(RXUDP),
-    igb_putreg(RXCFGL),
     igb_putreg(TSYNCRXCTL),
     igb_putreg(TSYNCTXCTL),
-    igb_putreg(EXTCNF_SIZE),
     igb_putreg(EEMNGCTL),
-    igb_putreg(RA),
+    igb_putreg(GPIE),
+    igb_putreg(TXPBS),
+    igb_putreg(RLPML),
+    igb_putreg(VET),
 
+    [TDH0]     = igb_set_16bit,
     [TDH1]     = igb_set_16bit,
+    [TDH2]     = igb_set_16bit,
+    [TDH3]     = igb_set_16bit,
+    [TDH4]     = igb_set_16bit,
+    [TDH5]     = igb_set_16bit,
+    [TDH6]     = igb_set_16bit,
+    [TDH7]     = igb_set_16bit,
+    [TDH8]     = igb_set_16bit,
+    [TDH9]     = igb_set_16bit,
+    [TDH10]    = igb_set_16bit,
+    [TDH11]    = igb_set_16bit,
+    [TDH12]    = igb_set_16bit,
+    [TDH13]    = igb_set_16bit,
+    [TDH14]    = igb_set_16bit,
+    [TDH15]    = igb_set_16bit,
+    [TDT0]     = igb_set_tdt,
     [TDT1]     = igb_set_tdt,
-    [TCTL]     = igb_set_tctl,
-    [TDT]      = igb_set_tdt,
+    [TDT2]     = igb_set_tdt,
+    [TDT3]     = igb_set_tdt,
+    [TDT4]     = igb_set_tdt,
+    [TDT5]     = igb_set_tdt,
+    [TDT6]     = igb_set_tdt,
+    [TDT7]     = igb_set_tdt,
+    [TDT8]     = igb_set_tdt,
+    [TDT9]     = igb_set_tdt,
+    [TDT10]    = igb_set_tdt,
+    [TDT11]    = igb_set_tdt,
+    [TDT12]    = igb_set_tdt,
+    [TDT13]    = igb_set_tdt,
+    [TDT14]    = igb_set_tdt,
+    [TDT15]    = igb_set_tdt,
     [MDIC]     = igb_set_mdic,
     [ICS]      = igb_set_ics,
-    [TDH]      = igb_set_16bit,
     [RDH0]     = igb_set_16bit,
+    [RDH1]     = igb_set_16bit,
+    [RDH2]     = igb_set_16bit,
+    [RDH3]     = igb_set_16bit,
+    [RDH4]     = igb_set_16bit,
+    [RDH5]     = igb_set_16bit,
+    [RDH6]     = igb_set_16bit,
+    [RDH7]     = igb_set_16bit,
+    [RDH8]     = igb_set_16bit,
+    [RDH9]     = igb_set_16bit,
+    [RDH10]    = igb_set_16bit,
+    [RDH11]    = igb_set_16bit,
+    [RDH12]    = igb_set_16bit,
+    [RDH13]    = igb_set_16bit,
+    [RDH14]    = igb_set_16bit,
+    [RDH15]    = igb_set_16bit,
     [RDT0]     = igb_set_rdt,
+    [RDT1]     = igb_set_rdt,
+    [RDT2]     = igb_set_rdt,
+    [RDT3]     = igb_set_rdt,
+    [RDT4]     = igb_set_rdt,
+    [RDT5]     = igb_set_rdt,
+    [RDT6]     = igb_set_rdt,
+    [RDT7]     = igb_set_rdt,
+    [RDT8]     = igb_set_rdt,
+    [RDT9]     = igb_set_rdt,
+    [RDT10]    = igb_set_rdt,
+    [RDT11]    = igb_set_rdt,
+    [RDT12]    = igb_set_rdt,
+    [RDT13]    = igb_set_rdt,
+    [RDT14]    = igb_set_rdt,
+    [RDT15]    = igb_set_rdt,
     [IMC]      = igb_set_imc,
     [IMS]      = igb_set_ims,
     [ICR]      = igb_set_icr,
     [EECD]     = igb_set_eecd,
     [RCTL]     = igb_set_rx_control,
     [CTRL]     = igb_set_ctrl,
-    [RDTR]     = igb_set_rdtr,
-    [RADV]     = igb_set_16bit,
-    [TADV]     = igb_set_16bit,
-    [ITR]      = igb_set_itr,
     [EERD]     = igb_set_eerd,
-    [AIT]      = igb_set_16bit,
     [TDFH]     = igb_set_13bit,
     [TDFT]     = igb_set_13bit,
     [TDFHS]    = igb_set_13bit,
     [TDFTS]    = igb_set_13bit,
     [TDFPC]    = igb_set_13bit,
     [RDFH]     = igb_set_13bit,
-    [RDFHS]    = igb_set_13bit,
     [RDFT]     = igb_set_13bit,
+    [RDFHS]    = igb_set_13bit,
     [RDFTS]    = igb_set_13bit,
     [RDFPC]    = igb_set_13bit,
-    [PBS]      = igb_set_6bit,
     [GCR]      = igb_set_gcr,
-    [PSRCTL]   = igb_set_psrctl,
     [RXCSUM]   = igb_set_rxcsum,
-    [RAID]     = igb_set_16bit,
-    [RSRPD]    = igb_set_12bit,
-    [TIDV]     = igb_set_tidv,
+    [TDLEN0]   = igb_set_dlen,
     [TDLEN1]   = igb_set_dlen,
-    [TDLEN]    = igb_set_dlen,
+    [TDLEN2]   = igb_set_dlen,
+    [TDLEN3]   = igb_set_dlen,
+    [TDLEN4]   = igb_set_dlen,
+    [TDLEN5]   = igb_set_dlen,
+    [TDLEN6]   = igb_set_dlen,
+    [TDLEN7]   = igb_set_dlen,
+    [TDLEN8]   = igb_set_dlen,
+    [TDLEN9]   = igb_set_dlen,
+    [TDLEN10]  = igb_set_dlen,
+    [TDLEN11]  = igb_set_dlen,
+    [TDLEN12]  = igb_set_dlen,
+    [TDLEN13]  = igb_set_dlen,
+    [TDLEN14]  = igb_set_dlen,
+    [TDLEN15]  = igb_set_dlen,
     [RDLEN0]   = igb_set_dlen,
     [RDLEN1]   = igb_set_dlen,
-    [TDBAL]    = igb_set_dbal,
+    [RDLEN2]   = igb_set_dlen,
+    [RDLEN3]   = igb_set_dlen,
+    [RDLEN4]   = igb_set_dlen,
+    [RDLEN5]   = igb_set_dlen,
+    [RDLEN6]   = igb_set_dlen,
+    [RDLEN7]   = igb_set_dlen,
+    [RDLEN8]   = igb_set_dlen,
+    [RDLEN9]   = igb_set_dlen,
+    [RDLEN10]  = igb_set_dlen,
+    [RDLEN11]  = igb_set_dlen,
+    [RDLEN12]  = igb_set_dlen,
+    [RDLEN13]  = igb_set_dlen,
+    [RDLEN14]  = igb_set_dlen,
+    [RDLEN15]  = igb_set_dlen,
+    [TDBAL0]   = igb_set_dbal,
     [TDBAL1]   = igb_set_dbal,
+    [TDBAL2]   = igb_set_dbal,
+    [TDBAL3]   = igb_set_dbal,
+    [TDBAL4]   = igb_set_dbal,
+    [TDBAL5]   = igb_set_dbal,
+    [TDBAL6]   = igb_set_dbal,
+    [TDBAL7]   = igb_set_dbal,
+    [TDBAL8]   = igb_set_dbal,
+    [TDBAL9]   = igb_set_dbal,
+    [TDBAL10]  = igb_set_dbal,
+    [TDBAL11]  = igb_set_dbal,
+    [TDBAL12]  = igb_set_dbal,
+    [TDBAL13]  = igb_set_dbal,
+    [TDBAL14]  = igb_set_dbal,
+    [TDBAL15]  = igb_set_dbal,
     [RDBAL0]   = igb_set_dbal,
     [RDBAL1]   = igb_set_dbal,
-    [RDH1]     = igb_set_16bit,
-    [RDT1]     = igb_set_rdt,
+    [RDBAL2]   = igb_set_dbal,
+    [RDBAL3]   = igb_set_dbal,
+    [RDBAL4]   = igb_set_dbal,
+    [RDBAL5]   = igb_set_dbal,
+    [RDBAL6]   = igb_set_dbal,
+    [RDBAL7]   = igb_set_dbal,
+    [RDBAL8]   = igb_set_dbal,
+    [RDBAL9]   = igb_set_dbal,
+    [RDBAL10]  = igb_set_dbal,
+    [RDBAL11]  = igb_set_dbal,
+    [RDBAL12]  = igb_set_dbal,
+    [RDBAL13]  = igb_set_dbal,
+    [RDBAL14]  = igb_set_dbal,
+    [RDBAL15]  = igb_set_dbal,
     [STATUS]   = igb_set_status,
     [PBACLR]   = igb_set_pbaclr,
     [CTRL_EXT] = igb_set_ctrlext,
@@ -3209,30 +3397,110 @@ static const writeops igb_macreg_writeops[] = {
     [FCRTV]    = igb_set_16bit,
     [FCRTH]    = igb_set_fcrth,
     [FCRTL]    = igb_set_fcrtl,
-    [VET]      = igb_set_vet,
-    [RXDCTL]   = igb_set_rxdctl,
-    [FLASHT]   = igb_set_16bit,
-    [EEWR]     = igb_set_eewr,
     [CTRL_DUP] = igb_set_ctrl,
     [RFCTL]    = igb_set_rfctl,
-    [RA + 1]   = igb_mac_setmacaddr,
 
     [IP6AT ... IP6AT + 3]    = igb_mac_writereg,
     [IP4AT ... IP4AT + 6]    = igb_mac_writereg,
+    [RA]                     = igb_mac_writereg,
+    [RA + 1]                 = igb_mac_setmacaddr,
     [RA + 2 ... RA + 31]     = igb_mac_writereg,
+    [RA2 ... RA2 + 31]       = igb_mac_writereg,
     [WUPM ... WUPM + 31]     = igb_mac_writereg,
     [MTA ... MTA + E1000_MC_TBL_SIZE - 1] = igb_mac_writereg,
-    [VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1]    = igb_mac_writereg,
+    [VFTA ... VFTA + E1000_VLAN_FILTER_TBL_SIZE - 1] = igb_mac_writereg,
     [FFMT ... FFMT + 254]    = igb_set_4bit,
-    [FFVT ... FFVT + 254]    = igb_mac_writereg,
-    [PBM ... PBM + 10239]    = igb_mac_writereg,
     [MDEF ... MDEF + 7]      = igb_mac_writereg,
-    [FFLT ... FFLT + 10]     = igb_set_11bit,
     [FTFT ... FTFT + 254]    = igb_mac_writereg,
     [RETA ... RETA + 31]     = igb_mac_writereg,
-    [RSSRK ... RSSRK + 31]   = igb_mac_writereg,
+    [RSSRK ... RSSRK + 9]    = igb_mac_writereg,
     [MAVTV0 ... MAVTV3]      = igb_mac_writereg,
-    [EITR...EITR + IGB_MSIX_VEC_NUM - 1] = igb_set_eitr
+    [EITR0 ... EITR0 + IGB_MSIX_VEC_NUM - 1] = igb_set_eitr,
+
+    /* IGB specific: */
+    [FWSM]     = igb_mac_writereg,
+    [SW_FW_SYNC] = igb_mac_writereg,
+    [EICR] = igb_set_eicr,
+    [EICS] = igb_set_eics,
+    [EIAC] = igb_set_eiac,
+    [EIAM] = igb_set_eiam,
+    [EIMC] = igb_set_eimc,
+    [EIMS] = igb_set_eims,
+    [IVAR0 ... IVAR0 + 7] = igb_mac_writereg,
+    igb_putreg(IVAR_MISC),
+    [P2VMAILBOX0 ... P2VMAILBOX7] = igb_set_pfmailbox,
+    [V2PMAILBOX0 ... V2PMAILBOX7] = igb_set_vfmailbox,
+    [MBVFICR] = igb_w1c,
+    [VMBMEM0 ... VMBMEM0 + 127] = igb_mac_writereg,
+    igb_putreg(MBVFIMR),
+    [VFLRE] = igb_w1c,
+    igb_putreg(VFRE),
+    igb_putreg(VFTE),
+    igb_putreg(QDE),
+    igb_putreg(DTXSWC),
+    igb_putreg(RPLOLR),
+    [VLVF0 ... VLVF0 + E1000_VLVF_ARRAY_SIZE - 1] = igb_mac_writereg,
+    [VMVIR0 ... VMVIR7] = igb_mac_writereg,
+    [VMOLR0 ... VMOLR7] = igb_mac_writereg,
+    [UTA ... UTA + E1000_MC_TBL_SIZE - 1] = igb_mac_writereg,
+    [PVTCTRL0] = igb_set_vtctrl,
+    [PVTCTRL1] = igb_set_vtctrl,
+    [PVTCTRL2] = igb_set_vtctrl,
+    [PVTCTRL3] = igb_set_vtctrl,
+    [PVTCTRL4] = igb_set_vtctrl,
+    [PVTCTRL5] = igb_set_vtctrl,
+    [PVTCTRL6] = igb_set_vtctrl,
+    [PVTCTRL7] = igb_set_vtctrl,
+    [PVTEICS0] = igb_set_vteics,
+    [PVTEICS1] = igb_set_vteics,
+    [PVTEICS2] = igb_set_vteics,
+    [PVTEICS3] = igb_set_vteics,
+    [PVTEICS4] = igb_set_vteics,
+    [PVTEICS5] = igb_set_vteics,
+    [PVTEICS6] = igb_set_vteics,
+    [PVTEICS7] = igb_set_vteics,
+    [PVTEIMS0] = igb_set_vteims,
+    [PVTEIMS1] = igb_set_vteims,
+    [PVTEIMS2] = igb_set_vteims,
+    [PVTEIMS3] = igb_set_vteims,
+    [PVTEIMS4] = igb_set_vteims,
+    [PVTEIMS5] = igb_set_vteims,
+    [PVTEIMS6] = igb_set_vteims,
+    [PVTEIMS7] = igb_set_vteims,
+    [PVTEIMC0] = igb_set_vteimc,
+    [PVTEIMC1] = igb_set_vteimc,
+    [PVTEIMC2] = igb_set_vteimc,
+    [PVTEIMC3] = igb_set_vteimc,
+    [PVTEIMC4] = igb_set_vteimc,
+    [PVTEIMC5] = igb_set_vteimc,
+    [PVTEIMC6] = igb_set_vteimc,
+    [PVTEIMC7] = igb_set_vteimc,
+    [PVTEIAC0] = igb_set_vteiac,
+    [PVTEIAC1] = igb_set_vteiac,
+    [PVTEIAC2] = igb_set_vteiac,
+    [PVTEIAC3] = igb_set_vteiac,
+    [PVTEIAC4] = igb_set_vteiac,
+    [PVTEIAC5] = igb_set_vteiac,
+    [PVTEIAC6] = igb_set_vteiac,
+    [PVTEIAC7] = igb_set_vteiac,
+    [PVTEIAM0] = igb_set_vteiam,
+    [PVTEIAM1] = igb_set_vteiam,
+    [PVTEIAM2] = igb_set_vteiam,
+    [PVTEIAM3] = igb_set_vteiam,
+    [PVTEIAM4] = igb_set_vteiam,
+    [PVTEIAM5] = igb_set_vteiam,
+    [PVTEIAM6] = igb_set_vteiam,
+    [PVTEIAM7] = igb_set_vteiam,
+    [PVTEICR0] = igb_set_vteicr,
+    [PVTEICR1] = igb_set_vteicr,
+    [PVTEICR2] = igb_set_vteicr,
+    [PVTEICR3] = igb_set_vteicr,
+    [PVTEICR4] = igb_set_vteicr,
+    [PVTEICR5] = igb_set_vteicr,
+    [PVTEICR6] = igb_set_vteicr,
+    [PVTEICR7] = igb_set_vteicr,
+    [VTIVAR ... VTIVAR + 7] = igb_set_vtivar,
+    [VTIVAR_MISC ... VTIVAR_MISC + 7] = igb_mac_writereg
 };
 enum { IGB_NWRITEOPS = ARRAY_SIZE(igb_macreg_writeops) };
 
@@ -3246,15 +3514,85 @@ enum { MAC_ACCESS_PARTIAL = 1 };
  */
 static const uint16_t mac_reg_access[E1000E_MAC_SIZE] = {
     /* Alias index offsets */
-    [FCRTL_A] = 0x07fe, [FCRTH_A] = 0x0802,
-    [RDH0_A]  = 0x09bc, [RDT0_A]  = 0x09bc, [RDTR_A] = 0x09c6,
+    [FCRTL_A] = 0x07fe,
     [RDFH_A]  = 0xe904, [RDFT_A]  = 0xe904,
-    [TDH_A]   = 0x0cf8, [TDT_A]   = 0x0cf8, [TIDV_A] = 0x0cf8,
     [TDFH_A]  = 0xed00, [TDFT_A]  = 0xed00,
     [RA_A ... RA_A + 31]      = 0x14f0,
     [VFTA_A ... VFTA_A + E1000_VLAN_FILTER_TBL_SIZE - 1] = 0x1400,
-    [RDBAL0_A ... RDLEN0_A] = 0x09bc,
-    [TDBAL_A ... TDLEN_A]   = 0x0cf8,
+
+    [RDBAL0_A] = 0x2600,
+    [RDBAH0_A] = 0x2600,
+    [RDLEN0_A] = 0x2600,
+    [SRRCTL0_A] = 0x2600,
+    [RDH0_A] = 0x2600,
+    [RDT0_A] = 0x2600,
+    [RXDCTL0_A] = 0x2600,
+    [RXCTL0_A] = 0x2600,
+    [RQDPC0_A] = 0x2600,
+    [RDBAL1_A] = 0x25D0,
+    [RDBAL2_A] = 0x25A0,
+    [RDBAL3_A] = 0x2570,
+    [RDBAH1_A] = 0x25D0,
+    [RDBAH2_A] = 0x25A0,
+    [RDBAH3_A] = 0x2570,
+    [RDLEN1_A] = 0x25D0,
+    [RDLEN2_A] = 0x25A0,
+    [RDLEN3_A] = 0x2570,
+    [SRRCTL1_A] = 0x25D0,
+    [SRRCTL2_A] = 0x25A0,
+    [SRRCTL3_A] = 0x2570,
+    [RDH1_A] = 0x25D0,
+    [RDH2_A] = 0x25A0,
+    [RDH3_A] = 0x2570,
+    [RDT1_A] = 0x25D0,
+    [RDT2_A] = 0x25A0,
+    [RDT3_A] = 0x2570,
+    [RXDCTL1_A] = 0x25D0,
+    [RXDCTL2_A] = 0x25A0,
+    [RXDCTL3_A] = 0x2570,
+    [RXCTL1_A] = 0x25D0,
+    [RXCTL2_A] = 0x25A0,
+    [RXCTL3_A] = 0x2570,
+    [RQDPC1_A] = 0x25D0,
+    [RQDPC2_A] = 0x25A0,
+    [RQDPC3_A] = 0x2570,
+    [TDBAL0_A] = 0x2A00,
+    [TDBAH0_A] = 0x2A00,
+    [TDLEN0_A] = 0x2A00,
+    [TDH0_A] = 0x2A00,
+    [TDT0_A] = 0x2A00,
+    [TXCTL0_A] = 0x2A00,
+    [TDWBAL0_A] = 0x2A00,
+    [TDWBAH0_A] = 0x2A00,
+    [TDBAL1_A] = 0x29D0,
+    [TDBAL2_A] = 0x29A0,
+    [TDBAL3_A] = 0x2970,
+    [TDBAH1_A] = 0x29D0,
+    [TDBAH2_A] = 0x29A0,
+    [TDBAH3_A] = 0x2970,
+    [TDLEN1_A] = 0x29D0,
+    [TDLEN2_A] = 0x29A0,
+    [TDLEN3_A] = 0x2970,
+    [TDH1_A] = 0x29D0,
+    [TDH2_A] = 0x29A0,
+    [TDH3_A] = 0x2970,
+    [TDT1_A] = 0x29D0,
+    [TDT2_A] = 0x29A0,
+    [TDT3_A] = 0x2970,
+    [TXDCTL0_A] = 0x2A00,
+    [TXDCTL1_A] = 0x29D0,
+    [TXDCTL2_A] = 0x29A0,
+    [TXDCTL3_A] = 0x2970,
+    [TXCTL1_A] = 0x29D0,
+    [TXCTL2_A] = 0x29A0,
+    [TXCTL3_A] = 0x29D0,
+    [TDWBAL1_A] = 0x29D0,
+    [TDWBAL2_A] = 0x29A0,
+    [TDWBAL3_A] = 0x2970,
+    [TDWBAH1_A] = 0x29D0,
+    [TDWBAH2_A] = 0x29A0,
+    [TDWBAH3_A] = 0x2970,
+
     /* Access options */
     [RDFH]  = MAC_ACCESS_PARTIAL,    [RDFT]  = MAC_ACCESS_PARTIAL,
     [RDFHS] = MAC_ACCESS_PARTIAL,    [RDFTS] = MAC_ACCESS_PARTIAL,
@@ -3262,12 +3600,11 @@ static const uint16_t mac_reg_access[E1000E_MAC_SIZE] = {
     [TDFH]  = MAC_ACCESS_PARTIAL,    [TDFT]  = MAC_ACCESS_PARTIAL,
     [TDFHS] = MAC_ACCESS_PARTIAL,    [TDFTS] = MAC_ACCESS_PARTIAL,
     [TDFPC] = MAC_ACCESS_PARTIAL,    [EECD]  = MAC_ACCESS_PARTIAL,
-    [PBM]   = MAC_ACCESS_PARTIAL,    [FLA]   = MAC_ACCESS_PARTIAL,
+    [FLA]   = MAC_ACCESS_PARTIAL,
     [FCAL]  = MAC_ACCESS_PARTIAL,    [FCAH]  = MAC_ACCESS_PARTIAL,
     [FCT]   = MAC_ACCESS_PARTIAL,    [FCTTV] = MAC_ACCESS_PARTIAL,
     [FCRTV] = MAC_ACCESS_PARTIAL,    [FCRTL] = MAC_ACCESS_PARTIAL,
-    [FCRTH] = MAC_ACCESS_PARTIAL,    [TXDCTL] = MAC_ACCESS_PARTIAL,
-    [TXDCTL1] = MAC_ACCESS_PARTIAL,
+    [FCRTH] = MAC_ACCESS_PARTIAL,
     [MAVTV0 ... MAVTV3] = MAC_ACCESS_PARTIAL
 };
 
@@ -3318,7 +3655,7 @@ static void
 igb_autoneg_resume(IGBCore *core)
 {
     if (igb_have_autoneg(core) &&
-        !(core->phy[0][MII_BMSR] & MII_BMSR_AN_COMP)) {
+        !(core->phy[MII_BMSR] & MII_BMSR_AN_COMP)) {
         qemu_get_queue(core->owner_nic)->link_down = false;
         timer_mod(core->autoneg_timer,
                   qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
@@ -3390,96 +3727,143 @@ igb_core_pci_uninit(IGBCore *core)
 }
 
 static const uint16_t
-igb_phy_reg_init[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE] = {
-    [0] = {
-        [MII_BMCR] = MII_BMCR_SPEED1000 |
-                     MII_BMCR_FD        |
-                     MII_BMCR_AUTOEN,
-
-        [MII_BMSR] = MII_BMSR_EXTCAP    |
-                     MII_BMSR_LINK_ST   |
-                     MII_BMSR_AUTONEG   |
-                     MII_BMSR_MFPS      |
-                     MII_BMSR_EXTSTAT   |
-                     MII_BMSR_10T_HD    |
-                     MII_BMSR_10T_FD    |
-                     MII_BMSR_100TX_HD  |
-                     MII_BMSR_100TX_FD,
-
-        [MII_PHYID1]            = 0x141,
-        [MII_PHYID2]            = E1000_PHY_ID2_82574x,
-        [MII_ANAR]              = MII_ANAR_CSMACD | MII_ANAR_10 |
-                                  MII_ANAR_10FD | MII_ANAR_TX |
-                                  MII_ANAR_TXFD | MII_ANAR_PAUSE |
-                                  MII_ANAR_PAUSE_ASYM,
-        [MII_ANLPAR]            = MII_ANLPAR_10 | MII_ANLPAR_10FD |
-                                  MII_ANLPAR_TX | MII_ANLPAR_TXFD |
-                                  MII_ANLPAR_T4 | MII_ANLPAR_PAUSE,
-        [MII_ANER]              = MII_ANER_NP | MII_ANER_NWAY,
-        [MII_ANNP]              = 1 | MII_ANNP_MP,
-        [MII_CTRL1000]          = MII_CTRL1000_HALF | MII_CTRL1000_FULL |
-                                  MII_CTRL1000_PORT | MII_CTRL1000_MASTER,
-        [MII_STAT1000]          = MII_STAT1000_HALF | MII_STAT1000_FULL |
-                                  MII_STAT1000_ROK | MII_STAT1000_LOK,
-        [MII_EXTSTAT]           = MII_EXTSTAT_1000T_HD | MII_EXTSTAT_1000T_FD,
-
-        [PHY_COPPER_CTRL1]      = BIT(5) | BIT(6) | BIT(8) | BIT(9) |
-                                  BIT(12) | BIT(13),
-        [PHY_COPPER_STAT1]      = BIT(3) | BIT(10) | BIT(11) | BIT(13) | BIT(15)
-    },
-    [2] = {
-        [PHY_MAC_CTRL1]         = BIT(3) | BIT(7),
-        [PHY_MAC_CTRL2]         = BIT(1) | BIT(2) | BIT(6) | BIT(12)
-    },
-    [3] = {
-        [PHY_LED_TIMER_CTRL]    = BIT(0) | BIT(2) | BIT(14)
-    }
+igb_phy_reg_init[] = {
+    [MII_BMCR] = MII_BMCR_SPEED1000 |
+                 MII_BMCR_FD        |
+                 MII_BMCR_AUTOEN,
+
+    [MII_BMSR] = MII_BMSR_EXTCAP    |
+                 MII_BMSR_LINK_ST   |
+                 MII_BMSR_AUTONEG   |
+                 MII_BMSR_MFPS      |
+                 MII_BMSR_EXTSTAT   |
+                 MII_BMSR_10T_HD    |
+                 MII_BMSR_10T_FD    |
+                 MII_BMSR_100TX_HD  |
+                 MII_BMSR_100TX_FD,
+
+    [MII_PHYID1]            = IGP03E1000_E_PHY_ID >> 16,
+    [MII_PHYID2]            = (IGP03E1000_E_PHY_ID & 0xfff0) | 1,
+    [MII_ANAR]              = MII_ANAR_CSMACD | MII_ANAR_10 |
+                              MII_ANAR_10FD | MII_ANAR_TX |
+                              MII_ANAR_TXFD | MII_ANAR_PAUSE |
+                              MII_ANAR_PAUSE_ASYM,
+    [MII_ANLPAR]            = MII_ANLPAR_10 | MII_ANLPAR_10FD |
+                              MII_ANLPAR_TX | MII_ANLPAR_TXFD |
+                              MII_ANLPAR_T4 | MII_ANLPAR_PAUSE,
+    [MII_ANER]              = MII_ANER_NP | MII_ANER_NWAY,
+    [MII_ANNP]              = 0x1 | MII_ANNP_MP,
+    [MII_CTRL1000]          = MII_CTRL1000_HALF | MII_CTRL1000_FULL |
+                              MII_CTRL1000_PORT | MII_CTRL1000_MASTER,
+    [MII_STAT1000]          = MII_STAT1000_HALF | MII_STAT1000_FULL |
+                              MII_STAT1000_ROK | MII_STAT1000_LOK,
+    [MII_EXTSTAT]           = MII_EXTSTAT_1000T_HD | MII_EXTSTAT_1000T_FD,
+
+    [IGP01E1000_PHY_PORT_CONFIG] = BIT(5) | BIT(8),
+    [IGP01E1000_PHY_PORT_STATUS] = IGP01E1000_PSSR_SPEED_1000MBPS,
+    [IGP02E1000_PHY_POWER_MGMT]  = BIT(0) | BIT(3) | IGP02E1000_PM_D3_LPLU |
+                                   IGP01E1000_PSCFR_SMART_SPEED
 };
 
 static const uint32_t igb_mac_reg_init[] = {
-    [PBA]           =     0x00140014,
-    [LEDCTL]        =  BIT(1) | BIT(8) | BIT(9) | BIT(15) | BIT(17) | BIT(18),
-    [EXTCNF_CTRL]   = BIT(3),
+    [LEDCTL]        = 2 | (3 << 8) | BIT(15) | (6 << 16) | (7 << 24),
     [EEMNGCTL]      = BIT(31),
-    [FLASHT]        = 0x2,
-    [FLSWCTL]       = BIT(30) | BIT(31),
-    [FLOL]          = BIT(0),
-    [RXDCTL]        = BIT(16),
-    [RXDCTL1]       = BIT(16),
-    [TIPG]          = 0x8 | (0x8 << 10) | (0x6 << 20),
-    [RXCFGL]        = 0x88F7,
-    [RXUDP]         = 0x319,
-    [CTRL]          = E1000_CTRL_FD | E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
-                      E1000_CTRL_SPD_1000 | E1000_CTRL_SLU |
+    [RXDCTL0]       = E1000_RXDCTL_QUEUE_ENABLE | (1 << 16),
+    [RXDCTL1]       = 1 << 16,
+    [RXDCTL2]       = 1 << 16,
+    [RXDCTL3]       = 1 << 16,
+    [RXDCTL4]       = 1 << 16,
+    [RXDCTL5]       = 1 << 16,
+    [RXDCTL6]       = 1 << 16,
+    [RXDCTL7]       = 1 << 16,
+    [RXDCTL8]       = 1 << 16,
+    [RXDCTL9]       = 1 << 16,
+    [RXDCTL10]      = 1 << 16,
+    [RXDCTL11]      = 1 << 16,
+    [RXDCTL12]      = 1 << 16,
+    [RXDCTL13]      = 1 << 16,
+    [RXDCTL14]      = 1 << 16,
+    [RXDCTL15]      = 1 << 16,
+    [TIPG]          = 0x08 | (0x04 << 10) | (0x06 << 20),
+    [CTRL]          = E1000_CTRL_FD | E1000_CTRL_LRST | E1000_CTRL_SPD_1000 |
                       E1000_CTRL_ADVD3WUC,
-    [STATUS]        =  E1000_STATUS_ASDV_1000 | E1000_STATUS_LU,
-    [PSRCTL]        = (2 << E1000_PSRCTL_BSIZE0_SHIFT) |
-                      (4 << E1000_PSRCTL_BSIZE1_SHIFT) |
-                      (4 << E1000_PSRCTL_BSIZE2_SHIFT),
-    [TARC0]         = 0x3 | E1000_TARC_ENABLE,
-    [TARC1]         = 0x3 | E1000_TARC_ENABLE,
-    [EECD]          = E1000_EECD_AUTO_RD | E1000_EECD_PRES,
-    [EERD]          = E1000_EERW_DONE,
-    [EEWR]          = E1000_EERW_DONE,
+    [STATUS]        = E1000_STATUS_PHYRA | BIT(31),
+    [EECD]          = E1000_EECD_FWE_DIS | E1000_EECD_PRES |
+                      (2 << E1000_EECD_SIZE_EX_SHIFT),
     [GCR]           = E1000_L0S_ADJUST |
+                      E1000_GCR_CMPL_TMOUT_RESEND |
+                      E1000_GCR_CAP_VER2 |
                       E1000_L1_ENTRY_LATENCY_MSB |
                       E1000_L1_ENTRY_LATENCY_LSB,
-    [TDFH]          = 0x600,
-    [TDFT]          = 0x600,
-    [TDFHS]         = 0x600,
-    [TDFTS]         = 0x600,
-    [POEMB]         = 0x30D,
-    [PBS]           = 0x028,
-    [MANC]          = E1000_MANC_DIS_IP_CHK_ARP,
-    [FACTPS]        = E1000_FACTPS_LAN0_ON | 0x20000000,
-    [SWSM]          = 1,
     [RXCSUM]        = E1000_RXCSUM_IPOFLD | E1000_RXCSUM_TUOFLD,
-    [ITR]           = E1000E_MIN_XITR,
-    [EITR...EITR + IGB_MSIX_VEC_NUM - 1] = E1000E_MIN_XITR,
+    [TXPBS]         = 0x28,
+    [RXPBS]         = 0x40,
+    [TCTL]          = E1000_TCTL_PSP | (0xF << E1000_CT_SHIFT) |
+                      (0x40 << E1000_COLD_SHIFT) | (0x1 << 26) | (0xA << 28),
+    [TCTL_EXT]      = 0x40 | (0x42 << 10),
+    [DTXCTL]        = E1000_DTXCTL_8023LL | E1000_DTXCTL_SPOOF_INT,
+    [VET]           = ETH_P_VLAN | (ETH_P_VLAN << 16),
+
+    [V2PMAILBOX0 ... V2PMAILBOX0 + IGB_MAX_VF_FUNCTIONS - 1] = E1000_V2PMAILBOX_RSTI,
+    [MBVFIMR]       = 0xFF,
+    [VFRE]          = 0xFF,
+    [VFTE]          = 0xFF,
+    [VMOLR0 ... VMOLR0 + IGB_MAX_VF_FUNCTIONS - 1] = 0x2600 | E1000_VMOLR_STRCRC,
+    [RPLOLR]        = E1000_RPLOLR_STRCRC,
+    [RLPML]         = 0x2600,
+    [TXCTL0]       = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL1]       = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL2]       = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL3]       = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL4]       = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL5]       = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL6]       = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL7]       = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL8]       = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL9]       = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL10]      = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL11]      = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL12]      = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL13]      = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL14]      = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
+    [TXCTL15]      = E1000_DCA_TXCTRL_DATA_RRO_EN |
+                     E1000_DCA_TXCTRL_TX_WB_RO_EN |
+                     E1000_DCA_TXCTRL_DESC_RRO_EN,
 };
 
 static void igb_reset(IGBCore *core, bool sw)
 {
+    struct igb_tx *tx;
     int i;
 
     timer_del(core->autoneg_timer);
@@ -3490,7 +3874,9 @@ static void igb_reset(IGBCore *core, bool sw)
     memcpy(core->phy, igb_phy_reg_init, sizeof igb_phy_reg_init);
 
     for (i = 0; i < E1000E_MAC_SIZE; i++) {
-        if (sw && (i == PBA || i == PBS || i == FLA)) {
+        if (sw &&
+            (i == RXPBS || i == TXPBS ||
+             (i >= EITR0 && i < EITR0 + IGB_MSIX_VEC_NUM))) {
             continue;
         }
 
@@ -3498,8 +3884,6 @@ static void igb_reset(IGBCore *core, bool sw)
                        igb_mac_reg_init[i] : 0;
     }
 
-    core->rxbuf_min_shift = 1 + E1000_RING_DESC_LEN_SHIFT;
-
     if (qemu_get_queue(core->owner_nic)->link_down) {
         igb_link_down(core);
     }
@@ -3507,9 +3891,15 @@ static void igb_reset(IGBCore *core, bool sw)
     e1000x_reset_mac_addr(core->owner_nic, core->mac, core->permanent_mac);
 
     for (i = 0; i < ARRAY_SIZE(core->tx); i++) {
-        net_tx_pkt_reset(core->tx[i].tx_pkt);
-        memset(&core->tx[i].props, 0, sizeof(core->tx[i].props));
-        core->tx[i].skip_cp = false;
+        tx = &core->tx[i];
+        net_tx_pkt_reset(tx->tx_pkt);
+        tx->vlan = 0;
+        tx->mss = 0;
+        tx->tse = false;
+        tx->ixsm = false;
+        tx->txsm = false;
+        tx->first = true;
+        tx->skip_cp = false;
     }
 }
 
@@ -3530,7 +3920,7 @@ void igb_core_pre_save(IGBCore *core)
      * at MII_BMSR_AN_COMP to infer link status on load.
      */
     if (nc->link_down && igb_have_autoneg(core)) {
-        core->phy[0][MII_BMSR] |= MII_BMSR_AN_COMP;
+        core->phy[MII_BMSR] |= MII_BMSR_AN_COMP;
         igb_update_flowctl_status(core);
     }
 
diff --git a/hw/net/igb_core.h b/hw/net/igb_core.h
index 4f70e45cb1..e8470c3ee8 100644
--- a/hw/net/igb_core.h
+++ b/hw/net/igb_core.h
@@ -1,13 +1,17 @@
 /*
  * Core code for QEMU igb emulation
  *
- * Software developer's manuals:
- * http://www.intel.com/content/dam/doc/datasheet/82574l-gbe-controller-datasheet.pdf
+ * Datasheet:
+ * https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eg-gbe-datasheet.pdf
  *
+ * Copyright (c) 2020-2023 Red Hat, Inc.
  * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
  * Developed by Daynix Computing LTD (http://www.daynix.com)
  *
  * Authors:
+ * Akihiko Odaki <akihiko.odaki@daynix.com>
+ * Gal Hammmer <gal.hammer@sap.com>
+ * Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
  * Dmitry Fleytman <dmitry@daynix.com>
  * Leonid Bloch <leonid@daynix.com>
  * Yan Vugenfirer <yan@daynix.com>
@@ -36,19 +40,21 @@
 #ifndef HW_NET_IGB_CORE_H
 #define HW_NET_IGB_CORE_H
 
-#define E1000E_PHY_PAGE_SIZE    (0x20)
-#define E1000E_PHY_PAGES        (0x07)
 #define E1000E_MAC_SIZE         (0x8000)
-#define IGB_EEPROM_SIZE         (64)
-#define IGB_MSIX_VEC_NUM        (5)
-#define IGB_NUM_QUEUES          (2)
+#define IGB_EEPROM_SIZE         (1024)
+
+/*
+ * TBD: handle igb sizes, vectors = 25, queues = 16!
+ * Just set some conservative values here to work with for now
+ */
+#define IGB_MSIX_VEC_NUM        (25)
+#define IGB_NUM_QUEUES          (16)
 
 typedef struct IGBCore IGBCore;
 
 enum { PHY_R = BIT(0),
        PHY_W = BIT(1),
-       PHY_RW = PHY_R | PHY_W,
-       PHY_ANYPAGE = BIT(2) };
+       PHY_RW = PHY_R | PHY_W };
 
 typedef struct IGBIntrDelayTimer_st {
     QEMUTimer *timer;
@@ -60,22 +66,24 @@ typedef struct IGBIntrDelayTimer_st {
 
 struct IGBCore {
     uint32_t mac[E1000E_MAC_SIZE];
-    uint16_t phy[E1000E_PHY_PAGES][E1000E_PHY_PAGE_SIZE];
+    uint16_t phy[MAX_PHY_REG_ADDRESS + 1];
     uint16_t eeprom[IGB_EEPROM_SIZE];
 
-    uint32_t rxbuf_sizes[E1000_PSRCTL_BUFFS_PER_DESC];
     uint32_t rx_desc_buf_size;
-    uint32_t rxbuf_min_shift;
     uint8_t rx_desc_len;
 
     QEMUTimer *autoneg_timer;
 
     struct igb_tx {
-        e1000x_txd_props props;
+        uint16_t vlan;  /* VLAN Tag */
+        uint16_t mss;   /* Maximum Segment Size */
+        bool tse;       /* TCP/UDP Segmentation Enable */
+        bool ixsm;      /* Insert IP Checksum */
+        bool txsm;      /* Insert TCP/UDP Checksum */
 
+        bool first;
         bool skip_cp;
-        unsigned char sum_needed;
-        bool cptse;
+
         struct NetTxPkt *tx_pkt;
     } tx[IGB_NUM_QUEUES];
 
@@ -84,34 +92,17 @@ struct IGBCore {
     bool has_vnet;
     int max_queue_num;
 
-    /* Interrupt moderation management */
-    uint32_t delayed_causes;
-
-    IGBIntrDelayTimer radv;
-    IGBIntrDelayTimer rdtr;
-    IGBIntrDelayTimer raid;
-
-    IGBIntrDelayTimer tadv;
-    IGBIntrDelayTimer tidv;
-
-    IGBIntrDelayTimer itr;
-
     IGBIntrDelayTimer eitr[IGB_MSIX_VEC_NUM];
 
     VMChangeStateEntry *vmstate;
 
-    uint32_t itr_guest_value;
     uint32_t eitr_guest_value[IGB_MSIX_VEC_NUM];
 
-    uint16_t vet;
-
     uint8_t permanent_mac[ETH_ALEN];
 
     NICState *owner_nic;
     PCIDevice *owner;
     void (*owner_start_recv)(PCIDevice *d);
-
-    uint32_t msi_causes_pending;
 };
 
 void
diff --git a/hw/net/igb_regs.h b/hw/net/igb_regs.h
new file mode 100644
index 0000000000..7d229c559d
--- /dev/null
+++ b/hw/net/igb_regs.h
@@ -0,0 +1,624 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This is copied + edited from kernel header files in
+ * drivers/net/ethernet/intel/igb
+ */
+
+#ifndef HW_IGB_REGS_H_
+#define HW_IGB_REGS_H_
+
+#include "e1000x_regs.h"
+
+/* from igb/e1000_hw.h */
+
+#define E1000_DEV_ID_82576                 0x10C9
+#define E1000_DEV_ID_82576_FIBER           0x10E6
+#define E1000_DEV_ID_82576_SERDES          0x10E7
+#define E1000_DEV_ID_82576_QUAD_COPPER             0x10E8
+#define E1000_DEV_ID_82576_QUAD_COPPER_ET2 0x1526
+#define E1000_DEV_ID_82576_NS                      0x150A
+#define E1000_DEV_ID_82576_NS_SERDES               0x1518
+#define E1000_DEV_ID_82576_SERDES_QUAD             0x150D
+
+/* Context Descriptor */
+struct e1000_adv_tx_context_desc {
+    __le32 vlan_macip_lens;
+    __le32 seqnum_seed;
+    __le32 type_tucmd_mlhl;
+    __le32 mss_l4len_idx;
+};
+
+/* Advanced Transmit Descriptor */
+union e1000_adv_tx_desc {
+    struct {
+        __le64 buffer_addr;     /* Address of descriptor's data buffer */
+        __le32 cmd_type_len;
+        __le32 olinfo_status;
+    } read;
+    struct {
+        __le64 rsvd;            /* Reserved */
+        __le32 nxtseq_seed;
+        __le32 status;
+    } wb;
+};
+
+#define E1000_ADVTXD_DTYP_CTXT  0x00200000 /* Advanced Context Descriptor */
+#define E1000_ADVTXD_DTYP_DATA  0x00300000 /* Advanced Data Descriptor */
+#define E1000_ADVTXD_DCMD_DEXT  0x20000000 /* Descriptor Extension (1=Adv) */
+#define E1000_ADVTXD_DCMD_TSE   0x80000000 /* TCP/UDP Segmentation Enable */
+
+#define E1000_ADVTXD_POTS_IXSM  0x00000100 /* Insert TCP/UDP Checksum */
+#define E1000_ADVTXD_POTS_TXSM  0x00000200 /* Insert TCP/UDP Checksum */
+
+#define E1000_TXD_POPTS_IXSM 0x00000001 /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x00000002 /* Insert TCP/UDP checksum */
+
+/* Receive Descriptor - Advanced */
+union e1000_adv_rx_desc {
+    struct {
+        __le64 pkt_addr;                /* Packet Buffer Address */
+        __le64 hdr_addr;                /* Header Buffer Address */
+    } read;
+    struct {
+        struct {
+            struct {
+                __le16 pkt_info;        /* RSS Type, Packet Type */
+                __le16 hdr_info;        /* Split Head, Buffer Length */
+            } lo_dword;
+            union {
+                __le32 rss;             /* RSS Hash */
+                struct {
+                        __le16 ip_id;   /* IP Id */
+                        __le16 csum;    /* Packet Checksum */
+                } csum_ip;
+            } hi_dword;
+        } lower;
+        struct {
+            __le32 status_error;        /* Ext Status/Error */
+            __le16 length;              /* Packet Length */
+            __le16 vlan;                /* VLAN tag */
+        } upper;
+    } wb;  /* writeback */
+};
+
+/* from igb/e1000_phy.h */
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG        0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS        0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL          0x12 /* Control */
+#define IGP01E1000_PHY_LINK_HEALTH        0x13 /* PHY Link Health */
+#define IGP02E1000_PHY_POWER_MGMT         0x19 /* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT        0x1F /* Page Select */
+#define IGP01E1000_PHY_PCS_INIT_REG       0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK      0x0078
+#define IGP01E1000_PSCR_AUTO_MDIX         0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX    0x2000 /* 0=MDI, 1=MDIX */
+#define IGP01E1000_PSCFR_SMART_SPEED      0x0080
+
+/* Enable flexible speed on link-up */
+#define IGP02E1000_PM_D0_LPLU             0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU             0x0004 /* For all other states */
+#define IGP01E1000_PLHR_SS_DOWNGRADE      0x8000
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_MDIX              0x0800
+#define IGP01E1000_PSSR_SPEED_MASK        0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS    0xC000
+#define IGP02E1000_PHY_CHANNEL_NUM        4
+#define IGP02E1000_PHY_AGC_A              0x11B1
+#define IGP02E1000_PHY_AGC_B              0x12B1
+#define IGP02E1000_PHY_AGC_C              0x14B1
+#define IGP02E1000_PHY_AGC_D              0x18B1
+#define IGP02E1000_AGC_LENGTH_SHIFT       9   /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK        0x7F
+#define IGP02E1000_AGC_RANGE              15
+
+/* from igb/igb.h */
+
+#define E1000_PCS_CFG_IGN_SD     1
+
+/* Interrupt defines */
+#define IGB_START_ITR            648 /* ~6000 ints/sec */
+#define IGB_4K_ITR               980
+#define IGB_20K_ITR              196
+#define IGB_70K_ITR              56
+
+/* TX/RX descriptor defines */
+#define IGB_DEFAULT_TXD          256
+#define IGB_DEFAULT_TX_WORK      128
+#define IGB_MIN_TXD              80
+#define IGB_MAX_TXD              4096
+
+#define IGB_DEFAULT_RXD          256
+#define IGB_MIN_RXD              80
+#define IGB_MAX_RXD              4096
+
+#define IGB_DEFAULT_ITR           3 /* dynamic */
+#define IGB_MAX_ITR_USECS         10000
+#define IGB_MIN_ITR_USECS         10
+#define NON_Q_VECTORS             1
+#define MAX_Q_VECTORS             8
+#define MAX_MSIX_ENTRIES          10
+
+/* Transmit and receive queues */
+#define IGB_MAX_RX_QUEUES          8
+#define IGB_MAX_RX_QUEUES_82575    4
+#define IGB_MAX_RX_QUEUES_I211     2
+#define IGB_MAX_TX_QUEUES          8
+#define IGB_MAX_VF_MC_ENTRIES      30
+#define IGB_MAX_VF_FUNCTIONS       8
+#define IGB_MAX_VFTA_ENTRIES       128
+#define IGB_82576_VF_DEV_ID        0x10CA
+#define IGB_I350_VF_DEV_ID         0x1520
+
+/* from igb/e1000_82575.h */
+
+#define E1000_MRQC_ENABLE_RSS_MQ            0x00000002
+#define E1000_MRQC_ENABLE_VMDQ              0x00000003
+#define E1000_MRQC_RSS_FIELD_IPV4_UDP       0x00400000
+#define E1000_MRQC_ENABLE_VMDQ_RSS_MQ       0x00000005
+#define E1000_MRQC_RSS_FIELD_IPV6_UDP       0x00800000
+#define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX    0x01000000
+
+/* Additional Receive Descriptor Control definitions */
+#define E1000_RXDCTL_QUEUE_ENABLE  0x02000000 /* Enable specific Rx Queue */
+
+/* Direct Cache Access (DCA) definitions */
+#define E1000_DCA_CTRL_DCA_MODE_DISABLE 0x01 /* DCA Disable */
+#define E1000_DCA_CTRL_DCA_MODE_CB2     0x02 /* DCA Mode CB2 */
+
+#define E1000_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */
+#define E1000_DCA_RXCTRL_DESC_DCA_EN BIT(5) /* DCA Rx Desc enable */
+#define E1000_DCA_RXCTRL_HEAD_DCA_EN BIT(6) /* DCA Rx Desc header enable */
+#define E1000_DCA_RXCTRL_DATA_DCA_EN BIT(7) /* DCA Rx Desc payload enable */
+#define E1000_DCA_RXCTRL_DESC_RRO_EN BIT(9) /* DCA Rx rd Desc Relax Order */
+
+#define E1000_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */
+#define E1000_DCA_TXCTRL_DESC_DCA_EN BIT(5) /* DCA Tx Desc enable */
+#define E1000_DCA_TXCTRL_DESC_RRO_EN BIT(9) /* Tx rd Desc Relax Order */
+#define E1000_DCA_TXCTRL_TX_WB_RO_EN BIT(11) /* Tx Desc writeback RO bit */
+#define E1000_DCA_TXCTRL_DATA_RRO_EN BIT(13) /* Tx rd data Relax Order */
+
+/* Additional DCA related definitions, note change in position of CPUID */
+#define E1000_DCA_TXCTRL_CPUID_MASK_82576 0xFF000000 /* Tx CPUID Mask */
+#define E1000_DCA_RXCTRL_CPUID_MASK_82576 0xFF000000 /* Rx CPUID Mask */
+#define E1000_DCA_TXCTRL_CPUID_SHIFT 24 /* Tx CPUID now in the last byte */
+#define E1000_DCA_RXCTRL_CPUID_SHIFT 24 /* Rx CPUID now in the last byte */
+
+#define E1000_DTXSWC_MAC_SPOOF_MASK   0x000000FF /* Per VF MAC spoof control */
+#define E1000_DTXSWC_VLAN_SPOOF_MASK  0x0000FF00 /* Per VF VLAN spoof control */
+#define E1000_DTXSWC_LLE_MASK         0x00FF0000 /* Per VF Local LB enables */
+#define E1000_DTXSWC_VLAN_SPOOF_SHIFT 8
+#define E1000_DTXSWC_VMDQ_LOOPBACK_EN BIT(31)  /* global VF LB enable */
+
+/* Per VM Offload register setup */
+#define E1000_VMOLR_RLPML_MASK 0x00003FFF /* Long Packet Maximum Length mask */
+#define E1000_VMOLR_LPE        0x00010000 /* Accept Long packet */
+#define E1000_VMOLR_RSSE       0x00020000 /* Enable RSS */
+#define E1000_VMOLR_AUPE       0x01000000 /* Accept untagged packets */
+#define E1000_VMOLR_ROMPE      0x02000000 /* Accept overflow multicast */
+#define E1000_VMOLR_ROPE       0x04000000 /* Accept overflow unicast */
+#define E1000_VMOLR_BAM        0x08000000 /* Accept Broadcast packets */
+#define E1000_VMOLR_MPME       0x10000000 /* Multicast promiscuous mode */
+#define E1000_VMOLR_STRVLAN    0x40000000 /* Vlan stripping enable */
+#define E1000_VMOLR_STRCRC     0x80000000 /* CRC stripping enable */
+
+#define E1000_DVMOLR_HIDEVLAN  0x20000000 /* Hide vlan enable */
+#define E1000_DVMOLR_STRVLAN   0x40000000 /* Vlan stripping enable */
+#define E1000_DVMOLR_STRCRC    0x80000000 /* CRC stripping enable */
+
+#define E1000_VLVF_ARRAY_SIZE     32
+#define E1000_VLVF_VLANID_MASK    0x00000FFF
+#define E1000_VLVF_POOLSEL_SHIFT  12
+#define E1000_VLVF_POOLSEL_MASK   (0xFF << E1000_VLVF_POOLSEL_SHIFT)
+#define E1000_VLVF_LVLAN          0x00100000
+#define E1000_VLVF_VLANID_ENABLE  0x80000000
+
+#define E1000_VMVIR_VLANA_DEFAULT      0x40000000 /* Always use default VLAN */
+#define E1000_VMVIR_VLANA_NEVER        0x80000000 /* Never insert VLAN tag */
+
+#define E1000_IOVCTL 0x05BBC
+#define E1000_IOVCTL_REUSE_VFQ 0x00000001
+
+#define E1000_RPLOLR_STRVLAN   0x40000000
+#define E1000_RPLOLR_STRCRC    0x80000000
+
+#define E1000_DTXCTL_8023LL     0x0004
+#define E1000_DTXCTL_VLAN_ADDED 0x0008
+#define E1000_DTXCTL_OOS_ENABLE 0x0010
+#define E1000_DTXCTL_MDP_EN     0x0020
+#define E1000_DTXCTL_SPOOF_INT  0x0040
+
+/* from igb/e1000_defines.h */
+
+#define E1000_IVAR_VALID     0x80
+#define E1000_GPIE_NSICR     0x00000001
+#define E1000_GPIE_MSIX_MODE 0x00000010
+#define E1000_GPIE_EIAME     0x40000000
+#define E1000_GPIE_PBA       0x80000000
+
+/* Transmit Control */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       15
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        63
+#define E1000_COLD_SHIFT                12
+
+#define E1000_RAH_POOL_MASK 0x03FC0000
+#define E1000_RAH_POOL_1 0x00040000
+
+#define E1000_ICR_VMMB         0x00000100 /* VM MB event */
+#define E1000_ICR_TS           0x00080000 /* Time Sync Interrupt */
+#define E1000_ICR_DRSTA        0x40000000 /* Device Reset Asserted */
+/* If this bit asserted, the driver should claim the interrupt */
+#define E1000_ICR_INT_ASSERTED 0x80000000
+/* LAN connected device generates an interrupt */
+#define E1000_ICR_DOUTSYNC     0x10000000 /* NIC DMA out of sync */
+
+/* Extended Interrupt Cause Read */
+#define E1000_EICR_RX_QUEUE0    0x00000001 /* Rx Queue 0 Interrupt */
+#define E1000_EICR_RX_QUEUE1    0x00000002 /* Rx Queue 1 Interrupt */
+#define E1000_EICR_RX_QUEUE2    0x00000004 /* Rx Queue 2 Interrupt */
+#define E1000_EICR_RX_QUEUE3    0x00000008 /* Rx Queue 3 Interrupt */
+#define E1000_EICR_TX_QUEUE0    0x00000100 /* Tx Queue 0 Interrupt */
+#define E1000_EICR_TX_QUEUE1    0x00000200 /* Tx Queue 1 Interrupt */
+#define E1000_EICR_TX_QUEUE2    0x00000400 /* Tx Queue 2 Interrupt */
+#define E1000_EICR_TX_QUEUE3    0x00000800 /* Tx Queue 3 Interrupt */
+#define E1000_EICR_OTHER        0x80000000 /* Interrupt Cause Active */
+
+/* Extended Interrupt Cause Set */
+/* E1000_EITR_CNT_IGNR is only for 82576 and newer */
+#define E1000_EITR_CNT_IGNR     0x80000000 /* Don't reset counters on write */
+
+/* PCI Express Control */
+#define E1000_GCR_CMPL_TMOUT_MASK       0x0000F000
+#define E1000_GCR_CMPL_TMOUT_10ms       0x00001000
+#define E1000_GCR_CMPL_TMOUT_RESEND     0x00010000
+#define E1000_GCR_CAP_VER2              0x00040000
+
+#define PHY_REVISION_MASK      0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+#define IGP03E1000_E_PHY_ID 0x02A80390
+
+/* from igb/e1000_mbox.h */
+
+#define E1000_P2VMAILBOX_STS  0x00000001 /* Initiate message send to VF */
+#define E1000_P2VMAILBOX_ACK  0x00000002 /* Ack message recv'd from VF */
+#define E1000_P2VMAILBOX_VFU  0x00000004 /* VF owns the mailbox buffer */
+#define E1000_P2VMAILBOX_PFU  0x00000008 /* PF owns the mailbox buffer */
+#define E1000_P2VMAILBOX_RVFU 0x00000010 /* Reset VFU - used when VF stuck */
+
+#define E1000_MBVFICR_VFREQ_MASK 0x000000FF /* bits for VF messages */
+#define E1000_MBVFICR_VFREQ_VF1  0x00000001 /* bit for VF 1 message */
+#define E1000_MBVFICR_VFACK_MASK 0x00FF0000 /* bits for VF acks */
+#define E1000_MBVFICR_VFACK_VF1  0x00010000 /* bit for VF 1 ack */
+
+#define E1000_V2PMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */
+
+/*
+ * If it's a E1000_VF_* msg then it originates in the VF and is sent to the
+ * PF.  The reverse is true if it is E1000_PF_*.
+ * Message ACK's are the value or'd with 0xF0000000
+ */
+/* Messages below or'd with this are the ACK */
+#define E1000_VT_MSGTYPE_ACK 0x80000000
+/* Messages below or'd with this are the NACK */
+#define E1000_VT_MSGTYPE_NACK 0x40000000
+/* Indicates that VF is still clear to send requests */
+#define E1000_VT_MSGTYPE_CTS 0x20000000
+#define E1000_VT_MSGINFO_SHIFT 16
+/* bits 23:16 are used for exra info for certain messages */
+#define E1000_VT_MSGINFO_MASK (0xFF << E1000_VT_MSGINFO_SHIFT)
+
+#define E1000_VF_RESET                 0x01 /* VF requests reset */
+#define E1000_VF_SET_MAC_ADDR          0x02 /* VF requests to set MAC addr */
+/* VF requests to clear all unicast MAC filters */
+#define E1000_VF_MAC_FILTER_CLR        (0x01 << E1000_VT_MSGINFO_SHIFT)
+/* VF requests to add unicast MAC filter */
+#define E1000_VF_MAC_FILTER_ADD        (0x02 << E1000_VT_MSGINFO_SHIFT)
+#define E1000_VF_SET_MULTICAST         0x03 /* VF requests to set MC addr */
+#define E1000_VF_SET_VLAN              0x04 /* VF requests to set VLAN */
+#define E1000_VF_SET_LPE               0x05 /* VF requests to set VMOLR.LPE */
+#define E1000_VF_SET_PROMISC           0x06 /*VF requests to clear VMOLR.ROPE/MPME*/
+#define E1000_VF_SET_PROMISC_MULTICAST (0x02 << E1000_VT_MSGINFO_SHIFT)
+
+#define E1000_PF_CONTROL_MSG 0x0100 /* PF control message */
+
+/* from igb/e1000_regs.h */
+
+#define E1000_EICR      0x01580  /* Ext. Interrupt Cause Read - R/clr */
+#define E1000_EITR(_n)  (0x01680 + (0x4 * (_n)))
+#define E1000_EICS      0x01520  /* Ext. Interrupt Cause Set - W0 */
+#define E1000_EIMS      0x01524  /* Ext. Interrupt Mask Set/Read - RW */
+#define E1000_EIMC      0x01528  /* Ext. Interrupt Mask Clear - WO */
+#define E1000_EIAC      0x0152C  /* Ext. Interrupt Auto Clear - RW */
+#define E1000_EIAM      0x01530  /* Ext. Interrupt Ack Auto Clear Mask - RW */
+#define E1000_GPIE      0x01514  /* General Purpose Interrupt Enable; RW */
+#define E1000_IVAR0     0x01700  /* Interrupt Vector Allocation Register - RW */
+#define E1000_IVAR_MISC 0x01740  /* Interrupt Vector Allocation Register (last) - RW */
+#define E1000_FRTIMER   0x01048  /* Free Running Timer - RW */
+#define E1000_FCRTV     0x02460  /* Flow Control Refresh Timer Value - RW */
+
+#define E1000_RQDPC(_n) (0x0C030 + ((_n) * 0x40))
+
+#define E1000_RXPBS 0x02404  /* Rx Packet Buffer Size - RW */
+#define E1000_TXPBS 0x03404  /* Tx Packet Buffer Size - RW */
+
+#define E1000_DTXCTL 0x03590  /* DMA TX Control - RW */
+
+#define E1000_HTCBDPC     0x04124  /* Host TX Circuit Breaker Dropped Count */
+#define E1000_RLPML       0x05004  /* RX Long Packet Max Length */
+#define E1000_RA2         0x054E0  /* 2nd half of Rx address array - RW Array */
+#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4))
+
+/* VT Registers */
+#define E1000_MBVFICR   0x00C80 /* Mailbox VF Cause - RWC */
+#define E1000_MBVFIMR   0x00C84 /* Mailbox VF int Mask - RW */
+#define E1000_VFLRE     0x00C88 /* VF Register Events - RWC */
+#define E1000_VFRE      0x00C8C /* VF Receive Enables */
+#define E1000_VFTE      0x00C90 /* VF Transmit Enables */
+#define E1000_QDE       0x02408 /* Queue Drop Enable - RW */
+#define E1000_DTXSWC    0x03500 /* DMA Tx Switch Control - RW */
+#define E1000_WVBR      0x03554 /* VM Wrong Behavior - RWS */
+#define E1000_RPLOLR    0x05AF0 /* Replication Offload - RW */
+#define E1000_UTA       0x0A000 /* Unicast Table Array - RW */
+#define E1000_IOVTCL    0x05BBC /* IOV Control Register */
+#define E1000_TXSWC     0x05ACC /* Tx Switch Control */
+#define E1000_LVMMC     0x03548 /* Last VM Misbehavior cause */
+/* These act per VF so an array friendly macro is used */
+#define E1000_P2VMAILBOX(_n)   (0x00C00 + (4 * (_n)))
+#define E1000_VMBMEM(_n)       (0x00800 + (64 * (_n)))
+#define E1000_VMOLR(_n)        (0x05AD0 + (4 * (_n)))
+#define E1000_DVMOLR(_n)       (0x0C038 + (64 * (_n)))
+#define E1000_VLVF(_n)         (0x05D00 + (4 * (_n))) /* VLAN VM Filter */
+#define E1000_VMVIR(_n)        (0x03700 + (4 * (_n)))
+
+/* from igbvf/mbox.h */
+
+#define E1000_V2PMAILBOX_REQ      0x00000001 /* Request for PF Ready bit */
+#define E1000_V2PMAILBOX_ACK      0x00000002 /* Ack PF message received */
+#define E1000_V2PMAILBOX_VFU      0x00000004 /* VF owns the mailbox buffer */
+#define E1000_V2PMAILBOX_PFU      0x00000008 /* PF owns the mailbox buffer */
+#define E1000_V2PMAILBOX_PFSTS    0x00000010 /* PF wrote a message in the MB */
+#define E1000_V2PMAILBOX_PFACK    0x00000020 /* PF ack the previous VF msg */
+#define E1000_V2PMAILBOX_RSTI     0x00000040 /* PF has reset indication */
+#define E1000_V2PMAILBOX_RSTD     0x00000080 /* PF has indicated reset done */
+#define E1000_V2PMAILBOX_R2C_BITS 0x000000B0 /* All read to clear bits */
+
+#define E1000_VFMAILBOX_SIZE      16 /* 16 32 bit words - 64 bytes */
+
+/*
+ * If it's a E1000_VF_* msg then it originates in the VF and is sent to the
+ * PF.  The reverse is true if it is E1000_PF_*.
+ * Message ACK's are the value or'd with 0xF0000000
+ */
+/* Messages below or'd with this are the ACK */
+#define E1000_VT_MSGTYPE_ACK      0x80000000
+/* Messages below or'd with this are the NACK */
+#define E1000_VT_MSGTYPE_NACK     0x40000000
+/* Indicates that VF is still clear to send requests */
+#define E1000_VT_MSGTYPE_CTS      0x20000000
+
+/* We have a total wait time of 1s for vf mailbox posted messages */
+#define E1000_VF_MBX_INIT_TIMEOUT 2000 /* retry count for mbx timeout */
+#define E1000_VF_MBX_INIT_DELAY   500  /* usec delay between retries */
+
+#define E1000_VT_MSGINFO_SHIFT    16
+/* bits 23:16 are used for exra info for certain messages */
+#define E1000_VT_MSGINFO_MASK     (0xFF << E1000_VT_MSGINFO_SHIFT)
+
+#define E1000_VF_RESET            0x01 /* VF requests reset */
+#define E1000_VF_SET_MAC_ADDR     0x02 /* VF requests PF to set MAC addr */
+/* VF requests PF to clear all unicast MAC filters */
+#define E1000_VF_MAC_FILTER_CLR   (0x01 << E1000_VT_MSGINFO_SHIFT)
+/* VF requests PF to add unicast MAC filter */
+#define E1000_VF_MAC_FILTER_ADD   (0x02 << E1000_VT_MSGINFO_SHIFT)
+#define E1000_VF_SET_MULTICAST    0x03 /* VF requests PF to set MC addr */
+#define E1000_VF_SET_VLAN         0x04 /* VF requests PF to set VLAN */
+#define E1000_VF_SET_LPE          0x05 /* VF requests PF to set VMOLR.LPE */
+
+#define E1000_PF_CONTROL_MSG      0x0100 /* PF control message */
+
+/* from igbvf/regs.h */
+
+/* Statistics registers */
+#define E1000_VFGPRC   0x00F10
+#define E1000_VFGORC   0x00F18
+#define E1000_VFMPRC   0x00F3C
+#define E1000_VFGPTC   0x00F14
+#define E1000_VFGOTC   0x00F34
+#define E1000_VFGOTLBC 0x00F50
+#define E1000_VFGPTLBC 0x00F44
+#define E1000_VFGORLBC 0x00F48
+#define E1000_VFGPRLBC 0x00F40
+
+/* These act per VF so an array friendly macro is used */
+#define E1000_V2PMAILBOX(_n) (0x00C40 + (4 * (_n)))
+#define E1000_VMBMEM(_n)     (0x00800 + (64 * (_n)))
+
+/* from igbvf/vf.h */
+
+#define E1000_DEV_ID_82576_VF 0x10CA
+
+/* new */
+
+/* Receive Registers */
+
+/* RX Descriptor Base Low; RW */
+#define E1000_RDBAL(_n)    (0x0C000 + (0x40  * (_n)))
+#define E1000_RDBAL_A(_n)  (0x02800 + (0x100 * (_n)))
+
+/* RX Descriptor Base High; RW */
+#define E1000_RDBAH(_n)    (0x0C004 + (0x40  * (_n)))
+#define E1000_RDBAH_A(_n)  (0x02804 + (0x100 * (_n)))
+
+/* RX Descriptor Ring Length; RW */
+#define E1000_RDLEN(_n)    (0x0C008 + (0x40  * (_n)))
+#define E1000_RDLEN_A(_n)  (0x02808 + (0x100 * (_n)))
+
+/* Split and Replication Receive Control; RW */
+#define E1000_SRRCTL(_n)   (0x0C00C + (0x40  * (_n)))
+#define E1000_SRRCTL_A(_n) (0x0280C + (0x100 * (_n)))
+
+/* RX Descriptor Head; RW */
+#define E1000_RDH(_n)      (0x0C010 + (0x40  * (_n)))
+#define E1000_RDH_A(_n)    (0x02810 + (0x100 * (_n)))
+
+/* RX DCA Control; RW */
+#define E1000_RXCTL(_n)    (0x0C014 + (0x40  * (_n)))
+#define E1000_RXCTL_A(_n)  (0x02814 + (0x100 * (_n)))
+
+/* RX Descriptor Tail; RW */
+#define E1000_RDT(_n)      (0x0C018 + (0x40  * (_n)))
+#define E1000_RDT_A(_n)    (0x02818 + (0x100 * (_n)))
+
+/* RX Descriptor Control; RW */
+#define E1000_RXDCTL(_n)   (0x0C028 + (0x40  * (_n)))
+#define E1000_RXDCTL_A(_n) (0x02828 + (0x100 * (_n)))
+
+/* RX Queue Drop Packet Count; RC */
+#define E1000_RQDPC_A(_n)  (0x02830 + (0x100 * (_n)))
+
+/* Transmit Registers */
+
+/* TX Descriptor Base Low; RW */
+#define E1000_TDBAL(_n)    (0x0E000 + (0x40  * (_n)))
+#define E1000_TDBAL_A(_n)  (0x03800 + (0x100 * (_n)))
+
+/* TX Descriptor Base High; RW */
+#define E1000_TDBAH(_n)    (0x0E004 + (0x40  * (_n)))
+#define E1000_TDBAH_A(_n)  (0x03804 + (0x100 * (_n)))
+
+/* TX Descriptor Ring Length; RW */
+#define E1000_TDLEN(_n)    (0x0E008 + (0x40  * (_n)))
+#define E1000_TDLEN_A(_n)  (0x03808 + (0x100 * (_n)))
+
+/* TX Descriptor Head; RW */
+#define E1000_TDH(_n)      (0x0E010 + (0x40  * (_n)))
+#define E1000_TDH_A(_n)    (0x03810 + (0x100 * (_n)))
+
+/* TX DCA Control; RW */
+#define E1000_TXCTL(_n)    (0x0E014 + (0x40  * (_n)))
+#define E1000_TXCTL_A(_n)  (0x03814 + (0x100 * (_n)))
+
+/* TX Descriptor Tail; RW */
+#define E1000_TDT(_n)      (0x0E018 + (0x40  * (_n)))
+#define E1000_TDT_A(_n)    (0x03818 + (0x100 * (_n)))
+
+/* TX Descriptor Control; RW */
+#define E1000_TXDCTL(_n)   (0x0E028 + (0x40  * (_n)))
+#define E1000_TXDCTL_A(_n) (0x03828 + (0x100 * (_n)))
+
+/* TX Descriptor Completion Write–Back Address Low; RW */
+#define E1000_TDWBAL(_n)   (0x0E038 + (0x40  * (_n)))
+#define E1000_TDWBAL_A(_n) (0x03838 + (0x100 * (_n)))
+
+/* TX Descriptor Completion Write–Back Address High; RW */
+#define E1000_TDWBAH(_n)   (0x0E03C + (0x40  * (_n)))
+#define E1000_TDWBAH_A(_n) (0x0383C + (0x100 * (_n)))
+
+#define E1000_MTA_A        0x0200
+
+#define E1000_XDBAL_MASK (~(BIT(5) - 1)) /* TDBAL and RDBAL Registers Mask */
+
+#define E1000_ICR_MACSEC   0x00000020 /* MACSec */
+#define E1000_ICR_RX0      0x00000040 /* Receiver Overrun */
+#define E1000_ICR_GPI_SDP0 0x00000800 /* General Purpose, SDP0 pin */
+#define E1000_ICR_GPI_SDP1 0x00001000 /* General Purpose, SDP1 pin */
+#define E1000_ICR_GPI_SDP2 0x00002000 /* General Purpose, SDP2 pin */
+#define E1000_ICR_GPI_SDP3 0x00004000 /* General Purpose, SDP3 pin */
+#define E1000_ICR_PTRAP    0x00008000 /* Probe Trap */
+#define E1000_ICR_MNG      0x00040000 /* Management Event */
+#define E1000_ICR_OMED     0x00100000 /* Other Media Energy Detected */
+#define E1000_ICR_FER      0x00400000 /* Fatal Error */
+#define E1000_ICR_NFER     0x00800000 /* Non Fatal Error */
+#define E1000_ICR_CSRTO    0x01000000 /* CSR access Time Out Indication */
+#define E1000_ICR_SCE      0x02000000 /* Storm Control Event */
+#define E1000_ICR_SW_WD    0x04000000 /* Software Watchdog */
+
+/* Extended Interrupts */
+
+#define E1000_EICR_MSIX_MASK   0x01FFFFFF /* Bits used in MSI-X mode */
+#define E1000_EICR_LEGACY_MASK 0x4000FFFF /* Bits used in non MSI-X mode */
+
+/* Mirror VF Control (only RST bit); RW */
+#define E1000_PVTCTRL(_n) (0x10000 + (_n) * 0x100)
+
+/* Mirror Good Packets Received Count; RO */
+#define E1000_PVFGPRC(_n) (0x10010 + (_n) * 0x100)
+
+/* Mirror Good Packets Transmitted Count; RO */
+#define E1000_PVFGPTC(_n) (0x10014 + (_n) * 0x100)
+
+/* Mirror Good Octets Received Count; RO */
+#define E1000_PVFGORC(_n) (0x10018 + (_n) * 0x100)
+
+/* Mirror Extended Interrupt Cause Set; WO */
+#define E1000_PVTEICS(_n) (0x10020 + (_n) * 0x100)
+
+/* Mirror Extended Interrupt Mask Set/Read; RW */
+#define E1000_PVTEIMS(_n) (0x10024 + (_n) * 0x100)
+
+/* Mirror Extended Interrupt Mask Clear; WO */
+#define E1000_PVTEIMC(_n) (0x10028 + (_n) * 0x100)
+
+/* Mirror Extended Interrupt Auto Clear; RW */
+#define E1000_PVTEIAC(_n) (0x1002C + (_n) * 0x100)
+
+/* Mirror Extended Interrupt Auto Mask Enable; RW */
+#define E1000_PVTEIAM(_n) (0x10030 + (_n) * 0x100)
+
+/* Mirror Good Octets Transmitted Count; RO */
+#define E1000_PVFGOTC(_n) (0x10034 + (_n) * 0x100)
+
+/* Mirror Multicast Packets Received Count; RO */
+#define E1000_PVFMPRC(_n) (0x1003C + (_n) * 0x100)
+
+/* Mirror Good RX Packets loopback Count; RO */
+#define E1000_PVFGPRLBC(_n) (0x10040 + (_n) * 0x100)
+
+/* Mirror Good TX packets loopback Count; RO */
+#define E1000_PVFGPTLBC(_n) (0x10044 + (_n) * 0x100)
+
+/* Mirror Good RX Octets loopback Count; RO */
+#define E1000_PVFGORLBC(_n) (0x10048 + (_n) * 0x100)
+
+/* Mirror Good TX Octets loopback Count; RO */
+#define E1000_PVFGOTLBC(_n) (0x10050 + (_n) * 0x100)
+
+/* Mirror Extended Interrupt Cause Set; RC/W1C */
+#define E1000_PVTEICR(_n) (0x10080 + (_n) * 0x100)
+
+/*
+ * These are fake addresses that, according to the specification, the device
+ * is not using. They are used to distinguish between the PF and the VFs
+ * accessing their VTIVAR register (which is the same address, 0x1700)
+ */
+#define E1000_VTIVAR      0x11700
+#define E1000_VTIVAR_MISC 0x11720
+
+#define E1000_RSS_QUEUE(reta, hash) (E1000_RETA_VAL(reta, hash) & 0x0F)
+
+#define E1000_STATUS_IOV_MODE 0x00040000
+
+#define E1000_STATUS_NUM_VFS_SHIFT 14
+
+static inline uint8_t igb_ivar_entry_rx(uint8_t i)
+{
+    return i < 8 ? i * 4 : (i - 8) * 4 + 2;
+}
+
+static inline uint8_t igb_ivar_entry_tx(uint8_t i)
+{
+    return i < 8 ? i * 4 + 1 : (i - 8) * 4 + 3;
+}
+
+#endif
diff --git a/hw/net/igbvf.c b/hw/net/igbvf.c
new file mode 100644
index 0000000000..f02cb7f283
--- /dev/null
+++ b/hw/net/igbvf.c
@@ -0,0 +1,327 @@
+/*
+ * QEMU Intel 82576 SR/IOV Ethernet Controller Emulation
+ *
+ * Datasheet:
+ * https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eg-gbe-datasheet.pdf
+ *
+ * Copyright (c) 2020-2023 Red Hat, Inc.
+ * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Akihiko Odaki <akihiko.odaki@daynix.com>
+ * Gal Hammmer <gal.hammer@sap.com>
+ * Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Leonid Bloch <leonid@daynix.com>
+ * Yan Vugenfirer <yan@daynix.com>
+ *
+ * Based on work done by:
+ * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
+ * Copyright (c) 2008 Qumranet
+ * Based on work done by:
+ * Copyright (c) 2007 Dan Aloni
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "hw/net/mii.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pcie.h"
+#include "hw/pci/msix.h"
+#include "net/net.h"
+#include "igb_common.h"
+#include "trace.h"
+#include "qapi/error.h"
+
+#define TYPE_IGBVF "igbvf"
+OBJECT_DECLARE_SIMPLE_TYPE(IgbVfState, IGBVF)
+
+#define IGBVF_MSIX_VECTORS  (3)
+
+#define IGBVF_MMIO_BAR_IDX  (0)
+#define IGBVF_MSIX_BAR_IDX  (3)
+
+#define IGBVF_MMIO_SIZE     (16 * 1024)
+#define IGBVF_MSIX_SIZE     (16 * 1024)
+
+struct IgbVfState {
+    PCIDevice parent_obj;
+
+    MemoryRegion mmio;
+    MemoryRegion msix;
+};
+
+static hwaddr vf_to_pf_addr(hwaddr addr, uint16_t vfn, bool write)
+{
+    switch (addr) {
+    case E1000_CTRL:
+    case E1000_CTRL_DUP:
+        return E1000_PVTCTRL(vfn);
+    case E1000_EICS:
+        return E1000_PVTEICS(vfn);
+    case E1000_EIMS:
+        return E1000_PVTEIMS(vfn);
+    case E1000_EIMC:
+        return E1000_PVTEIMC(vfn);
+    case E1000_EIAC:
+        return E1000_PVTEIAC(vfn);
+    case E1000_EIAM:
+        return E1000_PVTEIAM(vfn);
+    case E1000_EICR:
+        return E1000_PVTEICR(vfn);
+    case E1000_EITR(0):
+    case E1000_EITR(1):
+    case E1000_EITR(2):
+        return E1000_EITR(22) + (addr - E1000_EITR(0)) - vfn * 0xC;
+    case E1000_IVAR0:
+        return E1000_VTIVAR + vfn * 4;
+    case E1000_IVAR_MISC:
+        return E1000_VTIVAR_MISC + vfn * 4;
+    case 0x0F04: /* PBACL */
+        return E1000_PBACLR;
+    case 0x0F0C: /* PSRTYPE */
+        return E1000_PSRTYPE(vfn);
+    case E1000_V2PMAILBOX(0):
+        return E1000_V2PMAILBOX(vfn);
+    case E1000_VMBMEM(0) ... E1000_VMBMEM(0) + 0x3F:
+        return addr + vfn * 0x40;
+    case E1000_RDBAL_A(0):
+        return E1000_RDBAL(vfn);
+    case E1000_RDBAL_A(1):
+        return E1000_RDBAL(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_RDBAH_A(0):
+        return E1000_RDBAH(vfn);
+    case E1000_RDBAH_A(1):
+        return E1000_RDBAH(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_RDLEN_A(0):
+        return E1000_RDLEN(vfn);
+    case E1000_RDLEN_A(1):
+        return E1000_RDLEN(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_SRRCTL_A(0):
+        return E1000_SRRCTL(vfn);
+    case E1000_SRRCTL_A(1):
+        return E1000_SRRCTL(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_RDH_A(0):
+        return E1000_RDH(vfn);
+    case E1000_RDH_A(1):
+        return E1000_RDH(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_RXCTL_A(0):
+        return E1000_RXCTL(vfn);
+    case E1000_RXCTL_A(1):
+        return E1000_RXCTL(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_RDT_A(0):
+        return E1000_RDT(vfn);
+    case E1000_RDT_A(1):
+        return E1000_RDT(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_RXDCTL_A(0):
+        return E1000_RXDCTL(vfn);
+    case E1000_RXDCTL_A(1):
+        return E1000_RXDCTL(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_RQDPC_A(0):
+        return E1000_RQDPC(vfn);
+    case E1000_RQDPC_A(1):
+        return E1000_RQDPC(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_TDBAL_A(0):
+        return E1000_TDBAL(vfn);
+    case E1000_TDBAL_A(1):
+        return E1000_TDBAL(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_TDBAH_A(0):
+        return E1000_TDBAH(vfn);
+    case E1000_TDBAH_A(1):
+        return E1000_TDBAH(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_TDLEN_A(0):
+        return E1000_TDLEN(vfn);
+    case E1000_TDLEN_A(1):
+        return E1000_TDLEN(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_TDH_A(0):
+        return E1000_TDH(vfn);
+    case E1000_TDH_A(1):
+        return E1000_TDH(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_TXCTL_A(0):
+        return E1000_TXCTL(vfn);
+    case E1000_TXCTL_A(1):
+        return E1000_TXCTL(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_TDT_A(0):
+        return E1000_TDT(vfn);
+    case E1000_TDT_A(1):
+        return E1000_TDT(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_TXDCTL_A(0):
+        return E1000_TXDCTL(vfn);
+    case E1000_TXDCTL_A(1):
+        return E1000_TXDCTL(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_TDWBAL_A(0):
+        return E1000_TDWBAL(vfn);
+    case E1000_TDWBAL_A(1):
+        return E1000_TDWBAL(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_TDWBAH_A(0):
+        return E1000_TDWBAH(vfn);
+    case E1000_TDWBAH_A(1):
+        return E1000_TDWBAH(vfn + IGB_MAX_VF_FUNCTIONS);
+    case E1000_VFGPRC:
+        return E1000_PVFGPRC(vfn);
+    case E1000_VFGPTC:
+        return E1000_PVFGPTC(vfn);
+    case E1000_VFGORC:
+        return E1000_PVFGORC(vfn);
+    case E1000_VFGOTC:
+        return E1000_PVFGOTC(vfn);
+    case E1000_VFMPRC:
+        return E1000_PVFMPRC(vfn);
+    case E1000_VFGPRLBC:
+        return E1000_PVFGPRLBC(vfn);
+    case E1000_VFGPTLBC:
+        return E1000_PVFGPTLBC(vfn);
+    case E1000_VFGORLBC:
+        return E1000_PVFGORLBC(vfn);
+    case E1000_VFGOTLBC:
+        return E1000_PVFGOTLBC(vfn);
+    case E1000_STATUS:
+    case E1000_FRTIMER:
+        if (write) {
+            return HWADDR_MAX;
+        }
+        /* fallthrough */
+    case 0x34E8: /* PBTWAC */
+    case 0x24E8: /* PBRWAC */
+        return addr;
+    }
+
+    trace_igbvf_wrn_io_addr_unknown(addr);
+
+    return HWADDR_MAX;
+}
+
+static void igbvf_write_config(PCIDevice *dev, uint32_t addr, uint32_t val,
+    int len)
+{
+    trace_igbvf_write_config(addr, val, len);
+    pci_default_write_config(dev, addr, val, len);
+}
+
+static uint64_t igbvf_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+    PCIDevice *vf = PCI_DEVICE(opaque);
+    PCIDevice *pf = pcie_sriov_get_pf(vf);
+
+    addr = vf_to_pf_addr(addr, pcie_sriov_vf_number(vf), false);
+    return addr == HWADDR_MAX ? 0 : igb_mmio_read(pf, addr, size);
+}
+
+static void igbvf_mmio_write(void *opaque, hwaddr addr, uint64_t val,
+    unsigned size)
+{
+    PCIDevice *vf = PCI_DEVICE(opaque);
+    PCIDevice *pf = pcie_sriov_get_pf(vf);
+
+    addr = vf_to_pf_addr(addr, pcie_sriov_vf_number(vf), true);
+    if (addr != HWADDR_MAX) {
+        igb_mmio_write(pf, addr, val, size);
+    }
+}
+
+static const MemoryRegionOps mmio_ops = {
+    .read = igbvf_mmio_read,
+    .write = igbvf_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void igbvf_pci_realize(PCIDevice *dev, Error **errp)
+{
+    IgbVfState *s = IGBVF(dev);
+    int ret;
+    int i;
+
+    dev->config_write = igbvf_write_config;
+
+    memory_region_init_io(&s->mmio, OBJECT(dev), &mmio_ops, s, "igbvf-mmio",
+        IGBVF_MMIO_SIZE);
+    pcie_sriov_vf_register_bar(dev, IGBVF_MMIO_BAR_IDX, &s->mmio);
+
+    memory_region_init(&s->msix, OBJECT(dev), "igbvf-msix", IGBVF_MSIX_SIZE);
+    pcie_sriov_vf_register_bar(dev, IGBVF_MSIX_BAR_IDX, &s->msix);
+
+    ret = msix_init(dev, IGBVF_MSIX_VECTORS, &s->msix, IGBVF_MSIX_BAR_IDX, 0,
+        &s->msix, IGBVF_MSIX_BAR_IDX, 0x2000, 0x70, errp);
+    if (ret) {
+        return;
+    }
+
+    for (i = 0; i < IGBVF_MSIX_VECTORS; i++) {
+        msix_vector_use(dev, i);
+    }
+
+    if (pcie_endpoint_cap_init(dev, 0xa0) < 0) {
+        hw_error("Failed to initialize PCIe capability");
+    }
+
+    if (pcie_aer_init(dev, 1, 0x100, 0x40, errp) < 0) {
+        hw_error("Failed to initialize AER capability");
+    }
+
+    pcie_ari_init(dev, 0x150, 1);
+}
+
+static void igbvf_pci_uninit(PCIDevice *dev)
+{
+    IgbVfState *s = IGBVF(dev);
+
+    pcie_aer_exit(dev);
+    pcie_cap_exit(dev);
+    msix_unuse_all_vectors(dev);
+    msix_uninit(dev, &s->msix, &s->msix);
+}
+
+static void igbvf_class_init(ObjectClass *class, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(class);
+    PCIDeviceClass *c = PCI_DEVICE_CLASS(class);
+
+    c->realize = igbvf_pci_realize;
+    c->exit = igbvf_pci_uninit;
+    c->vendor_id = PCI_VENDOR_ID_INTEL;
+    c->device_id = E1000_DEV_ID_82576_VF;
+    c->revision = 1;
+    c->class_id = PCI_CLASS_NETWORK_ETHERNET;
+
+    dc->desc = "Intel 82576 Virtual Function";
+    dc->user_creatable = false;
+
+    set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
+}
+
+static const TypeInfo igbvf_info = {
+    .name = TYPE_IGBVF,
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(IgbVfState),
+    .class_init = igbvf_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_PCIE_DEVICE },
+        { }
+    },
+};
+
+static void igb_register_types(void)
+{
+    type_register_static(&igbvf_info);
+}
+
+type_init(igb_register_types)
diff --git a/hw/net/meson.build b/hw/net/meson.build
index 4974ad6bd2..49df3ca096 100644
--- a/hw/net/meson.build
+++ b/hw/net/meson.build
@@ -11,7 +11,7 @@ softmmu_ss.add(when: 'CONFIG_E1000_PCI', if_true: files('e1000.c', 'e1000x_commo
 softmmu_ss.add(when: 'CONFIG_E1000E_PCI_EXPRESS', if_true: files('net_tx_pkt.c', 'net_rx_pkt.c'))
 softmmu_ss.add(when: 'CONFIG_E1000E_PCI_EXPRESS', if_true: files('e1000e.c', 'e1000e_core.c', 'e1000x_common.c'))
 softmmu_ss.add(when: 'CONFIG_IGB_PCI_EXPRESS', if_true: files('net_tx_pkt.c', 'net_rx_pkt.c'))
-softmmu_ss.add(when: 'CONFIG_IGB_PCI_EXPRESS', if_true: files('igb.c', 'igb_core.c'))
+softmmu_ss.add(when: 'CONFIG_IGB_PCI_EXPRESS', if_true: files('igb.c', 'igbvf.c', 'igb_core.c'))
 softmmu_ss.add(when: 'CONFIG_RTL8139_PCI', if_true: files('rtl8139.c'))
 softmmu_ss.add(when: 'CONFIG_TULIP', if_true: files('tulip.c'))
 softmmu_ss.add(when: 'CONFIG_VMXNET3_PCI', if_true: files('net_tx_pkt.c', 'net_rx_pkt.c'))
diff --git a/hw/net/trace-events b/hw/net/trace-events
index c98ad12537..8b56146016 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -272,6 +272,38 @@ e1000e_msix_use_vector_fail(uint32_t vec, int32_t res) "Failed to use MSI-X vect
 e1000e_mac_set_permanent(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "Set permanent MAC: %02x:%02x:%02x:%02x:%02x:%02x"
 e1000e_cfg_support_virtio(bool support) "Virtio header supported: %d"
 
+# igb.c
+igb_write_config(uint32_t address, uint32_t val, int len) "CONFIG write 0x%"PRIx32", value: 0x%"PRIx32", len: %"PRId32
+igbvf_write_config(uint32_t address, uint32_t val, int len) "CONFIG write 0x%"PRIx32", value: 0x%"PRIx32", len: %"PRId32
+
+# igb_core.c
+igb_core_mdic_read(uint32_t addr, uint32_t data) "MDIC READ: PHY[%u] = 0x%x"
+igb_core_mdic_read_unhandled(uint32_t addr) "MDIC READ: PHY[%u] UNHANDLED"
+igb_core_mdic_write(uint32_t addr, uint32_t data) "MDIC WRITE: PHY[%u] = 0x%x"
+igb_core_mdic_write_unhandled(uint32_t addr) "MDIC WRITE: PHY[%u] UNHANDLED"
+
+igb_rx_desc_buff_size(uint32_t b) "buffer size: %u"
+igb_rx_desc_buff_write(uint64_t addr, uint16_t offset, const void* source, uint32_t len) "addr: 0x%"PRIx64", offset: %u, from: %p, length: %u"
+
+igb_rx_metadata_rss(uint32_t rss) "RSS data: 0x%X"
+
+igb_irq_icr_clear_gpie_nsicr(void) "Clearing ICR on read due to GPIE.NSICR enabled"
+igb_irq_icr_write(uint32_t bits, uint32_t old_icr, uint32_t new_icr) "Clearing ICR bits 0x%x: 0x%x --> 0x%x"
+igb_irq_set_iam(uint32_t icr) "Update IAM: 0x%x"
+igb_irq_read_iam(uint32_t icr) "Current IAM: 0x%x"
+igb_irq_write_eics(uint32_t val, bool msix) "Update EICS: 0x%x MSI-X: %d"
+igb_irq_write_eims(uint32_t val, bool msix) "Update EIMS: 0x%x MSI-X: %d"
+igb_irq_write_eimc(uint32_t val, uint32_t eims, bool msix) "Update EIMC: 0x%x EIMS: 0x%x MSI-X: %d"
+igb_irq_write_eiac(uint32_t val) "Update EIAC: 0x%x"
+igb_irq_write_eiam(uint32_t val, bool msix) "Update EIAM: 0x%x MSI-X: %d"
+igb_irq_write_eicr(uint32_t val, bool msix) "Update EICR: 0x%x MSI-X: %d"
+igb_irq_eitr_set(uint32_t eitr_num, uint32_t val) "EITR[%u] = 0x%x"
+igb_set_pfmailbox(uint32_t vf_num, uint32_t val) "PFMailbox[%d]: 0x%x"
+igb_set_vfmailbox(uint32_t vf_num, uint32_t val) "VFMailbox[%d]: 0x%x"
+
+# igbvf.c
+igbvf_wrn_io_addr_unknown(uint64_t addr) "IO unknown register 0x%"PRIx64
+
 # spapr_llan.c
 spapr_vlan_get_rx_bd_from_pool_found(int pool, int32_t count, uint32_t rx_bufs) "pool=%d count=%"PRId32" rxbufs=%"PRIu32
 spapr_vlan_get_rx_bd_from_page(int buf_ptr, uint64_t bd) "use_buf_ptr=%d bd=0x%016"PRIx64
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 08/13] tests/qtest/e1000e-test: Fabricate ethernet header
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
                   ` (6 preceding siblings ...)
  2023-01-14  4:09 ` [PATCH v2 07/13] igb: Transform to 82576 implementation Akihiko Odaki
@ 2023-01-14  4:09 ` Akihiko Odaki
  2023-01-14  4:10 ` [PATCH v2 09/13] tests/qtest/libqos/e1000e: Export macreg functions Akihiko Odaki
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:09 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich

e1000e understands ethernet header so fabricate something convincing.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 tests/qtest/e1000e-test.c   | 17 +++++++++++------
 tests/qtest/libqos/e1000e.h |  2 ++
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/tests/qtest/e1000e-test.c b/tests/qtest/e1000e-test.c
index b63a4d3c91..98706355e3 100644
--- a/tests/qtest/e1000e-test.c
+++ b/tests/qtest/e1000e-test.c
@@ -27,6 +27,7 @@
 #include "qemu/osdep.h"
 #include "libqtest-single.h"
 #include "libqos/pci-pc.h"
+#include "net/eth.h"
 #include "qemu/sockets.h"
 #include "qemu/iov.h"
 #include "qemu/module.h"
@@ -35,9 +36,13 @@
 #include "libqos/e1000e.h"
 #include "hw/net/e1000_regs.h"
 
+static const struct eth_header test = {
+    .h_dest = E1000E_ADDRESS,
+    .h_source = E1000E_ADDRESS,
+};
+
 static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
 {
-    static const char test[] = "TEST";
     struct e1000_tx_desc descr;
     char buffer[64];
     int ret;
@@ -45,7 +50,7 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a
 
     /* Prepare test data buffer */
     uint64_t data = guest_alloc(alloc, sizeof(buffer));
-    memwrite(data, test, sizeof(test));
+    memwrite(data, &test, sizeof(test));
 
     /* Prepare TX descriptor */
     memset(&descr, 0, sizeof(descr));
@@ -71,7 +76,7 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a
     g_assert_cmpint(ret, == , sizeof(recv_len));
     ret = recv(test_sockets[0], buffer, sizeof(buffer), 0);
     g_assert_cmpint(ret, ==, sizeof(buffer));
-    g_assert_cmpstr(buffer, == , test);
+    g_assert_false(memcmp(buffer, &test, sizeof(test)));
 
     /* Free test data buffer */
     guest_free(alloc, data);
@@ -81,14 +86,14 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator
 {
     union e1000_rx_desc_extended descr;
 
-    char test[] = "TEST";
+    struct eth_header test_iov = test;
     int len = htonl(sizeof(test));
     struct iovec iov[] = {
         {
             .iov_base = &len,
             .iov_len = sizeof(len),
         },{
-            .iov_base = test,
+            .iov_base = &test_iov,
             .iov_len = sizeof(test),
         },
     };
@@ -119,7 +124,7 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator
 
     /* Check data sent to the backend */
     memread(data, buffer, sizeof(buffer));
-    g_assert_cmpstr(buffer, == , test);
+    g_assert_false(memcmp(buffer, &test, sizeof(test)));
 
     /* Free test data buffer */
     guest_free(alloc, data);
diff --git a/tests/qtest/libqos/e1000e.h b/tests/qtest/libqos/e1000e.h
index 091ce139da..5e2b201aa7 100644
--- a/tests/qtest/libqos/e1000e.h
+++ b/tests/qtest/libqos/e1000e.h
@@ -25,6 +25,8 @@
 #define E1000E_RX0_MSG_ID           (0)
 #define E1000E_TX0_MSG_ID           (1)
 
+#define E1000E_ADDRESS { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 }
+
 typedef struct QE1000E QE1000E;
 typedef struct QE1000E_PCI QE1000E_PCI;
 
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 09/13] tests/qtest/libqos/e1000e: Export macreg functions
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
                   ` (7 preceding siblings ...)
  2023-01-14  4:09 ` [PATCH v2 08/13] tests/qtest/e1000e-test: Fabricate ethernet header Akihiko Odaki
@ 2023-01-14  4:10 ` Akihiko Odaki
  2023-01-14  4:10 ` [PATCH v2 10/13] tests/qtest/libqos/igb: Copy e1000e code Akihiko Odaki
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:10 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich

They will be useful for igb testing.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 tests/qtest/libqos/e1000e.c | 12 ------------
 tests/qtest/libqos/e1000e.h | 12 ++++++++++++
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/tests/qtest/libqos/e1000e.c b/tests/qtest/libqos/e1000e.c
index 28fb3052aa..925654c7fd 100644
--- a/tests/qtest/libqos/e1000e.c
+++ b/tests/qtest/libqos/e1000e.c
@@ -36,18 +36,6 @@
 
 #define E1000E_RING_LEN (0x1000)
 
-static void e1000e_macreg_write(QE1000E *d, uint32_t reg, uint32_t val)
-{
-    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
-    qpci_io_writel(&d_pci->pci_dev, d_pci->mac_regs, reg, val);
-}
-
-static uint32_t e1000e_macreg_read(QE1000E *d, uint32_t reg)
-{
-    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
-    return qpci_io_readl(&d_pci->pci_dev, d_pci->mac_regs, reg);
-}
-
 void e1000e_tx_ring_push(QE1000E *d, void *descr)
 {
     QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
diff --git a/tests/qtest/libqos/e1000e.h b/tests/qtest/libqos/e1000e.h
index 5e2b201aa7..30643c8094 100644
--- a/tests/qtest/libqos/e1000e.h
+++ b/tests/qtest/libqos/e1000e.h
@@ -42,6 +42,18 @@ struct QE1000E_PCI {
     QE1000E e1000e;
 };
 
+static inline void e1000e_macreg_write(QE1000E *d, uint32_t reg, uint32_t val)
+{
+    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
+    qpci_io_writel(&d_pci->pci_dev, d_pci->mac_regs, reg, val);
+}
+
+static inline uint32_t e1000e_macreg_read(QE1000E *d, uint32_t reg)
+{
+    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
+    return qpci_io_readl(&d_pci->pci_dev, d_pci->mac_regs, reg);
+}
+
 void e1000e_wait_isr(QE1000E *d, uint16_t msg_id);
 void e1000e_tx_ring_push(QE1000E *d, void *descr);
 void e1000e_rx_ring_push(QE1000E *d, void *descr);
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 10/13] tests/qtest/libqos/igb: Copy e1000e code
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
                   ` (8 preceding siblings ...)
  2023-01-14  4:10 ` [PATCH v2 09/13] tests/qtest/libqos/e1000e: Export macreg functions Akihiko Odaki
@ 2023-01-14  4:10 ` Akihiko Odaki
  2023-01-14  4:10 ` [PATCH v2 11/13] tests/qtest/libqos/igb: Transform to igb tests Akihiko Odaki
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:10 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich

Start off igb test implementation by copying e1000e code first as igb
resembles e1000e.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 MAINTAINERS              |   2 +
 tests/qtest/igb-test.c   | 242 +++++++++++++++++++++++++++++++++++++++
 tests/qtest/libqos/igb.c | 226 ++++++++++++++++++++++++++++++++++++
 3 files changed, 470 insertions(+)
 create mode 100644 tests/qtest/igb-test.c
 create mode 100644 tests/qtest/libqos/igb.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 8c59cd28a3..2599cd673c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2222,6 +2222,8 @@ igb
 M: Akihiko Odaki <akihiko.odaki@daynix.com>
 S: Maintained
 F: hw/net/igb*
+F: tests/qtest/igb-test.c
+F: tests/qtest/libqos/igb.c
 
 eepro100
 M: Stefan Weil <sw@weilnetz.de>
diff --git a/tests/qtest/igb-test.c b/tests/qtest/igb-test.c
new file mode 100644
index 0000000000..98706355e3
--- /dev/null
+++ b/tests/qtest/igb-test.c
@@ -0,0 +1,242 @@
+/*
+ * QTest testcase for e1000e NIC
+ *
+ * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Leonid Bloch <leonid@daynix.com>
+ * Yan Vugenfirer <yan@daynix.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+#include "libqos/pci-pc.h"
+#include "net/eth.h"
+#include "qemu/sockets.h"
+#include "qemu/iov.h"
+#include "qemu/module.h"
+#include "qemu/bitops.h"
+#include "libqos/libqos-malloc.h"
+#include "libqos/e1000e.h"
+#include "hw/net/e1000_regs.h"
+
+static const struct eth_header test = {
+    .h_dest = E1000E_ADDRESS,
+    .h_source = E1000E_ADDRESS,
+};
+
+static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
+{
+    struct e1000_tx_desc descr;
+    char buffer[64];
+    int ret;
+    uint32_t recv_len;
+
+    /* Prepare test data buffer */
+    uint64_t data = guest_alloc(alloc, sizeof(buffer));
+    memwrite(data, &test, sizeof(test));
+
+    /* Prepare TX descriptor */
+    memset(&descr, 0, sizeof(descr));
+    descr.buffer_addr = cpu_to_le64(data);
+    descr.lower.data = cpu_to_le32(E1000_TXD_CMD_RS   |
+                                   E1000_TXD_CMD_EOP  |
+                                   E1000_TXD_CMD_DEXT |
+                                   E1000_TXD_DTYP_D   |
+                                   sizeof(buffer));
+
+    /* Put descriptor to the ring */
+    e1000e_tx_ring_push(d, &descr);
+
+    /* Wait for TX WB interrupt */
+    e1000e_wait_isr(d, E1000E_TX0_MSG_ID);
+
+    /* Check DD bit */
+    g_assert_cmphex(le32_to_cpu(descr.upper.data) & E1000_TXD_STAT_DD, ==,
+                    E1000_TXD_STAT_DD);
+
+    /* Check data sent to the backend */
+    ret = recv(test_sockets[0], &recv_len, sizeof(recv_len), 0);
+    g_assert_cmpint(ret, == , sizeof(recv_len));
+    ret = recv(test_sockets[0], buffer, sizeof(buffer), 0);
+    g_assert_cmpint(ret, ==, sizeof(buffer));
+    g_assert_false(memcmp(buffer, &test, sizeof(test)));
+
+    /* Free test data buffer */
+    guest_free(alloc, data);
+}
+
+static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
+{
+    union e1000_rx_desc_extended descr;
+
+    struct eth_header test_iov = test;
+    int len = htonl(sizeof(test));
+    struct iovec iov[] = {
+        {
+            .iov_base = &len,
+            .iov_len = sizeof(len),
+        },{
+            .iov_base = &test_iov,
+            .iov_len = sizeof(test),
+        },
+    };
+
+    char buffer[64];
+    int ret;
+
+    /* Send a dummy packet to device's socket*/
+    ret = iov_send(test_sockets[0], iov, 2, 0, sizeof(len) + sizeof(test));
+    g_assert_cmpint(ret, == , sizeof(test) + sizeof(len));
+
+    /* Prepare test data buffer */
+    uint64_t data = guest_alloc(alloc, sizeof(buffer));
+
+    /* Prepare RX descriptor */
+    memset(&descr, 0, sizeof(descr));
+    descr.read.buffer_addr = cpu_to_le64(data);
+
+    /* Put descriptor to the ring */
+    e1000e_rx_ring_push(d, &descr);
+
+    /* Wait for TX WB interrupt */
+    e1000e_wait_isr(d, E1000E_RX0_MSG_ID);
+
+    /* Check DD bit */
+    g_assert_cmphex(le32_to_cpu(descr.wb.upper.status_error) &
+        E1000_RXD_STAT_DD, ==, E1000_RXD_STAT_DD);
+
+    /* Check data sent to the backend */
+    memread(data, buffer, sizeof(buffer));
+    g_assert_false(memcmp(buffer, &test, sizeof(test)));
+
+    /* Free test data buffer */
+    guest_free(alloc, data);
+}
+
+static void test_e1000e_init(void *obj, void *data, QGuestAllocator * alloc)
+{
+    /* init does nothing */
+}
+
+static void test_e1000e_tx(void *obj, void *data, QGuestAllocator * alloc)
+{
+    QE1000E_PCI *e1000e = obj;
+    QE1000E *d = &e1000e->e1000e;
+    QOSGraphObject *e_object = obj;
+    QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
+
+    /* FIXME: add spapr support */
+    if (qpci_check_buggy_msi(dev)) {
+        return;
+    }
+
+    e1000e_send_verify(d, data, alloc);
+}
+
+static void test_e1000e_rx(void *obj, void *data, QGuestAllocator * alloc)
+{
+    QE1000E_PCI *e1000e = obj;
+    QE1000E *d = &e1000e->e1000e;
+    QOSGraphObject *e_object = obj;
+    QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
+
+    /* FIXME: add spapr support */
+    if (qpci_check_buggy_msi(dev)) {
+        return;
+    }
+
+    e1000e_receive_verify(d, data, alloc);
+}
+
+static void test_e1000e_multiple_transfers(void *obj, void *data,
+                                           QGuestAllocator *alloc)
+{
+    static const long iterations = 4 * 1024;
+    long i;
+
+    QE1000E_PCI *e1000e = obj;
+    QE1000E *d = &e1000e->e1000e;
+    QOSGraphObject *e_object = obj;
+    QPCIDevice *dev = e_object->get_driver(e_object, "pci-device");
+
+    /* FIXME: add spapr support */
+    if (qpci_check_buggy_msi(dev)) {
+        return;
+    }
+
+    for (i = 0; i < iterations; i++) {
+        e1000e_send_verify(d, data, alloc);
+        e1000e_receive_verify(d, data, alloc);
+    }
+
+}
+
+static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
+{
+    QTestState *qts = global_qtest;  /* TODO: get rid of global_qtest here */
+    QE1000E_PCI *dev = obj;
+
+    if (dev->pci_dev.bus->not_hotpluggable) {
+        g_test_skip("pci bus does not support hotplug");
+        return;
+    }
+
+    qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}");
+    qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06);
+}
+
+static void data_test_clear(void *sockets)
+{
+    int *test_sockets = sockets;
+
+    close(test_sockets[0]);
+    qos_invalidate_command_line();
+    close(test_sockets[1]);
+    g_free(test_sockets);
+}
+
+static void *data_test_init(GString *cmd_line, void *arg)
+{
+    int *test_sockets = g_new(int, 2);
+    int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets);
+    g_assert_cmpint(ret, != , -1);
+
+    g_string_append_printf(cmd_line, " -netdev socket,fd=%d,id=hs0 ",
+                           test_sockets[1]);
+
+    g_test_queue_destroy(data_test_clear, test_sockets);
+    return test_sockets;
+}
+
+static void register_e1000e_test(void)
+{
+    QOSGraphTestOptions opts = {
+        .before = data_test_init,
+    };
+
+    qos_add_test("init", "e1000e", test_e1000e_init, &opts);
+    qos_add_test("tx", "e1000e", test_e1000e_tx, &opts);
+    qos_add_test("rx", "e1000e", test_e1000e_rx, &opts);
+    qos_add_test("multiple_transfers", "e1000e",
+                      test_e1000e_multiple_transfers, &opts);
+    qos_add_test("hotplug", "e1000e", test_e1000e_hotplug, &opts);
+}
+
+libqos_init(register_e1000e_test);
diff --git a/tests/qtest/libqos/igb.c b/tests/qtest/libqos/igb.c
new file mode 100644
index 0000000000..925654c7fd
--- /dev/null
+++ b/tests/qtest/libqos/igb.c
@@ -0,0 +1,226 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "hw/net/e1000_regs.h"
+#include "hw/pci/pci_ids.h"
+#include "../libqtest.h"
+#include "pci-pc.h"
+#include "qemu/sockets.h"
+#include "qemu/iov.h"
+#include "qemu/module.h"
+#include "qemu/bitops.h"
+#include "libqos-malloc.h"
+#include "qgraph.h"
+#include "e1000e.h"
+
+#define E1000E_IVAR_TEST_CFG \
+    (((E1000E_RX0_MSG_ID | E1000_IVAR_INT_ALLOC_VALID) << E1000_IVAR_RXQ0_SHIFT) | \
+     ((E1000E_TX0_MSG_ID | E1000_IVAR_INT_ALLOC_VALID) << E1000_IVAR_TXQ0_SHIFT) | \
+     E1000_IVAR_TX_INT_EVERY_WB)
+
+#define E1000E_RING_LEN (0x1000)
+
+void e1000e_tx_ring_push(QE1000E *d, void *descr)
+{
+    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
+    uint32_t tail = e1000e_macreg_read(d, E1000_TDT);
+    uint32_t len = e1000e_macreg_read(d, E1000_TDLEN) / E1000_RING_DESC_LEN;
+
+    qtest_memwrite(d_pci->pci_dev.bus->qts,
+                   d->tx_ring + tail * E1000_RING_DESC_LEN,
+                   descr, E1000_RING_DESC_LEN);
+    e1000e_macreg_write(d, E1000_TDT, (tail + 1) % len);
+
+    /* Read WB data for the packet transmitted */
+    qtest_memread(d_pci->pci_dev.bus->qts,
+                  d->tx_ring + tail * E1000_RING_DESC_LEN,
+                  descr, E1000_RING_DESC_LEN);
+}
+
+void e1000e_rx_ring_push(QE1000E *d, void *descr)
+{
+    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
+    uint32_t tail = e1000e_macreg_read(d, E1000_RDT);
+    uint32_t len = e1000e_macreg_read(d, E1000_RDLEN) / E1000_RING_DESC_LEN;
+
+    qtest_memwrite(d_pci->pci_dev.bus->qts,
+                   d->rx_ring + tail * E1000_RING_DESC_LEN,
+                   descr, E1000_RING_DESC_LEN);
+    e1000e_macreg_write(d, E1000_RDT, (tail + 1) % len);
+
+    /* Read WB data for the packet received */
+    qtest_memread(d_pci->pci_dev.bus->qts,
+                  d->rx_ring + tail * E1000_RING_DESC_LEN,
+                  descr, E1000_RING_DESC_LEN);
+}
+
+static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data)
+{
+    QPCIDevice *res = data;
+    memcpy(res, dev, sizeof(QPCIDevice));
+    g_free(dev);
+}
+
+void e1000e_wait_isr(QE1000E *d, uint16_t msg_id)
+{
+    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
+    guint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
+
+    do {
+        if (qpci_msix_pending(&d_pci->pci_dev, msg_id)) {
+            return;
+        }
+        qtest_clock_step(d_pci->pci_dev.bus->qts, 10000);
+    } while (g_get_monotonic_time() < end_time);
+
+    g_error("Timeout expired");
+}
+
+static void e1000e_pci_destructor(QOSGraphObject *obj)
+{
+    QE1000E_PCI *epci = (QE1000E_PCI *) obj;
+    qpci_iounmap(&epci->pci_dev, epci->mac_regs);
+    qpci_msix_disable(&epci->pci_dev);
+}
+
+static void e1000e_pci_start_hw(QOSGraphObject *obj)
+{
+    QE1000E_PCI *d = (QE1000E_PCI *) obj;
+    uint32_t val;
+
+    /* Enable the device */
+    qpci_device_enable(&d->pci_dev);
+
+    /* Reset the device */
+    val = e1000e_macreg_read(&d->e1000e, E1000_CTRL);
+    e1000e_macreg_write(&d->e1000e, E1000_CTRL, val | E1000_CTRL_RST | E1000_CTRL_SLU);
+
+    /* Enable and configure MSI-X */
+    qpci_msix_enable(&d->pci_dev);
+    e1000e_macreg_write(&d->e1000e, E1000_IVAR, E1000E_IVAR_TEST_CFG);
+
+    /* Check the device status - link and speed */
+    val = e1000e_macreg_read(&d->e1000e, E1000_STATUS);
+    g_assert_cmphex(val & (E1000_STATUS_LU | E1000_STATUS_ASDV_1000),
+        ==, E1000_STATUS_LU | E1000_STATUS_ASDV_1000);
+
+    /* Initialize TX/RX logic */
+    e1000e_macreg_write(&d->e1000e, E1000_RCTL, 0);
+    e1000e_macreg_write(&d->e1000e, E1000_TCTL, 0);
+
+    /* Notify the device that the driver is ready */
+    val = e1000e_macreg_read(&d->e1000e, E1000_CTRL_EXT);
+    e1000e_macreg_write(&d->e1000e, E1000_CTRL_EXT,
+        val | E1000_CTRL_EXT_DRV_LOAD);
+
+    e1000e_macreg_write(&d->e1000e, E1000_TDBAL,
+                           (uint32_t) d->e1000e.tx_ring);
+    e1000e_macreg_write(&d->e1000e, E1000_TDBAH,
+                           (uint32_t) (d->e1000e.tx_ring >> 32));
+    e1000e_macreg_write(&d->e1000e, E1000_TDLEN, E1000E_RING_LEN);
+    e1000e_macreg_write(&d->e1000e, E1000_TDT, 0);
+    e1000e_macreg_write(&d->e1000e, E1000_TDH, 0);
+
+    /* Enable transmit */
+    e1000e_macreg_write(&d->e1000e, E1000_TCTL, E1000_TCTL_EN);
+
+    e1000e_macreg_write(&d->e1000e, E1000_RDBAL,
+                           (uint32_t)d->e1000e.rx_ring);
+    e1000e_macreg_write(&d->e1000e, E1000_RDBAH,
+                           (uint32_t)(d->e1000e.rx_ring >> 32));
+    e1000e_macreg_write(&d->e1000e, E1000_RDLEN, E1000E_RING_LEN);
+    e1000e_macreg_write(&d->e1000e, E1000_RDT, 0);
+    e1000e_macreg_write(&d->e1000e, E1000_RDH, 0);
+
+    /* Enable receive */
+    e1000e_macreg_write(&d->e1000e, E1000_RFCTL, E1000_RFCTL_EXTEN);
+    e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN  |
+                                        E1000_RCTL_UPE |
+                                        E1000_RCTL_MPE);
+
+    /* Enable all interrupts */
+    e1000e_macreg_write(&d->e1000e, E1000_IMS, 0xFFFFFFFF);
+
+}
+
+static void *e1000e_pci_get_driver(void *obj, const char *interface)
+{
+    QE1000E_PCI *epci = obj;
+    if (!g_strcmp0(interface, "e1000e-if")) {
+        return &epci->e1000e;
+    }
+
+    /* implicit contains */
+    if (!g_strcmp0(interface, "pci-device")) {
+        return &epci->pci_dev;
+    }
+
+    fprintf(stderr, "%s not present in e1000e\n", interface);
+    g_assert_not_reached();
+}
+
+static void *e1000e_pci_create(void *pci_bus, QGuestAllocator *alloc,
+                               void *addr)
+{
+    QE1000E_PCI *d = g_new0(QE1000E_PCI, 1);
+    QPCIBus *bus = pci_bus;
+    QPCIAddress *address = addr;
+
+    qpci_device_foreach(bus, address->vendor_id, address->device_id,
+                        e1000e_foreach_callback, &d->pci_dev);
+
+    /* Map BAR0 (mac registers) */
+    d->mac_regs = qpci_iomap(&d->pci_dev, 0, NULL);
+
+    /* Allocate and setup TX ring */
+    d->e1000e.tx_ring = guest_alloc(alloc, E1000E_RING_LEN);
+    g_assert(d->e1000e.tx_ring != 0);
+
+    /* Allocate and setup RX ring */
+    d->e1000e.rx_ring = guest_alloc(alloc, E1000E_RING_LEN);
+    g_assert(d->e1000e.rx_ring != 0);
+
+    d->obj.get_driver = e1000e_pci_get_driver;
+    d->obj.start_hw = e1000e_pci_start_hw;
+    d->obj.destructor = e1000e_pci_destructor;
+
+    return &d->obj;
+}
+
+static void e1000e_register_nodes(void)
+{
+    QPCIAddress addr = {
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = E1000_DEV_ID_82574L,
+    };
+
+    /*
+     * FIXME: every test using this node needs to setup a -netdev socket,id=hs0
+     * otherwise QEMU is not going to start
+     */
+    QOSGraphEdgeOptions opts = {
+        .extra_device_opts = "netdev=hs0",
+    };
+    add_qpci_address(&opts, &addr);
+
+    qos_node_create_driver("e1000e", e1000e_pci_create);
+    qos_node_consumes("e1000e", "pci-bus", &opts);
+}
+
+libqos_init(e1000e_register_nodes);
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 11/13] tests/qtest/libqos/igb: Transform to igb tests
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
                   ` (9 preceding siblings ...)
  2023-01-14  4:10 ` [PATCH v2 10/13] tests/qtest/libqos/igb: Copy e1000e code Akihiko Odaki
@ 2023-01-14  4:10 ` Akihiko Odaki
  2023-01-14  4:10 ` [PATCH v2 12/13] tests/avocado: Add igb test Akihiko Odaki
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:10 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 tests/qtest/fuzz/generic_fuzz_configs.h |   5 +
 tests/qtest/igb-test.c                  |  67 ++++++------
 tests/qtest/libqos/igb.c                | 139 +++++++++---------------
 tests/qtest/libqos/meson.build          |   1 +
 tests/qtest/meson.build                 |   1 +
 5 files changed, 90 insertions(+), 123 deletions(-)

diff --git a/tests/qtest/fuzz/generic_fuzz_configs.h b/tests/qtest/fuzz/generic_fuzz_configs.h
index a825b78c14..50689da653 100644
--- a/tests/qtest/fuzz/generic_fuzz_configs.h
+++ b/tests/qtest/fuzz/generic_fuzz_configs.h
@@ -90,6 +90,11 @@ const generic_fuzz_config predefined_configs[] = {
         .args = "-M q35 -nodefaults "
         "-device e1000e,netdev=net0 -netdev user,id=net0",
         .objects = "e1000e",
+    },{
+        .name = "igb",
+        .args = "-M q35 -nodefaults "
+        "-device igb,netdev=net0 -netdev user,id=net0",
+        .objects = "igb",
     },{
         .name = "cirrus-vga",
         .args = "-machine q35 -nodefaults -device cirrus-vga",
diff --git a/tests/qtest/igb-test.c b/tests/qtest/igb-test.c
index 98706355e3..17d408f02a 100644
--- a/tests/qtest/igb-test.c
+++ b/tests/qtest/igb-test.c
@@ -1,10 +1,12 @@
 /*
- * QTest testcase for e1000e NIC
+ * QTest testcase for igb NIC
  *
+ * Copyright (c) 2022-2023 Red Hat, Inc.
  * Copyright (c) 2015 Ravello Systems LTD (http://ravellosystems.com)
  * Developed by Daynix Computing LTD (http://www.daynix.com)
  *
  * Authors:
+ * Akihiko Odaki <akihiko.odaki@daynix.com>
  * Dmitry Fleytman <dmitry@daynix.com>
  * Leonid Bloch <leonid@daynix.com>
  * Yan Vugenfirer <yan@daynix.com>
@@ -34,16 +36,16 @@
 #include "qemu/bitops.h"
 #include "libqos/libqos-malloc.h"
 #include "libqos/e1000e.h"
-#include "hw/net/e1000_regs.h"
+#include "hw/net/igb_regs.h"
 
 static const struct eth_header test = {
     .h_dest = E1000E_ADDRESS,
     .h_source = E1000E_ADDRESS,
 };
 
-static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
+static void igb_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
 {
-    struct e1000_tx_desc descr;
+    union e1000_adv_tx_desc descr;
     char buffer[64];
     int ret;
     uint32_t recv_len;
@@ -54,12 +56,11 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a
 
     /* Prepare TX descriptor */
     memset(&descr, 0, sizeof(descr));
-    descr.buffer_addr = cpu_to_le64(data);
-    descr.lower.data = cpu_to_le32(E1000_TXD_CMD_RS   |
-                                   E1000_TXD_CMD_EOP  |
-                                   E1000_TXD_CMD_DEXT |
-                                   E1000_TXD_DTYP_D   |
-                                   sizeof(buffer));
+    descr.read.buffer_addr = cpu_to_le64(data);
+    descr.read.cmd_type_len = cpu_to_le32(E1000_TXD_CMD_RS   |
+                                          E1000_TXD_CMD_EOP  |
+                                          E1000_TXD_DTYP_D   |
+                                          sizeof(buffer));
 
     /* Put descriptor to the ring */
     e1000e_tx_ring_push(d, &descr);
@@ -68,7 +69,7 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a
     e1000e_wait_isr(d, E1000E_TX0_MSG_ID);
 
     /* Check DD bit */
-    g_assert_cmphex(le32_to_cpu(descr.upper.data) & E1000_TXD_STAT_DD, ==,
+    g_assert_cmphex(le32_to_cpu(descr.wb.status) & E1000_TXD_STAT_DD, ==,
                     E1000_TXD_STAT_DD);
 
     /* Check data sent to the backend */
@@ -82,9 +83,9 @@ static void e1000e_send_verify(QE1000E *d, int *test_sockets, QGuestAllocator *a
     guest_free(alloc, data);
 }
 
-static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
+static void igb_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator *alloc)
 {
-    union e1000_rx_desc_extended descr;
+    union e1000_adv_rx_desc descr;
 
     struct eth_header test_iov = test;
     int len = htonl(sizeof(test));
@@ -110,7 +111,7 @@ static void e1000e_receive_verify(QE1000E *d, int *test_sockets, QGuestAllocator
 
     /* Prepare RX descriptor */
     memset(&descr, 0, sizeof(descr));
-    descr.read.buffer_addr = cpu_to_le64(data);
+    descr.read.pkt_addr = cpu_to_le64(data);
 
     /* Put descriptor to the ring */
     e1000e_rx_ring_push(d, &descr);
@@ -135,7 +136,7 @@ static void test_e1000e_init(void *obj, void *data, QGuestAllocator * alloc)
     /* init does nothing */
 }
 
-static void test_e1000e_tx(void *obj, void *data, QGuestAllocator * alloc)
+static void test_igb_tx(void *obj, void *data, QGuestAllocator * alloc)
 {
     QE1000E_PCI *e1000e = obj;
     QE1000E *d = &e1000e->e1000e;
@@ -147,10 +148,10 @@ static void test_e1000e_tx(void *obj, void *data, QGuestAllocator * alloc)
         return;
     }
 
-    e1000e_send_verify(d, data, alloc);
+    igb_send_verify(d, data, alloc);
 }
 
-static void test_e1000e_rx(void *obj, void *data, QGuestAllocator * alloc)
+static void test_igb_rx(void *obj, void *data, QGuestAllocator * alloc)
 {
     QE1000E_PCI *e1000e = obj;
     QE1000E *d = &e1000e->e1000e;
@@ -162,11 +163,11 @@ static void test_e1000e_rx(void *obj, void *data, QGuestAllocator * alloc)
         return;
     }
 
-    e1000e_receive_verify(d, data, alloc);
+    igb_receive_verify(d, data, alloc);
 }
 
-static void test_e1000e_multiple_transfers(void *obj, void *data,
-                                           QGuestAllocator *alloc)
+static void test_igb_multiple_transfers(void *obj, void *data,
+                                        QGuestAllocator *alloc)
 {
     static const long iterations = 4 * 1024;
     long i;
@@ -182,13 +183,13 @@ static void test_e1000e_multiple_transfers(void *obj, void *data,
     }
 
     for (i = 0; i < iterations; i++) {
-        e1000e_send_verify(d, data, alloc);
-        e1000e_receive_verify(d, data, alloc);
+        igb_send_verify(d, data, alloc);
+        igb_receive_verify(d, data, alloc);
     }
 
 }
 
-static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
+static void test_igb_hotplug(void *obj, void *data, QGuestAllocator * alloc)
 {
     QTestState *qts = global_qtest;  /* TODO: get rid of global_qtest here */
     QE1000E_PCI *dev = obj;
@@ -198,8 +199,8 @@ static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc)
         return;
     }
 
-    qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}");
-    qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06);
+    qtest_qmp_device_add(qts, "igb", "igb_net", "{'addr': '0x06'}");
+    qpci_unplug_acpi_device_test(qts, "igb_net", 0x06);
 }
 
 static void data_test_clear(void *sockets)
@@ -225,18 +226,18 @@ static void *data_test_init(GString *cmd_line, void *arg)
     return test_sockets;
 }
 
-static void register_e1000e_test(void)
+static void register_igb_test(void)
 {
     QOSGraphTestOptions opts = {
         .before = data_test_init,
     };
 
-    qos_add_test("init", "e1000e", test_e1000e_init, &opts);
-    qos_add_test("tx", "e1000e", test_e1000e_tx, &opts);
-    qos_add_test("rx", "e1000e", test_e1000e_rx, &opts);
-    qos_add_test("multiple_transfers", "e1000e",
-                      test_e1000e_multiple_transfers, &opts);
-    qos_add_test("hotplug", "e1000e", test_e1000e_hotplug, &opts);
+    qos_add_test("init", "igb", test_e1000e_init, &opts);
+    qos_add_test("tx", "igb", test_igb_tx, &opts);
+    qos_add_test("rx", "igb", test_igb_rx, &opts);
+    qos_add_test("multiple_transfers", "igb",
+                 test_igb_multiple_transfers, &opts);
+    qos_add_test("hotplug", "igb", test_igb_hotplug, &opts);
 }
 
-libqos_init(register_e1000e_test);
+libqos_init(register_igb_test);
diff --git a/tests/qtest/libqos/igb.c b/tests/qtest/libqos/igb.c
index 925654c7fd..12fb531bf0 100644
--- a/tests/qtest/libqos/igb.c
+++ b/tests/qtest/libqos/igb.c
@@ -1,6 +1,7 @@
 /*
  * libqos driver framework
  *
+ * Copyright (c) 2022-2023 Red Hat, Inc.
  * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
@@ -17,7 +18,8 @@
  */
 
 #include "qemu/osdep.h"
-#include "hw/net/e1000_regs.h"
+#include "hw/net/igb_regs.h"
+#include "hw/net/mii.h"
 #include "hw/pci/pci_ids.h"
 #include "../libqtest.h"
 #include "pci-pc.h"
@@ -29,47 +31,12 @@
 #include "qgraph.h"
 #include "e1000e.h"
 
-#define E1000E_IVAR_TEST_CFG \
-    (((E1000E_RX0_MSG_ID | E1000_IVAR_INT_ALLOC_VALID) << E1000_IVAR_RXQ0_SHIFT) | \
-     ((E1000E_TX0_MSG_ID | E1000_IVAR_INT_ALLOC_VALID) << E1000_IVAR_TXQ0_SHIFT) | \
-     E1000_IVAR_TX_INT_EVERY_WB)
+#define IGB_IVAR_TEST_CFG \
+    ((E1000E_RX0_MSG_ID | E1000_IVAR_VALID) << (igb_ivar_entry_rx(0) * 8)   | \
+     ((E1000E_TX0_MSG_ID | E1000_IVAR_VALID) << (igb_ivar_entry_tx(0) * 8)))
 
 #define E1000E_RING_LEN (0x1000)
 
-void e1000e_tx_ring_push(QE1000E *d, void *descr)
-{
-    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
-    uint32_t tail = e1000e_macreg_read(d, E1000_TDT);
-    uint32_t len = e1000e_macreg_read(d, E1000_TDLEN) / E1000_RING_DESC_LEN;
-
-    qtest_memwrite(d_pci->pci_dev.bus->qts,
-                   d->tx_ring + tail * E1000_RING_DESC_LEN,
-                   descr, E1000_RING_DESC_LEN);
-    e1000e_macreg_write(d, E1000_TDT, (tail + 1) % len);
-
-    /* Read WB data for the packet transmitted */
-    qtest_memread(d_pci->pci_dev.bus->qts,
-                  d->tx_ring + tail * E1000_RING_DESC_LEN,
-                  descr, E1000_RING_DESC_LEN);
-}
-
-void e1000e_rx_ring_push(QE1000E *d, void *descr)
-{
-    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
-    uint32_t tail = e1000e_macreg_read(d, E1000_RDT);
-    uint32_t len = e1000e_macreg_read(d, E1000_RDLEN) / E1000_RING_DESC_LEN;
-
-    qtest_memwrite(d_pci->pci_dev.bus->qts,
-                   d->rx_ring + tail * E1000_RING_DESC_LEN,
-                   descr, E1000_RING_DESC_LEN);
-    e1000e_macreg_write(d, E1000_RDT, (tail + 1) % len);
-
-    /* Read WB data for the packet received */
-    qtest_memread(d_pci->pci_dev.bus->qts,
-                  d->rx_ring + tail * E1000_RING_DESC_LEN,
-                  descr, E1000_RING_DESC_LEN);
-}
-
 static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data)
 {
     QPCIDevice *res = data;
@@ -77,21 +44,6 @@ static void e1000e_foreach_callback(QPCIDevice *dev, int devfn, void *data)
     g_free(dev);
 }
 
-void e1000e_wait_isr(QE1000E *d, uint16_t msg_id)
-{
-    QE1000E_PCI *d_pci = container_of(d, QE1000E_PCI, e1000e);
-    guint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
-
-    do {
-        if (qpci_msix_pending(&d_pci->pci_dev, msg_id)) {
-            return;
-        }
-        qtest_clock_step(d_pci->pci_dev.bus->qts, 10000);
-    } while (g_get_monotonic_time() < end_time);
-
-    g_error("Timeout expired");
-}
-
 static void e1000e_pci_destructor(QOSGraphObject *obj)
 {
     QE1000E_PCI *epci = (QE1000E_PCI *) obj;
@@ -99,8 +51,9 @@ static void e1000e_pci_destructor(QOSGraphObject *obj)
     qpci_msix_disable(&epci->pci_dev);
 }
 
-static void e1000e_pci_start_hw(QOSGraphObject *obj)
+static void igb_pci_start_hw(QOSGraphObject *obj)
 {
+    static const uint8_t address[] = E1000E_ADDRESS;
     QE1000E_PCI *d = (QE1000E_PCI *) obj;
     uint32_t val;
 
@@ -111,58 +64,65 @@ static void e1000e_pci_start_hw(QOSGraphObject *obj)
     val = e1000e_macreg_read(&d->e1000e, E1000_CTRL);
     e1000e_macreg_write(&d->e1000e, E1000_CTRL, val | E1000_CTRL_RST | E1000_CTRL_SLU);
 
+    /* Setup link */
+    e1000e_macreg_write(&d->e1000e, E1000_MDIC,
+                        MII_BMCR_AUTOEN | MII_BMCR_ANRESTART |
+                        (MII_BMCR << E1000_MDIC_REG_SHIFT) |
+                        (1 << E1000_MDIC_PHY_SHIFT) |
+                        E1000_MDIC_OP_WRITE);
+
+    qtest_clock_step(d->pci_dev.bus->qts, 900000000);
+
     /* Enable and configure MSI-X */
     qpci_msix_enable(&d->pci_dev);
-    e1000e_macreg_write(&d->e1000e, E1000_IVAR, E1000E_IVAR_TEST_CFG);
+    e1000e_macreg_write(&d->e1000e, E1000_IVAR0, IGB_IVAR_TEST_CFG);
 
-    /* Check the device status - link and speed */
+    /* Check the device link status */
     val = e1000e_macreg_read(&d->e1000e, E1000_STATUS);
-    g_assert_cmphex(val & (E1000_STATUS_LU | E1000_STATUS_ASDV_1000),
-        ==, E1000_STATUS_LU | E1000_STATUS_ASDV_1000);
+    g_assert_cmphex(val & E1000_STATUS_LU, ==, E1000_STATUS_LU);
 
     /* Initialize TX/RX logic */
     e1000e_macreg_write(&d->e1000e, E1000_RCTL, 0);
     e1000e_macreg_write(&d->e1000e, E1000_TCTL, 0);
 
-    /* Notify the device that the driver is ready */
-    val = e1000e_macreg_read(&d->e1000e, E1000_CTRL_EXT);
-    e1000e_macreg_write(&d->e1000e, E1000_CTRL_EXT,
-        val | E1000_CTRL_EXT_DRV_LOAD);
-
-    e1000e_macreg_write(&d->e1000e, E1000_TDBAL,
+    e1000e_macreg_write(&d->e1000e, E1000_TDBAL(0),
                            (uint32_t) d->e1000e.tx_ring);
-    e1000e_macreg_write(&d->e1000e, E1000_TDBAH,
+    e1000e_macreg_write(&d->e1000e, E1000_TDBAH(0),
                            (uint32_t) (d->e1000e.tx_ring >> 32));
-    e1000e_macreg_write(&d->e1000e, E1000_TDLEN, E1000E_RING_LEN);
-    e1000e_macreg_write(&d->e1000e, E1000_TDT, 0);
-    e1000e_macreg_write(&d->e1000e, E1000_TDH, 0);
+    e1000e_macreg_write(&d->e1000e, E1000_TDLEN(0), E1000E_RING_LEN);
+    e1000e_macreg_write(&d->e1000e, E1000_TDT(0), 0);
+    e1000e_macreg_write(&d->e1000e, E1000_TDH(0), 0);
 
     /* Enable transmit */
     e1000e_macreg_write(&d->e1000e, E1000_TCTL, E1000_TCTL_EN);
 
-    e1000e_macreg_write(&d->e1000e, E1000_RDBAL,
+    e1000e_macreg_write(&d->e1000e, E1000_RDBAL(0),
                            (uint32_t)d->e1000e.rx_ring);
-    e1000e_macreg_write(&d->e1000e, E1000_RDBAH,
+    e1000e_macreg_write(&d->e1000e, E1000_RDBAH(0),
                            (uint32_t)(d->e1000e.rx_ring >> 32));
-    e1000e_macreg_write(&d->e1000e, E1000_RDLEN, E1000E_RING_LEN);
-    e1000e_macreg_write(&d->e1000e, E1000_RDT, 0);
-    e1000e_macreg_write(&d->e1000e, E1000_RDH, 0);
+    e1000e_macreg_write(&d->e1000e, E1000_RDLEN(0), E1000E_RING_LEN);
+    e1000e_macreg_write(&d->e1000e, E1000_RDT(0), 0);
+    e1000e_macreg_write(&d->e1000e, E1000_RDH(0), 0);
+    e1000e_macreg_write(&d->e1000e, E1000_RA,
+                        le32_to_cpu(*(uint32_t *)address));
+    e1000e_macreg_write(&d->e1000e, E1000_RA + 4,
+                        E1000_RAH_AV | E1000_RAH_POOL_1 |
+                        le16_to_cpu(*(uint16_t *)(address + 4)));
 
     /* Enable receive */
     e1000e_macreg_write(&d->e1000e, E1000_RFCTL, E1000_RFCTL_EXTEN);
-    e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN  |
-                                        E1000_RCTL_UPE |
-                                        E1000_RCTL_MPE);
+    e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN);
 
     /* Enable all interrupts */
-    e1000e_macreg_write(&d->e1000e, E1000_IMS, 0xFFFFFFFF);
+    e1000e_macreg_write(&d->e1000e, E1000_IMS,  0xFFFFFFFF);
+    e1000e_macreg_write(&d->e1000e, E1000_EIMS, 0xFFFFFFFF);
 
 }
 
-static void *e1000e_pci_get_driver(void *obj, const char *interface)
+static void *igb_pci_get_driver(void *obj, const char *interface)
 {
     QE1000E_PCI *epci = obj;
-    if (!g_strcmp0(interface, "e1000e-if")) {
+    if (!g_strcmp0(interface, "igb-if")) {
         return &epci->e1000e;
     }
 
@@ -171,12 +131,11 @@ static void *e1000e_pci_get_driver(void *obj, const char *interface)
         return &epci->pci_dev;
     }
 
-    fprintf(stderr, "%s not present in e1000e\n", interface);
+    fprintf(stderr, "%s not present in igb\n", interface);
     g_assert_not_reached();
 }
 
-static void *e1000e_pci_create(void *pci_bus, QGuestAllocator *alloc,
-                               void *addr)
+static void *igb_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr)
 {
     QE1000E_PCI *d = g_new0(QE1000E_PCI, 1);
     QPCIBus *bus = pci_bus;
@@ -196,18 +155,18 @@ static void *e1000e_pci_create(void *pci_bus, QGuestAllocator *alloc,
     d->e1000e.rx_ring = guest_alloc(alloc, E1000E_RING_LEN);
     g_assert(d->e1000e.rx_ring != 0);
 
-    d->obj.get_driver = e1000e_pci_get_driver;
-    d->obj.start_hw = e1000e_pci_start_hw;
+    d->obj.get_driver = igb_pci_get_driver;
+    d->obj.start_hw = igb_pci_start_hw;
     d->obj.destructor = e1000e_pci_destructor;
 
     return &d->obj;
 }
 
-static void e1000e_register_nodes(void)
+static void igb_register_nodes(void)
 {
     QPCIAddress addr = {
         .vendor_id = PCI_VENDOR_ID_INTEL,
-        .device_id = E1000_DEV_ID_82574L,
+        .device_id = E1000_DEV_ID_82576,
     };
 
     /*
@@ -219,8 +178,8 @@ static void e1000e_register_nodes(void)
     };
     add_qpci_address(&opts, &addr);
 
-    qos_node_create_driver("e1000e", e1000e_pci_create);
-    qos_node_consumes("e1000e", "pci-bus", &opts);
+    qos_node_create_driver("igb", igb_pci_create);
+    qos_node_consumes("igb", "pci-bus", &opts);
 }
 
-libqos_init(e1000e_register_nodes);
+libqos_init(igb_register_nodes);
diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build
index 32f028872c..cc209a8de5 100644
--- a/tests/qtest/libqos/meson.build
+++ b/tests/qtest/libqos/meson.build
@@ -30,6 +30,7 @@ libqos_srcs = files(
         'i2c.c',
         'i2c-imx.c',
         'i2c-omap.c',
+        'igb.c',
         'sdhci.c',
         'tpci200.c',
         'virtio.c',
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index f0ebb5fac6..10279ed3bf 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -256,6 +256,7 @@ qos_test_ss.add(
   'virtio-serial-test.c',
   'virtio-iommu-test.c',
   'vmxnet3-test.c',
+  'igb-test.c',
 )
 if config_host.has_key('CONFIG_POSIX')
   qos_test_ss.add(files('e1000e-test.c'))
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 12/13] tests/avocado: Add igb test
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
                   ` (10 preceding siblings ...)
  2023-01-14  4:10 ` [PATCH v2 11/13] tests/qtest/libqos/igb: Transform to igb tests Akihiko Odaki
@ 2023-01-14  4:10 ` Akihiko Odaki
  2023-01-14  4:10 ` [PATCH v2 13/13] docs/system/devices/igb: Add igb documentation Akihiko Odaki
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:10 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich

This automates ethtool tests for igb registers, interrupts, etc.

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 MAINTAINERS                                   |  1 +
 .../org.centos/stream/8/x86_64/test-avocado   |  1 +
 tests/avocado/igb.py                          | 38 +++++++++++++++++++
 3 files changed, 40 insertions(+)
 create mode 100644 tests/avocado/igb.py

diff --git a/MAINTAINERS b/MAINTAINERS
index 2599cd673c..5409f2d625 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2222,6 +2222,7 @@ igb
 M: Akihiko Odaki <akihiko.odaki@daynix.com>
 S: Maintained
 F: hw/net/igb*
+F: tests/avocado/igb.py
 F: tests/qtest/igb-test.c
 F: tests/qtest/libqos/igb.c
 
diff --git a/scripts/ci/org.centos/stream/8/x86_64/test-avocado b/scripts/ci/org.centos/stream/8/x86_64/test-avocado
index 7aeecbcfb8..7e07dbcc89 100755
--- a/scripts/ci/org.centos/stream/8/x86_64/test-avocado
+++ b/scripts/ci/org.centos/stream/8/x86_64/test-avocado
@@ -37,6 +37,7 @@ make get-vm-images
     tests/avocado/cpu_queries.py:QueryCPUModelExpansion.test \
     tests/avocado/empty_cpu_model.py:EmptyCPUModel.test \
     tests/avocado/hotplug_cpu.py:HotPlugCPU.test \
+    tests/avocado/igb.py:IGB.test \
     tests/avocado/info_usernet.py:InfoUsernet.test_hostfwd \
     tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu \
     tests/avocado/intel_iommu.py:IntelIOMMU.test_intel_iommu_pt \
diff --git a/tests/avocado/igb.py b/tests/avocado/igb.py
new file mode 100644
index 0000000000..abf5dfa07f
--- /dev/null
+++ b/tests/avocado/igb.py
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# ethtool tests for igb registers, interrupts, etc
+
+from avocado_qemu import LinuxTest
+
+class IGB(LinuxTest):
+    """
+    :avocado: tags=accel:kvm
+    :avocado: tags=arch:x86_64
+    :avocado: tags=distro:fedora
+    :avocado: tags=distro_version:31
+    :avocado: tags=machine:q35
+    """
+
+    timeout = 180
+
+    def test(self):
+        self.require_accelerator('kvm')
+        kernel_url = self.distro.pxeboot_url + 'vmlinuz'
+        kernel_hash = '5b6f6876e1b5bda314f93893271da0d5777b1f3c'
+        kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+        initrd_url = self.distro.pxeboot_url + 'initrd.img'
+        initrd_hash = 'dd0340a1b39bd28f88532babd4581c67649ec5b1'
+        initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
+
+        # Ideally we want to test MSI as well, but it is blocked by a bug
+        # fixed with:
+        # https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=28e96556baca7056d11d9fb3cdd0aba4483e00d8
+        kernel_params = self.distro.default_kernel_params + ' pci=nomsi'
+
+        self.vm.add_args('-kernel', kernel_path,
+                         '-initrd', initrd_path,
+                         '-append', kernel_params,
+                         '-accel', 'kvm',
+                         '-device', 'igb')
+        self.launch_and_wait()
+        self.ssh_command('dnf -y install ethtool')
+        self.ssh_command('ethtool -t eth1 offline')
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 13/13] docs/system/devices/igb: Add igb documentation
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
                   ` (11 preceding siblings ...)
  2023-01-14  4:10 ` [PATCH v2 12/13] tests/avocado: Add igb test Akihiko Odaki
@ 2023-01-14  4:10 ` Akihiko Odaki
  2023-01-16  8:01 ` [PATCH v2 00/13] Introduce igb Jason Wang
       [not found] ` <20230129053316.1071513-1-alxndr@bu.edu>
  14 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-14  4:10 UTC (permalink / raw)
  Cc: Akihiko Odaki, Jason Wang, Dmitry Fleytman, Michael S. Tsirkin,
	Marcel Apfelbaum, Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich

Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
---
 MAINTAINERS                      |  1 +
 docs/system/device-emulation.rst |  1 +
 docs/system/devices/igb.rst      | 70 ++++++++++++++++++++++++++++++++
 3 files changed, 72 insertions(+)
 create mode 100644 docs/system/devices/igb.rst

diff --git a/MAINTAINERS b/MAINTAINERS
index 5409f2d625..8a72a29658 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2221,6 +2221,7 @@ F: tests/qtest/fuzz-e1000e-test.c
 igb
 M: Akihiko Odaki <akihiko.odaki@daynix.com>
 S: Maintained
+F: docs/system/devices/igb.rst
 F: hw/net/igb*
 F: tests/avocado/igb.py
 F: tests/qtest/igb-test.c
diff --git a/docs/system/device-emulation.rst b/docs/system/device-emulation.rst
index 0506006056..c1b1934e3d 100644
--- a/docs/system/device-emulation.rst
+++ b/docs/system/device-emulation.rst
@@ -93,3 +93,4 @@ Emulated Devices
    devices/virtio-pmem.rst
    devices/vhost-user-rng.rst
    devices/canokey.rst
+   devices/igb.rst
diff --git a/docs/system/devices/igb.rst b/docs/system/devices/igb.rst
new file mode 100644
index 0000000000..1a77c82ed8
--- /dev/null
+++ b/docs/system/devices/igb.rst
@@ -0,0 +1,70 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+.. _igb:
+
+igb
+---
+
+igb is a family of Intel's gigabit ethernet controllers. In QEMU, 82576
+emulation is implemented in particular. Its datasheet is available at [1]_.
+
+This implementation is expected to be useful to test SR-IOV networking without
+requiring physical hardware.
+
+Limitations
+===========
+
+This igb implementation was tested with Linux Test Project [2]_ during the
+initial development. The command used when testing is:
+
+.. code-block:: shell
+
+  network.sh -6mta
+
+Be aware that this implementation lacks many functionalities available with the
+actual hardware, and you may experience various failures if you try to use it
+with a different operating system other than Linux or if you try functionalities
+not covered by the tests.
+
+Using igb
+=========
+
+Using igb should be nothing different from using another network device. See
+:ref:`pcsys_005fnetwork` in general.
+
+However, you may also need to perform additional steps to activate SR-IOV
+feature on your guest. For Linux, refer to [3]_.
+
+Developing igb
+==============
+
+igb is the successor of e1000e, and e1000e is the successor of e1000 in turn.
+As these devices are very similar, if you make a change for igb and the same
+change can be applied to e1000e and e1000, please do so.
+
+Please do not forget to run tests before submitting a change. As tests included
+in QEMU is very minimal, run some application which is likely to be affected by
+the change to confirm it works in an integrated system.
+
+Testing igb
+===========
+
+A qtest of the basic functionality is available. Run the below at the build
+directory:
+
+.. code-block:: shell
+
+  meson test qtest-x86_64/qos-test
+
+ethtool can test register accesses, interrupts, etc. It is automated as an
+Avocado test and can be ran with the following command:
+
+.. code:: shell
+
+  make check-avocado AVOCADO_TESTS=tests/avocado/igb.py
+
+References
+==========
+
+.. [1] https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82576eb-gigabit-ethernet-controller-datasheet.pdf
+.. [2] https://github.com/linux-test-project/ltp
+.. [3] https://docs.kernel.org/PCI/pci-iov-howto.html
-- 
2.39.0



^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 00/13] Introduce igb
  2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
                   ` (12 preceding siblings ...)
  2023-01-14  4:10 ` [PATCH v2 13/13] docs/system/devices/igb: Add igb documentation Akihiko Odaki
@ 2023-01-16  8:01 ` Jason Wang
  2023-01-24  4:53   ` Akihiko Odaki
       [not found] ` <20230129053316.1071513-1-alxndr@bu.edu>
  14 siblings, 1 reply; 24+ messages in thread
From: Jason Wang @ 2023-01-16  8:01 UTC (permalink / raw)
  To: Akihiko Odaki
  Cc: Dmitry Fleytman, Michael S. Tsirkin, Marcel Apfelbaum,
	Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich

On Sat, Jan 14, 2023 at 12:10 PM Akihiko Odaki <akihiko.odaki@daynix.com> wrote:
>
> Based-on: <20230114035919.35251-1-akihiko.odaki@daynix.com>
> ([PATCH 00/19] e1000x cleanups (preliminary for IGB))
>
> igb is a family of Intel's gigabit ethernet controllers. This series implements
> 82576 emulation in particular. You can see the last patch for the documentation.
>
> Note that there is another effort to bring 82576 emulation. This series was
> developed independently by Sriram Yagnaraman.
> https://lists.gnu.org/archive/html/qemu-devel/2022-12/msg04670.html
>
> It is possible to merge the work from Sriram Yagnaraman and to cherry-pick
> useful changes from this series later.
>
> I think there are several different ways to get the changes into the mainline.
> I'm open to any options.

I can only do reviews for the general networking part but not the
82576 specific part. It would be better if either of the series can
get some ACKs from some ones that they are familiar with 82576, then I
can try to merge.

Thanks

>
> V1 -> V2:
> - Spun off e1000e general improvements to a distinct series.
> - Restored vnet_hdr offload as there seems nothing preventing from that.
>
> Akihiko Odaki (13):
>   hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr
>   pcie: Introduce pcie_sriov_num_vfs
>   e1000: Split header files
>   igb: Copy e1000e code
>   igb: Rename identifiers
>   igb: Build igb
>   igb: Transform to 82576 implementation
>   tests/qtest/e1000e-test: Fabricate ethernet header
>   tests/qtest/libqos/e1000e: Export macreg functions
>   tests/qtest/libqos/igb: Copy e1000e code
>   tests/qtest/libqos/igb: Transform to igb tests
>   tests/avocado: Add igb test
>   docs/system/devices/igb: Add igb documentation
>
>  MAINTAINERS                                   |    9 +
>  docs/system/device-emulation.rst              |    1 +
>  docs/system/devices/igb.rst                   |   70 +
>  hw/net/Kconfig                                |    5 +
>  hw/net/e1000.c                                |    1 +
>  hw/net/e1000_common.h                         |  102 +
>  hw/net/e1000_regs.h                           |  927 +---
>  hw/net/e1000e.c                               |    3 +-
>  hw/net/e1000e_core.c                          |    1 +
>  hw/net/e1000x_common.c                        |    1 +
>  hw/net/e1000x_common.h                        |   74 -
>  hw/net/e1000x_regs.h                          |  940 ++++
>  hw/net/igb.c                                  |  615 +++
>  hw/net/igb_common.h                           |  144 +
>  hw/net/igb_core.c                             | 3946 +++++++++++++++++
>  hw/net/igb_core.h                             |  147 +
>  hw/net/igb_regs.h                             |  624 +++
>  hw/net/igbvf.c                                |  327 ++
>  hw/net/meson.build                            |    2 +
>  hw/net/net_tx_pkt.c                           |    6 +
>  hw/net/net_tx_pkt.h                           |    8 +
>  hw/net/trace-events                           |   32 +
>  hw/pci/pcie_sriov.c                           |    5 +
>  include/hw/pci/pcie_sriov.h                   |    3 +
>  .../org.centos/stream/8/x86_64/test-avocado   |    1 +
>  tests/avocado/igb.py                          |   38 +
>  tests/qtest/e1000e-test.c                     |   17 +-
>  tests/qtest/fuzz/generic_fuzz_configs.h       |    5 +
>  tests/qtest/igb-test.c                        |  243 +
>  tests/qtest/libqos/e1000e.c                   |   12 -
>  tests/qtest/libqos/e1000e.h                   |   14 +
>  tests/qtest/libqos/igb.c                      |  185 +
>  tests/qtest/libqos/meson.build                |    1 +
>  tests/qtest/meson.build                       |    1 +
>  34 files changed, 7492 insertions(+), 1018 deletions(-)
>  create mode 100644 docs/system/devices/igb.rst
>  create mode 100644 hw/net/e1000_common.h
>  create mode 100644 hw/net/e1000x_regs.h
>  create mode 100644 hw/net/igb.c
>  create mode 100644 hw/net/igb_common.h
>  create mode 100644 hw/net/igb_core.c
>  create mode 100644 hw/net/igb_core.h
>  create mode 100644 hw/net/igb_regs.h
>  create mode 100644 hw/net/igbvf.c
>  create mode 100644 tests/avocado/igb.py
>  create mode 100644 tests/qtest/igb-test.c
>  create mode 100644 tests/qtest/libqos/igb.c
>
> --
> 2.39.0
>



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 00/13] Introduce igb
  2023-01-16  8:01 ` [PATCH v2 00/13] Introduce igb Jason Wang
@ 2023-01-24  4:53   ` Akihiko Odaki
  2023-01-24  8:53     ` Sriram Yagnaraman
  0 siblings, 1 reply; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-24  4:53 UTC (permalink / raw)
  To: Jason Wang, Sriram Yagnaraman
  Cc: Dmitry Fleytman, Michael S. Tsirkin, Marcel Apfelbaum,
	Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich

On 2023/01/16 17:01, Jason Wang wrote:
> On Sat, Jan 14, 2023 at 12:10 PM Akihiko Odaki <akihiko.odaki@daynix.com> wrote:
>>
>> Based-on: <20230114035919.35251-1-akihiko.odaki@daynix.com>
>> ([PATCH 00/19] e1000x cleanups (preliminary for IGB))
>>
>> igb is a family of Intel's gigabit ethernet controllers. This series implements
>> 82576 emulation in particular. You can see the last patch for the documentation.
>>
>> Note that there is another effort to bring 82576 emulation. This series was
>> developed independently by Sriram Yagnaraman.
>> https://lists.gnu.org/archive/html/qemu-devel/2022-12/msg04670.html
>>
>> It is possible to merge the work from Sriram Yagnaraman and to cherry-pick
>> useful changes from this series later.
>>
>> I think there are several different ways to get the changes into the mainline.
>> I'm open to any options.
> 
> I can only do reviews for the general networking part but not the
> 82576 specific part. It would be better if either of the series can
> get some ACKs from some ones that they are familiar with 82576, then I
> can try to merge.
> 
> Thanks

I have just sent v3 to the list.

Sriram Yagnaraman, who wrote another series for 82576, is the only 
person I know who is familiar with the device.

Sriram, can you take a look at v3 I have just sent?

Regards,
Akihiko Odaki

> 
>>
>> V1 -> V2:
>> - Spun off e1000e general improvements to a distinct series.
>> - Restored vnet_hdr offload as there seems nothing preventing from that.
>>
>> Akihiko Odaki (13):
>>    hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr
>>    pcie: Introduce pcie_sriov_num_vfs
>>    e1000: Split header files
>>    igb: Copy e1000e code
>>    igb: Rename identifiers
>>    igb: Build igb
>>    igb: Transform to 82576 implementation
>>    tests/qtest/e1000e-test: Fabricate ethernet header
>>    tests/qtest/libqos/e1000e: Export macreg functions
>>    tests/qtest/libqos/igb: Copy e1000e code
>>    tests/qtest/libqos/igb: Transform to igb tests
>>    tests/avocado: Add igb test
>>    docs/system/devices/igb: Add igb documentation
>>
>>   MAINTAINERS                                   |    9 +
>>   docs/system/device-emulation.rst              |    1 +
>>   docs/system/devices/igb.rst                   |   70 +
>>   hw/net/Kconfig                                |    5 +
>>   hw/net/e1000.c                                |    1 +
>>   hw/net/e1000_common.h                         |  102 +
>>   hw/net/e1000_regs.h                           |  927 +---
>>   hw/net/e1000e.c                               |    3 +-
>>   hw/net/e1000e_core.c                          |    1 +
>>   hw/net/e1000x_common.c                        |    1 +
>>   hw/net/e1000x_common.h                        |   74 -
>>   hw/net/e1000x_regs.h                          |  940 ++++
>>   hw/net/igb.c                                  |  615 +++
>>   hw/net/igb_common.h                           |  144 +
>>   hw/net/igb_core.c                             | 3946 +++++++++++++++++
>>   hw/net/igb_core.h                             |  147 +
>>   hw/net/igb_regs.h                             |  624 +++
>>   hw/net/igbvf.c                                |  327 ++
>>   hw/net/meson.build                            |    2 +
>>   hw/net/net_tx_pkt.c                           |    6 +
>>   hw/net/net_tx_pkt.h                           |    8 +
>>   hw/net/trace-events                           |   32 +
>>   hw/pci/pcie_sriov.c                           |    5 +
>>   include/hw/pci/pcie_sriov.h                   |    3 +
>>   .../org.centos/stream/8/x86_64/test-avocado   |    1 +
>>   tests/avocado/igb.py                          |   38 +
>>   tests/qtest/e1000e-test.c                     |   17 +-
>>   tests/qtest/fuzz/generic_fuzz_configs.h       |    5 +
>>   tests/qtest/igb-test.c                        |  243 +
>>   tests/qtest/libqos/e1000e.c                   |   12 -
>>   tests/qtest/libqos/e1000e.h                   |   14 +
>>   tests/qtest/libqos/igb.c                      |  185 +
>>   tests/qtest/libqos/meson.build                |    1 +
>>   tests/qtest/meson.build                       |    1 +
>>   34 files changed, 7492 insertions(+), 1018 deletions(-)
>>   create mode 100644 docs/system/devices/igb.rst
>>   create mode 100644 hw/net/e1000_common.h
>>   create mode 100644 hw/net/e1000x_regs.h
>>   create mode 100644 hw/net/igb.c
>>   create mode 100644 hw/net/igb_common.h
>>   create mode 100644 hw/net/igb_core.c
>>   create mode 100644 hw/net/igb_core.h
>>   create mode 100644 hw/net/igb_regs.h
>>   create mode 100644 hw/net/igbvf.c
>>   create mode 100644 tests/avocado/igb.py
>>   create mode 100644 tests/qtest/igb-test.c
>>   create mode 100644 tests/qtest/libqos/igb.c
>>
>> --
>> 2.39.0
>>
> 


^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v2 00/13] Introduce igb
  2023-01-24  4:53   ` Akihiko Odaki
@ 2023-01-24  8:53     ` Sriram Yagnaraman
  2023-01-26  9:34       ` Sriram Yagnaraman
  0 siblings, 1 reply; 24+ messages in thread
From: Sriram Yagnaraman @ 2023-01-24  8:53 UTC (permalink / raw)
  To: Akihiko Odaki, Jason Wang
  Cc: Dmitry Fleytman, Michael S. Tsirkin, Marcel Apfelbaum,
	Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich


> -----Original Message-----
> From: Akihiko Odaki <akihiko.odaki@daynix.com>
> Sent: Tuesday, 24 January 2023 05:54
> To: Jason Wang <jasowang@redhat.com>; Sriram Yagnaraman
> <sriram.yagnaraman@est.tech>
> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
> <mst@redhat.com>; Marcel Apfelbaum <marcel.apfelbaum@gmail.com>;
> Alex Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos Santos
> Moschetta <wainersm@redhat.com>; Beraldo Leal <bleal@redhat.com>;
> Cleber Rosa <crosa@redhat.com>; Laurent Vivier <lvivier@redhat.com>;
> Paolo Bonzini <pbonzini@redhat.com>; Alexander Bulekov <alxndr@bu.edu>;
> Bandan Das <bsd@redhat.com>; Stefan Hajnoczi <stefanha@redhat.com>;
> Darren Kenny <darren.kenny@oracle.com>; Qiuhao Li
> <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
> <yvugenfi@redhat.com>; Yuri Benditovich <yuri.benditovich@daynix.com>
> Subject: Re: [PATCH v2 00/13] Introduce igb
> 
> On 2023/01/16 17:01, Jason Wang wrote:
> > On Sat, Jan 14, 2023 at 12:10 PM Akihiko Odaki
> <akihiko.odaki@daynix.com> wrote:
> >>
> >> Based-on: <20230114035919.35251-1-akihiko.odaki@daynix.com>
> >> ([PATCH 00/19] e1000x cleanups (preliminary for IGB))
> >>
> >> igb is a family of Intel's gigabit ethernet controllers. This series
> >> implements
> >> 82576 emulation in particular. You can see the last patch for the
> documentation.
> >>
> >> Note that there is another effort to bring 82576 emulation. This
> >> series was developed independently by Sriram Yagnaraman.
> >> https://lists.gnu.org/archive/html/qemu-devel/2022-12/msg04670.html
> >>
> >> It is possible to merge the work from Sriram Yagnaraman and to
> >> cherry-pick useful changes from this series later.
> >>
> >> I think there are several different ways to get the changes into the mainline.
> >> I'm open to any options.
> >
> > I can only do reviews for the general networking part but not the
> > 82576 specific part. It would be better if either of the series can
> > get some ACKs from some ones that they are familiar with 82576, then I
> > can try to merge.
> >
> > Thanks
> 
> I have just sent v3 to the list.
> 
> Sriram Yagnaraman, who wrote another series for 82576, is the only person I
> know who is familiar with the device.
> 
> Sriram, can you take a look at v3 I have just sent?

I am at best a good interpreter of the 82576 datasheet. I will review your changes get back here.

> 
> Regards,
> Akihiko Odaki
> 
> >
> >>
> >> V1 -> V2:
> >> - Spun off e1000e general improvements to a distinct series.
> >> - Restored vnet_hdr offload as there seems nothing preventing from that.
> >>
> >> Akihiko Odaki (13):
> >>    hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr
> >>    pcie: Introduce pcie_sriov_num_vfs
> >>    e1000: Split header files
> >>    igb: Copy e1000e code
> >>    igb: Rename identifiers
> >>    igb: Build igb
> >>    igb: Transform to 82576 implementation
> >>    tests/qtest/e1000e-test: Fabricate ethernet header
> >>    tests/qtest/libqos/e1000e: Export macreg functions
> >>    tests/qtest/libqos/igb: Copy e1000e code
> >>    tests/qtest/libqos/igb: Transform to igb tests
> >>    tests/avocado: Add igb test
> >>    docs/system/devices/igb: Add igb documentation
> >>
> >>   MAINTAINERS                                   |    9 +
> >>   docs/system/device-emulation.rst              |    1 +
> >>   docs/system/devices/igb.rst                   |   70 +
> >>   hw/net/Kconfig                                |    5 +
> >>   hw/net/e1000.c                                |    1 +
> >>   hw/net/e1000_common.h                         |  102 +
> >>   hw/net/e1000_regs.h                           |  927 +---
> >>   hw/net/e1000e.c                               |    3 +-
> >>   hw/net/e1000e_core.c                          |    1 +
> >>   hw/net/e1000x_common.c                        |    1 +
> >>   hw/net/e1000x_common.h                        |   74 -
> >>   hw/net/e1000x_regs.h                          |  940 ++++
> >>   hw/net/igb.c                                  |  615 +++
> >>   hw/net/igb_common.h                           |  144 +
> >>   hw/net/igb_core.c                             | 3946 +++++++++++++++++
> >>   hw/net/igb_core.h                             |  147 +
> >>   hw/net/igb_regs.h                             |  624 +++
> >>   hw/net/igbvf.c                                |  327 ++
> >>   hw/net/meson.build                            |    2 +
> >>   hw/net/net_tx_pkt.c                           |    6 +
> >>   hw/net/net_tx_pkt.h                           |    8 +
> >>   hw/net/trace-events                           |   32 +
> >>   hw/pci/pcie_sriov.c                           |    5 +
> >>   include/hw/pci/pcie_sriov.h                   |    3 +
> >>   .../org.centos/stream/8/x86_64/test-avocado   |    1 +
> >>   tests/avocado/igb.py                          |   38 +
> >>   tests/qtest/e1000e-test.c                     |   17 +-
> >>   tests/qtest/fuzz/generic_fuzz_configs.h       |    5 +
> >>   tests/qtest/igb-test.c                        |  243 +
> >>   tests/qtest/libqos/e1000e.c                   |   12 -
> >>   tests/qtest/libqos/e1000e.h                   |   14 +
> >>   tests/qtest/libqos/igb.c                      |  185 +
> >>   tests/qtest/libqos/meson.build                |    1 +
> >>   tests/qtest/meson.build                       |    1 +
> >>   34 files changed, 7492 insertions(+), 1018 deletions(-)
> >>   create mode 100644 docs/system/devices/igb.rst
> >>   create mode 100644 hw/net/e1000_common.h
> >>   create mode 100644 hw/net/e1000x_regs.h
> >>   create mode 100644 hw/net/igb.c
> >>   create mode 100644 hw/net/igb_common.h
> >>   create mode 100644 hw/net/igb_core.c
> >>   create mode 100644 hw/net/igb_core.h
> >>   create mode 100644 hw/net/igb_regs.h
> >>   create mode 100644 hw/net/igbvf.c
> >>   create mode 100644 tests/avocado/igb.py
> >>   create mode 100644 tests/qtest/igb-test.c
> >>   create mode 100644 tests/qtest/libqos/igb.c
> >>
> >> --
> >> 2.39.0
> >>
> >

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v2 00/13] Introduce igb
  2023-01-24  8:53     ` Sriram Yagnaraman
@ 2023-01-26  9:34       ` Sriram Yagnaraman
  2023-01-26 11:31         ` Akihiko Odaki
  0 siblings, 1 reply; 24+ messages in thread
From: Sriram Yagnaraman @ 2023-01-26  9:34 UTC (permalink / raw)
  To: Akihiko Odaki, Jason Wang
  Cc: Dmitry Fleytman, Michael S. Tsirkin, Marcel Apfelbaum,
	Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich


> -----Original Message-----
> From: Sriram Yagnaraman
> Sent: Tuesday, 24 January 2023 09:54
> To: Akihiko Odaki <akihiko.odaki@daynix.com>; Jason Wang
> <jasowang@redhat.com>
> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
> <mst@redhat.com>; Marcel Apfelbaum <marcel.apfelbaum@gmail.com>;
> Alex Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos Santos
> Moschetta <wainersm@redhat.com>; Beraldo Leal <bleal@redhat.com>;
> Cleber Rosa <crosa@redhat.com>; Laurent Vivier <lvivier@redhat.com>;
> Paolo Bonzini <pbonzini@redhat.com>; Alexander Bulekov <alxndr@bu.edu>;
> Bandan Das <bsd@redhat.com>; Stefan Hajnoczi <stefanha@redhat.com>;
> Darren Kenny <darren.kenny@oracle.com>; Qiuhao Li
> <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
> <yvugenfi@redhat.com>; Yuri Benditovich <yuri.benditovich@daynix.com>
> Subject: RE: [PATCH v2 00/13] Introduce igb
> 
> 
> > -----Original Message-----
> > From: Akihiko Odaki <akihiko.odaki@daynix.com>
> > Sent: Tuesday, 24 January 2023 05:54
> > To: Jason Wang <jasowang@redhat.com>; Sriram Yagnaraman
> > <sriram.yagnaraman@est.tech>
> > Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
> > <mst@redhat.com>; Marcel Apfelbaum <marcel.apfelbaum@gmail.com>;
> Alex
> > Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
> > <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos
> Santos
> > Moschetta <wainersm@redhat.com>; Beraldo Leal <bleal@redhat.com>;
> > Cleber Rosa <crosa@redhat.com>; Laurent Vivier <lvivier@redhat.com>;
> > Paolo Bonzini <pbonzini@redhat.com>; Alexander Bulekov
> > <alxndr@bu.edu>; Bandan Das <bsd@redhat.com>; Stefan Hajnoczi
> > <stefanha@redhat.com>; Darren Kenny <darren.kenny@oracle.com>;
> Qiuhao
> > Li <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
> > ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
> > <yvugenfi@redhat.com>; Yuri Benditovich <yuri.benditovich@daynix.com>
> > Subject: Re: [PATCH v2 00/13] Introduce igb
> >
> > On 2023/01/16 17:01, Jason Wang wrote:
> > > On Sat, Jan 14, 2023 at 12:10 PM Akihiko Odaki
> > <akihiko.odaki@daynix.com> wrote:
> > >>
> > >> Based-on: <20230114035919.35251-1-akihiko.odaki@daynix.com>
> > >> ([PATCH 00/19] e1000x cleanups (preliminary for IGB))
> > >>
> > >> igb is a family of Intel's gigabit ethernet controllers. This
> > >> series implements
> > >> 82576 emulation in particular. You can see the last patch for the
> > documentation.
> > >>
> > >> Note that there is another effort to bring 82576 emulation. This
> > >> series was developed independently by Sriram Yagnaraman.
> > >> https://lists.gnu.org/archive/html/qemu-devel/2022-12/msg04670.html
> > >>
> > >> It is possible to merge the work from Sriram Yagnaraman and to
> > >> cherry-pick useful changes from this series later.
> > >>
> > >> I think there are several different ways to get the changes into the
> mainline.
> > >> I'm open to any options.
> > >
> > > I can only do reviews for the general networking part but not the
> > > 82576 specific part. It would be better if either of the series can
> > > get some ACKs from some ones that they are familiar with 82576, then
> > > I can try to merge.
> > >
> > > Thanks
> >
> > I have just sent v3 to the list.
> >
> > Sriram Yagnaraman, who wrote another series for 82576, is the only
> > person I know who is familiar with the device.
> >
> > Sriram, can you take a look at v3 I have just sent?
> 
> I am at best a good interpreter of the 82576 datasheet. I will review your
> changes get back here.

I have reviewed and tested your changes and it looks great to me in general.
I would like to note some features that I would like to add on top of your patch, if you have not worked on these already :)
- PFRSTD (PF reset done)
- SRRCTL (Rx desc buf size)
- RLPML (oversized packet handling)
- MAC/VLAN anti-spoof checks
- VMOLR_STRVLAN and RPLOLR_STRVLAN (VLAN stripping for VFs)
- VMVIR (VLAN insertion for VFs)
- VF reset
- VFTE, VFRE, VFLRE
- VF stats
- Set EITR initial value

Since this is a new device and there are no existing users, is it possible to get the change into baseline first and fix missing features and bugs soon after?

> 
> >
> > Regards,
> > Akihiko Odaki
> >
> > >
> > >>
> > >> V1 -> V2:
> > >> - Spun off e1000e general improvements to a distinct series.
> > >> - Restored vnet_hdr offload as there seems nothing preventing from that.
> > >>
> > >> Akihiko Odaki (13):
> > >>    hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr
> > >>    pcie: Introduce pcie_sriov_num_vfs
> > >>    e1000: Split header files
> > >>    igb: Copy e1000e code
> > >>    igb: Rename identifiers
> > >>    igb: Build igb
> > >>    igb: Transform to 82576 implementation
> > >>    tests/qtest/e1000e-test: Fabricate ethernet header
> > >>    tests/qtest/libqos/e1000e: Export macreg functions
> > >>    tests/qtest/libqos/igb: Copy e1000e code
> > >>    tests/qtest/libqos/igb: Transform to igb tests
> > >>    tests/avocado: Add igb test
> > >>    docs/system/devices/igb: Add igb documentation
> > >>
> > >>   MAINTAINERS                                   |    9 +
> > >>   docs/system/device-emulation.rst              |    1 +
> > >>   docs/system/devices/igb.rst                   |   70 +
> > >>   hw/net/Kconfig                                |    5 +
> > >>   hw/net/e1000.c                                |    1 +
> > >>   hw/net/e1000_common.h                         |  102 +
> > >>   hw/net/e1000_regs.h                           |  927 +---
> > >>   hw/net/e1000e.c                               |    3 +-
> > >>   hw/net/e1000e_core.c                          |    1 +
> > >>   hw/net/e1000x_common.c                        |    1 +
> > >>   hw/net/e1000x_common.h                        |   74 -
> > >>   hw/net/e1000x_regs.h                          |  940 ++++
> > >>   hw/net/igb.c                                  |  615 +++
> > >>   hw/net/igb_common.h                           |  144 +
> > >>   hw/net/igb_core.c                             | 3946 +++++++++++++++++
> > >>   hw/net/igb_core.h                             |  147 +
> > >>   hw/net/igb_regs.h                             |  624 +++
> > >>   hw/net/igbvf.c                                |  327 ++
> > >>   hw/net/meson.build                            |    2 +
> > >>   hw/net/net_tx_pkt.c                           |    6 +
> > >>   hw/net/net_tx_pkt.h                           |    8 +
> > >>   hw/net/trace-events                           |   32 +
> > >>   hw/pci/pcie_sriov.c                           |    5 +
> > >>   include/hw/pci/pcie_sriov.h                   |    3 +
> > >>   .../org.centos/stream/8/x86_64/test-avocado   |    1 +
> > >>   tests/avocado/igb.py                          |   38 +
> > >>   tests/qtest/e1000e-test.c                     |   17 +-
> > >>   tests/qtest/fuzz/generic_fuzz_configs.h       |    5 +
> > >>   tests/qtest/igb-test.c                        |  243 +
> > >>   tests/qtest/libqos/e1000e.c                   |   12 -
> > >>   tests/qtest/libqos/e1000e.h                   |   14 +
> > >>   tests/qtest/libqos/igb.c                      |  185 +
> > >>   tests/qtest/libqos/meson.build                |    1 +
> > >>   tests/qtest/meson.build                       |    1 +
> > >>   34 files changed, 7492 insertions(+), 1018 deletions(-)
> > >>   create mode 100644 docs/system/devices/igb.rst
> > >>   create mode 100644 hw/net/e1000_common.h
> > >>   create mode 100644 hw/net/e1000x_regs.h
> > >>   create mode 100644 hw/net/igb.c
> > >>   create mode 100644 hw/net/igb_common.h
> > >>   create mode 100644 hw/net/igb_core.c
> > >>   create mode 100644 hw/net/igb_core.h
> > >>   create mode 100644 hw/net/igb_regs.h
> > >>   create mode 100644 hw/net/igbvf.c
> > >>   create mode 100644 tests/avocado/igb.py
> > >>   create mode 100644 tests/qtest/igb-test.c
> > >>   create mode 100644 tests/qtest/libqos/igb.c
> > >>
> > >> --
> > >> 2.39.0
> > >>
> > >

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 00/13] Introduce igb
  2023-01-26  9:34       ` Sriram Yagnaraman
@ 2023-01-26 11:31         ` Akihiko Odaki
  2023-01-28 20:57           ` Sriram Yagnaraman
  0 siblings, 1 reply; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-26 11:31 UTC (permalink / raw)
  To: Sriram Yagnaraman, Jason Wang
  Cc: Dmitry Fleytman, Michael S. Tsirkin, Marcel Apfelbaum,
	Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich

On 2023/01/26 18:34, Sriram Yagnaraman wrote:
> 
>> -----Original Message-----
>> From: Sriram Yagnaraman
>> Sent: Tuesday, 24 January 2023 09:54
>> To: Akihiko Odaki <akihiko.odaki@daynix.com>; Jason Wang
>> <jasowang@redhat.com>
>> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
>> <mst@redhat.com>; Marcel Apfelbaum <marcel.apfelbaum@gmail.com>;
>> Alex Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
>> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos Santos
>> Moschetta <wainersm@redhat.com>; Beraldo Leal <bleal@redhat.com>;
>> Cleber Rosa <crosa@redhat.com>; Laurent Vivier <lvivier@redhat.com>;
>> Paolo Bonzini <pbonzini@redhat.com>; Alexander Bulekov <alxndr@bu.edu>;
>> Bandan Das <bsd@redhat.com>; Stefan Hajnoczi <stefanha@redhat.com>;
>> Darren Kenny <darren.kenny@oracle.com>; Qiuhao Li
>> <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
>> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
>> <yvugenfi@redhat.com>; Yuri Benditovich <yuri.benditovich@daynix.com>
>> Subject: RE: [PATCH v2 00/13] Introduce igb
>>
>>
>>> -----Original Message-----
>>> From: Akihiko Odaki <akihiko.odaki@daynix.com>
>>> Sent: Tuesday, 24 January 2023 05:54
>>> To: Jason Wang <jasowang@redhat.com>; Sriram Yagnaraman
>>> <sriram.yagnaraman@est.tech>
>>> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
>>> <mst@redhat.com>; Marcel Apfelbaum <marcel.apfelbaum@gmail.com>;
>> Alex
>>> Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
>>> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos
>> Santos
>>> Moschetta <wainersm@redhat.com>; Beraldo Leal <bleal@redhat.com>;
>>> Cleber Rosa <crosa@redhat.com>; Laurent Vivier <lvivier@redhat.com>;
>>> Paolo Bonzini <pbonzini@redhat.com>; Alexander Bulekov
>>> <alxndr@bu.edu>; Bandan Das <bsd@redhat.com>; Stefan Hajnoczi
>>> <stefanha@redhat.com>; Darren Kenny <darren.kenny@oracle.com>;
>> Qiuhao
>>> Li <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
>>> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
>>> <yvugenfi@redhat.com>; Yuri Benditovich <yuri.benditovich@daynix.com>
>>> Subject: Re: [PATCH v2 00/13] Introduce igb
>>>
>>> On 2023/01/16 17:01, Jason Wang wrote:
>>>> On Sat, Jan 14, 2023 at 12:10 PM Akihiko Odaki
>>> <akihiko.odaki@daynix.com> wrote:
>>>>>
>>>>> Based-on: <20230114035919.35251-1-akihiko.odaki@daynix.com>
>>>>> ([PATCH 00/19] e1000x cleanups (preliminary for IGB))
>>>>>
>>>>> igb is a family of Intel's gigabit ethernet controllers. This
>>>>> series implements
>>>>> 82576 emulation in particular. You can see the last patch for the
>>> documentation.
>>>>>
>>>>> Note that there is another effort to bring 82576 emulation. This
>>>>> series was developed independently by Sriram Yagnaraman.
>>>>> https://lists.gnu.org/archive/html/qemu-devel/2022-12/msg04670.html
>>>>>
>>>>> It is possible to merge the work from Sriram Yagnaraman and to
>>>>> cherry-pick useful changes from this series later.
>>>>>
>>>>> I think there are several different ways to get the changes into the
>> mainline.
>>>>> I'm open to any options.
>>>>
>>>> I can only do reviews for the general networking part but not the
>>>> 82576 specific part. It would be better if either of the series can
>>>> get some ACKs from some ones that they are familiar with 82576, then
>>>> I can try to merge.
>>>>
>>>> Thanks
>>>
>>> I have just sent v3 to the list.
>>>
>>> Sriram Yagnaraman, who wrote another series for 82576, is the only
>>> person I know who is familiar with the device.
>>>
>>> Sriram, can you take a look at v3 I have just sent?
>>
>> I am at best a good interpreter of the 82576 datasheet. I will review your
>> changes get back here.
> 
> I have reviewed and tested your changes and it looks great to me in general.
> I would like to note some features that I would like to add on top of your patch, if you have not worked on these already :)
> - PFRSTD (PF reset done)
> - SRRCTL (Rx desc buf size)
> - RLPML (oversized packet handling)
> - MAC/VLAN anti-spoof checks
> - VMOLR_STRVLAN and RPLOLR_STRVLAN (VLAN stripping for VFs)
> - VMVIR (VLAN insertion for VFs)
> - VF reset
> - VFTE, VFRE, VFLRE
> - VF stats
> - Set EITR initial value
> 
> Since this is a new device and there are no existing users, is it possible to get the change into baseline first and fix missing features and bugs soon after?

Thanks for reviewing,

I have just submitted v4. The difference from v3 is only that igb now 
correctly specifies VFs associated with queues for DMA.

RX descriptor buffer size in SRRCTL is respected since v3. I think the 
other features are missing. I am not planning to implement them either, 
but I'm considering to test the code with DPDK and I may add features it 
requires.

I also want to get this series into the mainline before adding new 
features as it is already so big, but please tell me if you noticed 
bugs, especially ones which can be fixed without adding more code.

Regards,
Akihiko Odaki

> 
>>
>>>
>>> Regards,
>>> Akihiko Odaki
>>>
>>>>
>>>>>
>>>>> V1 -> V2:
>>>>> - Spun off e1000e general improvements to a distinct series.
>>>>> - Restored vnet_hdr offload as there seems nothing preventing from that.
>>>>>
>>>>> Akihiko Odaki (13):
>>>>>     hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr
>>>>>     pcie: Introduce pcie_sriov_num_vfs
>>>>>     e1000: Split header files
>>>>>     igb: Copy e1000e code
>>>>>     igb: Rename identifiers
>>>>>     igb: Build igb
>>>>>     igb: Transform to 82576 implementation
>>>>>     tests/qtest/e1000e-test: Fabricate ethernet header
>>>>>     tests/qtest/libqos/e1000e: Export macreg functions
>>>>>     tests/qtest/libqos/igb: Copy e1000e code
>>>>>     tests/qtest/libqos/igb: Transform to igb tests
>>>>>     tests/avocado: Add igb test
>>>>>     docs/system/devices/igb: Add igb documentation
>>>>>
>>>>>    MAINTAINERS                                   |    9 +
>>>>>    docs/system/device-emulation.rst              |    1 +
>>>>>    docs/system/devices/igb.rst                   |   70 +
>>>>>    hw/net/Kconfig                                |    5 +
>>>>>    hw/net/e1000.c                                |    1 +
>>>>>    hw/net/e1000_common.h                         |  102 +
>>>>>    hw/net/e1000_regs.h                           |  927 +---
>>>>>    hw/net/e1000e.c                               |    3 +-
>>>>>    hw/net/e1000e_core.c                          |    1 +
>>>>>    hw/net/e1000x_common.c                        |    1 +
>>>>>    hw/net/e1000x_common.h                        |   74 -
>>>>>    hw/net/e1000x_regs.h                          |  940 ++++
>>>>>    hw/net/igb.c                                  |  615 +++
>>>>>    hw/net/igb_common.h                           |  144 +
>>>>>    hw/net/igb_core.c                             | 3946 +++++++++++++++++
>>>>>    hw/net/igb_core.h                             |  147 +
>>>>>    hw/net/igb_regs.h                             |  624 +++
>>>>>    hw/net/igbvf.c                                |  327 ++
>>>>>    hw/net/meson.build                            |    2 +
>>>>>    hw/net/net_tx_pkt.c                           |    6 +
>>>>>    hw/net/net_tx_pkt.h                           |    8 +
>>>>>    hw/net/trace-events                           |   32 +
>>>>>    hw/pci/pcie_sriov.c                           |    5 +
>>>>>    include/hw/pci/pcie_sriov.h                   |    3 +
>>>>>    .../org.centos/stream/8/x86_64/test-avocado   |    1 +
>>>>>    tests/avocado/igb.py                          |   38 +
>>>>>    tests/qtest/e1000e-test.c                     |   17 +-
>>>>>    tests/qtest/fuzz/generic_fuzz_configs.h       |    5 +
>>>>>    tests/qtest/igb-test.c                        |  243 +
>>>>>    tests/qtest/libqos/e1000e.c                   |   12 -
>>>>>    tests/qtest/libqos/e1000e.h                   |   14 +
>>>>>    tests/qtest/libqos/igb.c                      |  185 +
>>>>>    tests/qtest/libqos/meson.build                |    1 +
>>>>>    tests/qtest/meson.build                       |    1 +
>>>>>    34 files changed, 7492 insertions(+), 1018 deletions(-)
>>>>>    create mode 100644 docs/system/devices/igb.rst
>>>>>    create mode 100644 hw/net/e1000_common.h
>>>>>    create mode 100644 hw/net/e1000x_regs.h
>>>>>    create mode 100644 hw/net/igb.c
>>>>>    create mode 100644 hw/net/igb_common.h
>>>>>    create mode 100644 hw/net/igb_core.c
>>>>>    create mode 100644 hw/net/igb_core.h
>>>>>    create mode 100644 hw/net/igb_regs.h
>>>>>    create mode 100644 hw/net/igbvf.c
>>>>>    create mode 100644 tests/avocado/igb.py
>>>>>    create mode 100644 tests/qtest/igb-test.c
>>>>>    create mode 100644 tests/qtest/libqos/igb.c
>>>>>
>>>>> --
>>>>> 2.39.0
>>>>>
>>>>


^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v2 00/13] Introduce igb
  2023-01-26 11:31         ` Akihiko Odaki
@ 2023-01-28 20:57           ` Sriram Yagnaraman
  2023-01-30 14:38             ` Akihiko Odaki
  0 siblings, 1 reply; 24+ messages in thread
From: Sriram Yagnaraman @ 2023-01-28 20:57 UTC (permalink / raw)
  To: Akihiko Odaki, Jason Wang
  Cc: Dmitry Fleytman, Michael S. Tsirkin, Marcel Apfelbaum,
	Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich

> -----Original Message-----
> From: Akihiko Odaki <akihiko.odaki@daynix.com>
> Sent: Thursday, 26 January 2023 12:32
> To: Sriram Yagnaraman <sriram.yagnaraman@est.tech>; Jason Wang
> <jasowang@redhat.com>
> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
> <mst@redhat.com>; Marcel Apfelbaum <marcel.apfelbaum@gmail.com>;
> Alex Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos Santos
> Moschetta <wainersm@redhat.com>; Beraldo Leal <bleal@redhat.com>;
> Cleber Rosa <crosa@redhat.com>; Laurent Vivier <lvivier@redhat.com>;
> Paolo Bonzini <pbonzini@redhat.com>; Alexander Bulekov <alxndr@bu.edu>;
> Bandan Das <bsd@redhat.com>; Stefan Hajnoczi <stefanha@redhat.com>;
> Darren Kenny <darren.kenny@oracle.com>; Qiuhao Li
> <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
> <yvugenfi@redhat.com>; Yuri Benditovich <yuri.benditovich@daynix.com>
> Subject: Re: [PATCH v2 00/13] Introduce igb
> 
> On 2023/01/26 18:34, Sriram Yagnaraman wrote:
> >
> >> -----Original Message-----
> >> From: Sriram Yagnaraman
> >> Sent: Tuesday, 24 January 2023 09:54
> >> To: Akihiko Odaki <akihiko.odaki@daynix.com>; Jason Wang
> >> <jasowang@redhat.com>
> >> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
> >> <mst@redhat.com>; Marcel Apfelbaum <marcel.apfelbaum@gmail.com>;
> Alex
> >> Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
> >> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos
> >> Santos Moschetta <wainersm@redhat.com>; Beraldo Leal
> >> <bleal@redhat.com>; Cleber Rosa <crosa@redhat.com>; Laurent Vivier
> >> <lvivier@redhat.com>; Paolo Bonzini <pbonzini@redhat.com>; Alexander
> >> Bulekov <alxndr@bu.edu>; Bandan Das <bsd@redhat.com>; Stefan
> Hajnoczi
> >> <stefanha@redhat.com>; Darren Kenny <darren.kenny@oracle.com>;
> Qiuhao
> >> Li <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
> >> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
> >> <yvugenfi@redhat.com>; Yuri Benditovich <yuri.benditovich@daynix.com>
> >> Subject: RE: [PATCH v2 00/13] Introduce igb
> >>
> >>
> >>> -----Original Message-----
> >>> From: Akihiko Odaki <akihiko.odaki@daynix.com>
> >>> Sent: Tuesday, 24 January 2023 05:54
> >>> To: Jason Wang <jasowang@redhat.com>; Sriram Yagnaraman
> >>> <sriram.yagnaraman@est.tech>
> >>> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
> >>> <mst@redhat.com>; Marcel Apfelbaum
> <marcel.apfelbaum@gmail.com>;
> >> Alex
> >>> Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
> >>> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos
> >> Santos
> >>> Moschetta <wainersm@redhat.com>; Beraldo Leal <bleal@redhat.com>;
> >>> Cleber Rosa <crosa@redhat.com>; Laurent Vivier <lvivier@redhat.com>;
> >>> Paolo Bonzini <pbonzini@redhat.com>; Alexander Bulekov
> >>> <alxndr@bu.edu>; Bandan Das <bsd@redhat.com>; Stefan Hajnoczi
> >>> <stefanha@redhat.com>; Darren Kenny <darren.kenny@oracle.com>;
> >> Qiuhao
> >>> Li <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
> >>> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
> >>> <yvugenfi@redhat.com>; Yuri Benditovich
> >>> <yuri.benditovich@daynix.com>
> >>> Subject: Re: [PATCH v2 00/13] Introduce igb
> >>>
> >>> On 2023/01/16 17:01, Jason Wang wrote:
> >>>> On Sat, Jan 14, 2023 at 12:10 PM Akihiko Odaki
> >>> <akihiko.odaki@daynix.com> wrote:
> >>>>>
> >>>>> Based-on: <20230114035919.35251-1-akihiko.odaki@daynix.com>
> >>>>> ([PATCH 00/19] e1000x cleanups (preliminary for IGB))
> >>>>>
> >>>>> igb is a family of Intel's gigabit ethernet controllers. This
> >>>>> series implements
> >>>>> 82576 emulation in particular. You can see the last patch for the
> >>> documentation.
> >>>>>
> >>>>> Note that there is another effort to bring 82576 emulation. This
> >>>>> series was developed independently by Sriram Yagnaraman.
> >>>>> https://lists.gnu.org/archive/html/qemu-devel/2022-
> 12/msg04670.htm
> >>>>> l
> >>>>>
> >>>>> It is possible to merge the work from Sriram Yagnaraman and to
> >>>>> cherry-pick useful changes from this series later.
> >>>>>
> >>>>> I think there are several different ways to get the changes into
> >>>>> the
> >> mainline.
> >>>>> I'm open to any options.
> >>>>
> >>>> I can only do reviews for the general networking part but not the
> >>>> 82576 specific part. It would be better if either of the series can
> >>>> get some ACKs from some ones that they are familiar with 82576,
> >>>> then I can try to merge.
> >>>>
> >>>> Thanks
> >>>
> >>> I have just sent v3 to the list.
> >>>
> >>> Sriram Yagnaraman, who wrote another series for 82576, is the only
> >>> person I know who is familiar with the device.
> >>>
> >>> Sriram, can you take a look at v3 I have just sent?
> >>
> >> I am at best a good interpreter of the 82576 datasheet. I will review
> >> your changes get back here.
> >
> > I have reviewed and tested your changes and it looks great to me in general.
> > I would like to note some features that I would like to add on top of
> > your patch, if you have not worked on these already :)
> > - PFRSTD (PF reset done)
> > - SRRCTL (Rx desc buf size)
> > - RLPML (oversized packet handling)
> > - MAC/VLAN anti-spoof checks
> > - VMOLR_STRVLAN and RPLOLR_STRVLAN (VLAN stripping for VFs)
> > - VMVIR (VLAN insertion for VFs)
> > - VF reset
> > - VFTE, VFRE, VFLRE
> > - VF stats
> > - Set EITR initial value
> >
> > Since this is a new device and there are no existing users, is it possible to get
> the change into baseline first and fix missing features and bugs soon after?
> 
> Thanks for reviewing,
> 
> I have just submitted v4. The difference from v3 is only that igb now correctly
> specifies VFs associated with queues for DMA.
> 
> RX descriptor buffer size in SRRCTL is respected since v3. I think the other
> features are missing. I am not planning to implement them either, but I'm
> considering to test the code with DPDK and I may add features it requires.

Ok, I just sent a patchset adding most of the features I listed above ([PATCH 0/9] igb: add missing feature set).

> 
> I also want to get this series into the mainline before adding new features as it
> is already so big, but please tell me if you noticed bugs, especially ones which
> can be fixed without adding more code.

LGTM, I have tested your changes and it works perfectly. Thank you.
Is it possible to squash your igb commits into one patch that I can give an ACK to?

> 
> Regards,
> Akihiko Odaki
> 
> >
> >>
> >>>
> >>> Regards,
> >>> Akihiko Odaki
> >>>
> >>>>
> >>>>>
> >>>>> V1 -> V2:
> >>>>> - Spun off e1000e general improvements to a distinct series.
> >>>>> - Restored vnet_hdr offload as there seems nothing preventing from
> that.
> >>>>>
> >>>>> Akihiko Odaki (13):
> >>>>>     hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr
> >>>>>     pcie: Introduce pcie_sriov_num_vfs
> >>>>>     e1000: Split header files
> >>>>>     igb: Copy e1000e code
> >>>>>     igb: Rename identifiers
> >>>>>     igb: Build igb
> >>>>>     igb: Transform to 82576 implementation
> >>>>>     tests/qtest/e1000e-test: Fabricate ethernet header
> >>>>>     tests/qtest/libqos/e1000e: Export macreg functions
> >>>>>     tests/qtest/libqos/igb: Copy e1000e code
> >>>>>     tests/qtest/libqos/igb: Transform to igb tests
> >>>>>     tests/avocado: Add igb test
> >>>>>     docs/system/devices/igb: Add igb documentation
> >>>>>
> >>>>>    MAINTAINERS                                   |    9 +
> >>>>>    docs/system/device-emulation.rst              |    1 +
> >>>>>    docs/system/devices/igb.rst                   |   70 +
> >>>>>    hw/net/Kconfig                                |    5 +
> >>>>>    hw/net/e1000.c                                |    1 +
> >>>>>    hw/net/e1000_common.h                         |  102 +
> >>>>>    hw/net/e1000_regs.h                           |  927 +---
> >>>>>    hw/net/e1000e.c                               |    3 +-
> >>>>>    hw/net/e1000e_core.c                          |    1 +
> >>>>>    hw/net/e1000x_common.c                        |    1 +
> >>>>>    hw/net/e1000x_common.h                        |   74 -
> >>>>>    hw/net/e1000x_regs.h                          |  940 ++++
> >>>>>    hw/net/igb.c                                  |  615 +++
> >>>>>    hw/net/igb_common.h                           |  144 +
> >>>>>    hw/net/igb_core.c                             | 3946 +++++++++++++++++
> >>>>>    hw/net/igb_core.h                             |  147 +
> >>>>>    hw/net/igb_regs.h                             |  624 +++
> >>>>>    hw/net/igbvf.c                                |  327 ++
> >>>>>    hw/net/meson.build                            |    2 +
> >>>>>    hw/net/net_tx_pkt.c                           |    6 +
> >>>>>    hw/net/net_tx_pkt.h                           |    8 +
> >>>>>    hw/net/trace-events                           |   32 +
> >>>>>    hw/pci/pcie_sriov.c                           |    5 +
> >>>>>    include/hw/pci/pcie_sriov.h                   |    3 +
> >>>>>    .../org.centos/stream/8/x86_64/test-avocado   |    1 +
> >>>>>    tests/avocado/igb.py                          |   38 +
> >>>>>    tests/qtest/e1000e-test.c                     |   17 +-
> >>>>>    tests/qtest/fuzz/generic_fuzz_configs.h       |    5 +
> >>>>>    tests/qtest/igb-test.c                        |  243 +
> >>>>>    tests/qtest/libqos/e1000e.c                   |   12 -
> >>>>>    tests/qtest/libqos/e1000e.h                   |   14 +
> >>>>>    tests/qtest/libqos/igb.c                      |  185 +
> >>>>>    tests/qtest/libqos/meson.build                |    1 +
> >>>>>    tests/qtest/meson.build                       |    1 +
> >>>>>    34 files changed, 7492 insertions(+), 1018 deletions(-)
> >>>>>    create mode 100644 docs/system/devices/igb.rst
> >>>>>    create mode 100644 hw/net/e1000_common.h
> >>>>>    create mode 100644 hw/net/e1000x_regs.h
> >>>>>    create mode 100644 hw/net/igb.c
> >>>>>    create mode 100644 hw/net/igb_common.h
> >>>>>    create mode 100644 hw/net/igb_core.c
> >>>>>    create mode 100644 hw/net/igb_core.h
> >>>>>    create mode 100644 hw/net/igb_regs.h
> >>>>>    create mode 100644 hw/net/igbvf.c
> >>>>>    create mode 100644 tests/avocado/igb.py
> >>>>>    create mode 100644 tests/qtest/igb-test.c
> >>>>>    create mode 100644 tests/qtest/libqos/igb.c
> >>>>>
> >>>>> --
> >>>>> 2.39.0
> >>>>>
> >>>>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 00/13] Introduce igb
  2023-01-28 20:57           ` Sriram Yagnaraman
@ 2023-01-30 14:38             ` Akihiko Odaki
  2023-01-31  9:48               ` Sriram Yagnaraman
  0 siblings, 1 reply; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-30 14:38 UTC (permalink / raw)
  To: Sriram Yagnaraman, Jason Wang
  Cc: Dmitry Fleytman, Michael S. Tsirkin, Marcel Apfelbaum,
	Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich

On 2023/01/29 5:57, Sriram Yagnaraman wrote:
>> -----Original Message-----
>> From: Akihiko Odaki <akihiko.odaki@daynix.com>
>> Sent: Thursday, 26 January 2023 12:32
>> To: Sriram Yagnaraman <sriram.yagnaraman@est.tech>; Jason Wang
>> <jasowang@redhat.com>
>> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
>> <mst@redhat.com>; Marcel Apfelbaum <marcel.apfelbaum@gmail.com>;
>> Alex Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
>> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos Santos
>> Moschetta <wainersm@redhat.com>; Beraldo Leal <bleal@redhat.com>;
>> Cleber Rosa <crosa@redhat.com>; Laurent Vivier <lvivier@redhat.com>;
>> Paolo Bonzini <pbonzini@redhat.com>; Alexander Bulekov <alxndr@bu.edu>;
>> Bandan Das <bsd@redhat.com>; Stefan Hajnoczi <stefanha@redhat.com>;
>> Darren Kenny <darren.kenny@oracle.com>; Qiuhao Li
>> <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
>> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
>> <yvugenfi@redhat.com>; Yuri Benditovich <yuri.benditovich@daynix.com>
>> Subject: Re: [PATCH v2 00/13] Introduce igb
>>
>> On 2023/01/26 18:34, Sriram Yagnaraman wrote:
>>>
>>>> -----Original Message-----
>>>> From: Sriram Yagnaraman
>>>> Sent: Tuesday, 24 January 2023 09:54
>>>> To: Akihiko Odaki <akihiko.odaki@daynix.com>; Jason Wang
>>>> <jasowang@redhat.com>
>>>> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
>>>> <mst@redhat.com>; Marcel Apfelbaum <marcel.apfelbaum@gmail.com>;
>> Alex
>>>> Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
>>>> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos
>>>> Santos Moschetta <wainersm@redhat.com>; Beraldo Leal
>>>> <bleal@redhat.com>; Cleber Rosa <crosa@redhat.com>; Laurent Vivier
>>>> <lvivier@redhat.com>; Paolo Bonzini <pbonzini@redhat.com>; Alexander
>>>> Bulekov <alxndr@bu.edu>; Bandan Das <bsd@redhat.com>; Stefan
>> Hajnoczi
>>>> <stefanha@redhat.com>; Darren Kenny <darren.kenny@oracle.com>;
>> Qiuhao
>>>> Li <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
>>>> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
>>>> <yvugenfi@redhat.com>; Yuri Benditovich <yuri.benditovich@daynix.com>
>>>> Subject: RE: [PATCH v2 00/13] Introduce igb
>>>>
>>>>
>>>>> -----Original Message-----
>>>>> From: Akihiko Odaki <akihiko.odaki@daynix.com>
>>>>> Sent: Tuesday, 24 January 2023 05:54
>>>>> To: Jason Wang <jasowang@redhat.com>; Sriram Yagnaraman
>>>>> <sriram.yagnaraman@est.tech>
>>>>> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
>>>>> <mst@redhat.com>; Marcel Apfelbaum
>> <marcel.apfelbaum@gmail.com>;
>>>> Alex
>>>>> Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
>>>>> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos
>>>> Santos
>>>>> Moschetta <wainersm@redhat.com>; Beraldo Leal <bleal@redhat.com>;
>>>>> Cleber Rosa <crosa@redhat.com>; Laurent Vivier <lvivier@redhat.com>;
>>>>> Paolo Bonzini <pbonzini@redhat.com>; Alexander Bulekov
>>>>> <alxndr@bu.edu>; Bandan Das <bsd@redhat.com>; Stefan Hajnoczi
>>>>> <stefanha@redhat.com>; Darren Kenny <darren.kenny@oracle.com>;
>>>> Qiuhao
>>>>> Li <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
>>>>> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
>>>>> <yvugenfi@redhat.com>; Yuri Benditovich
>>>>> <yuri.benditovich@daynix.com>
>>>>> Subject: Re: [PATCH v2 00/13] Introduce igb
>>>>>
>>>>> On 2023/01/16 17:01, Jason Wang wrote:
>>>>>> On Sat, Jan 14, 2023 at 12:10 PM Akihiko Odaki
>>>>> <akihiko.odaki@daynix.com> wrote:
>>>>>>>
>>>>>>> Based-on: <20230114035919.35251-1-akihiko.odaki@daynix.com>
>>>>>>> ([PATCH 00/19] e1000x cleanups (preliminary for IGB))
>>>>>>>
>>>>>>> igb is a family of Intel's gigabit ethernet controllers. This
>>>>>>> series implements
>>>>>>> 82576 emulation in particular. You can see the last patch for the
>>>>> documentation.
>>>>>>>
>>>>>>> Note that there is another effort to bring 82576 emulation. This
>>>>>>> series was developed independently by Sriram Yagnaraman.
>>>>>>> https://lists.gnu.org/archive/html/qemu-devel/2022-
>> 12/msg04670.htm
>>>>>>> l
>>>>>>>
>>>>>>> It is possible to merge the work from Sriram Yagnaraman and to
>>>>>>> cherry-pick useful changes from this series later.
>>>>>>>
>>>>>>> I think there are several different ways to get the changes into
>>>>>>> the
>>>> mainline.
>>>>>>> I'm open to any options.
>>>>>>
>>>>>> I can only do reviews for the general networking part but not the
>>>>>> 82576 specific part. It would be better if either of the series can
>>>>>> get some ACKs from some ones that they are familiar with 82576,
>>>>>> then I can try to merge.
>>>>>>
>>>>>> Thanks
>>>>>
>>>>> I have just sent v3 to the list.
>>>>>
>>>>> Sriram Yagnaraman, who wrote another series for 82576, is the only
>>>>> person I know who is familiar with the device.
>>>>>
>>>>> Sriram, can you take a look at v3 I have just sent?
>>>>
>>>> I am at best a good interpreter of the 82576 datasheet. I will review
>>>> your changes get back here.
>>>
>>> I have reviewed and tested your changes and it looks great to me in general.
>>> I would like to note some features that I would like to add on top of
>>> your patch, if you have not worked on these already :)
>>> - PFRSTD (PF reset done)
>>> - SRRCTL (Rx desc buf size)
>>> - RLPML (oversized packet handling)
>>> - MAC/VLAN anti-spoof checks
>>> - VMOLR_STRVLAN and RPLOLR_STRVLAN (VLAN stripping for VFs)
>>> - VMVIR (VLAN insertion for VFs)
>>> - VF reset
>>> - VFTE, VFRE, VFLRE
>>> - VF stats
>>> - Set EITR initial value
>>>
>>> Since this is a new device and there are no existing users, is it possible to get
>> the change into baseline first and fix missing features and bugs soon after?
>>
>> Thanks for reviewing,
>>
>> I have just submitted v4. The difference from v3 is only that igb now correctly
>> specifies VFs associated with queues for DMA.
>>
>> RX descriptor buffer size in SRRCTL is respected since v3. I think the other
>> features are missing. I am not planning to implement them either, but I'm
>> considering to test the code with DPDK and I may add features it requires.
> 
> Ok, I just sent a patchset adding most of the features I listed above ([PATCH 0/9] igb: add missing feature set).

Thanks for your work and responding to my comments. Please check the 
comments for the latest series I have just sent, and also rebase it to 
the latest version of this series.

> 
>>
>> I also want to get this series into the mainline before adding new features as it
>> is already so big, but please tell me if you noticed bugs, especially ones which
>> can be fixed without adding more code.
> 
> LGTM, I have tested your changes and it works perfectly. Thank you.
> Is it possible to squash your igb commits into one patch that I can give an ACK to?

igb patches are now squahed in the latest version, which I have just sent.

> 
>>
>> Regards,
>> Akihiko Odaki
>>
>>>
>>>>
>>>>>
>>>>> Regards,
>>>>> Akihiko Odaki
>>>>>
>>>>>>
>>>>>>>
>>>>>>> V1 -> V2:
>>>>>>> - Spun off e1000e general improvements to a distinct series.
>>>>>>> - Restored vnet_hdr offload as there seems nothing preventing from
>> that.
>>>>>>>
>>>>>>> Akihiko Odaki (13):
>>>>>>>      hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr
>>>>>>>      pcie: Introduce pcie_sriov_num_vfs
>>>>>>>      e1000: Split header files
>>>>>>>      igb: Copy e1000e code
>>>>>>>      igb: Rename identifiers
>>>>>>>      igb: Build igb
>>>>>>>      igb: Transform to 82576 implementation
>>>>>>>      tests/qtest/e1000e-test: Fabricate ethernet header
>>>>>>>      tests/qtest/libqos/e1000e: Export macreg functions
>>>>>>>      tests/qtest/libqos/igb: Copy e1000e code
>>>>>>>      tests/qtest/libqos/igb: Transform to igb tests
>>>>>>>      tests/avocado: Add igb test
>>>>>>>      docs/system/devices/igb: Add igb documentation
>>>>>>>
>>>>>>>     MAINTAINERS                                   |    9 +
>>>>>>>     docs/system/device-emulation.rst              |    1 +
>>>>>>>     docs/system/devices/igb.rst                   |   70 +
>>>>>>>     hw/net/Kconfig                                |    5 +
>>>>>>>     hw/net/e1000.c                                |    1 +
>>>>>>>     hw/net/e1000_common.h                         |  102 +
>>>>>>>     hw/net/e1000_regs.h                           |  927 +---
>>>>>>>     hw/net/e1000e.c                               |    3 +-
>>>>>>>     hw/net/e1000e_core.c                          |    1 +
>>>>>>>     hw/net/e1000x_common.c                        |    1 +
>>>>>>>     hw/net/e1000x_common.h                        |   74 -
>>>>>>>     hw/net/e1000x_regs.h                          |  940 ++++
>>>>>>>     hw/net/igb.c                                  |  615 +++
>>>>>>>     hw/net/igb_common.h                           |  144 +
>>>>>>>     hw/net/igb_core.c                             | 3946 +++++++++++++++++
>>>>>>>     hw/net/igb_core.h                             |  147 +
>>>>>>>     hw/net/igb_regs.h                             |  624 +++
>>>>>>>     hw/net/igbvf.c                                |  327 ++
>>>>>>>     hw/net/meson.build                            |    2 +
>>>>>>>     hw/net/net_tx_pkt.c                           |    6 +
>>>>>>>     hw/net/net_tx_pkt.h                           |    8 +
>>>>>>>     hw/net/trace-events                           |   32 +
>>>>>>>     hw/pci/pcie_sriov.c                           |    5 +
>>>>>>>     include/hw/pci/pcie_sriov.h                   |    3 +
>>>>>>>     .../org.centos/stream/8/x86_64/test-avocado   |    1 +
>>>>>>>     tests/avocado/igb.py                          |   38 +
>>>>>>>     tests/qtest/e1000e-test.c                     |   17 +-
>>>>>>>     tests/qtest/fuzz/generic_fuzz_configs.h       |    5 +
>>>>>>>     tests/qtest/igb-test.c                        |  243 +
>>>>>>>     tests/qtest/libqos/e1000e.c                   |   12 -
>>>>>>>     tests/qtest/libqos/e1000e.h                   |   14 +
>>>>>>>     tests/qtest/libqos/igb.c                      |  185 +
>>>>>>>     tests/qtest/libqos/meson.build                |    1 +
>>>>>>>     tests/qtest/meson.build                       |    1 +
>>>>>>>     34 files changed, 7492 insertions(+), 1018 deletions(-)
>>>>>>>     create mode 100644 docs/system/devices/igb.rst
>>>>>>>     create mode 100644 hw/net/e1000_common.h
>>>>>>>     create mode 100644 hw/net/e1000x_regs.h
>>>>>>>     create mode 100644 hw/net/igb.c
>>>>>>>     create mode 100644 hw/net/igb_common.h
>>>>>>>     create mode 100644 hw/net/igb_core.c
>>>>>>>     create mode 100644 hw/net/igb_core.h
>>>>>>>     create mode 100644 hw/net/igb_regs.h
>>>>>>>     create mode 100644 hw/net/igbvf.c
>>>>>>>     create mode 100644 tests/avocado/igb.py
>>>>>>>     create mode 100644 tests/qtest/igb-test.c
>>>>>>>     create mode 100644 tests/qtest/libqos/igb.c
>>>>>>>
>>>>>>> --
>>>>>>> 2.39.0
>>>>>>>
>>>>>>


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] fuzz: add igb testcases
       [not found] ` <20230129053316.1071513-1-alxndr@bu.edu>
@ 2023-01-30 14:42   ` Akihiko Odaki
  0 siblings, 0 replies; 24+ messages in thread
From: Akihiko Odaki @ 2023-01-30 14:42 UTC (permalink / raw)
  To: Alexander Bulekov, qemu-devel
  Cc: Paolo Bonzini, Bandan Das, Stefan Hajnoczi, Thomas Huth,
	Darren Kenny, Qiuhao Li, Laurent Vivier

On 2023/01/29 14:33, Alexander Bulekov wrote:
> Signed-off-by: Alexander Bulekov<alxndr@bu.edu>
> ---
> 
> Hi Akihiko,
> Thank you for adding a fuzzer config for this device. The fuzzer found
> some crashes. Many of these are probably duplicates - the crash
> deduplication script has limitations. Also some of these might not
> specific to igb (e.g. -net user/slirp issues) - I had not good way to
> filter those out.

Hi,

Thanks for testing igb. I have just sent fixes to the list. The below is 
the link to them:

[PATCH v5 0/9] Introduce igb
https://patchew.org/QEMU/20230130140809.78262-1-akihiko.odaki@daynix.com/

[PATCH] hw/timer/hpet: Fix expiration time overflow
https://patchew.org/QEMU/20230130135001.76841-1-akihiko.odaki@daynix.com/

[PATCH] softmmu: Use memmove in flatview_write_continue
https://patchew.org/QEMU/20230130135152.76882-1-akihiko.odaki@daynix.com/

ip: Enforce strict aliasing
https://gitlab.freedesktop.org/slirp/libslirp/-/merge_requests/131

Regards,
Akihiko Odaki


^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v2 00/13] Introduce igb
  2023-01-30 14:38             ` Akihiko Odaki
@ 2023-01-31  9:48               ` Sriram Yagnaraman
  0 siblings, 0 replies; 24+ messages in thread
From: Sriram Yagnaraman @ 2023-01-31  9:48 UTC (permalink / raw)
  To: Akihiko Odaki, Jason Wang
  Cc: Dmitry Fleytman, Michael S. Tsirkin, Marcel Apfelbaum,
	Alex Bennée, Philippe Mathieu-Daudé,
	Thomas Huth, Wainer dos Santos Moschetta, Beraldo Leal,
	Cleber Rosa, Laurent Vivier, Paolo Bonzini, Alexander Bulekov,
	Bandan Das, Stefan Hajnoczi, Darren Kenny, Qiuhao Li, qemu-devel,
	qemu-ppc, devel, Yan Vugenfirer, Yuri Benditovich



> -----Original Message-----
> From: Akihiko Odaki <akihiko.odaki@daynix.com>
> Sent: Monday, 30 January 2023 15:39
> To: Sriram Yagnaraman <sriram.yagnaraman@est.tech>; Jason Wang
> <jasowang@redhat.com>
> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
> <mst@redhat.com>; Marcel Apfelbaum <marcel.apfelbaum@gmail.com>;
> Alex Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos Santos
> Moschetta <wainersm@redhat.com>; Beraldo Leal <bleal@redhat.com>;
> Cleber Rosa <crosa@redhat.com>; Laurent Vivier <lvivier@redhat.com>;
> Paolo Bonzini <pbonzini@redhat.com>; Alexander Bulekov <alxndr@bu.edu>;
> Bandan Das <bsd@redhat.com>; Stefan Hajnoczi <stefanha@redhat.com>;
> Darren Kenny <darren.kenny@oracle.com>; Qiuhao Li
> <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
> <yvugenfi@redhat.com>; Yuri Benditovich <yuri.benditovich@daynix.com>
> Subject: Re: [PATCH v2 00/13] Introduce igb
> 
> On 2023/01/29 5:57, Sriram Yagnaraman wrote:
> >> -----Original Message-----
> >> From: Akihiko Odaki <akihiko.odaki@daynix.com>
> >> Sent: Thursday, 26 January 2023 12:32
> >> To: Sriram Yagnaraman <sriram.yagnaraman@est.tech>; Jason Wang
> >> <jasowang@redhat.com>
> >> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
> >> <mst@redhat.com>; Marcel Apfelbaum <marcel.apfelbaum@gmail.com>;
> Alex
> >> Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
> >> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos
> >> Santos Moschetta <wainersm@redhat.com>; Beraldo Leal
> >> <bleal@redhat.com>; Cleber Rosa <crosa@redhat.com>; Laurent Vivier
> >> <lvivier@redhat.com>; Paolo Bonzini <pbonzini@redhat.com>; Alexander
> >> Bulekov <alxndr@bu.edu>; Bandan Das <bsd@redhat.com>; Stefan
> Hajnoczi
> >> <stefanha@redhat.com>; Darren Kenny <darren.kenny@oracle.com>;
> Qiuhao
> >> Li <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
> >> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
> >> <yvugenfi@redhat.com>; Yuri Benditovich <yuri.benditovich@daynix.com>
> >> Subject: Re: [PATCH v2 00/13] Introduce igb
> >>
> >> On 2023/01/26 18:34, Sriram Yagnaraman wrote:
> >>>
> >>>> -----Original Message-----
> >>>> From: Sriram Yagnaraman
> >>>> Sent: Tuesday, 24 January 2023 09:54
> >>>> To: Akihiko Odaki <akihiko.odaki@daynix.com>; Jason Wang
> >>>> <jasowang@redhat.com>
> >>>> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S. Tsirkin
> >>>> <mst@redhat.com>; Marcel Apfelbaum
> <marcel.apfelbaum@gmail.com>;
> >> Alex
> >>>> Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
> >>>> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos
> >>>> Santos Moschetta <wainersm@redhat.com>; Beraldo Leal
> >>>> <bleal@redhat.com>; Cleber Rosa <crosa@redhat.com>; Laurent Vivier
> >>>> <lvivier@redhat.com>; Paolo Bonzini <pbonzini@redhat.com>;
> >>>> Alexander Bulekov <alxndr@bu.edu>; Bandan Das <bsd@redhat.com>;
> >>>> Stefan
> >> Hajnoczi
> >>>> <stefanha@redhat.com>; Darren Kenny <darren.kenny@oracle.com>;
> >> Qiuhao
> >>>> Li <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
> >>>> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
> >>>> <yvugenfi@redhat.com>; Yuri Benditovich
> >>>> <yuri.benditovich@daynix.com>
> >>>> Subject: RE: [PATCH v2 00/13] Introduce igb
> >>>>
> >>>>
> >>>>> -----Original Message-----
> >>>>> From: Akihiko Odaki <akihiko.odaki@daynix.com>
> >>>>> Sent: Tuesday, 24 January 2023 05:54
> >>>>> To: Jason Wang <jasowang@redhat.com>; Sriram Yagnaraman
> >>>>> <sriram.yagnaraman@est.tech>
> >>>>> Cc: Dmitry Fleytman <dmitry.fleytman@gmail.com>; Michael S.
> >>>>> Tsirkin <mst@redhat.com>; Marcel Apfelbaum
> >> <marcel.apfelbaum@gmail.com>;
> >>>> Alex
> >>>>> Bennée <alex.bennee@linaro.org>; Philippe Mathieu-Daudé
> >>>>> <philmd@linaro.org>; Thomas Huth <thuth@redhat.com>; Wainer dos
> >>>> Santos
> >>>>> Moschetta <wainersm@redhat.com>; Beraldo Leal
> <bleal@redhat.com>;
> >>>>> Cleber Rosa <crosa@redhat.com>; Laurent Vivier
> >>>>> <lvivier@redhat.com>; Paolo Bonzini <pbonzini@redhat.com>;
> >>>>> Alexander Bulekov <alxndr@bu.edu>; Bandan Das <bsd@redhat.com>;
> >>>>> Stefan Hajnoczi <stefanha@redhat.com>; Darren Kenny
> >>>>> <darren.kenny@oracle.com>;
> >>>> Qiuhao
> >>>>> Li <Qiuhao.Li@outlook.com>; qemu-devel@nongnu.org; qemu-
> >>>>> ppc@nongnu.org; devel@daynix.com; Yan Vugenfirer
> >>>>> <yvugenfi@redhat.com>; Yuri Benditovich
> >>>>> <yuri.benditovich@daynix.com>
> >>>>> Subject: Re: [PATCH v2 00/13] Introduce igb
> >>>>>
> >>>>> On 2023/01/16 17:01, Jason Wang wrote:
> >>>>>> On Sat, Jan 14, 2023 at 12:10 PM Akihiko Odaki
> >>>>> <akihiko.odaki@daynix.com> wrote:
> >>>>>>>
> >>>>>>> Based-on: <20230114035919.35251-1-akihiko.odaki@daynix.com>
> >>>>>>> ([PATCH 00/19] e1000x cleanups (preliminary for IGB))
> >>>>>>>
> >>>>>>> igb is a family of Intel's gigabit ethernet controllers. This
> >>>>>>> series implements
> >>>>>>> 82576 emulation in particular. You can see the last patch for
> >>>>>>> the
> >>>>> documentation.
> >>>>>>>
> >>>>>>> Note that there is another effort to bring 82576 emulation. This
> >>>>>>> series was developed independently by Sriram Yagnaraman.
> >>>>>>> https://lists.gnu.org/archive/html/qemu-devel/2022-
> >> 12/msg04670.htm
> >>>>>>> l
> >>>>>>>
> >>>>>>> It is possible to merge the work from Sriram Yagnaraman and to
> >>>>>>> cherry-pick useful changes from this series later.
> >>>>>>>
> >>>>>>> I think there are several different ways to get the changes into
> >>>>>>> the
> >>>> mainline.
> >>>>>>> I'm open to any options.
> >>>>>>
> >>>>>> I can only do reviews for the general networking part but not the
> >>>>>> 82576 specific part. It would be better if either of the series
> >>>>>> can get some ACKs from some ones that they are familiar with
> >>>>>> 82576, then I can try to merge.
> >>>>>>
> >>>>>> Thanks
> >>>>>
> >>>>> I have just sent v3 to the list.
> >>>>>
> >>>>> Sriram Yagnaraman, who wrote another series for 82576, is the only
> >>>>> person I know who is familiar with the device.
> >>>>>
> >>>>> Sriram, can you take a look at v3 I have just sent?
> >>>>
> >>>> I am at best a good interpreter of the 82576 datasheet. I will
> >>>> review your changes get back here.
> >>>
> >>> I have reviewed and tested your changes and it looks great to me in
> general.
> >>> I would like to note some features that I would like to add on top
> >>> of your patch, if you have not worked on these already :)
> >>> - PFRSTD (PF reset done)
> >>> - SRRCTL (Rx desc buf size)
> >>> - RLPML (oversized packet handling)
> >>> - MAC/VLAN anti-spoof checks
> >>> - VMOLR_STRVLAN and RPLOLR_STRVLAN (VLAN stripping for VFs)
> >>> - VMVIR (VLAN insertion for VFs)
> >>> - VF reset
> >>> - VFTE, VFRE, VFLRE
> >>> - VF stats
> >>> - Set EITR initial value
> >>>
> >>> Since this is a new device and there are no existing users, is it
> >>> possible to get
> >> the change into baseline first and fix missing features and bugs soon after?
> >>
> >> Thanks for reviewing,
> >>
> >> I have just submitted v4. The difference from v3 is only that igb now
> >> correctly specifies VFs associated with queues for DMA.
> >>
> >> RX descriptor buffer size in SRRCTL is respected since v3. I think
> >> the other features are missing. I am not planning to implement them
> >> either, but I'm considering to test the code with DPDK and I may add
> features it requires.
> >
> > Ok, I just sent a patchset adding most of the features I listed above ([PATCH
> 0/9] igb: add missing feature set).
> 
> Thanks for your work and responding to my comments. Please check the
> comments for the latest series I have just sent, and also rebase it to the latest
> version of this series.

Done now. Thanks for the review, and really great work with this patch to introduce igb.

> 
> >
> >>
> >> I also want to get this series into the mainline before adding new
> >> features as it is already so big, but please tell me if you noticed
> >> bugs, especially ones which can be fixed without adding more code.
> >
> > LGTM, I have tested your changes and it works perfectly. Thank you.
> > Is it possible to squash your igb commits into one patch that I can give an
> ACK to?
> 
> igb patches are now squahed in the latest version, which I have just sent.

I have reviewed and put a Reviewed-By tag for the igb patch.
I hope it is OK for me to do that, since I am new to qemu-devel.

> 
> >
> >>
> >> Regards,
> >> Akihiko Odaki
> >>
> >>>
> >>>>
> >>>>>
> >>>>> Regards,
> >>>>> Akihiko Odaki
> >>>>>
> >>>>>>
> >>>>>>>
> >>>>>>> V1 -> V2:
> >>>>>>> - Spun off e1000e general improvements to a distinct series.
> >>>>>>> - Restored vnet_hdr offload as there seems nothing preventing
> >>>>>>> from
> >> that.
> >>>>>>>
> >>>>>>> Akihiko Odaki (13):
> >>>>>>>      hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr
> >>>>>>>      pcie: Introduce pcie_sriov_num_vfs
> >>>>>>>      e1000: Split header files
> >>>>>>>      igb: Copy e1000e code
> >>>>>>>      igb: Rename identifiers
> >>>>>>>      igb: Build igb
> >>>>>>>      igb: Transform to 82576 implementation
> >>>>>>>      tests/qtest/e1000e-test: Fabricate ethernet header
> >>>>>>>      tests/qtest/libqos/e1000e: Export macreg functions
> >>>>>>>      tests/qtest/libqos/igb: Copy e1000e code
> >>>>>>>      tests/qtest/libqos/igb: Transform to igb tests
> >>>>>>>      tests/avocado: Add igb test
> >>>>>>>      docs/system/devices/igb: Add igb documentation
> >>>>>>>
> >>>>>>>     MAINTAINERS                                   |    9 +
> >>>>>>>     docs/system/device-emulation.rst              |    1 +
> >>>>>>>     docs/system/devices/igb.rst                   |   70 +
> >>>>>>>     hw/net/Kconfig                                |    5 +
> >>>>>>>     hw/net/e1000.c                                |    1 +
> >>>>>>>     hw/net/e1000_common.h                         |  102 +
> >>>>>>>     hw/net/e1000_regs.h                           |  927 +---
> >>>>>>>     hw/net/e1000e.c                               |    3 +-
> >>>>>>>     hw/net/e1000e_core.c                          |    1 +
> >>>>>>>     hw/net/e1000x_common.c                        |    1 +
> >>>>>>>     hw/net/e1000x_common.h                        |   74 -
> >>>>>>>     hw/net/e1000x_regs.h                          |  940 ++++
> >>>>>>>     hw/net/igb.c                                  |  615 +++
> >>>>>>>     hw/net/igb_common.h                           |  144 +
> >>>>>>>     hw/net/igb_core.c                             | 3946 +++++++++++++++++
> >>>>>>>     hw/net/igb_core.h                             |  147 +
> >>>>>>>     hw/net/igb_regs.h                             |  624 +++
> >>>>>>>     hw/net/igbvf.c                                |  327 ++
> >>>>>>>     hw/net/meson.build                            |    2 +
> >>>>>>>     hw/net/net_tx_pkt.c                           |    6 +
> >>>>>>>     hw/net/net_tx_pkt.h                           |    8 +
> >>>>>>>     hw/net/trace-events                           |   32 +
> >>>>>>>     hw/pci/pcie_sriov.c                           |    5 +
> >>>>>>>     include/hw/pci/pcie_sriov.h                   |    3 +
> >>>>>>>     .../org.centos/stream/8/x86_64/test-avocado   |    1 +
> >>>>>>>     tests/avocado/igb.py                          |   38 +
> >>>>>>>     tests/qtest/e1000e-test.c                     |   17 +-
> >>>>>>>     tests/qtest/fuzz/generic_fuzz_configs.h       |    5 +
> >>>>>>>     tests/qtest/igb-test.c                        |  243 +
> >>>>>>>     tests/qtest/libqos/e1000e.c                   |   12 -
> >>>>>>>     tests/qtest/libqos/e1000e.h                   |   14 +
> >>>>>>>     tests/qtest/libqos/igb.c                      |  185 +
> >>>>>>>     tests/qtest/libqos/meson.build                |    1 +
> >>>>>>>     tests/qtest/meson.build                       |    1 +
> >>>>>>>     34 files changed, 7492 insertions(+), 1018 deletions(-)
> >>>>>>>     create mode 100644 docs/system/devices/igb.rst
> >>>>>>>     create mode 100644 hw/net/e1000_common.h
> >>>>>>>     create mode 100644 hw/net/e1000x_regs.h
> >>>>>>>     create mode 100644 hw/net/igb.c
> >>>>>>>     create mode 100644 hw/net/igb_common.h
> >>>>>>>     create mode 100644 hw/net/igb_core.c
> >>>>>>>     create mode 100644 hw/net/igb_core.h
> >>>>>>>     create mode 100644 hw/net/igb_regs.h
> >>>>>>>     create mode 100644 hw/net/igbvf.c
> >>>>>>>     create mode 100644 tests/avocado/igb.py
> >>>>>>>     create mode 100644 tests/qtest/igb-test.c
> >>>>>>>     create mode 100644 tests/qtest/libqos/igb.c
> >>>>>>>
> >>>>>>> --
> >>>>>>> 2.39.0
> >>>>>>>
> >>>>>>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH v2 00/13] Introduce igb
       [not found] <CACGkMEvAwrfUwQVAj0qZFy+Wib5FSBwayyN_qGbZ8edNwB_18g () mail ! gmail ! com>
@ 2023-01-17 10:06 ` Sriram Yagnaraman
  0 siblings, 0 replies; 24+ messages in thread
From: Sriram Yagnaraman @ 2023-01-17 10:06 UTC (permalink / raw)
  To: Jason Wang, qemu-devel

> -----Original Message-----
> From: Jason Wang <jasowang () redhat ! com>
> Sent: Monday, 16 January 2023 09:01
> To: qemu-devel
> Subject: Re: [PATCH v2 00/13] Introduce igb
> 
> On Sat, Jan 14, 2023 at 12:10 PM Akihiko Odaki <akihiko.odaki@daynix.com>
> wrote:
> >
> > Based-on: <20230114035919.35251-1-akihiko.odaki@daynix.com>
> > ([PATCH 00/19] e1000x cleanups (preliminary for IGB))
> >
> > igb is a family of Intel's gigabit ethernet controllers. This series
> > implements
> > 82576 emulation in particular. You can see the last patch for the
> documentation.
> >
> > Note that there is another effort to bring 82576 emulation. This
> > series was developed independently by Sriram Yagnaraman.
> > https://lists.gnu.org/archive/html/qemu-devel/2022-12/msg04670.html
> >
> > It is possible to merge the work from Sriram Yagnaraman and to
> > cherry-pick useful changes from this series later.
> >
> > I think there are several different ways to get the changes into the
> mainline.
> > I'm open to any options.
> 
> I can only do reviews for the general networking part but not the
> 82576 specific part. It would be better if either of the series can get some
> ACKs from some ones that they are familiar with 82576, then I can try to
> merge.
> 
I can rebase my changes on top of this and push any extra changes that I have in my implementation as a patchset with "Based-on:" tag pointing to this series. Hopefully, that will make it review easier.
I think I can be ready in a week's time.

> Thanks
> 
> >
> > V1 -> V2:
> > - Spun off e1000e general improvements to a distinct series.
> > - Restored vnet_hdr offload as there seems nothing preventing from that.
> >
> > Akihiko Odaki (13):
> >   hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr
> >   pcie: Introduce pcie_sriov_num_vfs
> >   e1000: Split header files
> >   igb: Copy e1000e code
> >   igb: Rename identifiers
> >   igb: Build igb
> >   igb: Transform to 82576 implementation
> >   tests/qtest/e1000e-test: Fabricate ethernet header
> >   tests/qtest/libqos/e1000e: Export macreg functions
> >   tests/qtest/libqos/igb: Copy e1000e code
> >   tests/qtest/libqos/igb: Transform to igb tests
> >   tests/avocado: Add igb test
> >   docs/system/devices/igb: Add igb documentation
> >
> >  MAINTAINERS                                   |    9 +
> >  docs/system/device-emulation.rst              |    1 +
> >  docs/system/devices/igb.rst                   |   70 +
> >  hw/net/Kconfig                                |    5 +
> >  hw/net/e1000.c                                |    1 +
> >  hw/net/e1000_common.h                         |  102 +
> >  hw/net/e1000_regs.h                           |  927 +---
> >  hw/net/e1000e.c                               |    3 +-
> >  hw/net/e1000e_core.c                          |    1 +
> >  hw/net/e1000x_common.c                        |    1 +
> >  hw/net/e1000x_common.h                        |   74 -
> >  hw/net/e1000x_regs.h                          |  940 ++++
> >  hw/net/igb.c                                  |  615 +++
> >  hw/net/igb_common.h                           |  144 +
> >  hw/net/igb_core.c                             | 3946 +++++++++++++++++
> >  hw/net/igb_core.h                             |  147 +
> >  hw/net/igb_regs.h                             |  624 +++
> >  hw/net/igbvf.c                                |  327 ++
> >  hw/net/meson.build                            |    2 +
> >  hw/net/net_tx_pkt.c                           |    6 +
> >  hw/net/net_tx_pkt.h                           |    8 +
> >  hw/net/trace-events                           |   32 +
> >  hw/pci/pcie_sriov.c                           |    5 +
> >  include/hw/pci/pcie_sriov.h                   |    3 +
> >  .../org.centos/stream/8/x86_64/test-avocado   |    1 +
> >  tests/avocado/igb.py                          |   38 +
> >  tests/qtest/e1000e-test.c                     |   17 +-
> >  tests/qtest/fuzz/generic_fuzz_configs.h       |    5 +
> >  tests/qtest/igb-test.c                        |  243 +
> >  tests/qtest/libqos/e1000e.c                   |   12 -
> >  tests/qtest/libqos/e1000e.h                   |   14 +
> >  tests/qtest/libqos/igb.c                      |  185 +
> >  tests/qtest/libqos/meson.build                |    1 +
> >  tests/qtest/meson.build                       |    1 +
> >  34 files changed, 7492 insertions(+), 1018 deletions(-)  create mode
> > 100644 docs/system/devices/igb.rst  create mode 100644
> > hw/net/e1000_common.h  create mode 100644 hw/net/e1000x_regs.h
> create
> > mode 100644 hw/net/igb.c  create mode 100644 hw/net/igb_common.h
> > create mode 100644 hw/net/igb_core.c  create mode 100644
> > hw/net/igb_core.h  create mode 100644 hw/net/igb_regs.h  create mode
> > 100644 hw/net/igbvf.c  create mode 100644 tests/avocado/igb.py  create
> > mode 100644 tests/qtest/igb-test.c  create mode 100644
> > tests/qtest/libqos/igb.c
> >
> > --
> > 2.39.0
> >

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2023-01-31  9:48 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-14  4:09 [PATCH v2 00/13] Introduce igb Akihiko Odaki
2023-01-14  4:09 ` [PATCH v2 01/13] hw/net/net_tx_pkt: Introduce net_tx_pkt_get_eth_hdr Akihiko Odaki
2023-01-14  4:09 ` [PATCH v2 02/13] pcie: Introduce pcie_sriov_num_vfs Akihiko Odaki
2023-01-14  4:09 ` [PATCH v2 03/13] e1000: Split header files Akihiko Odaki
2023-01-14  4:09 ` [PATCH v2 04/13] igb: Copy e1000e code Akihiko Odaki
2023-01-14  4:09 ` [PATCH v2 05/13] igb: Rename identifiers Akihiko Odaki
2023-01-14  4:09 ` [PATCH v2 06/13] igb: Build igb Akihiko Odaki
2023-01-14  4:09 ` [PATCH v2 07/13] igb: Transform to 82576 implementation Akihiko Odaki
2023-01-14  4:09 ` [PATCH v2 08/13] tests/qtest/e1000e-test: Fabricate ethernet header Akihiko Odaki
2023-01-14  4:10 ` [PATCH v2 09/13] tests/qtest/libqos/e1000e: Export macreg functions Akihiko Odaki
2023-01-14  4:10 ` [PATCH v2 10/13] tests/qtest/libqos/igb: Copy e1000e code Akihiko Odaki
2023-01-14  4:10 ` [PATCH v2 11/13] tests/qtest/libqos/igb: Transform to igb tests Akihiko Odaki
2023-01-14  4:10 ` [PATCH v2 12/13] tests/avocado: Add igb test Akihiko Odaki
2023-01-14  4:10 ` [PATCH v2 13/13] docs/system/devices/igb: Add igb documentation Akihiko Odaki
2023-01-16  8:01 ` [PATCH v2 00/13] Introduce igb Jason Wang
2023-01-24  4:53   ` Akihiko Odaki
2023-01-24  8:53     ` Sriram Yagnaraman
2023-01-26  9:34       ` Sriram Yagnaraman
2023-01-26 11:31         ` Akihiko Odaki
2023-01-28 20:57           ` Sriram Yagnaraman
2023-01-30 14:38             ` Akihiko Odaki
2023-01-31  9:48               ` Sriram Yagnaraman
     [not found] ` <20230129053316.1071513-1-alxndr@bu.edu>
2023-01-30 14:42   ` [PATCH] fuzz: add igb testcases Akihiko Odaki
     [not found] <CACGkMEvAwrfUwQVAj0qZFy+Wib5FSBwayyN_qGbZ8edNwB_18g () mail ! gmail ! com>
2023-01-17 10:06 ` [PATCH v2 00/13] Introduce igb Sriram Yagnaraman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.