All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Fleytman <dmitry@daynix.com>
To: qemu-devel@nongnu.org
Cc: Jason Wang <jasowang@redhat.com>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	Yan Vugenfirer <yan@daynix.com>, Leonid Bloch <leonid@daynix.com>,
	Shmulik Ladkani <shmulik.ladkani@ravellosystems.com>
Subject: [Qemu-devel] [PATCH v7 15/17] e1000: Move out code that will be reused in e1000e
Date: Tue, 31 May 2016 10:20:57 +0300	[thread overview]
Message-ID: <1464679259-1378-16-git-send-email-dmitry@daynix.com> (raw)
In-Reply-To: <1464679259-1378-1-git-send-email-dmitry@daynix.com>

From: Dmitry Fleytman <dmitry.fleytman@ravellosystems.com>

Code that will be shared moved to a separate files.

Signed-off-by: Dmitry Fleytman <dmitry.fleytman@ravellosystems.com>
Signed-off-by: Leonid Bloch <leonid.bloch@ravellosystems.com>
---
 MAINTAINERS            |   5 +
 hw/net/Makefile.objs   |   2 +-
 hw/net/e1000.c         | 411 +++++++++++--------------------------------------
 hw/net/e1000x_common.c | 267 ++++++++++++++++++++++++++++++++
 hw/net/e1000x_common.h | 213 +++++++++++++++++++++++++
 trace-events           |  13 ++
 6 files changed, 591 insertions(+), 320 deletions(-)
 create mode 100644 hw/net/e1000x_common.c
 create mode 100644 hw/net/e1000x_common.h

diff --git a/MAINTAINERS b/MAINTAINERS
index e890849..ab4e884 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -981,6 +981,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..94f85c9
--- /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..21bf28e
--- /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 e1000x_txd_props {
+    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 dbcfb8d..d7646a7 100644
--- a/trace-events
+++ b/trace-events
@@ -1986,3 +1986,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 %lu bytes: 0x%X"
 net_rx_pkt_rss_add_chunk(void* ptr, size_t size, size_t input_offset) "Add RSS chunk %p, %lu bytes, RSS input offset %lu 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 (%lu 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"
-- 
2.5.5

  parent reply	other threads:[~2016-05-31  7:21 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-05-31  7:20 [Qemu-devel] [PATCH v7 00/17] Introduce Intel 82574 GbE Controller Emulation (e1000e) Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 01/17] pci: fix unaligned access in pci_xxx_quad() Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 02/17] msix: make msix_clr_pending() visible for clients Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 03/17] pci: Introduce define for PM capability version 1.1 Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 04/17] pcie: Add support for PCIe CAP v1 Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 05/17] pcie: Introduce function for DSN capability creation Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 06/17] vmxnet3: Use generic function for DSN capability definition Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 07/17] net: Introduce Toeplitz hash calculator Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 08/17] net: Add macros for MAC address tracing Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 09/17] vmxnet3: Use common MAC address tracing macros Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 10/17] net_pkt: Name vmxnet3 packet abstractions more generic Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 11/17] rtl8139: Move more TCP definitions to common header Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 12/17] net_pkt: Extend packet abstraction as required by e1000e functionality Dmitry Fleytman
2016-06-01  4:25   ` Jason Wang
2016-06-01  6:54     ` Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 13/17] vmxnet3: Use pci_dma_* API instead of cpu_physical_memory_* Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 14/17] e1000_regs: Add definitions for Intel 82574-specific bits Dmitry Fleytman
2016-05-31  7:20 ` Dmitry Fleytman [this message]
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 16/17] net: Introduce e1000e device emulation Dmitry Fleytman
2016-05-31  7:20 ` [Qemu-devel] [PATCH v7 17/17] e1000e: Introduce qtest for e1000e device Dmitry Fleytman
2016-05-31 10:43 ` [Qemu-devel] [PATCH v7 00/17] Introduce Intel 82574 GbE Controller Emulation (e1000e) Michael S. Tsirkin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1464679259-1378-16-git-send-email-dmitry@daynix.com \
    --to=dmitry@daynix.com \
    --cc=jasowang@redhat.com \
    --cc=leonid@daynix.com \
    --cc=mst@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=shmulik.ladkani@ravellosystems.com \
    --cc=yan@daynix.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.