diff --git a/MAINTAINERS b/MAINTAINERS
index dc5e536..e379f38 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -980,6 +980,11 @@ F: hw/acpi/nvdimm.c
 F: hw/mem/nvdimm.c
 F: include/hw/mem/nvdimm.h
 
+e1000x
+M: Dmitry Fleytman <dmitry@daynix.com>
+S: Maintained
+F: hw/net/e1000x*
+
 Subsystems
 ----------
 Audio
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index 527d264..bc69948 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -6,7 +6,7 @@ common-obj-$(CONFIG_NE2000_PCI) += ne2000.o
 common-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
 common-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
 common-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
-common-obj-$(CONFIG_E1000_PCI) += e1000.o
+common-obj-$(CONFIG_E1000_PCI) += e1000.o e1000x_common.o
 common-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
 common-obj-$(CONFIG_VMXNET3_PCI) += net_tx_pkt.o net_rx_pkt.o
 common-obj-$(CONFIG_VMXNET3_PCI) += vmxnet3.o
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 8e79b55..36e3dbe 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -36,7 +36,7 @@
 #include "qemu/iov.h"
 #include "qemu/range.h"
 
-#include "e1000_regs.h"
+#include "e1000x_common.h"
 
 static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
@@ -64,11 +64,6 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
 #define PNPMMIO_SIZE      0x20000
 #define MIN_BUF_SIZE      60 /* Min. octets in an ethernet frame sans FCS */
 
-/* this is the size past which hardware will drop packets when setting LPE=0 */
-#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
-/* this is the size past which hardware will drop packets when setting LPE=1 */
-#define MAXIMUM_ETHERNET_LPE_SIZE 16384
-
 #define MAXIMUM_ETHERNET_HDR_LEN (14+4)
 
 /*
@@ -102,22 +97,9 @@ typedef struct E1000State_st {
         unsigned char vlan[4];
         unsigned char data[0x10000];
         uint16_t size;
-        unsigned char sum_needed;
         unsigned char vlan_needed;
-        uint8_t ipcss;
-        uint8_t ipcso;
-        uint16_t ipcse;
-        uint8_t tucss;
-        uint8_t tucso;
-        uint16_t tucse;
-        uint8_t hdr_len;
-        uint16_t mss;
-        uint32_t paylen;
+        e1000x_txd_props props;
         uint16_t tso_frames;
-        char tse;
-        int8_t ip;
-        int8_t tcp;
-        char cptse;     // current packet tse bit
     } tx;
 
     struct {
@@ -162,52 +144,19 @@ typedef struct E1000BaseClass {
 #define E1000_DEVICE_GET_CLASS(obj) \
     OBJECT_GET_CLASS(E1000BaseClass, (obj), TYPE_E1000_BASE)
 
-#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(RDBAH),
-    defreg(RDBAL),   defreg(RDH),     defreg(RDLEN),   defreg(RDT),
-    defreg(STATUS),  defreg(SWSM),    defreg(TCTL),    defreg(TDBAH),
-    defreg(TDBAL),   defreg(TDH),     defreg(TDLEN),   defreg(TDT),
-    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(FCRUC),   defreg(TDFH),    defreg(TDFT),
-    defreg(TDFHS),   defreg(TDFTS),   defreg(TDFPC),   defreg(RDFH),
-    defreg(RDFT),    defreg(RDFHS),   defreg(RDFTS),   defreg(RDFPC),
-    defreg(IPAV),    defreg(WUC),     defreg(WUS),     defreg(AIT),
-    defreg(IP6AT),   defreg(IP4AT),   defreg(FFLT),    defreg(FFMT),
-    defreg(FFVT),    defreg(WUPM),    defreg(PBM),     defreg(SCC),
-    defreg(ECOL),    defreg(MCC),     defreg(LATECOL), defreg(COLC),
-    defreg(DC),      defreg(TNCRS),   defreg(SEC),     defreg(CEXTERR),
-    defreg(RLEC),    defreg(XONRXC),  defreg(XONTXC),  defreg(XOFFRXC),
-    defreg(XOFFTXC), defreg(RFC),     defreg(RJC),     defreg(RNBC),
-    defreg(TSCTFC),  defreg(MGTPRC),  defreg(MGTPDC),  defreg(MGTPTC),
-    defreg(RUC),     defreg(ROC),     defreg(GORCL),   defreg(GORCH),
-    defreg(GOTCL),   defreg(GOTCH),   defreg(BPRC),    defreg(MPRC),
-    defreg(TSCTC),   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(MPTC),    defreg(BPTC)
-};
-
 static void
-e1000_link_down(E1000State *s)
+e1000_link_up(E1000State *s)
 {
-    s->mac_reg[STATUS] &= ~E1000_STATUS_LU;
-    s->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
-    s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
-    s->phy_reg[PHY_LP_ABILITY] &= ~MII_LPAR_LPACK;
+    e1000x_update_regs_on_link_up(s->mac_reg, s->phy_reg);
+
+    /* E1000_STATUS_LU is tested by e1000_can_receive() */
+    qemu_flush_queued_packets(qemu_get_queue(s->nic));
 }
 
 static void
