diff mbox

[1/2,V4] e1000: add the ability to select among several specific types of e1000[e]; 82566DM emulation ; some pointers to documentations and details.

Message ID 1394198414-22504-2-git-send-email-romain@dolbeau.org
State New
Headers show

Commit Message

Romain Dolbeau March 7, 2014, 1:20 p.m. UTC
Try to implement proper QOM

some cleaning up, and (hopefully proper) E1000State versioning support

Signed-off-by: Romain Dolbeau <romain@dolbeau.org>
---
 hw/net/e1000.c      |  398 +++++++++++++++++++++++++++++++++++++++++++++++----
 hw/net/e1000_regs.h |  149 ++++++++++++++++---
 2 files changed, 496 insertions(+), 51 deletions(-)

Comments

Stefan Hajnoczi March 10, 2014, 12:56 p.m. UTC | #1
On Fri, Mar 07, 2014 at 02:20:13PM +0100, Romain Dolbeau wrote:

Subject: e1000: add the ability to select among several specific types of e1000[e]; 82566DM emulation ; some pointers to documentations and details.

This subject suggests that the patch does several different things that
should be split into several smaller, logical steps:

Patch 1: e1000: introduce e1000-base class
Patch 2: e1000: add device names for more NIC models
Patch 3: e1000: add 82566DM emulation
...

Do them step-by-step and the patches will be cleaner, easier to review,
and the commit messages will be easy to come up with.

> Try to implement proper QOM
> 
> some cleaning up, and (hopefully proper) E1000State versioning support

Once the patch is split into logical steps the commit descriptions will
be easy to improve.  They should contain the rationale for the change.