-e1000_link_up(E1000State *s)
+e1000_autoneg_done(E1000State *s)
 {
-    s->mac_reg[STATUS] |= E1000_STATUS_LU;
-    s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
+    e1000x_update_regs_on_autoneg_done(s->mac_reg, s->phy_reg);
 
     /* E1000_STATUS_LU is tested by e1000_can_receive() */
     qemu_flush_queued_packets(qemu_get_queue(s->nic));
@@ -233,10 +182,7 @@ set_phy_ctrl(E1000State *s, int index, uint16_t val)
      * down.
      */
     if (have_autoneg(s) && (val & MII_CR_RESTART_AUTO_NEG)) {
-        e1000_link_down(s);
-        DBGOUT(PHY, "Start link auto negotiation\n");
-        timer_mod(s->autoneg_timer,
-                  qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
+        e1000x_restart_autoneg(s->mac_reg, s->phy_reg, s->autoneg_timer);
     }
 }
 
@@ -401,43 +347,16 @@ e1000_autoneg_timer(void *opaque)
 {
     E1000State *s = opaque;
     if (!qemu_get_queue(s->nic)->link_down) {
-        e1000_link_up(s);
-        s->phy_reg[PHY_LP_ABILITY] |= MII_LPAR_LPACK;
-        s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
-        DBGOUT(PHY, "Auto negotiation is completed\n");
+        e1000_autoneg_done(s);
         set_ics(s, 0, E1000_ICS_LSC); /* signal link status change to guest */
     }
 }
 
-static int
-rxbufsize(uint32_t v)
-{
-    v &= E1000_RCTL_BSEX | E1000_RCTL_SZ_16384 | E1000_RCTL_SZ_8192 |
-         E1000_RCTL_SZ_4096 | E1000_RCTL_SZ_2048 | E1000_RCTL_SZ_1024 |
-         E1000_RCTL_SZ_512 | E1000_RCTL_SZ_256;
-    switch (v) {
-    case E1000_RCTL_BSEX | E1000_RCTL_SZ_16384:
-        return 16384;
-    case E1000_RCTL_BSEX | E1000_RCTL_SZ_8192:
-        return 8192;
-    case E1000_RCTL_BSEX | E1000_RCTL_SZ_4096:
-        return 4096;
-    case E1000_RCTL_SZ_1024:
-        return 1024;
-    case E1000_RCTL_SZ_512:
-        return 512;
-    case E1000_RCTL_SZ_256:
-        return 256;
-    }
-    return 2048;
-}
-
 static void e1000_reset(void *opaque)
 {
     E1000State *d = opaque;
     E1000BaseClass *edc = E1000_DEVICE_GET_CLASS(d);
     uint8_t *macaddr = d->conf.macaddr.a;
-    int i;
 
     timer_del(d->autoneg_timer);
     timer_del(d->mit_timer);
@@ -453,17 +372,10 @@ static void e1000_reset(void *opaque)
     memset(&d->tx, 0, sizeof d->tx);
 
     if (qemu_get_queue(d->nic)->link_down) {
-        e1000_link_down(d);
+        e1000x_update_regs_on_link_down(d->mac_reg, d->phy_reg);
     }
 
-    /* Some guests expect pre-initialized RAH/RAL (AddrValid flag + MACaddr) */
-    d->mac_reg[RA] = 0;
-    d->mac_reg[RA + 1] = E1000_RAH_AV;
-    for (i = 0; i < 4; i++) {
-        d->mac_reg[RA] |= macaddr[i] << (8 * i);
-        d->mac_reg[RA + 1] |= (i < 2) ? macaddr[i + 4] << (8 * i) : 0;
-    }
-    qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr);
+    e1000x_reset_mac_addr(d->nic, d->mac_reg, macaddr);
 }
 
 static void
@@ -477,7 +389,7 @@ static void
 set_rx_control(E1000State *s, int index, uint32_t val)
 {
     s->mac_reg[RCTL] = val;
-    s->rxbuf_size = rxbufsize(val);
+    s->rxbuf_size = e1000x_rxbufsize(val);
     s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
     DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
            s->mac_reg[RCTL]);
@@ -598,89 +510,15 @@ putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse)
 }
 
 static inline void
-inc_reg_if_not_full(E1000State *s, int index)
-{
-    if (s->mac_reg[index] != 0xffffffff) {
-        s->mac_reg[index]++;
-    }
-}
-
-static inline void
 inc_tx_bcast_or_mcast_count(E1000State *s, const unsigned char *arr)
 {
     if (!memcmp(arr, bcast, sizeof bcast)) {
-        inc_reg_if_not_full(s, BPTC);
+        e1000x_inc_reg_if_not_full(s->mac_reg, BPTC);
     } else if (arr[0] & 1) {
-        inc_reg_if_not_full(s, MPTC);
-    }
-}
-
-static void
-grow_8reg_if_not_full(E1000State *s, int index, int size)
-{
-    uint64_t sum = s->mac_reg[index] | (uint64_t)s->mac_reg[index+1] << 32;
-
-    if (sum + size < sum) {
-        sum = ~0ULL;
-    } else {
-        sum += size;
-    }
-    s->mac_reg[index] = sum;
-    s->mac_reg[index+1] = sum >> 32;
-}
-
-static void
-increase_size_stats(E1000State *s, const int *size_regs, int size)
-{
-    if (size > 1023) {
-        inc_reg_if_not_full(s, size_regs[5]);
-    } else if (size > 511) {
-        inc_reg_if_not_full(s, size_regs[4]);
-    } else if (size > 255) {
-        inc_reg_if_not_full(s, size_regs[3]);
-    } else if (size > 127) {
-        inc_reg_if_not_full(s, size_regs[2]);
-    } else if (size > 64) {
-        inc_reg_if_not_full(s, size_regs[1]);
-    } else if (size == 64) {
-        inc_reg_if_not_full(s, size_regs[0]);
+        e1000x_inc_reg_if_not_full(s->mac_reg, MPTC);
     }
 }
 
-static inline int
-vlan_enabled(E1000State *s)
-{
-    return ((s->mac_reg[CTRL] & E1000_CTRL_VME) != 0);
-}
-
-static inline int
-vlan_rx_filter_enabled(E1000State *s)
-{
-    return ((s->mac_reg[RCTL] & E1000_RCTL_VFE) != 0);
-}
-
-static inline int
-is_vlan_packet(E1000State *s, const uint8_t *buf)
-{
-    return (be16_to_cpup((uint16_t *)(buf + 12)) ==
-                le16_to_cpu(s->mac_reg[VET]));
-}
-
-static inline int
-is_vlan_txd(uint32_t txd_lower)
-{
-    return ((txd_lower & E1000_TXD_CMD_VLE) != 0);
-}
-
-/* FCS aka Ethernet CRC-32. We don't get it from backends and can't
- * fill it in, just pad descriptor length by 4 bytes unless guest
- * told us to strip it off the packet. */
-static inline int
-fcs_len(E1000State *s)
-{
-    return (s->mac_reg[RCTL] & E1000_RCTL_SECRC) ? 0 : 4;
-}
-
 static void
 e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
 {
@@ -694,7 +532,7 @@ e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
         qemu_send_packet(nc, buf, size);
     }
     inc_tx_bcast_or_mcast_count(s, buf);