> @@ -409,6 +468,9 @@ set_ctrl(E1000State *s, int index, uint32_t val)
>  {
>      /* RST is self clearing */
>      s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
> +    if (val & E1000_CTRL_RST) {
> +        e1000_reset(s);
> +    }

Maybe this should be a separate commit.  Is this a bugfix?

> @@ -1017,7 +1079,21 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
>          } else { // as per intel docs; skip descriptors with null buf addr
>              DBGOUT(RX, "Null RX descriptor!!\n");
>          }
> -        pci_dma_write(d, base, &desc, sizeof(desc));
> +        if (!s->rxbuf_edesc) {
> +            pci_dma_write(d, base, &desc, sizeof(desc));
> +        } else { /* extended rx descriptor */
> +            union e1000_rx_desc_extended edesc;
> +            edesc.wb.lower.mrq = 0;
> +            edesc.wb.lower.hi_dword.rss = 0;
> +            /* note: we deliberately ignore desc.errors here, as it comes
> +             * from what we pci_dma_read earlier, and that wasn't
> +             * e1000_rx_desc but a e1000_rx_desc_extended.
> +             */
> +            edesc.wb.upper.status_error = desc.status;
> +            edesc.wb.upper.length = desc.length;
> +            edesc.wb.upper.vlan = desc.special;

The descriptor fields need to be little-endian.  The host could be
big-endian so use cpu_to_le32() and friends.

> @@ -1234,6 +1312,69 @@ e1000_mmio_read(void *opaque, hwaddr addr, unsigned size)
>      return 0;
>  }
>  
> +static void
> +e1000_flash_write(void *opaque, hwaddr addr, uint64_t val,
> +                 unsigned size)
> +{
> +    E1000State *s = opaque;
> +    unsigned int index = addr % 2048;

Why this magic number?

> +static const uint16_t e1000_ich8_flash_template[64] = {

Where does this template come from and what is the relationship between
the EEPROM and the flash?  Does the device have both EEPROM and flash?

> @@ -1523,7 +1774,9 @@ static int pci_e1000_init(PCIDevice *pci_dev)
>  
>      pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
>  
> -    pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
> +    pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->flash);
> +
> +    pci_register_bar(pci_dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &d->io);

How are the BARs numbered on the real device?  Do all models have flash?

We cannot change the BARs, it would break migration between old and new
QEMU.

>  
>      memmove(d->eeprom_data, e1000_eeprom_template,
>          sizeof e1000_eeprom_template);
> @@ -1531,11 +1784,42 @@ static int pci_e1000_init(PCIDevice *pci_dev)
>      macaddr = d->conf.macaddr.a;
>      for (i = 0; i < 3; i++)
>          d->eeprom_data[i] = (macaddr[2*i+1]<<8) | macaddr[2*i];
> +    /* update eeprom with the proper device_id */
> +    d->eeprom_data[11] = pdc->device_id;
> +    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;
> -
> +    d->rxbuf_edesc = 0;
> +    if (pdc->device_id == E1000_DEV_ID_ICH9_IGP_AMT) {
> +        /* FIXME: this changes the default values only
> +         * for one device type, whereas we probably should
> +         * have a more generic per-device way of specifying
> +         * the eeprom/flash content & extended descriptor
> +         * support */

You can define a method that e1000 subclasses can implement to
post-initialized ->eeprom_data[].  The the if statement isn't needed.

>  static void e1000_register_types(void)
>  {
> -    type_register_static(&e1000_info);
> +    int i;
> +    type_register_static(&e1000_info_abstract);

The naming is inconsistent.  Please use:

"e1000-base" with E1000_BASE() as the macro and e1000_base_info as the
TypeInfo.  (Or name it slightly differently if you like but keep it
consistent.)

> @@ -542,9 +587,9 @@
>  #define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
>  #define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
>  #define E1000_EEPROM_RW_REG_DATA   16   /* Offset to data in EEPROM read/write registers */
> -#define E1000_EEPROM_RW_REG_DONE   0x10 /* Offset to READ/WRITE done bit */
> +#define E1000_EEPROM_RW_REG_DONE   0x2  /* Offset to READ/WRITE done bit */

Please put a change like this in a separate commit and explain the
reasoning.

>  #define E1000_EEPROM_RW_REG_START  1    /* First bit for telling part to start operation */
> -#define E1000_EEPROM_RW_ADDR_SHIFT 8    /* Shift to the address bits */
> +#define E1000_EEPROM_RW_ADDR_SHIFT 2    /* Shift to the address bits */

This can go together with the E1000_EEPROM_RW_REG_DONE change.

> +/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
> +/* Offset 04h HSFSTS */
> +union ich8_hws_flash_status {
> +        struct ich8_hsfsts {
> +                uint16_t flcdone:1;  /* bit 0 Flash Cycle Done */
> +                uint16_t flcerr:1;   /* bit 1 Flash Cycle Error */
> +                uint16_t dael:1;     /* bit 2 Direct Access error Log */
> +                uint16_t berasesz:2; /* bit 4:3 Sector Erase Size */
> +                uint16_t flcinprog:1;        /* bit 5 flash cycle in Progress */
> +                uint16_t reserved1:2;        /* bit 13:6 Reserved */
> +                uint16_t reserved2:6;        /* bit 13:6 Reserved */
> +                uint16_t fldesvalid:1;       /* bit 14 Flash Descriptor Valid */
> +                uint16_t flockdn:1;  /* bit 15 Flash Config Lock-Down */
> +        } hsf_status;

I don't think you can use C bitfields since the bit-ordering is up to
the compiler.  It may or may not match the hardware register layout!

Instead, use uint16_t and define bitmask constants so you can use
bitwise-AND/OR.
diff mbox

Patch

diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 8387443..4d7204c 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -1,8 +1,10 @@ 
 /*
  * QEMU e1000 emulation
  *
- * Software developer's manual:
- * http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
+ * Software developer's manual (PCI, PCI-X):
+ * <http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf>
+ * Software developer's manual (PCIe):
+ * <http://www.intel.com/content/dam/www/public/us/en/documents/manuals/pcie-gbe-controllers-open-source-manual.pdf>
  *
  * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
  * Copyright (c) 2008 Qumranet
@@ -10,6 +12,8 @@ 
  * Copyright (c) 2007 Dan Aloni
  * Copyright (c) 2004 Antony T Curtis
  *
+ * Additional modifications (c) 2014 Romain Dolbeau
+ *
  * 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
@@ -58,6 +62,7 @@  static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
 
 #define IOPORT_SIZE       0x40
 #define PNPMMIO_SIZE      0x20000
+#define FLASH_RSIZE       0x80
 #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 */
@@ -69,10 +74,12 @@  static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
 
 /*
  * HW models:
- *  E1000_DEV_ID_82540EM works with Windows and Linux
- *  E1000_DEV_ID_82573L OK with windoze and Linux 2.6.22,
- *	appears to perform better than 82540EM, but breaks with Linux 2.6.18
+ *  E1000_DEV_ID_82540EM works with Windows and Linux, and is the default
  *  E1000_DEV_ID_82544GC_COPPER appears to work; not well tested
+ *  E1000_DEV_ID_82545EM_COPPER appears to work with OSX 10.9[.1]; not well tested
+ *  E1000_DEV_ID_ICH9_IGP_AMT appears to work with Linux kernel 3.12; not well tested
+ *  It seems those 3 are mostly identical anyway, so picking one
+ *  over the others is a matter of guest support.
  *  Others never tested
  */
 enum { E1000_DEVID = E1000_DEV_ID_82540EM };
@@ -81,10 +88,24 @@  enum { E1000_DEVID = E1000_DEV_ID_82540EM };
  * May need to specify additional MAC-to-PHY entries --
  * Intel's Windows driver refuses to initialize unless they match
  */
-enum {
-    PHY_ID2_INIT = E1000_DEVID == E1000_DEV_ID_82573L ?		0xcc2 :
-                   E1000_DEVID == E1000_DEV_ID_82544GC_COPPER ?	0xc30 :
-                   /* default to E1000_DEV_ID_82540EM */	0xc20
+/* PHY_ID1:
+ * Most 8254x uses 0x141, but 82541xx and 82547GI/EI uses 0x2a8,
+ * and so do the 631xESB/632xESB, 82571EB/82572EI.
+ * The 82573E/82573V/82573L and 82563EB/82564EB also uses 0x141.
+ * <http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf> page 250
+ * <http://www.intel.com/content/dam/www/public/us/en/documents/manuals/pcie-gbe-controllers-open-source-manual.pdf> page 305
+ */
+const uint16_t PHY_ID1_INIT[][2] = {
+  { E1000_DEV_ID_80003ES2LAN_COPPER_DPT, 0x2a8 },
+  { E1000_DEV_ID_ICH9_IGP_AMT, 0x2a8 },
+  { -1, 0x141 } /* default for 82540EM and many others */
+};
+const uint16_t PHY_ID2_INIT[][2] = {
+  { E1000_DEV_ID_82573L, 0xcc2 },
+  { E1000_DEV_ID_82544GC_COPPER, 0xc30 },
+  { E1000_DEV_ID_ICH9_IGP_AMT, 0x390 },
+  { -1, 0xc20 } /* default for 82540EM and many others; this one
+                   is a lot more device-specific than phy_id1 */
 };
 
 typedef struct E1000State_st {
@@ -95,12 +116,15 @@  typedef struct E1000State_st {
     NICState *nic;
     NICConf conf;
     MemoryRegion mmio;
+    MemoryRegion flash;
     MemoryRegion io;
 
     uint32_t mac_reg[0x8000];
     uint16_t phy_reg[0x20];
     uint16_t eeprom_data[64];
+    uint16_t flash_reg[FLASH_RSIZE];
 
+    uint32_t rxbuf_edesc;
     uint32_t rxbuf_size;
     uint32_t rxbuf_min_shift;
     struct e1000_tx {
@@ -151,7 +175,7 @@  typedef struct E1000State_st {
     uint32_t compat_flags;
 } E1000State;
 
-#define TYPE_E1000 "e1000"
+#define TYPE_E1000 "base-e1000"
 
 #define E1000(obj) \
     OBJECT_CHECK(E1000State, (obj), TYPE_E1000)
@@ -170,6 +194,7 @@  enum {
     defreg(RA),		defreg(MTA),	defreg(CRCERRS),defreg(VFTA),
     defreg(VET),        defreg(RDTR),   defreg(RADV),   defreg(TADV),
     defreg(ITR),
+    defreg(EXTCNF_CTRL), defreg(FWSM), defreg(KABGTXD), defreg(FACTPS),
 };
 
 static void
@@ -229,13 +254,19 @@  static const char phy_regcap[0x20] = {
     [PHY_CTRL] = PHY_RW,	[PHY_1000T_CTRL] = PHY_RW,
     [PHY_LP_ABILITY] = PHY_R,	[PHY_1000T_STATUS] = PHY_R,
     [PHY_AUTONEG_ADV] = PHY_RW,	[M88E1000_RX_ERR_CNTR] = PHY_R,
-    [PHY_ID2] = PHY_R,		[M88E1000_PHY_SPEC_STATUS] = PHY_R
+    [PHY_ID2] = PHY_R,          [M88E1000_PHY_SPEC_STATUS] = PHY_R,
+    [ICH_IGP_PHY_REGADD_ALT_MDIO] = PHY_RW /* ICH IGP ? */,
+    [PHY_AUTONEG_EXP] = PHY_RW, /* ICH IGP ? */
+    [PHY_EXT_STATUS] = PHY_RW, /* ICH IGP ? */
+    [M88E1000_INT_ENABLE] = PHY_RW, /* ICH IGP ? */
+    [M88E1000_INT_STATUS] = PHY_RW, /* ICH IGP ? */
 };
 
 static const uint16_t phy_reg_init[] = {
     [PHY_CTRL] = 0x1140,
     [PHY_STATUS] = 0x794d, /* link initially up with not completed autoneg */
-    [PHY_ID1] = 0x141,				[PHY_ID2] = PHY_ID2_INIT,
+     /* both phy_id will be replaced */
+    [PHY_ID1] = 0x141,                          [PHY_ID2] = 0xc20,
     [PHY_1000T_CTRL] = 0x0e00,			[M88E1000_PHY_SPEC_CTRL] = 0x360,
     [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60,	[PHY_AUTONEG_ADV] = 0xde1,
     [PHY_LP_ABILITY] = 0x1e0,			[PHY_1000T_STATUS] = 0x3c00,
@@ -269,10 +300,11 @@  static void
 set_interrupt_cause(E1000State *s, int index, uint32_t val)
 {
     PCIDevice *d = PCI_DEVICE(s);
+    PCIDeviceClass *pdc = PCI_DEVICE_GET_CLASS(d);
     uint32_t pending_ints;
     uint32_t mit_delay;
 
-    if (val && (E1000_DEVID >= E1000_DEV_ID_82547EI_MOBILE)) {
+    if (val && (pdc->device_id >= E1000_DEV_ID_82547EI_MOBILE)) {
         /* Only for 8257x */
         val |= E1000_ICR_INT_ASSERTED;
     }
@@ -375,8 +407,10 @@  rxbufsize(uint32_t v)
 static void e1000_reset(void *opaque)
 {
     E1000State *d = opaque;
+    PCIDeviceClass *pdc = PCI_DEVICE_GET_CLASS(d);
     uint8_t *macaddr = d->conf.macaddr.a;
     int i;
+    uint16_t phy_id1 = -1, phy_id2 = -1;
 
     timer_del(d->autoneg_timer);
     timer_del(d->mit_timer);
@@ -385,6 +419,24 @@  static void e1000_reset(void *opaque)
     d->mit_ide = 0;
     memset(d->phy_reg, 0, sizeof d->phy_reg);
     memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
+    for (i = 0; PHY_ID1_INIT[i][0] != (uint16_t)-1; i++) {
+        if (PHY_ID1_INIT[i][0] == pdc->device_id) {
+            phy_id1 = PHY_ID1_INIT[i][1];
+        }
+    }
+    if (phy_id1 == (uint16_t)-1) {
+        phy_id1 = PHY_ID1_INIT[i][1];
+    }
+    for (i = 0; PHY_ID2_INIT[i][0] != (uint16_t)-1; i++) {
+        if (PHY_ID2_INIT[i][0] == pdc->device_id) {
+            phy_id2 = PHY_ID2_INIT[i][1];
+        }
+    }
+    if (phy_id2 == (uint16_t)-1) {
+        phy_id2 = PHY_ID2_INIT[i][1];
+    }
+    d->phy_reg[PHY_ID1] = phy_id1;
+    d->phy_reg[PHY_ID2] = phy_id2;
     memset(d->mac_reg, 0, sizeof d->mac_reg);
     memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
     d->rxbuf_min_shift = 1;
@@ -402,6 +454,13 @@  static void e1000_reset(void *opaque)
         d->mac_reg[RA + 1] |= (i < 2) ? macaddr[i + 4] << (8 * i) : 0;
     }
     qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr);
+
+    /* reset flash (clear locks) */
+    memset(d->flash_reg, 0, FLASH_RSIZE * sizeof(uint16_t));
+    union ich8_hws_flash_status hsfsts;
+    hsfsts.regval = 0;
+    hsfsts.hsf_status.fldesvalid = 1;
+    d->flash_reg[ICH_FLASH_HSFSTS] = hsfsts.regval;
 }
 
 static void
@@ -409,6 +468,9 @@  set_ctrl(E1000State *s, int index, uint32_t val)
 {
     /* RST is self clearing */
     s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
+    if (val & E1000_CTRL_RST) {
+        e1000_reset(s);
+    }
 }
 
 static void
@@ -1017,7 +1079,21 @@  e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
         } else { // as per intel docs; skip descriptors with null buf addr
             DBGOUT(RX, "Null RX descriptor!!\n");
         }
-        pci_dma_write(d, base, &desc, sizeof(desc));
+        if (!s->rxbuf_edesc) {
+            pci_dma_write(d, base, &desc, sizeof(desc));
+        } else { /* extended rx descriptor */
+            union e1000_rx_desc_extended edesc;
+            edesc.wb.lower.mrq = 0;
+            edesc.wb.lower.hi_dword.rss = 0;
+            /* note: we deliberately ignore desc.errors here, as it comes
+             * from what we pci_dma_read earlier, and that wasn't
+             * e1000_rx_desc but a e1000_rx_desc_extended.
+             */
+            edesc.wb.upper.status_error = desc.status;
+            edesc.wb.upper.length = desc.length;
+            edesc.wb.upper.vlan = desc.special;
+            pci_dma_write(d, base, &edesc, sizeof(edesc));
+        }
 
         if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
             s->mac_reg[RDH] = 0;
@@ -1173,6 +1249,7 @@  static uint32_t (*macreg_readops[])(E1000State *, int) = {
     getreg(TDBAL),	getreg(TDBAH),	getreg(RDBAH),	getreg(RDBAL),
     getreg(TDLEN),      getreg(RDLEN),  getreg(RDTR),   getreg(RADV),
     getreg(TADV),       getreg(ITR),
+    getreg(EXTCNF_CTRL), getreg(FWSM), getreg(KABGTXD), getreg(FACTPS),
 
     [TOTH] = mac_read_clr8,	[TORH] = mac_read_clr8,	[GPRC] = mac_read_clr4,
     [GPTC] = mac_read_clr4,	[TPR] = mac_read_clr4,	[TPT] = mac_read_clr4,
@@ -1189,6 +1266,7 @@  static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
     putreg(PBA),	putreg(EERD),	putreg(SWSM),	putreg(WUFC),
     putreg(TDBAL),	putreg(TDBAH),	putreg(TXDCTL),	putreg(RDBAH),
     putreg(RDBAL),	putreg(LEDCTL), putreg(VET),
+    putreg(EXTCNF_CTRL), putreg(FWSM), putreg(KABGTXD), putreg(FACTPS),
     [TDLEN] = set_dlen,	[RDLEN] = set_dlen,	[TCTL] = set_tctl,
     [TDT] = set_tctl,	[MDIC] = set_mdic,	[ICS] = set_ics,
     [TDH] = set_16bit,	[RDH] = set_16bit,	[RDT] = set_rdt,
@@ -1234,6 +1312,69 @@  e1000_mmio_read(void *opaque, hwaddr addr, unsigned size)
     return 0;
 }
 
+static void
+e1000_flash_write(void *opaque, hwaddr addr, uint64_t val,
+                 unsigned size)
+{
+    E1000State *s = opaque;
+    unsigned int index = addr % 2048;
+
+    if (index < FLASH_RSIZE) {
+        s->flash_reg[index] = val & 0xFFFF;
+        switch (index) {
+        case ICH_FLASH_HSFSTS:
+            break;
+        case ICH_FLASH_HSFCTL: {
+            union ich8_hws_flash_ctrl ctrl;
+            ctrl.regval = s->flash_reg[ICH_FLASH_HSFCTL];
+            if (ctrl.hsf_ctrl.flcgo) {
+                /* says we're done, clear go,
+                   copy data to proper register */
+                union ich8_hws_flash_status hsfsts;
+                int fldbcount;
+                uint16_t offset;
+                uint16_t res;
+                hsfsts.regval = s->flash_reg[ICH_FLASH_HSFSTS];
+                hsfsts.hsf_status.flcdone = 1;
+                hsfsts.hsf_status.flcerr = 0;
+                s->flash_reg[ICH_FLASH_HSFSTS] = hsfsts.regval;
+                fldbcount = ctrl.hsf_ctrl.fldbcount;
+                ctrl.hsf_ctrl.flcgo = 0;
+                s->flash_reg[ICH_FLASH_HSFCTL] = ctrl.regval;
+                offset = s->flash_reg[ICH_FLASH_FADDR] >> 1;
+                res = s->eeprom_data[offset];
+                if (fldbcount == 0) {
+                    if (s->flash_reg[ICH_FLASH_FADDR] % 2) {
+                        res = res >> 8;
+                    } else {
+                        res = res & 0x00FF;
+                    }
+                }
+                s->flash_reg[ICH_FLASH_FDATA0] = res;
+            }
+        }
+        default:
+            break;
+        }
+    } else {
+        DBGOUT(UNKNOWN, "Flash unknown write addr=0x%08x,val=0x%08"PRIx64"\n",
+               index<<2, val);
+    }
+}
+
+static uint64_t
+e1000_flash_read(void *opaque, hwaddr addr, unsigned size)
+{
+    E1000State *s = opaque;
+    unsigned int index = addr % 2048;
+
+    if (index < FLASH_RSIZE) {
+        return s->flash_reg[index];
+    }
+    DBGOUT(UNKNOWN, "Flash unknown read addr=0x%08x\n", index<<2);
+    return 0;
+}
+
 static const MemoryRegionOps e1000_mmio_ops = {
     .read = e1000_mmio_read,
     .write = e1000_mmio_write,
@@ -1244,6 +1385,16 @@  static const MemoryRegionOps e1000_mmio_ops = {
     },
 };
 
+static const MemoryRegionOps e1000_flash_ops = {
+    .read = e1000_flash_read,
+    .write = e1000_flash_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
 static uint64_t e1000_io_read(void *opaque, hwaddr addr,
                               unsigned size)
 {
@@ -1354,7 +1505,7 @@  static const VMStateDescription vmstate_e1000_mit_state = {
 
 static const VMStateDescription vmstate_e1000 = {
     .name = "e1000",
-    .version_id = 2,
+    .version_id = 3,
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .pre_save = e1000_pre_save,
@@ -1425,6 +1576,10 @@  static const VMStateDescription vmstate_e1000 = {
         VMSTATE_UINT32(mac_reg[TXDCTL], E1000State),
         VMSTATE_UINT32(mac_reg[WUFC], E1000State),
         VMSTATE_UINT32(mac_reg[VET], E1000State),
+        VMSTATE_UINT32_V(mac_reg[EXTCNF_CTRL], E1000State, 3),
+        VMSTATE_UINT32_V(mac_reg[FWSM], E1000State, 3),
+        VMSTATE_UINT16_V(flash_reg[ICH_FLASH_HSFSTS], E1000State, 3),
+        VMSTATE_UINT16_V(flash_reg[ICH_FLASH_HSFCTL], E1000State, 3),
         VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32),
         VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128),
         VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
@@ -1440,15 +1595,106 @@  static const VMStateDescription vmstate_e1000 = {
     }
 };
 
+/*
+ * The content of EEPROM is documented in the documentation
+ * PCI/X: "Table 5-2. Ethernet Controller Address Map" page 98 (except 82544GC/EI and 82541ER)
+ * PCI/X: "Table 5-3. 82544GC/EI and 82541ER EEPROM Address Map" page 102
+ * PCIe: "Table 5-2. Ethernet Controller EEPROM Map" page 134
+ */
 static const uint16_t e1000_eeprom_template[64] = {
-    0x0000, 0x0000, 0x0000, 0x0000,      0xffff, 0x0000,      0x0000, 0x0000,
-    0x3000, 0x1000, 0x6403, E1000_DEVID, 0x8086, E1000_DEVID, 0x8086, 0x3040,
-    0x0008, 0x2000, 0x7e14, 0x0048,      0x1000, 0x00d8,      0x0000, 0x2700,
-    0x6cc9, 0x3150, 0x0722, 0x040b,      0x0984, 0x0000,      0xc000, 0x0706,
-    0x1008, 0x0000, 0x0f04, 0x7fff,      0x4d01, 0xffff,      0xffff, 0xffff,
-    0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
-    0x0100, 0x4000, 0x121c, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
-    0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0x0000,
+    /* 00h - 02h: Ethernet address, will be overridden */
+    0x0000, 0x0000, 0x0000,
+    /* 03h: compatibility, this seems a bit device-specific
+            and probably should be overridden */
+    0x0000,
+    /* 04h: compatibility (PCIe) or SerDes config (most PCI/X) or LED */
+    0xffff,
+    /* 05h - 07h: EEprom version & OEM (PCIe other than 82573),
+                  compatibility (most PCI/X, 82573) */
+    0x0000, 0x0000, 0x0000,
+    /* 08h - 09h: PBA (irrelevant) */
+    0x3000, 0x1000,
+    /* 0ah: init control 1 */
+    0x6403,
+    /* 0bh - 0eh: PCI ID, will be overridden */
+    E1000_DEVID, 0x8086, E1000_DEVID, 0x8086,
+    /* 0fh: init control 2 */
+    0x3040,
+    /* 10h - 12h: seem quite device-specific with several variants */
+    0x0008, 0x2000, 0x7e14,
+    /* 13h: management */
+    0x0048,
+    /* 14h: init control 3 (2nd LAN?), not 82573 */
+    0x1000,
+    /* 15h - 16h: IPv4 (PCI/X) or  reserved (PCIe), not 82573 */
+    0x00d8, 0x0000,
+    /* 17h - 1Eh: Another batch of variants; IPv6 LAN in PCI/X
+     * but is FW Config Start Address (17h, most PCIe) followed
+     * by PCI init configuration and stuff
+     */
+    0x2700, 0x6cc9, 0x3150, 0x0722, 0x040b, 0x0984, 0x0000, 0xc000,
+    /* 1fh: mostly reserved (PCI/X), LED conf (PCIe) */
+    0x0706,
+    /* 20h - 21h: software defined pin controls, 21h: mostly control */
+    0x1008, 0x0000,
+    /* 22h - 23h: LAN power, management control (not 82573) */
+    0x0f04, 0x7fff,
+    /* 24h: init control 3 (again?) */
+    0x4d01,
+    /* 25h-2eh: either IP4/6 (PCI/X) or mostly reserved (PCIe) */
+    0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+    /* 2fh: LEDCTL Default (PCI/X) or Vital Product Data (VPD) Pointer (PCIe) */
+    0xffff,
+    /* 30h-3eh: mostly PXE/boot stuff */
+    0x0100, 0x4000, 0x121c, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+    /* 3fh: checksum to be computed */
+    0x0000
+};
+static const uint16_t e1000_ich8_flash_template[64] = {
+    /* 00h - 02h: Ethernet address, will be overridden */
+    0x0000, 0x0000, 0x0000,
+    /* 03h - 04h: reserved */
+    0x0800, 0xFFFF,
+    /* 05h - 07h: image version information, reserved*/
+    0x0000, 0xFFFF, 0xFFFF,
+    /* 08h - 09h: PBA (irrelevant) */
+    0x3000, 0x1000,
+    /* 0ah: init control 1 */
+    0x10c7,
+    /* 0bh - 0eh: PCI ID, will be overridden */
+    E1000_DEVID, 0x8086, E1000_DEVID, 0x8086,
+    /* 0fh: device revision id (ich9), reserved (ich8) */
+    0x0000, /* fixme */
+    /* 10h - 12h: LAN power consumption, reserved */
+    0x0D01, 0x0000, 0x0000,
+    /* 13h: Shared Initialization Control Word */
+    0x9607,
+    /* 14h - 16h: extended configuration word 1-3 */
+    0x7020, 0x3800, 0x0000,
+    /* 17h - 18h: LEDCTL 1, LEDCTL 0 2 */
+    0x8d07, 0x0684,
+    /* 19h - 1ah: future initialization words */
+    (0x0181 | 0x0040), 0x0800,
+    /* 1bh - 1dh: reserved */
+    0x0000, 0x294C, 0x294C,
+    /* 1eh - 1fh: device id (some devices) */
+    0x10BE, 0x10BF,
+    /* 20h - 21h: reserved */
+    0x294C, 0x294C,
+    /* 22h - 23h: device id (some devices) */
+    0x10bd, 0x294C,
+    /* 24h-2fh: reserved */
+    0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+    0xffff, 0xffff,
+    /* 30h-3eh: mostly PXE/boot stuff & reserved */
+    0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+    /* 3fh: checksum to be computed */
+    0x0000
 };
 
 /* PCI interface */
@@ -1468,6 +1714,10 @@  e1000_mmio_setup(E1000State *d)
     for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
         memory_region_add_coalescing(&d->mmio, excluded_regs[i] + 4,
                                      excluded_regs[i+1] - excluded_regs[i] - 4);
+
+    memory_region_init_io(&d->flash, OBJECT(d), &e1000_flash_ops, d,
+                          "e1000-flash", FLASH_RSIZE);
+
     memory_region_init_io(&d->io, OBJECT(d), &e1000_io_ops, d, "e1000-io", IOPORT_SIZE);
 }
 
@@ -1506,6 +1756,7 @@  static NetClientInfo net_e1000_info = {
 static int pci_e1000_init(PCIDevice *pci_dev)
 {
     DeviceState *dev = DEVICE(pci_dev);
+    PCIDeviceClass *pdc = PCI_DEVICE_GET_CLASS(pci_dev);
     E1000State *d = E1000(pci_dev);
     uint8_t *pci_conf;
     uint16_t checksum = 0;
@@ -1523,7 +1774,9 @@  static int pci_e1000_init(PCIDevice *pci_dev)
 
     pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
 
-    pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
+    pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->flash);
+
+    pci_register_bar(pci_dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
 
     memmove(d->eeprom_data, e1000_eeprom_template,
         sizeof e1000_eeprom_template);
@@ -1531,11 +1784,42 @@  static int pci_e1000_init(PCIDevice *pci_dev)
     macaddr = d->conf.macaddr.a;
     for (i = 0; i < 3; i++)
         d->eeprom_data[i] = (macaddr[2*i+1]<<8) | macaddr[2*i];
+    /* update eeprom with the proper device_id */
+    d->eeprom_data[11] = pdc->device_id;
+    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;
-
+    d->rxbuf_edesc = 0;
+    if (pdc->device_id == E1000_DEV_ID_ICH9_IGP_AMT) {
+        /* FIXME: this changes the default values only
+         * for one device type, whereas we probably should
+         * have a more generic per-device way of specifying
+         * the eeprom/flash content & extended descriptor
+         * support */
+        union ich8_hws_flash_status hsfsts;
+        for (i = 0; i < EEPROM_CHECKSUM_REG; i++) {
+            d->eeprom_data[i] = e1000_ich8_flash_template[i];
+        }
+        for (i = 0; i < 3; i++) {
+            d->eeprom_data[i] = (macaddr[2*i+1]<<8) | macaddr[2*i];
+        }
+        d->eeprom_data[11] = pdc->device_id;
+        d->eeprom_data[13] = pdc->device_id;
+        checksum = 0;
+        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;
+        /* init flash registers */
+        memset(d->flash_reg, 0, FLASH_RSIZE * sizeof(uint16_t));
+        hsfsts.regval = 0;
+        hsfsts.hsf_status.fldesvalid = 1;
+        d->flash_reg[ICH_FLASH_HSFSTS] = hsfsts.regval;
+        d->rxbuf_edesc = 1;
+    }
     d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
                           object_get_typename(OBJECT(d)), dev->id, d);
 
@@ -1564,17 +1848,26 @@  static Property e1000_properties[] = {
     DEFINE_PROP_END_OF_LIST(),
 };
 
+typedef struct E1000Info E1000Info;
+struct E1000Info {
+    const char *name;
+    uint16_t   vendor_id;
+    uint16_t   device_id;
+    uint8_t    revision;
+};
+
 static void e1000_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    const E1000Info *info = data;
 
     k->init = pci_e1000_init;
     k->exit = pci_e1000_uninit;
     k->romfile = "efi-e1000.rom";
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = E1000_DEVID;
-    k->revision = 0x03;
+    k->vendor_id = info->vendor_id;
+    k->device_id = info->device_id;
+    k->revision = info->revision;
     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
     dc->desc = "Intel Gigabit Ethernet";
@@ -1583,16 +1876,59 @@  static void e1000_class_init(ObjectClass *klass, void *data)
     dc->props = e1000_properties;
 }
 
-static const TypeInfo e1000_info = {
+static const E1000Info e1000_info_array[] = {
+    {
+        .name      = "e1000",
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = E1000_DEVID,
+        .revision  = 0x03,
+    },
+    {
+        .name      = "82540EM",
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = E1000_DEV_ID_82540EM,
+        .revision  = 0x03,
+    },
+    {
+        .name      = "82544GC",
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = E1000_DEV_ID_82544GC_COPPER,
+        .revision  = 0x03,
+    },
+    {
+        .name      = "82545EM",
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = E1000_DEV_ID_82545EM_COPPER,
+        .revision  = 0x03,
+    },
+    {
+        .name      = "82566DM",
+        .vendor_id = PCI_VENDOR_ID_INTEL,
+        .device_id = E1000_DEV_ID_ICH9_IGP_AMT,
+        .revision  = 0x00,
+    }
+};
+
+static const TypeInfo e1000_info_abstract = {
     .name          = TYPE_E1000,
     .parent        = TYPE_PCI_DEVICE,
     .instance_size = sizeof(E1000State),
-    .class_init    = e1000_class_init,
+    .abstract      = true,
 };
 
 static void e1000_register_types(void)
 {
-    type_register_static(&e1000_info);
+    int i;
+    type_register_static(&e1000_info_abstract);
+    for (i = 0; i < ARRAY_SIZE(e1000_info_array); i++) {
+        TypeInfo e1000_info = {
+          .name = e1000_info_array[i].name,
+          .parent = TYPE_E1000,
+          .class_data = (void *)&e1000_info_array[i],
+          .class_init = e1000_class_init,
+        };
+        type_register(&e1000_info);
+    }
 }
 
 type_init(e1000_register_types)
diff --git a/hw/net/e1000_regs.h b/hw/net/e1000_regs.h
index c9cb79e..0262174 100644
--- a/hw/net/e1000_regs.h
+++ b/hw/net/e1000_regs.h
@@ -34,46 +34,71 @@ 
 
 
 /* PCI Device IDs */
+/* Where is the documentation for those 3 ?
+   (they are nonetheless in e1000.ko) */
 #define E1000_DEV_ID_82542               0x1000
 #define E1000_DEV_ID_82543GC_FIBER       0x1001
 #define E1000_DEV_ID_82543GC_COPPER      0x1004
-#define E1000_DEV_ID_82544EI_COPPER      0x1008
-#define E1000_DEV_ID_82544EI_FIBER       0x1009
-#define E1000_DEV_ID_82544GC_COPPER      0x100C
-#define E1000_DEV_ID_82544GC_LOM         0x100D
+/* <http://www.intel.com/content/dam/doc/manual/pci-pci-x-family-gbe-controllers-software-dev-manual.pdf>
+ * "PCI/PCI-X Family of Gigabit Ethernet Controllers Software Developer's Manual"
+ * documents
+ * 82540EP/EM, 82541xx, 82544GC/EI, 82545GM/EM, 82546GB/EB, and 82547xx
+ * Those are handled by driver 'e1000'
+ */
 #define E1000_DEV_ID_82540EM             0x100E
 #define E1000_DEV_ID_82540EM_LOM         0x1015
 #define E1000_DEV_ID_82540EP_LOM         0x1016
 #define E1000_DEV_ID_82540EP             0x1017
 #define E1000_DEV_ID_82540EP_LP          0x101E
+
+#define E1000_DEV_ID_82541EI             0x1013
+#define E1000_DEV_ID_82541EI_MOBILE      0x1018
+#define E1000_DEV_ID_82541ER_LOM         0x1014
+#define E1000_DEV_ID_82541ER             0x1078
+#define E1000_DEV_ID_82541GI             0x1076
+#define E1000_DEV_ID_82541GI_MOBILE      0x1077
+#define E1000_DEV_ID_82541GI_LF          0x107C
+
+#define E1000_DEV_ID_82544EI_COPPER      0x1008
+#define E1000_DEV_ID_82544EI_FIBER       0x1009
+#define E1000_DEV_ID_82544GC_COPPER      0x100C
+#define E1000_DEV_ID_82544GC_LOM         0x100D
+
 #define E1000_DEV_ID_82545EM_COPPER      0x100F
 #define E1000_DEV_ID_82545EM_FIBER       0x1011
 #define E1000_DEV_ID_82545GM_COPPER      0x1026
 #define E1000_DEV_ID_82545GM_FIBER       0x1027
 #define E1000_DEV_ID_82545GM_SERDES      0x1028
+
 #define E1000_DEV_ID_82546EB_COPPER      0x1010
 #define E1000_DEV_ID_82546EB_FIBER       0x1012
 #define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
-#define E1000_DEV_ID_82541EI             0x1013
-#define E1000_DEV_ID_82541EI_MOBILE      0x1018
-#define E1000_DEV_ID_82541ER_LOM         0x1014
-#define E1000_DEV_ID_82541ER             0x1078
-#define E1000_DEV_ID_82547GI             0x1075
-#define E1000_DEV_ID_82541GI             0x1076
-#define E1000_DEV_ID_82541GI_MOBILE      0x1077
-#define E1000_DEV_ID_82541GI_LF          0x107C
 #define E1000_DEV_ID_82546GB_COPPER      0x1079
 #define E1000_DEV_ID_82546GB_FIBER       0x107A
 #define E1000_DEV_ID_82546GB_SERDES      0x107B
 #define E1000_DEV_ID_82546GB_PCIE        0x108A
 #define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
+#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
+
+#define E1000_DEV_ID_82547GI             0x1075
 #define E1000_DEV_ID_82547EI             0x1019
 #define E1000_DEV_ID_82547EI_MOBILE      0x101A
+/* <http://www.intel.com/content/dam/www/public/us/en/documents/manuals/pcie-gbe-controllers-open-source-manual.pdf>
+ * "PCIe* GbE Controllers Open Source Software Developer's Manual"
+ * documents:
+ * 631xESB/632xESB, 82563EB/82564EB, 82571EB/82572EI & 82573E/82573V/82573L
+ * Those are actually handled by driver 'e1000e', not 'e1000'
+ */
+/* it seems the next four are alternative names for 631xESB/632xESB */
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT     0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT     0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT     0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT     0x10BB
+
 #define E1000_DEV_ID_82571EB_COPPER      0x105E
 #define E1000_DEV_ID_82571EB_FIBER       0x105F
 #define E1000_DEV_ID_82571EB_SERDES      0x1060
 #define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
-#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
 #define E1000_DEV_ID_82571EB_QUAD_FIBER  0x10A5
 #define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE  0x10BC
 #define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
@@ -82,15 +107,18 @@ 
 #define E1000_DEV_ID_82572EI_FIBER       0x107E
 #define E1000_DEV_ID_82572EI_SERDES      0x107F
 #define E1000_DEV_ID_82572EI             0x10B9
+/* is the next one from the same document ? */
+#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
+
 #define E1000_DEV_ID_82573E              0x108B
 #define E1000_DEV_ID_82573E_IAMT         0x108C
 #define E1000_DEV_ID_82573L              0x109A
-#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
-#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT     0x1096
-#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT     0x1098
-#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT     0x10BA
-#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT     0x10BB
 
+/* <http://www.intel.com/content/dam/doc/manual/i-o-controller-hub-8-9-10-82566-82567-82562v-software-dev-manual.pdf>
+ * and also
+ * <http://www.intel.com/content/dam/www/public/us/en/documents/design-guides/i-o-controller-hub-8-9-nvm-map-guide.pdf>
+ */
+#define E1000_DEV_ID_ICH8_82567V_3       0x1501
 #define E1000_DEV_ID_ICH8_IGP_M_AMT      0x1049
 #define E1000_DEV_ID_ICH8_IGP_AMT        0x104A
 #define E1000_DEV_ID_ICH8_IGP_C          0x104B
@@ -98,6 +126,21 @@ 
 #define E1000_DEV_ID_ICH8_IFE_GT         0x10C4
 #define E1000_DEV_ID_ICH8_IFE_G          0x10C5
 #define E1000_DEV_ID_ICH8_IGP_M          0x104D
+#define E1000_DEV_ID_ICH9_IGP_AMT        0x10BD
+#define E1000_DEV_ID_ICH9_BM             0x10E5
+#define E1000_DEV_ID_ICH9_IGP_M_AMT      0x10F5
+#define E1000_DEV_ID_ICH9_IGP_M          0x10BF
+#define E1000_DEV_ID_ICH9_IGP_M_V        0x10CB
+#define E1000_DEV_ID_ICH9_IGP_C          0x294C
+#define E1000_DEV_ID_ICH9_IFE            0x10C0
+#define E1000_DEV_ID_ICH9_IFE_GT         0x10C3
+#define E1000_DEV_ID_ICH9_IFE_G          0x10C2
+#define E1000_DEV_ID_ICH10_R_BM_LM       0x10CC
+#define E1000_DEV_ID_ICH10_R_BM_LF       0x10CD
+#define E1000_DEV_ID_ICH10_R_BM_V        0x10CE
+#define E1000_DEV_ID_ICH10_D_BM_LM       0x10DE
+#define E1000_DEV_ID_ICH10_D_BM_LF       0x10DF
+
 
 /* Register Set. (82543, 82544)
  *
@@ -349,6 +392,8 @@ 
 #define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
 #define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
 
+#define ICH_IGP_PHY_REGADD_ALT_MDIO 0x1F
+
 /* PHY Control Register */
 #define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
 #define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
@@ -542,9 +587,9 @@ 
 #define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
 #define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
 #define E1000_EEPROM_RW_REG_DATA   16   /* Offset to data in EEPROM read/write registers */
-#define E1000_EEPROM_RW_REG_DONE   0x10 /* Offset to READ/WRITE done bit */
+#define E1000_EEPROM_RW_REG_DONE   0x2  /* Offset to READ/WRITE done bit */
 #define E1000_EEPROM_RW_REG_START  1    /* First bit for telling part to start operation */
-#define E1000_EEPROM_RW_ADDR_SHIFT 8    /* Shift to the address bits */
+#define E1000_EEPROM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
 #define E1000_EEPROM_POLL_WRITE    1    /* Flag for polling for write complete */
 #define E1000_EEPROM_POLL_READ     0    /* Flag for polling for read complete */
 /* Register Bit Masks */
@@ -761,6 +806,31 @@  struct e1000_rx_desc {
     uint8_t errors;      /* Descriptor Errors */
     uint16_t special;
 };
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+        struct {
+                uint64_t buffer_addr;
+                uint64_t reserved;
+        } read;
+        struct {
+                struct {
+                        uint32_t mrq;     /* Multiple Rx Queues */
+                        union {
+                                uint32_t rss;     /* RSS Hash */
+                                struct {
+                                        uint16_t ip_id;   /* IP id */
+                                        uint16_t csum;    /* Packet Checksum */
+                                } csum_ip;
+                        } hi_dword;
+                } lower;
+                struct {
+                        uint32_t status_error;    /* ext status/error */
+                        uint16_t length;
+                        uint16_t vlan;    /* VLAN tag */
+                } upper;
+        } wb;                   /* writeback */
+};
+
 
 /* Receive Descriptor bit definitions */
 #define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
@@ -890,4 +960,43 @@  struct e1000_data_desc {
 /* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
 #define EEPROM_SUM 0xBABA
 
+
+
+/* FLASH stuff ; straight from the linux driver */
+#define ICH_FLASH_GFPREG              0x0000
+#define ICH_FLASH_HSFSTS              0x0004
+#define ICH_FLASH_HSFCTL              0x0006
+#define ICH_FLASH_FADDR                       0x0008
+#define ICH_FLASH_FDATA0              0x0010
+#define ICH_FLASH_PR0                 0x0074
+/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
+/* Offset 04h HSFSTS */
+union ich8_hws_flash_status {
+        struct ich8_hsfsts {
+                uint16_t flcdone:1;  /* bit 0 Flash Cycle Done */
+                uint16_t flcerr:1;   /* bit 1 Flash Cycle Error */
+                uint16_t dael:1;     /* bit 2 Direct Access error Log */
+                uint16_t berasesz:2; /* bit 4:3 Sector Erase Size */
+                uint16_t flcinprog:1;        /* bit 5 flash cycle in Progress */
+                uint16_t reserved1:2;        /* bit 13:6 Reserved */
+                uint16_t reserved2:6;        /* bit 13:6 Reserved */
+                uint16_t fldesvalid:1;       /* bit 14 Flash Descriptor Valid */
+                uint16_t flockdn:1;  /* bit 15 Flash Config Lock-Down */
+        } hsf_status;
+        uint16_t regval;
+};
+
+/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
+/* Offset 06h FLCTL */
+union ich8_hws_flash_ctrl {
+        struct ich8_hsflctl {
+                uint16_t flcgo:1;    /* 0 Flash Cycle Go */
+                uint16_t flcycle:2;  /* 2:1 Flash Cycle */
+                uint16_t reserved:5; /* 7:3 Reserved  */
+                uint16_t fldbcount:2;        /* 9:8 Flash Data Byte Count */
+                uint16_t flockdn:6;  /* 15:10 Reserved */
+        } hsf_ctrl;
+        uint16_t regval;
+};
+
 #endif /* _E1000_HW_H_ */