-    increase_size_stats(s, PTCregs, size);
+    e1000x_increase_size_stats(s->mac_reg, PTCregs, size);
 }
 
 static void
@@ -704,34 +542,34 @@ xmit_seg(E1000State *s)
     unsigned int frames = s->tx.tso_frames, css, sofar;
     struct e1000_tx *tp = &s->tx;
 
-    if (tp->tse && tp->cptse) {
-        css = tp->ipcss;
+    if (tp->props.tse && tp->props.cptse) {
+        css = tp->props.ipcss;
         DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
                frames, tp->size, css);
-        if (tp->ip) {    /* IPv4 */
+        if (tp->props.ip) {    /* IPv4 */
             stw_be_p(tp->data+css+2, tp->size - css);
             stw_be_p(tp->data+css+4,
                      be16_to_cpup((uint16_t *)(tp->data+css+4))+frames);
         } else {         /* IPv6 */
             stw_be_p(tp->data+css+4, tp->size - css);
         }
-        css = tp->tucss;
+        css = tp->props.tucss;
         len = tp->size - css;
-        DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->tcp, css, len);
-        if (tp->tcp) {
-            sofar = frames * tp->mss;
+        DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->props.tcp, css, len);
+        if (tp->props.tcp) {
+            sofar = frames * tp->props.mss;
             stl_be_p(tp->data+css+4, ldl_be_p(tp->data+css+4)+sofar); /* seq */
-            if (tp->paylen - sofar > tp->mss) {
+            if (tp->props.paylen - sofar > tp->props.mss) {
                 tp->data[css + 13] &= ~9;    /* PSH, FIN */
             } else if (frames) {
-                inc_reg_if_not_full(s, TSCTC);
+                e1000x_inc_reg_if_not_full(s->mac_reg, TSCTC);
             }
         } else    /* UDP */
             stw_be_p(tp->data+css+4, len);
-        if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
+        if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) {
             unsigned int phsum;
             // add pseudo-header length before checksum calculation
-            sp = (uint16_t *)(tp->data + tp->tucso);
+            sp = (uint16_t *)(tp->data + tp->props.tucso);
             phsum = be16_to_cpup(sp) + len;
             phsum = (phsum >> 16) + (phsum & 0xffff);
             stw_be_p(sp, phsum);
@@ -739,10 +577,14 @@ xmit_seg(E1000State *s)
         tp->tso_frames++;
     }
 
-    if (tp->sum_needed & E1000_TXD_POPTS_TXSM)
-        putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse);
-    if (tp->sum_needed & E1000_TXD_POPTS_IXSM)
-        putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse);
+    if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) {
+        putsum(tp->data, tp->size, tp->props.tucso,
+               tp->props.tucss, tp->props.tucse);
+    }
+    if (tp->props.sum_needed & E1000_TXD_POPTS_IXSM) {
+        putsum(tp->data, tp->size, tp->props.ipcso,
+               tp->props.ipcss, tp->props.ipcse);
+    }
     if (tp->vlan_needed) {
         memmove(tp->vlan, tp->data, 4);
         memmove(tp->data, tp->data + 4, 8);
@@ -752,8 +594,8 @@ xmit_seg(E1000State *s)
         e1000_send_packet(s, tp->data, tp->size);
     }
 
-    inc_reg_if_not_full(s, TPT);
-    grow_8reg_if_not_full(s, TOTL, s->tx.size);
+    e1000x_inc_reg_if_not_full(s->mac_reg, TPT);
+    e1000x_grow_8reg_if_not_full(s->mac_reg, TOTL, s->tx.size);
     s->mac_reg[GPTC] = s->mac_reg[TPT];
     s->mac_reg[GOTCL] = s->mac_reg[TOTL];
     s->mac_reg[GOTCH] = s->mac_reg[TOTH];
@@ -765,7 +607,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
     PCIDevice *d = PCI_DEVICE(s);
     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, bytes, sz, op;
+    unsigned int split_size = txd_lower & 0xffff, bytes, sz;
     unsigned int msh = 0xfffff;
     uint64_t addr;
     struct e1000_context_desc *xp = (struct e1000_context_desc *)dp;
@@ -773,38 +615,27 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
 
     s->mit_ide |= (txd_lower & E1000_TXD_CMD_IDE);
     if (dtype == E1000_TXD_CMD_DEXT) {    /* context descriptor */
-        op = le32_to_cpu(xp->cmd_and_length);
-        tp->ipcss = xp->lower_setup.ip_fields.ipcss;
-        tp->ipcso = xp->lower_setup.ip_fields.ipcso;
-        tp->ipcse = le16_to_cpu(xp->lower_setup.ip_fields.ipcse);
-        tp->tucss = xp->upper_setup.tcp_fields.tucss;
-        tp->tucso = xp->upper_setup.tcp_fields.tucso;
-        tp->tucse = le16_to_cpu(xp->upper_setup.tcp_fields.tucse);
-        tp->paylen = op & 0xfffff;
-        tp->hdr_len = xp->tcp_seg_setup.fields.hdr_len;
-        tp->mss = le16_to_cpu(xp->tcp_seg_setup.fields.mss);
-        tp->ip = (op & E1000_TXD_CMD_IP) ? 1 : 0;
-        tp->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0;
-        tp->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0;
+        e1000x_read_tx_ctx_descr(xp, &tp->props);
         tp->tso_frames = 0;
-        if (tp->tucso == 0) {    /* this is probably wrong */
+        if (tp->props.tucso == 0) {    /* this is probably wrong */
             DBGOUT(TXSUM, "TCP/UDP: cso 0!\n");
-            tp->tucso = tp->tucss + (tp->tcp ? 16 : 6);
+            tp->props.tucso = tp->props.tucss + (tp->props.tcp ? 16 : 6);
         }
         return;
     } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
         // data descriptor
         if (tp->size == 0) {
-            tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
+            tp->props.sum_needed = le32_to_cpu(dp->upper.data) >> 8;
         }
-        tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
+        tp->props.cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0;
     } else {
         // legacy descriptor
-        tp->cptse = 0;
+        tp->props.cptse = 0;
     }
 
-    if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
-        (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
+    if (e1000x_vlan_enabled(s->mac_reg) &&
+        e1000x_is_vlan_txd(txd_lower) &&
+        (tp->props.cptse || txd_lower & E1000_TXD_CMD_EOP)) {
         tp->vlan_needed = 1;
         stw_be_p(tp->vlan_header,
                       le16_to_cpu(s->mac_reg[VET]));
@@ -813,8 +644,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
     }
 
     addr = le64_to_cpu(dp->buffer_addr);
-    if (tp->tse && tp->cptse) {
-        msh = tp->hdr_len + tp->mss;
+    if (tp->props.tse && tp->props.cptse) {
+        msh = tp->props.hdr_len + tp->props.mss;
         do {
             bytes = split_size;
             if (tp->size + bytes > msh)
@@ -823,19 +654,19 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
             bytes = MIN(sizeof(tp->data) - tp->size, bytes);
             pci_dma_read(d, addr, tp->data + tp->size, bytes);
             sz = tp->size + bytes;
-            if (sz >= tp->hdr_len && tp->size < tp->hdr_len) {
-                memmove(tp->header, tp->data, tp->hdr_len);
+            if (sz >= tp->props.hdr_len && tp->size < tp->props.hdr_len) {
+                memmove(tp->header, tp->data, tp->props.hdr_len);
             }
             tp->size = sz;
             addr += bytes;
             if (sz == msh) {
                 xmit_seg(s);
-                memmove(tp->data, tp->header, tp->hdr_len);
-                tp->size = tp->hdr_len;
+                memmove(tp->data, tp->header, tp->props.hdr_len);
+                tp->size = tp->props.hdr_len;
             }
             split_size -= bytes;
         } while (bytes && split_size);
-    } else if (!tp->tse && tp->cptse) {
+    } else if (!tp->props.tse && tp->props.cptse) {
         // context descriptor TSE is not set, while data descriptor TSE is set
         DBGOUT(TXERR, "TCP segmentation error\n");
     } else {
@@ -846,14 +677,14 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
 
     if (!(txd_lower & E1000_TXD_CMD_EOP))
         return;
-    if (!(tp->tse && tp->cptse && tp->size < tp->hdr_len)) {
+    if (!(tp->props.tse && tp->props.cptse && tp->size < tp->props.hdr_len)) {
         xmit_seg(s);
     }
     tp->tso_frames = 0;
-    tp->sum_needed = 0;
+    tp->props.sum_needed = 0;
     tp->vlan_needed = 0;
     tp->size = 0;
-    tp->cptse = 0;
+    tp->props.cptse = 0;
 }
 
 static uint32_t
@@ -925,11 +756,11 @@ start_xmit(E1000State *s)
 static int
 receive_filter(E1000State *s, const uint8_t *buf, int size)
 {
-    static const int mta_shift[] = {4, 3, 2, 0};
-    uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp;
+    uint32_t rctl = s->mac_reg[RCTL];
     int isbcast = !memcmp(buf, bcast, sizeof bcast), ismcast = (buf[0] & 1);
 
-    if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) {
+    if (e1000x_is_vlan_packet(buf, le16_to_cpu(s->mac_reg[VET])) &&
+        e1000x_vlan_rx_filter_enabled(s->mac_reg)) {
         uint16_t vid = be16_to_cpup((uint16_t *)(buf + 14));
         uint32_t vfta = le32_to_cpup((uint32_t *)(s->mac_reg + VFTA) +
                                      ((vid >> 5) & 0x7f));
@@ -942,44 +773,16 @@ receive_filter(E1000State *s, const uint8_t *buf, int size)
     }
 
     if (ismcast && (rctl & E1000_RCTL_MPE)) {          /* promiscuous mcast */
-        inc_reg_if_not_full(s, MPRC);
+        e1000x_inc_reg_if_not_full(s->mac_reg, MPRC);
         return 1;
     }
 
     if (isbcast && (rctl & E1000_RCTL_BAM)) {          /* broadcast enabled */
-        inc_reg_if_not_full(s, BPRC);
-        return 1;
-    }
-
-    for (rp = s->mac_reg + RA; rp < s->mac_reg + RA + 32; rp += 2) {
-        if (!(rp[1] & E1000_RAH_AV))
-            continue;
-        ra[0] = cpu_to_le32(rp[0]);
-        ra[1] = cpu_to_le32(rp[1]);
-        if (!memcmp(buf, (uint8_t *)ra, 6)) {
-            DBGOUT(RXFILTER,
-                   "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n",
-                   (int)(rp - s->mac_reg - RA)/2,
-                   buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
-            return 1;
-        }
-    }
-    DBGOUT(RXFILTER, "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x\n",
-           buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
-
-    f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
-    f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff;
-    if (s->mac_reg[MTA + (f >> 5)] & (1 << (f & 0x1f))) {
-        inc_reg_if_not_full(s, MPRC);
+        e1000x_inc_reg_if_not_full(s->mac_reg, BPRC);
         return 1;
     }
-    DBGOUT(RXFILTER,
-           "dropping, inexact filter mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x\n",
-           buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
-           (rctl >> E1000_RCTL_MO_SHIFT) & 3, f >> 5,
-           s->mac_reg[MTA + (f >> 5)]);
 
-    return 0;
+    return e1000x_rx_group_filter(s->mac_reg, buf);
 }
 
 static void
@@ -989,13 +792,11 @@ e1000_set_link_status(NetClientState *nc)
     uint32_t old_status = s->mac_reg[STATUS];
 
     if (nc->link_down) {
-        e1000_link_down(s);
+        e1000x_update_regs_on_link_down(s->mac_reg, s->phy_reg);
     } else {
         if (have_autoneg(s) &&
             !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
-            /* emulate auto-negotiation if supported */
-            timer_mod(s->autoneg_timer,
-                      qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
+            e1000x_restart_autoneg(s->mac_reg, s->phy_reg, s->autoneg_timer);
         } else {
             e1000_link_up(s);
         }
@@ -1028,9 +829,7 @@ e1000_can_receive(NetClientState *nc)
 {
     E1000State *s = qemu_get_nic_opaque(nc);
 
-    return (s->mac_reg[STATUS] & E1000_STATUS_LU) &&
-        (s->mac_reg[RCTL] & E1000_RCTL_EN) &&
-        (s->parent_obj.config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
+    return e1000x_rx_ready(&s->parent_obj, s->mac_reg) &&
         e1000_has_rxbufs(s, 1);
 }
 
@@ -1061,14 +860,8 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
     size_t desc_offset;
     size_t desc_size;
     size_t total_size;
-    static const int PRCregs[6] = { PRC64, PRC127, PRC255, PRC511,
-                                    PRC1023, PRC1522 };
-
-    if (!(s->mac_reg[STATUS] & E1000_STATUS_LU)) {
-        return -1;
-    }
 
-    if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) {
+    if (!e1000x_hw_rx_enabled(s->mac_reg)) {
         return -1;
     }
 
@@ -1076,7 +869,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
     if (size < sizeof(min_buf)) {
         iov_to_buf(iov, iovcnt, 0, min_buf, size);
         memset(&min_buf[size], 0, sizeof(min_buf) - size);
-        inc_reg_if_not_full(s, RUC);
+        e1000x_inc_reg_if_not_full(s->mac_reg, RUC);
         min_iov.iov_base = filter_buf = min_buf;
         min_iov.iov_len = size = sizeof(min_buf);
         iovcnt = 1;
@@ -1088,11 +881,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
     }
 
     /* Discard oversized packets if !LPE and !SBP. */
-    if ((size > MAXIMUM_ETHERNET_LPE_SIZE ||
-        (size > MAXIMUM_ETHERNET_VLAN_SIZE
-        && !(s->mac_reg[RCTL] & E1000_RCTL_LPE)))
-        && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) {
-        inc_reg_if_not_full(s, ROC);
+    if (e1000x_is_oversized(s->mac_reg, size)) {
         return size;
     }
 
@@ -1100,7 +889,8 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
         return size;
     }
 
-    if (vlan_enabled(s) && is_vlan_packet(s, filter_buf)) {
+    if (e1000x_vlan_enabled(s->mac_reg) &&
+        e1000x_is_vlan_packet(filter_buf, le16_to_cpu(s->mac_reg[VET]))) {
         vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(filter_buf
                                                                 + 14)));
         iov_ofs = 4;
@@ -1119,7 +909,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
 
     rdh_start = s->mac_reg[RDH];
     desc_offset = 0;
-    total_size = size + fcs_len(s);
+    total_size = size + e1000x_fcs_len(s->mac_reg);
     if (!e1000_has_rxbufs(s, total_size)) {
             set_ics(s, 0, E1000_ICS_RXO);
             return -1;
@@ -1179,17 +969,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
         }
     } while (desc_offset < total_size);
 
-    increase_size_stats(s, PRCregs, total_size);
-    inc_reg_if_not_full(s, TPR);
-    s->mac_reg[GPRC] = s->mac_reg[TPR];
-    /* TOR - Total Octets Received:
-     * This register includes bytes received in a packet from the <Destination
-     * Address> field through the <CRC> field, inclusively.
-     * Always include FCS length (4) in size.
-     */
-    grow_8reg_if_not_full(s, TORL, size+4);
-    s->mac_reg[GORCL] = s->mac_reg[TORL];
-    s->mac_reg[GORCH] = s->mac_reg[TORH];
+    e1000x_update_rx_total_stats(s->mac_reg, size, total_size);
 
     n = E1000_ICS_RXT0;
     if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
@@ -1670,20 +1450,20 @@ static const VMStateDescription vmstate_e1000 = {
         VMSTATE_UINT16(eecd_state.bitnum_out, E1000State),
         VMSTATE_UINT16(eecd_state.reading, E1000State),
         VMSTATE_UINT32(eecd_state.old_eecd, E1000State),
-        VMSTATE_UINT8(tx.ipcss, E1000State),
-        VMSTATE_UINT8(tx.ipcso, E1000State),
-        VMSTATE_UINT16(tx.ipcse, E1000State),
-        VMSTATE_UINT8(tx.tucss, E1000State),
-        VMSTATE_UINT8(tx.tucso, E1000State),
-        VMSTATE_UINT16(tx.tucse, E1000State),
-        VMSTATE_UINT32(tx.paylen, E1000State),
-        VMSTATE_UINT8(tx.hdr_len, E1000State),
-        VMSTATE_UINT16(tx.mss, E1000State),
+        VMSTATE_UINT8(tx.props.ipcss, E1000State),
+        VMSTATE_UINT8(tx.props.ipcso, E1000State),
+        VMSTATE_UINT16(tx.props.ipcse, E1000State),
+        VMSTATE_UINT8(tx.props.tucss, E1000State),
+        VMSTATE_UINT8(tx.props.tucso, E1000State),
+        VMSTATE_UINT16(tx.props.tucse, E1000State),
+        VMSTATE_UINT32(tx.props.paylen, E1000State),
+        VMSTATE_UINT8(tx.props.hdr_len, E1000State),
+        VMSTATE_UINT16(tx.props.mss, E1000State),
         VMSTATE_UINT16(tx.size, E1000State),
         VMSTATE_UINT16(tx.tso_frames, E1000State),
-        VMSTATE_UINT8(tx.sum_needed, E1000State),
-        VMSTATE_INT8(tx.ip, E1000State),
-        VMSTATE_INT8(tx.tcp, E1000State),
+        VMSTATE_UINT8(tx.props.sum_needed, E1000State),
+        VMSTATE_INT8(tx.props.ip, E1000State),
+        VMSTATE_INT8(tx.props.tcp, E1000State),
         VMSTATE_BUFFER(tx.header, E1000State),
         VMSTATE_BUFFER(tx.data, E1000State),
         VMSTATE_UINT16_ARRAY(eeprom_data, E1000State, 64),
@@ -1806,15 +1586,11 @@ static void e1000_write_config(PCIDevice *pci_dev, uint32_t address,
     }
 }
 
-
 static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp)
 {
     DeviceState *dev = DEVICE(pci_dev);
     E1000State *d = E1000(pci_dev);
-    PCIDeviceClass *pdc = PCI_DEVICE_GET_CLASS(pci_dev);
     uint8_t *pci_conf;
-    uint16_t checksum = 0;
-    int i;
     uint8_t *macaddr;
 
     pci_dev->config_write = e1000_write_config;
@@ -1832,17 +1608,14 @@ static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp)
 
     pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
 
-    memmove(d->eeprom_data, e1000_eeprom_template,
-        sizeof e1000_eeprom_template);
     qemu_macaddr_default_if_unset(&d->conf.macaddr);
     macaddr = d->conf.macaddr.a;
-    for (i = 0; i < 3; i++)
-        d->eeprom_data[i] = (macaddr[2*i+1]<<8) | macaddr[2*i];
-    d->eeprom_data[11] = d->eeprom_data[13] = pdc->device_id;
-    for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
-        checksum += d->eeprom_data[i];
-    checksum = (uint16_t) EEPROM_SUM - checksum;
-    d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
+
+    e1000x_core_prepare_eeprom(d->eeprom_data,
+                               e1000_eeprom_template,
+                               sizeof(e1000_eeprom_template),
+                               PCI_DEVICE_GET_CLASS(pci_dev)->device_id,
+                               macaddr);
 
     d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
                           object_get_typename(OBJECT(d)), dev->id, d);
diff --git a/hw/net/e1000x_common.c b/hw/net/e1000x_common.c
new file mode 100644
index 0000000..e1a5e7c
--- /dev/null
+++ b/hw/net/e1000x_common.c
@@ -0,0 +1,267 @@
+/*
+* QEMU e1000(e) emulation - shared code
+*
+* 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 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/pci/pci.h"
+#include "net/net.h"
+
+#include "e1000x_common.h"
+
+#include "trace.h"
+
+bool e1000x_rx_ready(PCIDevice *d, uint32_t *mac)
+{
+    bool link_up = mac[STATUS] & E1000_STATUS_LU;
+    bool rx_enabled = mac[RCTL] & E1000_RCTL_EN;
+    bool pci_master = d->config[PCI_COMMAND] & PCI_COMMAND_MASTER;
+
+    if (!link_up || !rx_enabled || !pci_master) {
+        trace_e1000x_rx_can_recv_disabled(link_up, rx_enabled, pci_master);
+        return false;
+    }
+
+    return true;
+}
+
+bool e1000x_is_vlan_packet(const uint8_t *buf, uint16_t vet)
+{
+    uint16_t eth_proto = be16_to_cpup((uint16_t *)(buf + 12));
+    bool res = (eth_proto == vet);
+
+    trace_e1000x_vlan_is_vlan_pkt(res, eth_proto, vet);
+
+    return res;
+}
+
+bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf)
+{
+    static const int mta_shift[] = { 4, 3, 2, 0 };
+    uint32_t f, ra[2], *rp, rctl = mac[RCTL];
+
+    for (rp = mac + RA; rp < mac + RA + 32; rp += 2) {
+        if (!(rp[1] & E1000_RAH_AV)) {
+            continue;
+        }
+        ra[0] = cpu_to_le32(rp[0]);
+        ra[1] = cpu_to_le32(rp[1]);
+        if (!memcmp(buf, (uint8_t *)ra, 6)) {
+            trace_e1000x_rx_flt_ucast_match((int)(rp - mac - RA) / 2,
+                                            MAC_ARG(buf));
+            return true;
+        }
+    }
+    trace_e1000x_rx_flt_ucast_mismatch(MAC_ARG(buf));
+
+    f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
+    f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff;
+    if (mac[MTA + (f >> 5)] & (1 << (f & 0x1f))) {
+        e1000x_inc_reg_if_not_full(mac, MPRC);
+        return true;
+    }
+
+    trace_e1000x_rx_flt_inexact_mismatch(MAC_ARG(buf),
+                                         (rctl >> E1000_RCTL_MO_SHIFT) & 3,
+                                         f >> 5,
+                                         mac[MTA + (f >> 5)]);
+
+    return false;
+}
+
+bool e1000x_hw_rx_enabled(uint32_t *mac)
+{
+    if (!(mac[STATUS] & E1000_STATUS_LU)) {
+        trace_e1000x_rx_link_down(mac[STATUS]);
+        return false;
+    }
+
+    if (!(mac[RCTL] & E1000_RCTL_EN)) {
+        trace_e1000x_rx_disabled(mac[RCTL]);
+        return false;
+    }
+
+    return true;
+}
+
+bool e1000x_is_oversized(uint32_t *mac, size_t size)
+{
+    /* this is the size past which hardware will
+       drop packets when setting LPE=0 */
+    static const int MAXIMUM_ETHERNET_VLAN_SIZE = 1522;
+    /* this is the size past which hardware will
+       drop packets when setting LPE=1 */
+    static const int MAXIMUM_ETHERNET_LPE_SIZE = 16384;
+
+    if ((size > MAXIMUM_ETHERNET_LPE_SIZE ||
+        (size > MAXIMUM_ETHERNET_VLAN_SIZE
+            && !(mac[RCTL] & E1000_RCTL_LPE)))
+        && !(mac[RCTL] & E1000_RCTL_SBP)) {
+        e1000x_inc_reg_if_not_full(mac, ROC);
+        trace_e1000x_rx_oversized(size);
+        return true;
+    }
+
+    return false;
+}
+
+void e1000x_restart_autoneg(uint32_t *mac, uint16_t *phy, QEMUTimer *timer)
+{
+    e1000x_update_regs_on_link_down(mac, phy);
+    trace_e1000x_link_negotiation_start();
+    timer_mod(timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
+}
+
+void e1000x_reset_mac_addr(NICState *nic, uint32_t *mac_regs,
+                           uint8_t *mac_addr)
+{
+    int i;
+
+    mac_regs[RA] = 0;
+    mac_regs[RA + 1] = E1000_RAH_AV;
+    for (i = 0; i < 4; i++) {
+        mac_regs[RA] |= mac_addr[i] << (8 * i);
+        mac_regs[RA + 1] |=
+            (i < 2) ? mac_addr[i + 4] << (8 * i) : 0;
+    }
+
+    qemu_format_nic_info_str(qemu_get_queue(nic), mac_addr);
+    trace_e1000x_mac_indicate(MAC_ARG(mac_addr));
+}
+
+void e1000x_update_regs_on_autoneg_done(uint32_t *mac, uint16_t *phy)
+{
+    e1000x_update_regs_on_link_up(mac, phy);
+    phy[PHY_LP_ABILITY] |= MII_LPAR_LPACK;
+    phy[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
+    trace_e1000x_link_negotiation_done();
+}
+
+void
+e1000x_core_prepare_eeprom(uint16_t       *eeprom,
+                           const uint16_t *templ,
+                           uint32_t        templ_size,
+                           uint16_t        dev_id,
+                           const uint8_t  *macaddr)
+{
+    uint16_t checksum = 0;
+    int i;
+
+    memmove(eeprom, templ, templ_size);
+
+    for (i = 0; i < 3; i++) {
+        eeprom[i] = (macaddr[2 * i + 1] << 8) | macaddr[2 * i];
+    }
+
+    eeprom[11] = eeprom[13] = dev_id;
+
+    for (i = 0; i < EEPROM_CHECKSUM_REG; i++) {
+        checksum += eeprom[i];
+    }
+
+    checksum = (uint16_t) EEPROM_SUM - checksum;
+
+    eeprom[EEPROM_CHECKSUM_REG] = checksum;
+}
+
+uint32_t
+e1000x_rxbufsize(uint32_t rctl)
+{
+    rctl &= E1000_RCTL_BSEX | E1000_RCTL_SZ_16384 | E1000_RCTL_SZ_8192 |
+        E1000_RCTL_SZ_4096 | E1000_RCTL_SZ_2048 | E1000_RCTL_SZ_1024 |
+        E1000_RCTL_SZ_512 | E1000_RCTL_SZ_256;
+    switch (rctl) {
+    case E1000_RCTL_BSEX | E1000_RCTL_SZ_16384:
+        return 16384;
+    case E1000_RCTL_BSEX | E1000_RCTL_SZ_8192:
+        return 8192;
+    case E1000_RCTL_BSEX | E1000_RCTL_SZ_4096:
+        return 4096;
+    case E1000_RCTL_SZ_1024:
+        return 1024;
+    case E1000_RCTL_SZ_512:
+        return 512;
+    case E1000_RCTL_SZ_256:
+        return 256;
+    }
+    return 2048;
+}
+
+void
+e1000x_update_rx_total_stats(uint32_t *mac,
+                             size_t data_size,
+                             size_t data_fcs_size)
+{
+    static const int PRCregs[6] = { PRC64, PRC127, PRC255, PRC511,
+                                    PRC1023, PRC1522 };
+
+    e1000x_increase_size_stats(mac, PRCregs, data_fcs_size);
+    e1000x_inc_reg_if_not_full(mac, TPR);
+    mac[GPRC] = mac[TPR];
+    /* TOR - Total Octets Received:
+    * This register includes bytes received in a packet from the <Destination
+    * Address> field through the <CRC> field, inclusively.
+    * Always include FCS length (4) in size.
+    */
+    e1000x_grow_8reg_if_not_full(mac, TORL, data_size + 4);
+    mac[GORCL] = mac[TORL];
+    mac[GORCH] = mac[TORH];
+}
+
+void
+e1000x_increase_size_stats(uint32_t *mac, const int *size_regs, int size)
+{
+    if (size > 1023) {
+        e1000x_inc_reg_if_not_full(mac, size_regs[5]);
+    } else if (size > 511) {
+        e1000x_inc_reg_if_not_full(mac, size_regs[4]);
+    } else if (size > 255) {
+        e1000x_inc_reg_if_not_full(mac, size_regs[3]);
+    } else if (size > 127) {
+        e1000x_inc_reg_if_not_full(mac, size_regs[2]);
+    } else if (size > 64) {
+        e1000x_inc_reg_if_not_full(mac, size_regs[1]);
+    } else if (size == 64) {
+        e1000x_inc_reg_if_not_full(mac, size_regs[0]);
+    }
+}
+
+void
+e1000x_read_tx_ctx_descr(struct e1000_context_desc *d,
+                         e1000x_txd_props *props)
+{
+    uint32_t op = le32_to_cpu(d->cmd_and_length);
+
+    props->ipcss = d->lower_setup.ip_fields.ipcss;
+    props->ipcso = d->lower_setup.ip_fields.ipcso;
+    props->ipcse = le16_to_cpu(d->lower_setup.ip_fields.ipcse);
+    props->tucss = d->upper_setup.tcp_fields.tucss;
+    props->tucso = d->upper_setup.tcp_fields.tucso;
+    props->tucse = le16_to_cpu(d->upper_setup.tcp_fields.tucse);
+    props->paylen = op & 0xfffff;
+    props->hdr_len = d->tcp_seg_setup.fields.hdr_len;
+    props->mss = le16_to_cpu(d->tcp_seg_setup.fields.mss);
+    props->ip = (op & E1000_TXD_CMD_IP) ? 1 : 0;
+    props->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0;
+    props->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0;
+}
diff --git a/hw/net/e1000x_common.h b/hw/net/e1000x_common.h
new file mode 100644
index 0000000..36243e6
--- /dev/null
+++ b/hw/net/e1000x_common.h
@@ -0,0 +1,213 @@
+/*
+* QEMU e1000(e) emulation - shared code
+*
+* 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 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 "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(SEC),     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)
+{
+    if (mac[index] != 0xffffffff) {
+        mac[index]++;
+    }
+}
+
+static inline void
+e1000x_grow_8reg_if_not_full(uint32_t *mac, int index, int size)
+{
+    uint64_t sum = mac[index] | (uint64_t)mac[index + 1] << 32;
+
+    if (sum + size < sum) {
+        sum = ~0ULL;
+    } else {
+        sum += size;
+    }
+    mac[index] = sum;
+    mac[index + 1] = sum >> 32;
+}
+
+static inline int
+e1000x_vlan_enabled(uint32_t *mac)
+{
+    return ((mac[CTRL] & E1000_CTRL_VME) != 0);
+}
+
+static inline int
+e1000x_is_vlan_txd(uint32_t txd_lower)
+{
+    return ((txd_lower & E1000_TXD_CMD_VLE) != 0);
+}
+
+static inline int
+e1000x_vlan_rx_filter_enabled(uint32_t *mac)
+{
+    return ((mac[RCTL] & E1000_RCTL_VFE) != 0);
+}
+
+static inline int
+e1000x_fcs_len(uint32_t *mac)
+{
+    /* FCS aka Ethernet CRC-32. We don't get it from backends and can't
+    * fill it in, just pad descriptor length by 4 bytes unless guest
+    * told us to strip it off the packet. */
+    return (mac[RCTL] & E1000_RCTL_SECRC) ? 0 : 4;
+}
+
+static inline void
+e1000x_update_regs_on_link_down(uint32_t *mac, uint16_t *phy)
+{
+    mac[STATUS] &= ~E1000_STATUS_LU;
+    phy[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
+    phy[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
+    phy[PHY_LP_ABILITY] &= ~MII_LPAR_LPACK;
+}
+
+static inline void
+e1000x_update_regs_on_link_up(uint32_t *mac, uint16_t *phy)
+{
+    mac[STATUS] |= E1000_STATUS_LU;
+    phy[PHY_STATUS] |= MII_SR_LINK_STATUS;
+}
+
+void e1000x_update_rx_total_stats(uint32_t *mac,
+                                  size_t data_size,
+                                  size_t data_fcs_size);
+
+void e1000x_core_prepare_eeprom(uint16_t       *eeprom,
+                                const uint16_t *templ,
+                                uint32_t        templ_size,
+                                uint16_t        dev_id,
+                                const uint8_t  *macaddr);
+
+uint32_t e1000x_rxbufsize(uint32_t rctl);
+
+bool e1000x_rx_ready(PCIDevice *d, uint32_t *mac);
+
+bool e1000x_is_vlan_packet(const uint8_t *buf, uint16_t vet);
+
+bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf);
+
+bool e1000x_hw_rx_enabled(uint32_t *mac);
+
+bool e1000x_is_oversized(uint32_t *mac, size_t size);
+
+void e1000x_restart_autoneg(uint32_t *mac, uint16_t *phy, QEMUTimer *timer);
+
+void e1000x_reset_mac_addr(NICState *nic, uint32_t *mac_regs,
+                           uint8_t *mac_addr);
+
+void e1000x_update_regs_on_autoneg_done(uint32_t *mac, uint16_t *phy);
+
+void e1000x_increase_size_stats(uint32_t *mac, const int *size_regs, int size);
+
+typedef struct {
+    unsigned char sum_needed;
+    uint8_t ipcss;
+    uint8_t ipcso;
+    uint16_t ipcse;
+    uint8_t tucss;
+    uint8_t tucso;
+    uint16_t tucse;
+    uint32_t paylen;
+    uint8_t hdr_len;
+    uint16_t mss;
+    int8_t ip;
+    int8_t tcp;
+    bool tse;
+    bool cptse;
+} e1000x_txd_props;
+
+void e1000x_read_tx_ctx_descr(struct e1000_context_desc *d,
+                              e1000x_txd_props *props);
diff --git a/trace-events b/trace-events
index 9a50d8d..99d9e87 100644
--- a/trace-events
+++ b/trace-events
@@ -1953,3 +1953,16 @@ net_rx_pkt_rss_ip6(void) "Calculating IPv6 RSS  hash"
 net_rx_pkt_rss_ip6_ex(void) "Calculating IPv6/EX RSS  hash"
 net_rx_pkt_rss_hash(size_t rss_length, uint32_t rss_hash) "RSS hash for %zu bytes: 0x%X"
 net_rx_pkt_rss_add_chunk(void* ptr, size_t size, size_t input_offset) "Add RSS chunk %p, %zu bytes, RSS input offset %zu bytes"
+
+# hw/net/e1000x_common.c
+e1000x_rx_can_recv_disabled(bool link_up, bool rx_enabled, bool pci_master) "link_up: %d, rx_enabled %d, pci_master %d"
+e1000x_vlan_is_vlan_pkt(bool is_vlan_pkt, uint16_t eth_proto, uint16_t vet) "Is VLAN packet: %d, ETH proto: 0x%X, VET: 0x%X"
+e1000x_rx_flt_ucast_match(uint32_t idx, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x"
+e1000x_rx_flt_ucast_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x"
+e1000x_rx_flt_inexact_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5, uint32_t mo, uint32_t mta, uint32_t mta_val) "inexact mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x"
+e1000x_rx_link_down(uint32_t status_reg) "Received packet dropped because the link is down STATUS = %u"
+e1000x_rx_disabled(uint32_t rctl_reg) "Received packet dropped because receive is disabled RCTL = %u"
+e1000x_rx_oversized(size_t size) "Received packet dropped because it was oversized (%zu bytes)"
+e1000x_mac_indicate(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "Indicating MAC to guest: %02x:%02x:%02x:%02x:%02x:%02x"
+e1000x_link_negotiation_start(void) "Start link auto negotiation"
+e1000x_link_negotiation_done(void) "Auto negotiation is completed"
