qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Fw: [PATCH 2/2] Add Enhanced Three-Speed EthernetController


From: Yao Xingtao
Subject: [Qemu-devel] Fw: [PATCH 2/2] Add Enhanced Three-Speed EthernetController (eTSEC)
Date: Mon, 15 Jul 2013 09:25:11 +0800

>-------------------------------------------------------------
>发件人:Fabien Chouteau
>发送日期:2013-07-11 01:11:11
>收件人:qemu-devel
>抄送:qemu-ppc; agraf
>主题:[Qemu-devel] [PATCH 2/2] Add Enhanced Three-Speed EthernetController (eTSEC)
>
>This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
>
>Signed-off-by: Fabien Chouteau <address@hidden>
>---
> default-configs/ppc-softmmu.mak |    1 +
> hw/net/Makefile.objs            |    1 +
> hw/net/etsec.c                  |  472 +++++++++++++++++++++++++++
> hw/net/etsec.h                  |  169 ++++++++++
> hw/net/etsec_miim.c             |  146 +++++++++
> hw/net/etsec_registers.c        |  295 +++++++++++++++++
> hw/net/etsec_registers.h        |  302 ++++++++++++++++++
> hw/net/etsec_rings.c            |  673 +++++++++++++++++++++++++++++++++++++++
> 8 files changed, 2059 insertions(+)
> create mode 100644 hw/net/etsec.c
> create mode 100644 hw/net/etsec.h
> create mode 100644 hw/net/etsec_miim.c
> create mode 100644 hw/net/etsec_registers.c
> create mode 100644 hw/net/etsec_registers.h
> create mode 100644 hw/net/etsec_rings.c
>
>diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
>index 73e4cc5..c7541cf 100644
>--- a/default-configs/ppc-softmmu.mak
>+++ b/default-configs/ppc-softmmu.mak
>@@ -46,3 +46,4 @@ CONFIG_E500=y
> CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
> # For PReP
> CONFIG_MC146818RTC=y
>+CONFIG_ETSEC=y
>diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
>index 951cca3..ca03c3f 100644
>--- a/hw/net/Makefile.objs
>+++ b/hw/net/Makefile.objs
>@@ -28,6 +28,7 @@ obj-$(CONFIG_COLDFIRE) += mcf_fec.o
> obj-$(CONFIG_MILKYMIST) += milkymist-minimac2.o
> obj-$(CONFIG_PSERIES) += spapr_llan.o
> obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
>+obj-$(CONFIG_ETSEC) += etsec.o etsec_registers.o etsec_rings.o etsec_miim.o
> 
> obj-$(CONFIG_VIRTIO) += virtio-net.o
> obj-y += vhost_net.o
>diff --git a/hw/net/etsec.c b/hw/net/etsec.c
>new file mode 100644
>index 0000000..4516b01
>--- /dev/null
>+++ b/hw/net/etsec.c
>@@ -0,0 +1,472 @@
>+/*
>+ * QEMU Freescale eTSEC Emulator
>+ *
>+ * Copyright (c) 2011-2013 AdaCore
>+ *
>+ * Permission is hereby granted, free of charge, to any person obtaining a 
>copy
>+ * of this software and associated documentation files (the "Software"), to 
>deal
>+ * in the Software without restriction, including without limitation the 
>rights
>+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>+ * copies of the Software, and to permit persons to whom the Software is
>+ * furnished to do so, subject to the following conditions:
>+ *
>+ * The above copyright notice and this permission notice shall be included in
>+ * all copies or substantial portions of the Software.
>+ *
>+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
>FROM,
>+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>+ * THE SOFTWARE.
>+ */
>+
>+#include "sysemu/sysemu.h"
>+#include "hw/sysbus.h"
>+#include "trace.h"
>+#include "hw/ptimer.h"
>+#include "hw/net/etsec.h"
>+#include "hw/net/etsec_registers.h"
>+
>+/* #define HEX_DUMP */
>+/* #define DEBUG_REGISTER */
>+
>+static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
>+{
>+    eTSEC          *etsec     = opaque;
>+    uint32_t        reg_index = addr / 4;
>+    eTSEC_Register *reg       = NULL;
>+    uint32_t        ret       = 0x0;
>+
>+    assert(reg_index < REG_NUMBER);
>+
>+    reg = &etsec->regs[reg_index];
>+
>+
>+    switch (reg->access) {
>+    case ACC_WO:
>+        ret = 0x00000000;
>+        break;
>+
>+    case ACC_RW:
>+    case ACC_w1c:
>+    case ACC_RO:
>+    default:
>+        ret = reg->value;
>+        break;
>+    }
>+
>+#ifdef DEBUG_REGISTER
>+    printf("Read  0x%08x @ 0x" TARGET_FMT_plx
>+           "                            : %s (%s)\n",
>+           ret, addr, reg->name, reg->desc);
>+#endif
>+
>+    return ret;
>+}
>+
>+static void write_tstat(eTSEC          *etsec,
>+                        eTSEC_Register *reg,
>+                        uint32_t        reg_index,
>+                        uint32_t        value)
>+{
>+    int i = 0;
>+
>+    for (i = 0; i < 8; i++) {
>+        /* Check THLTi flag in TSTAT */
>+        if (value & (1 << (31 - i))) {
>+            walk_tx_ring(etsec, i);
>+        }
>+    }
>+
>+    /* Write 1 to clear */
>+    reg->value &= ~value;
>+}
>+
>+static void write_rstat(eTSEC          *etsec,
>+                        eTSEC_Register *reg,
>+                        uint32_t        reg_index,
>+                        uint32_t        value)
>+{
>+    int i = 0;
>+
>+    for (i = 0; i < 8; i++) {
>+        /* Check QHLTi flag in RSTAT */
>+        if (value & (1 << (23 - i)) && !(reg->value & (1 << (23 - i)))) {
>+            walk_rx_ring(etsec, i);
>+        }
>+    }
>+
>+    /* Write 1 to clear */
>+    reg->value &= ~value;
>+}
>+
>+static void write_tbasex(eTSEC          *etsec,
>+                         eTSEC_Register *reg,
>+                         uint32_t        reg_index,
>+                         uint32_t        value)
>+{
>+    reg->value = value & ~0x7;
>+
>+    /* Copy this value in the ring's TxBD pointer */
>+    etsec->regs[TBPTR0 + (reg_index - TBASE0)].value = value & ~0x7;
>+}
>+
>+static void write_rbasex(eTSEC          *etsec,
>+                         eTSEC_Register *reg,
>+                         uint32_t        reg_index,
>+                         uint32_t        value)
>+{
>+    reg->value = value & ~0x7;
>+
>+    /* Copy this value in the ring's RxBD pointer */
>+    etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
>+}
>+
>+static void write_ievent(eTSEC          *etsec,
>+                         eTSEC_Register *reg,
>+                         uint32_t        reg_index,
>+                         uint32_t        value)
>+{
>+    if (value & IEVENT_TXF) {
>+        qemu_irq_lower(etsec->tx_irq);
>+    }
>+    if (value & IEVENT_RXF) {
>+        qemu_irq_lower(etsec->rx_irq);
>+    }
>+
>+    /* Write 1 to clear */
>+    reg->value &= ~value;
>+}
>+
>+static void write_dmactrl(eTSEC          *etsec,
>+                          eTSEC_Register *reg,
>+                          uint32_t        reg_index,
>+                          uint32_t        value)
>+{
>+    reg->value = value;
>+
>+    if (value & DMACTRL_GRS) {
>+
>+        if (etsec->rx_buffer_len != 0) {
>+            /* Graceful receive stop delayed until end of frame */
>+        } else {
>+            /* Graceful receive stop now */
>+            etsec->regs[IEVENT].value |= IEVENT_GRSC;
>+            if (etsec->regs[IMASK].value & IMASK_GRSCEN) {
>+                qemu_irq_raise(etsec->err_irq);
>+            }
>+        }
>+    }
>+
>+    if (value & DMACTRL_GTS) {
>+
>+        if (etsec->tx_buffer_len != 0) {
>+            /* Graceful transmit stop delayed until end of frame */
>+        } else {
>+            /* Graceful transmit stop now */
>+            etsec->regs[IEVENT].value |= IEVENT_GTSC;
>+            if (etsec->regs[IMASK].value & IMASK_GTSCEN) {
>+                qemu_irq_raise(etsec->err_irq);
>+            }
>+        }
>+    }
>+
>+    if (!(value & DMACTRL_WOP)) {
>+        /* Start polling */
>+        ptimer_stop(etsec->ptimer);
>+        ptimer_set_count(etsec->ptimer, 1);
>+        ptimer_run(etsec->ptimer, 1);
>+    }
>+}
>+
>+static void etsec_write(void     *opaque,
>+                        hwaddr    addr,
>+                        uint64_t  value,
>+                        unsigned  size)
>+{
>+    eTSEC          *etsec     = opaque;
>+    uint32_t        reg_index = addr / 4;
>+    eTSEC_Register *reg       = NULL;
>+    uint32_t        before    = 0x0;
>+
>+    assert(reg_index < REG_NUMBER);
>+
>+    reg = &etsec->regs[reg_index];
>+    before = reg->value;
>+
>+    switch (reg_index) {
>+    case IEVENT:
>+        write_ievent(etsec, reg, reg_index, value);
>+        break;
>+
>+    case DMACTRL:
>+        write_dmactrl(etsec, reg, reg_index, value);
>+        break;
>+
>+    case TSTAT:
>+        write_tstat(etsec, reg, reg_index, value);
>+        break;
>+
>+    case RSTAT:
>+        write_rstat(etsec, reg, reg_index, value);
>+        break;
>+
>+    case TBASE0 ... TBASE7:
>+        write_tbasex(etsec, reg, reg_index, value);
>+        break;
>+
>+    case RBASE0 ... RBASE7:
>+        write_rbasex(etsec, reg, reg_index, value);
>+        break;
>+
>+    case MIIMCFG ... MIIMIND:
>+        write_miim(etsec, reg, reg_index, value);
>+        break;
>+
>+    default:
>+        /* Default handling */
>+        switch (reg->access) {
>+
>+        case ACC_RW:
>+        case ACC_WO:
>+            reg->value = value;
>+            break;
>+
>+        case ACC_w1c:
>+            reg->value &= ~value;
>+            break;
>+
>+        case ACC_RO:
>+        default:
>+            /* Read Only or Unknown register */
>+            break;
>+        }
>+    }
>+
>+#ifdef DEBUG_REGISTER
>+    printf("Write 0x%08x @ 0x" TARGET_FMT_plx" val:0x%08x->0x%08x : %s 
>(%s)\n",
>+           (unsigned int)value, addr, before, reg->value, reg->name, 
>reg->desc);
>+#else
>+    (void)before; /* Unreferenced */
>+#endif
>+
>+}
>+
>+static const MemoryRegionOps etsec_ops = {
>+    .read = etsec_read,
>+    .write = etsec_write,
>+    .endianness = DEVICE_NATIVE_ENDIAN,
>+    .impl = {
>+        .min_access_size = 4,
>+        .max_access_size = 4,
>+    },
>+};
>+
>+static void etsec_timer_hit(void *opaque)
>+{
>+    eTSEC *etsec = opaque;
>+
>+    ptimer_stop(etsec->ptimer);
>+
>+    if (!(etsec->regs[DMACTRL].value & DMACTRL_WOP)) {
>+
>+        if (!(etsec->regs[DMACTRL].value & DMACTRL_GTS)) {
>+            walk_tx_ring(etsec, 0);
>+        }
>+        ptimer_set_count(etsec->ptimer, 1);
>+        ptimer_run(etsec->ptimer, 1);
>+    }
>+}
>+
>+static void etsec_reset(DeviceState *d)
>+{
>+    eTSEC *etsec = container_of(d, eTSEC, busdev.qdev);
>+    int i = 0;
>+    int reg_index = 0;
>+
>+    /* Default value for all registers */
>+    for (i = 0; i < REG_NUMBER; i++) {
>+        etsec->regs[i].name   = "Reserved";
>+        etsec->regs[i].desc   = "";
>+        etsec->regs[i].access = ACC_UNKNOWN;
>+        etsec->regs[i].value  = 0x00000000;
>+    }
>+
>+    /* Set-up known registers */
>+    for (i = 0; eTSEC_registers_def[i].name != NULL; i++) {
>+
>+        reg_index = eTSEC_registers_def[i].offset / 4;
>+
>+        etsec->regs[reg_index].name   = eTSEC_registers_def[i].name;
>+        etsec->regs[reg_index].desc   = eTSEC_registers_def[i].desc;
>+        etsec->regs[reg_index].access = eTSEC_registers_def[i].access;
>+        etsec->regs[reg_index].value  = eTSEC_registers_def[i].reset;
>+    }
>+
>+    etsec->tx_buffer     = NULL;
>+    etsec->tx_buffer_len = 0;
>+    etsec->rx_buffer     = NULL;
>+    etsec->rx_buffer_len = 0;
>+
>+    etsec->phy_status =
>+        MII_SR_EXTENDED_CAPS    | MII_SR_LINK_STATUS   | MII_SR_AUTONEG_CAPS  
>|
>+        MII_SR_AUTONEG_COMPLETE | MII_SR_PREAMBLE_SUPPRESS |
>+        MII_SR_EXTENDED_STATUS  | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS 
>|
>+        MII_SR_10T_HD_CAPS      | MII_SR_10T_FD_CAPS   | MII_SR_100X_HD_CAPS  
>|
>+        MII_SR_100X_FD_CAPS     | MII_SR_100T4_CAPS;
>+}
>+
>+static void etsec_cleanup(NetClientState *nc)
>+{
>+    /* printf("eTSEC cleanup\n"); */
>+}
>+
>+static int etsec_can_receive(NetClientState *nc)
>+{
>+    /* Yes we always can\ */
>+    return 1;
>+}
>+
>+#ifdef HEX_DUMP
>+static void hex_dump(FILE *f, const uint8_t *buf, int size)
>+{
>+    int len, i, j, c;
>+
>+    for (i = 0; i < size; i += 16) {
>+        len = size - i;
>+        if (len > 16) {
>+            len = 16;
>+        }
>+        fprintf(f, "%08x ", i);
>+        for (j = 0; j < 16; j++) {
>+            if (j < len) {
>+                fprintf(f, " %02x", buf[i + j]);
>+            } else {
>+                fprintf(f, "   ");
>+            }
>+        }
>+        fprintf(f, " ");
>+        for (j = 0; j < len; j++) {
>+            c = buf[i + j];
>+            if (c < ' ' || c > '~') {
>+                c = '.';
>+            }
>+            fprintf(f, "%c", c);
>+        }
>+        fprintf(f, "\n");
>+    }
>+}
>+#endif
>+
>+static ssize_t etsec_receive(NetClientState *nc,
>+                             const uint8_t  *buf,
>+                             size_t          size)
>+{
>+    eTSEC *etsec = qemu_get_nic_opaque(nc);
>+
>+#if defined(HEX_DUMP)
>+    fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size);
>+    hex_dump(stderr, buf, size);
>+#endif
>+    rx_ring_write(etsec, buf, size);
>+    return size;
>+}
>+
>+
>+static void etsec_set_link_status(NetClientState *nc)
>+{
>+    eTSEC *etsec = qemu_get_nic_opaque(nc);
>+
>+    miim_link_status(etsec, nc);
>+}
>+
>+static NetClientInfo net_etsec_info = {
>+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
>+    .size = sizeof(NICState),
>+    .can_receive = etsec_can_receive,
>+    .receive = etsec_receive,
>+    .cleanup = etsec_cleanup,
>+    .link_status_changed = etsec_set_link_status,
>+};
>+
>+static int etsec_init(SysBusDevice *dev)
>+{
>+    eTSEC *etsec = FROM_SYSBUS(typeof(*etsec), dev);
>+
>+    memory_region_init_io(&etsec->io_area, OBJECT(etsec), &etsec_ops, etsec,
>+                          "eTSEC", 0x1000);
>+
>+    sysbus_init_mmio(dev, &etsec->io_area);
>+
>+    sysbus_init_irq(dev, &etsec->tx_irq);
>+    sysbus_init_irq(dev, &etsec->rx_irq);
>+    sysbus_init_irq(dev, &etsec->err_irq);
>+
>+    etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf,
>+                              "eTSEC", etsec->busdev.qdev.id, etsec);
>+    qemu_format_nic_info_str(qemu_get_queue(etsec->nic), 
>etsec->conf.macaddr.a);
>+
>+
>+    etsec->bh     = qemu_bh_new(etsec_timer_hit, etsec);
>+    etsec->ptimer = ptimer_init(etsec->bh);
>+    ptimer_set_freq(etsec->ptimer, 100);
>+
>+    return 0;
>+}
>+
>+static Property etsec_properties[] = {
>+    DEFINE_NIC_PROPERTIES(eTSEC, conf),
>+    DEFINE_PROP_END_OF_LIST(),
>+};
>+
>+static void etsec_class_init(ObjectClass *klass, void *data)
>+{
>+    DeviceClass *dc = DEVICE_CLASS(klass);
>+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
>+
>+    k->init = etsec_init;
>+    dc->reset = etsec_reset;
>+    dc->props = etsec_properties;
>+}
>+
>+static TypeInfo etsec_info = {
>+    .name          = "eTSEC",
>+    .parent        = TYPE_SYS_BUS_DEVICE,
>+    .instance_size = sizeof(eTSEC),
>+    .class_init    = etsec_class_init,
>+};
>+
>+static void etsec_register_types(void)
>+{
>+    type_register_static(&etsec_info);
>+}
>+
>+type_init(etsec_register_types)
>+
>+DeviceState *etsec_create(hwaddr         base,
>+                          MemoryRegion * mr,
>+                          NICInfo      * nd,
>+                          qemu_irq       tx_irq,
>+                          qemu_irq       rx_irq,
>+                          qemu_irq       err_irq)
>+{
>+    DeviceState *dev;
>+
>+    dev = qdev_create(NULL, "eTSEC");
>+    qdev_set_nic_properties(dev, nd);
>+
>+    if (qdev_init(dev)) {
>+        return NULL;
>+    }
>+
>+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq);
>+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq);
>+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, err_irq);
>+
>+    memory_region_add_subregion(mr, base,
>+                                SYS_BUS_DEVICE(dev)->mmio[0].memory);
>+
>+    return dev;
>+}
>diff --git a/hw/net/etsec.h b/hw/net/etsec.h
>new file mode 100644
>index 0000000..4fa9edc
>--- /dev/null
>+++ b/hw/net/etsec.h
>@@ -0,0 +1,169 @@
>+/*
>+ * QEMU Freescale eTSEC Emulator
>+ *
>+ * Copyright (c) 2011-2013 AdaCore
>+ *
>+ * Permission is hereby granted, free of charge, to any person obtaining a 
>copy
>+ * of this software and associated documentation files (the "Software"), to 
>deal
>+ * in the Software without restriction, including without limitation the 
>rights
>+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>+ * copies of the Software, and to permit persons to whom the Software is
>+ * furnished to do so, subject to the following conditions:
>+ *
>+ * The above copyright notice and this permission notice shall be included in
>+ * all copies or substantial portions of the Software.
>+ *
>+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
>FROM,
>+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>+ * THE SOFTWARE.
>+ */
>+#ifndef _ETSEC_H_
>+#define _ETSEC_H_
>+
>+#include "hw/qdev.h"
>+#include "hw/sysbus.h"
>+#include "net/net.h"
>+#include "hw/ptimer.h"
>+
>+/* Buffer Descriptors */
>+
>+typedef struct eTSEC_rxtx_bd {
>+    uint16_t flags;
>+    uint16_t length;
>+    uint32_t bufptr;
>+} eTSEC_rxtx_bd;
>+
>+#define BD_WRAP       (1 << 13)
>+#define BD_INTERRUPT  (1 << 12)
>+#define BD_LAST       (1 << 11)
>+
>+#define BD_TX_READY     (1 << 15)
>+#define BD_TX_PADCRC    (1 << 14)
>+#define BD_TX_TC        (1 << 10)
>+#define BD_TX_PREDEF    (1 << 9)
>+#define BD_TX_HFELC     (1 << 7)
>+#define BD_TX_CFRL      (1 << 6)
>+#define BD_TX_RC_MASK   0xF
>+#define BD_TX_RC_OFFSET 0x2
>+#define BD_TX_TOEUN     (1 << 1)
>+#define BD_TX_TR        (1 << 0)
>+
>+#define BD_RX_EMPTY     (1 << 15)
>+#define BD_RX_RO1       (1 << 14)
>+#define BD_RX_FIRST     (1 << 10)
>+#define BD_RX_MISS      (1 << 8)
>+#define BD_RX_BROADCAST (1 << 7)
>+#define BD_RX_MULTICAST (1 << 6)
>+#define BD_RX_LG        (1 << 5)
>+#define BD_RX_NO        (1 << 4)
>+#define BD_RX_SH        (1 << 3)
>+#define BD_RX_CR        (1 << 2)
>+#define BD_RX_OV        (1 << 1)
>+#define BD_RX_TR        (1 << 0)
>+
>+/* Tx FCB flags */
>+#define FCB_TX_VLN     (1 << 7)
>+#define FCB_TX_IP      (1 << 6)
>+#define FCB_TX_IP6     (1 << 5)
>+#define FCB_TX_TUP     (1 << 4)
>+#define FCB_TX_UDP     (1 << 3)
>+#define FCB_TX_CIP     (1 << 2)
>+#define FCB_TX_CTU     (1 << 1)
>+#define FCB_TX_NPH     (1 << 0)
>+
>+/* PHY Status Register */
>+#define MII_SR_EXTENDED_CAPS     0x0001    /* Extended register capabilities 
>*/
>+#define MII_SR_JABBER_DETECT     0x0002    /* Jabber Detected */
>+#define MII_SR_LINK_STATUS       0x0004    /* Link Status 1 = link */
>+#define MII_SR_AUTONEG_CAPS      0x0008    /* Auto Neg Capable */
>+#define MII_SR_REMOTE_FAULT      0x0010    /* Remote Fault Detect */
>+#define MII_SR_AUTONEG_COMPLETE  0x0020    /* Auto Neg Complete */
>+#define MII_SR_PREAMBLE_SUPPRESS 0x0040    /* Preamble may be suppressed */
>+#define MII_SR_EXTENDED_STATUS   0x0100    /* Ext. status info in Reg 0x0F */
>+#define MII_SR_100T2_HD_CAPS     0x0200    /* 100T2 Half Duplex Capable */
>+#define MII_SR_100T2_FD_CAPS     0x0400    /* 100T2 Full Duplex Capable */
>+#define MII_SR_10T_HD_CAPS       0x0800    /* 10T   Half Duplex Capable */
>+#define MII_SR_10T_FD_CAPS       0x1000    /* 10T   Full Duplex Capable */
>+#define MII_SR_100X_HD_CAPS      0x2000    /* 100X  Half Duplex Capable */
>+#define MII_SR_100X_FD_CAPS      0x4000    /* 100X  Full Duplex Capable */
>+#define MII_SR_100T4_CAPS        0x8000    /* 100T4 Capable */
>+
>+/* eTSEC */
>+
>+#define REG_NUMBER 1024
>+
>+typedef struct eTSEC_Register {
>+    const char *name;
>+    const char *desc;
>+    uint32_t    access;
>+    uint32_t    value;
>+} eTSEC_Register;
>+
>+typedef struct eTSEC {
>+    SysBusDevice  busdev;
>+
>+    MemoryRegion  io_area;
>+
>+    eTSEC_Register regs[REG_NUMBER];
>+
>+    NICState *nic;
>+    NICConf   conf;
>+
>+    /* Tx */
>+
>+    uint8_t       *tx_buffer;
>+    uint32_t       tx_buffer_len;
>+    eTSEC_rxtx_bd  first_bd;
>+
>+    /* Rx */
>+
>+    uint8_t       *rx_buffer;
>+    uint32_t       rx_buffer_len;
>+    uint32_t       rx_remaining_data;
>+    uint8_t        rx_first_in_frame;
>+    uint8_t        rx_fcb_size;
>+    eTSEC_rxtx_bd  rx_first_bd;
>+    uint8_t        rx_fcb[10];
>+    uint32_t       rx_padding;
>+
>+    /* IRQs */
>+    qemu_irq     tx_irq;
>+    qemu_irq     rx_irq;
>+    qemu_irq     err_irq;
>+
>+
>+    uint16_t phy_status;
>+    uint16_t phy_control;
>+
>+    /* Polling */
>+    QEMUBH *bh;
>+    struct ptimer_state *ptimer;
>+
>+} eTSEC;
>+
>+#define eTSEC_TRANSMIT 1
>+#define eTSEC_RECEIVE  2
>+
>+DeviceState *etsec_create(hwaddr        base,
>+                          MemoryRegion *mr,
>+                          NICInfo      *nd,
>+                          qemu_irq      tx_irq,
>+                          qemu_irq      rx_irq,
>+                          qemu_irq      err_irq);
>+
>+void walk_tx_ring(eTSEC *etsec, int ring_nbr);
>+void walk_rx_ring(eTSEC *etsec, int ring_nbr);
>+void rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size);
>+
>+void write_miim(eTSEC          *etsec,
>+                eTSEC_Register *reg,
>+                uint32_t        reg_index,
>+                uint32_t        value);
>+
>+void miim_link_status(eTSEC *etsec, NetClientState *nc);
>+
>+#endif /* ! _ETSEC_H_ */
>diff --git a/hw/net/etsec_miim.c b/hw/net/etsec_miim.c
>new file mode 100644
>index 0000000..2bd9f0d
>--- /dev/null
>+++ b/hw/net/etsec_miim.c
>@@ -0,0 +1,146 @@
>+/*
>+ * QEMU Freescale eTSEC Emulator
>+ *
>+ * Copyright (c) 2011-2013 AdaCore
>+ *
>+ * Permission is hereby granted, free of charge, to any person obtaining a 
>copy
>+ * of this software and associated documentation files (the "Software"), to 
>deal
>+ * in the Software without restriction, including without limitation the 
>rights
>+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>+ * copies of the Software, and to permit persons to whom the Software is
>+ * furnished to do so, subject to the following conditions:
>+ *
>+ * The above copyright notice and this permission notice shall be included in
>+ * all copies or substantial portions of the Software.
>+ *
>+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
>FROM,
>+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>+ * THE SOFTWARE.
>+ */
>+
>+#include "etsec.h"
>+#include "etsec_registers.h"
>+
>+/* #define DEBUG_MIIM */
>+
>+#define MIIM_CONTROL    0
>+#define MIIM_STATUS     1
>+#define MIIM_PHY_ID_1   2
>+#define MIIM_PHY_ID_2   3
>+#define MIIM_T2_STATUS  10
>+#define MIIM_EXT_STATUS 15
>+
>+static void miim_read_cycle(eTSEC *etsec)
>+{
>+    uint8_t  phy;
>+    uint8_t  addr;
>+    uint16_t value;
>+
>+    phy  = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
>+    (void)phy; /* Unreferenced */
>+    addr = etsec->regs[MIIMADD].value & 0x1F;
>+
>+    switch (addr) {
>+    case MIIM_CONTROL:
>+        value = etsec->phy_control;
>+        break;
>+    case MIIM_STATUS:
>+        value = etsec->phy_status;
>+        break;
>+    case MIIM_T2_STATUS:
>+        value = 0x1800;           /* Local and remote receivers OK */
>+        break;
>+    default:
>+        value = 0x0;
>+        break;
>+    };
>+
>+#ifdef DEBUG_MIIM
>+    printf("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
>+#endif
>+
>+    etsec->regs[MIIMSTAT].value = value;
>+}
>+
>+static void miim_write_cycle(eTSEC *etsec)
>+{
>+    uint8_t  phy;
>+    uint8_t  addr;
>+    uint16_t value;
>+
>+    phy   = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
>+    (void)phy; /* Unreferenced */
>+    addr  = etsec->regs[MIIMADD].value & 0x1F;
>+    value = etsec->regs[MIIMCON].value & 0xffff;
>+
>+#ifdef DEBUG_MIIM
>+    printf("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
>+#endif
>+
>+    switch (addr) {
>+    case MIIM_CONTROL:
>+        etsec->phy_control = value & ~(0x8100);
>+        break;
>+    default:
>+        break;
>+    };
>+}
>+
>+void write_miim(eTSEC          *etsec,
>+               eTSEC_Register *reg,
>+               uint32_t        reg_index,
>+               uint32_t        value)
>+{
>+
>+    switch (reg_index) {
>+
>+    case MIIMCOM:
>+        /* Read and scan cycle */
>+
>+        if ((!(reg->value & MIIMCOM_READ)) && (value & MIIMCOM_READ)) {
>+            /* Read */
>+            miim_read_cycle(etsec);
>+        }
>+        reg->value = value;
>+        break;
>+
>+    case MIIMCON:
>+        reg->value = value & 0xffff;
>+        miim_write_cycle(etsec);
>+        break;
>+
>+    default:
>+        /* Default handling */
>+        switch (reg->access) {
>+
>+        case ACC_RW:
>+        case ACC_WO:
>+            reg->value = value;
>+            break;
>+
>+        case ACC_w1c:
>+            reg->value &= ~value;
>+            break;
>+
>+        case ACC_RO:
>+        default:
>+            /* Read Only or Unknown register */
>+            break;
>+        }
>+    }
>+
>+}
>+
>+void miim_link_status(eTSEC *etsec, NetClientState *nc)
>+{
>+    /* Set link status */
>+    if (nc->link_down) {
>+        etsec->phy_status &= ~MII_SR_LINK_STATUS;
>+    } else {
>+        etsec->phy_status |= MII_SR_LINK_STATUS;
>+    }
>+}
>diff --git a/hw/net/etsec_registers.c b/hw/net/etsec_registers.c
>new file mode 100644
>index 0000000..719a886
>--- /dev/null
>+++ b/hw/net/etsec_registers.c
>@@ -0,0 +1,295 @@
>+/*
>+ * QEMU Freescale eTSEC Emulator
>+ *
>+ * Copyright (c) 2011-2013 AdaCore
>+ *
>+ * Permission is hereby granted, free of charge, to any person obtaining a 
>copy
>+ * of this software and associated documentation files (the "Software"), to 
>deal
>+ * in the Software without restriction, including without limitation the 
>rights
>+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>+ * copies of the Software, and to permit persons to whom the Software is
>+ * furnished to do so, subject to the following conditions:
>+ *
>+ * The above copyright notice and this permission notice shall be included in
>+ * all copies or substantial portions of the Software.
>+ *
>+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
>FROM,
>+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>+ * THE SOFTWARE.
>+ */
>+#include "etsec_registers.h"
>+
>+const eTSEC_Register_Definition eTSEC_registers_def[] = {
>+{0x000, "TSEC_ID",  "Controller ID register",    ACC_RO,  0x01240000},
>+{0x004, "TSEC_ID2", "Controller ID register 2",  ACC_RO,  0x003000F0},
>+{0x010, "IEVENT",   "Interrupt event register",  ACC_w1c, 0x00000000},
>+{0x014, "IMASK",    "Interrupt mask register",   ACC_RW,  0x00000000},
>+{0x018, "EDIS",     "Error disabled register",   ACC_RW,  0x00000000},
>+{0x020, "ECNTRL",   "Ethernet control register", ACC_RW,  0x00000040},
>+{0x028, "PTV",      "Pause time value register", ACC_RW,  0x00000000},
>+{0x02C, "DMACTRL",  "DMA control register",      ACC_RW,  0x00000000},
>+{0x030, "TBIPA",    "TBI PHY address register",  ACC_RW,  0x00000000},
>+
>+/* eTSEC FIFO Control and Status Registers */
>+
>+{0x058, "FIFO_RX_ALARM",          "FIFO receive alarm start threshold 
>register",    ACC_RW, 0x00000040},
>+{0x05C, "FIFO_RX_ALARM_SHUTOFF",  "FIFO receive alarm shut-off threshold 
>register", ACC_RW, 0x00000080},
>+{0x08C, "FIFO_TX_THR",            "FIFO transmit threshold register",         
>      ACC_RW, 0x00000080},
>+{0x098, "FIFO_TX_STARVE",         "FIFO transmit starve register",            
>      ACC_RW, 0x00000040},
>+{0x09C, "FIFO_TX_STARVE_SHUTOFF", "FIFO transmit starve shut-off register",   
>      ACC_RW, 0x00000080},
>+
>+/* eTSEC Transmit Control and Status Registers */
>+
>+{0x100, "TCTRL",        "Transmit control register",                ACC_RW,  
>0x00000000},
>+{0x104, "TSTAT",        "Transmit status register",                 ACC_w1c, 
>0x00000000},
>+{0x108, "DFVLAN",       "Default VLAN control word",                ACC_RW,  
>0x81000000},
>+{0x110, "TXIC",         "Transmit interrupt coalescing register",   ACC_RW,  
>0x00000000},
>+{0x114, "TQUEUE",       "Transmit queue control register",          ACC_RW,  
>0x00008000},
>+{0x140, "TR03WT",       "TxBD Rings 0-3 round-robin weightings",    ACC_RW,  
>0x00000000},
>+{0x144, "TR47WT",       "TxBD Rings 4-7 round-robin weightings",    ACC_RW,  
>0x00000000},
>+{0x180, "TBDBPH",       "Tx data buffer pointer high bits",         ACC_RW,  
>0x00000000},
>+{0x184, "TBPTR0",       "TxBD pointer for ring 0",                  ACC_RW,  
>0x00000000},
>+{0x18C, "TBPTR1",       "TxBD pointer for ring 1",                  ACC_RW,  
>0x00000000},
>+{0x194, "TBPTR2",       "TxBD pointer for ring 2",                  ACC_RW,  
>0x00000000},
>+{0x19C, "TBPTR3",       "TxBD pointer for ring 3",                  ACC_RW,  
>0x00000000},
>+{0x1A4, "TBPTR4",       "TxBD pointer for ring 4",                  ACC_RW,  
>0x00000000},
>+{0x1AC, "TBPTR5",       "TxBD pointer for ring 5",                  ACC_RW,  
>0x00000000},
>+{0x1B4, "TBPTR6",       "TxBD pointer for ring 6",                  ACC_RW,  
>0x00000000},
>+{0x1BC, "TBPTR7",       "TxBD pointer for ring 7",                  ACC_RW,  
>0x00000000},
>+{0x200, "TBASEH",       "TxBD base address high bits",              ACC_RW,  
>0x00000000},
>+{0x204, "TBASE0",       "TxBD base address of ring 0",              ACC_RW,  
>0x00000000},
>+{0x20C, "TBASE1",       "TxBD base address of ring 1",              ACC_RW,  
>0x00000000},
>+{0x214, "TBASE2",       "TxBD base address of ring 2",              ACC_RW,  
>0x00000000},
>+{0x21C, "TBASE3",       "TxBD base address of ring 3",              ACC_RW,  
>0x00000000},
>+{0x224, "TBASE4",       "TxBD base address of ring 4",              ACC_RW,  
>0x00000000},
>+{0x22C, "TBASE5",       "TxBD base address of ring 5",              ACC_RW,  
>0x00000000},
>+{0x234, "TBASE6",       "TxBD base address of ring 6",              ACC_RW,  
>0x00000000},
>+{0x23C, "TBASE7",       "TxBD base address of ring 7",              ACC_RW,  
>0x00000000},
>+{0x280, "TMR_TXTS1_ID", "Tx time stamp identification tag (set 1)", ACC_RO,  
>0x00000000},
>+{0x284, "TMR_TXTS2_ID", "Tx time stamp identification tag (set 2)", ACC_RO,  
>0x00000000},
>+{0x2C0, "TMR_TXTS1_H",  "Tx time stamp high (set 1)",               ACC_RO,  
>0x00000000},
>+{0x2C4, "TMR_TXTS1_L",  "Tx time stamp high (set 1)",               ACC_RO,  
>0x00000000},
>+{0x2C8, "TMR_TXTS2_H",  "Tx time stamp high (set 2)",               ACC_RO,  
>0x00000000},
>+{0x2CC, "TMR_TXTS2_L",  "Tx time stamp high (set 2)",               ACC_RO,  
>0x00000000},
>+
>+/* eTSEC Receive Control and Status Registers */
>+
>+{0x300, "RCTRL",      "Receive control register",                     ACC_RW, 
> 0x00000000},
>+{0x304, "RSTAT",      "Receive status register",                      
>ACC_w1c, 0x00000000},
>+{0x310, "RXIC",       "Receive interrupt coalescing register",        ACC_RW, 
> 0x00000000},
>+{0x314, "RQUEUE",     "Receive queue control register.",              ACC_RW, 
> 0x00800080},
>+{0x330, "RBIFX",      "Receive bit field extract control register",   ACC_RW, 
> 0x00000000},
>+{0x334, "RQFAR",      "Receive queue filing table address register",  ACC_RW, 
> 0x00000000},
>+{0x338, "RQFCR",      "Receive queue filing table control register",  ACC_RW, 
> 0x00000000},
>+{0x33C, "RQFPR",      "Receive queue filing table property register", ACC_RW, 
> 0x00000000},
>+{0x340, "MRBLR",      "Maximum receive buffer length register",       ACC_RW, 
> 0x00000000},
>+{0x380, "RBDBPH",     "Rx data buffer pointer high bits",             ACC_RW, 
> 0x00000000},
>+{0x384, "RBPTR0",     "RxBD pointer for ring 0",                      ACC_RW, 
> 0x00000000},
>+{0x38C, "RBPTR1",     "RxBD pointer for ring 1",                      ACC_RW, 
> 0x00000000},
>+{0x394, "RBPTR2",     "RxBD pointer for ring 2",                      ACC_RW, 
> 0x00000000},
>+{0x39C, "RBPTR3",     "RxBD pointer for ring 3",                      ACC_RW, 
> 0x00000000},
>+{0x3A4, "RBPTR4",     "RxBD pointer for ring 4",                      ACC_RW, 
> 0x00000000},
>+{0x3AC, "RBPTR5",     "RxBD pointer for ring 5",                      ACC_RW, 
> 0x00000000},
>+{0x3B4, "RBPTR6",     "RxBD pointer for ring 6",                      ACC_RW, 
> 0x00000000},
>+{0x3BC, "RBPTR7",     "RxBD pointer for ring 7",                      ACC_RW, 
> 0x00000000},
>+{0x400, "RBASEH",     "RxBD base address high bits",                  ACC_RW, 
> 0x00000000},
>+{0x404, "RBASE0",     "RxBD base address of ring 0",                  ACC_RW, 
> 0x00000000},
>+{0x40C, "RBASE1",     "RxBD base address of ring 1",                  ACC_RW, 
> 0x00000000},
>+{0x414, "RBASE2",     "RxBD base address of ring 2",                  ACC_RW, 
> 0x00000000},
>+{0x41C, "RBASE3",     "RxBD base address of ring 3",                  ACC_RW, 
> 0x00000000},
>+{0x424, "RBASE4",     "RxBD base address of ring 4",                  ACC_RW, 
> 0x00000000},
>+{0x42C, "RBASE5",     "RxBD base address of ring 5",                  ACC_RW, 
> 0x00000000},
>+{0x434, "RBASE6",     "RxBD base address of ring 6",                  ACC_RW, 
> 0x00000000},
>+{0x43C, "RBASE7",     "RxBD base address of ring 7",                  ACC_RW, 
> 0x00000000},
>+{0x4C0, "TMR_RXTS_H", "Rx timer time stamp register high",            ACC_RW, 
> 0x00000000},
>+{0x4C4, "TMR_RXTS_L", "Rx timer time stamp register low",             ACC_RW, 
> 0x00000000},
>+
>+/* eTSEC MAC Registers */
>+
>+{0x500, "MACCFG1",     "MAC configuration register 1",          ACC_RW, 
>0x00000000},
>+{0x504, "MACCFG2",     "MAC configuration register 2",          ACC_RW, 
>0x00007000},
>+{0x508, "IPGIFG",      "Inter-packet/inter-frame gap register", ACC_RW, 
>0x40605060},
>+{0x50C, "HAFDUP",      "Half-duplex control",                   ACC_RW, 
>0x00A1F037},
>+{0x510, "MAXFRM",      "Maximum frame length",                  ACC_RW, 
>0x00000600},
>+{0x520, "MIIMCFG",     "MII management configuration",          ACC_RW, 
>0x00000007},
>+{0x524, "MIIMCOM",     "MII management command",                ACC_RW, 
>0x00000000},
>+{0x528, "MIIMADD",     "MII management address",                ACC_RW, 
>0x00000000},
>+{0x52C, "MIIMCON",     "MII management control",                ACC_WO, 
>0x00000000},
>+{0x530, "MIIMSTAT",    "MII management status",                 ACC_RO, 
>0x00000000},
>+{0x534, "MIIMIND",     "MII management indicator",              ACC_RO, 
>0x00000000},
>+{0x53C, "IFSTAT",      "Interface status",                      ACC_RO, 
>0x00000000},
>+{0x540, "MACSTNADDR1", "MAC station address register 1",        ACC_RW, 
>0x00000000},
>+{0x544, "MACSTNADDR2", "MAC station address register 2",        ACC_RW, 
>0x00000000},
>+{0x548, "MAC01ADDR1",  "MAC exact match address 1, part 1",     ACC_RW, 
>0x00000000},
>+{0x54C, "MAC01ADDR2",  "MAC exact match address 1, part 2",     ACC_RW, 
>0x00000000},
>+{0x550, "MAC02ADDR1",  "MAC exact match address 2, part 1",     ACC_RW, 
>0x00000000},
>+{0x554, "MAC02ADDR2",  "MAC exact match address 2, part 2",     ACC_RW, 
>0x00000000},
>+{0x558, "MAC03ADDR1",  "MAC exact match address 3, part 1",     ACC_RW, 
>0x00000000},
>+{0x55C, "MAC03ADDR2",  "MAC exact match address 3, part 2",     ACC_RW, 
>0x00000000},
>+{0x560, "MAC04ADDR1",  "MAC exact match address 4, part 1",     ACC_RW, 
>0x00000000},
>+{0x564, "MAC04ADDR2",  "MAC exact match address 4, part 2",     ACC_RW, 
>0x00000000},
>+{0x568, "MAC05ADDR1",  "MAC exact match address 5, part 1",     ACC_RW, 
>0x00000000},
>+{0x56C, "MAC05ADDR2",  "MAC exact match address 5, part 2",     ACC_RW, 
>0x00000000},
>+{0x570, "MAC06ADDR1",  "MAC exact match address 6, part 1",     ACC_RW, 
>0x00000000},
>+{0x574, "MAC06ADDR2",  "MAC exact match address 6, part 2",     ACC_RW, 
>0x00000000},
>+{0x578, "MAC07ADDR1",  "MAC exact match address 7, part 1",     ACC_RW, 
>0x00000000},
>+{0x57C, "MAC07ADDR2",  "MAC exact match address 7, part 2",     ACC_RW, 
>0x00000000},
>+{0x580, "MAC08ADDR1",  "MAC exact match address 8, part 1",     ACC_RW, 
>0x00000000},
>+{0x584, "MAC08ADDR2",  "MAC exact match address 8, part 2",     ACC_RW, 
>0x00000000},
>+{0x588, "MAC09ADDR1",  "MAC exact match address 9, part 1",     ACC_RW, 
>0x00000000},
>+{0x58C, "MAC09ADDR2",  "MAC exact match address 9, part 2",     ACC_RW, 
>0x00000000},
>+{0x590, "MAC10ADDR1",  "MAC exact match address 10, part 1",    ACC_RW, 
>0x00000000},
>+{0x594, "MAC10ADDR2",  "MAC exact match address 10, part 2",    ACC_RW, 
>0x00000000},
>+{0x598, "MAC11ADDR1",  "MAC exact match address 11, part 1",    ACC_RW, 
>0x00000000},
>+{0x59C, "MAC11ADDR2",  "MAC exact match address 11, part 2",    ACC_RW, 
>0x00000000},
>+{0x5A0, "MAC12ADDR1",  "MAC exact match address 12, part 1",    ACC_RW, 
>0x00000000},
>+{0x5A4, "MAC12ADDR2",  "MAC exact match address 12, part 2",    ACC_RW, 
>0x00000000},
>+{0x5A8, "MAC13ADDR1",  "MAC exact match address 13, part 1",    ACC_RW, 
>0x00000000},
>+{0x5AC, "MAC13ADDR2",  "MAC exact match address 13, part 2",    ACC_RW, 
>0x00000000},
>+{0x5B0, "MAC14ADDR1",  "MAC exact match address 14, part 1",    ACC_RW, 
>0x00000000},
>+{0x5B4, "MAC14ADDR2",  "MAC exact match address 14, part 2",    ACC_RW, 
>0x00000000},
>+{0x5B8, "MAC15ADDR1",  "MAC exact match address 15, part 1",    ACC_RW, 
>0x00000000},
>+{0x5BC, "MAC15ADDR2",  "MAC exact match address 15, part 2",    ACC_RW, 
>0x00000000},
>+
>+/* eTSEC, "Transmit", "and", Receive, Counters */
>+
>+{0x680, "TR64",  "Transmit and receive 64-byte frame counter ",               
>    ACC_RW, 0x00000000},
>+{0x684, "TR127", "Transmit and receive 65- to 127-byte frame counter",        
>    ACC_RW, 0x00000000},
>+{0x688, "TR255", "Transmit and receive 128- to 255-byte frame counter",       
>    ACC_RW, 0x00000000},
>+{0x68C, "TR511", "Transmit and receive 256- to 511-byte frame counter",       
>    ACC_RW, 0x00000000},
>+{0x690, "TR1K",  "Transmit and receive 512- to 1023-byte frame counter",      
>    ACC_RW, 0x00000000},
>+{0x694, "TRMAX", "Transmit and receive 1024- to 1518-byte frame counter",     
>    ACC_RW, 0x00000000},
>+{0x698, "TRMGV", "Transmit and receive 1519- to 1522-byte good VLAN frame 
>count", ACC_RW, 0x00000000},
>+
>+/* eTSEC Receive Counters */
>+
>+{0x69C, "RBYT", "Receive byte counter",                  ACC_RW, 0x00000000},
>+{0x6A0, "RPKT", "Receive packet counter",                ACC_RW, 0x00000000},
>+{0x6A4, "RFCS", "Receive FCS error counter",             ACC_RW, 0x00000000},
>+{0x6A8, "RMCA", "Receive multicast packet counter",      ACC_RW, 0x00000000},
>+{0x6AC, "RBCA", "Receive broadcast packet counter",      ACC_RW, 0x00000000},
>+{0x6B0, "RXCF", "Receive control frame packet counter ", ACC_RW, 0x00000000},
>+{0x6B4, "RXPF", "Receive PAUSE frame packet counter",    ACC_RW, 0x00000000},
>+{0x6B8, "RXUO", "Receive unknown OP code counter ",      ACC_RW, 0x00000000},
>+{0x6BC, "RALN", "Receive alignment error counter ",      ACC_RW, 0x00000000},
>+{0x6C0, "RFLR", "Receive frame length error counter ",   ACC_RW, 0x00000000},
>+{0x6C4, "RCDE", "Receive code error counter ",           ACC_RW, 0x00000000},
>+{0x6C8, "RCSE", "Receive carrier sense error counter",   ACC_RW, 0x00000000},
>+{0x6CC, "RUND", "Receive undersize packet counter",      ACC_RW, 0x00000000},
>+{0x6D0, "ROVR", "Receive oversize packet counter ",      ACC_RW, 0x00000000},
>+{0x6D4, "RFRG", "Receive fragments counter",             ACC_RW, 0x00000000},
>+{0x6D8, "RJBR", "Receive jabber counter ",               ACC_RW, 0x00000000},
>+{0x6DC, "RDRP", "Receive drop counter",                  ACC_RW, 0x00000000},
>+
>+/* eTSEC Transmit Counters */
>+
>+{0x6E0, "TBYT", "Transmit byte counter",                       ACC_RW, 
>0x00000000},
>+{0x6E4, "TPKT", "Transmit packet counter",                     ACC_RW, 
>0x00000000},
>+{0x6E8, "TMCA", "Transmit multicast packet counter ",          ACC_RW, 
>0x00000000},
>+{0x6EC, "TBCA", "Transmit broadcast packet counter ",          ACC_RW, 
>0x00000000},
>+{0x6F0, "TXPF", "Transmit PAUSE control frame counter ",       ACC_RW, 
>0x00000000},
>+{0x6F4, "TDFR", "Transmit deferral packet counter ",           ACC_RW, 
>0x00000000},
>+{0x6F8, "TEDF", "Transmit excessive deferral packet counter ", ACC_RW, 
>0x00000000},
>+{0x6FC, "TSCL", "Transmit single collision packet counter",    ACC_RW, 
>0x00000000},
>+{0x700, "TMCL", "Transmit multiple collision packet counter",  ACC_RW, 
>0x00000000},
>+{0x704, "TLCL", "Transmit late collision packet counter",      ACC_RW, 
>0x00000000},
>+{0x708, "TXCL", "Transmit excessive collision packet counter", ACC_RW, 
>0x00000000},
>+{0x70C, "TNCL", "Transmit total collision counter ",           ACC_RW, 
>0x00000000},
>+{0x714, "TDRP", "Transmit drop frame counter",                 ACC_RW, 
>0x00000000},
>+{0x718, "TJBR", "Transmit jabber frame counter ",              ACC_RW, 
>0x00000000},
>+{0x71C, "TFCS", "Transmit FCS error counter",                  ACC_RW, 
>0x00000000},
>+{0x720, "TXCF", "Transmit control frame counter ",             ACC_RW, 
>0x00000000},
>+{0x724, "TOVR", "Transmit oversize frame counter",             ACC_RW, 
>0x00000000},
>+{0x728, "TUND", "Transmit undersize frame counter ",           ACC_RW, 
>0x00000000},
>+{0x72C, "TFRG", "Transmit fragments frame counter ",           ACC_RW, 
>0x00000000},
>+
>+/* eTSEC Counter Control and TOE Statistics Registers */
>+
>+{0x730, "CAR1", "Carry register one register",           ACC_w1c, 0x00000000},
>+{0x734, "CAR2", "Carry register two register ",          ACC_w1c, 0x00000000},
>+{0x738, "CAM1", "Carry register one mask register ",     ACC_RW,  0xFE03FFFF},
>+{0x73C, "CAM2", "Carry register two mask register ",     ACC_RW,  0x000FFFFD},
>+{0x740, "RREJ", "Receive filer rejected packet counter", ACC_RW,  0x00000000},
>+
>+/* Hash Function Registers */
>+
>+{0x800, "IGADDR0", "Individual/group address register 0", ACC_RW, 0x00000000},
>+{0x804, "IGADDR1", "Individual/group address register 1", ACC_RW, 0x00000000},
>+{0x808, "IGADDR2", "Individual/group address register 2", ACC_RW, 0x00000000},
>+{0x80C, "IGADDR3", "Individual/group address register 3", ACC_RW, 0x00000000},
>+{0x810, "IGADDR4", "Individual/group address register 4", ACC_RW, 0x00000000},
>+{0x814, "IGADDR5", "Individual/group address register 5", ACC_RW, 0x00000000},
>+{0x818, "IGADDR6", "Individual/group address register 6", ACC_RW, 0x00000000},
>+{0x81C, "IGADDR7", "Individual/group address register 7", ACC_RW, 0x00000000},
>+{0x880, "GADDR0",  "Group address register 0",            ACC_RW, 0x00000000},
>+{0x884, "GADDR1",  "Group address register 1",            ACC_RW, 0x00000000},
>+{0x888, "GADDR2",  "Group address register 2",            ACC_RW, 0x00000000},
>+{0x88C, "GADDR3",  "Group address register 3",            ACC_RW, 0x00000000},
>+{0x890, "GADDR4",  "Group address register 4",            ACC_RW, 0x00000000},
>+{0x894, "GADDR5",  "Group address register 5",            ACC_RW, 0x00000000},
>+{0x898, "GADDR6",  "Group address register 6",            ACC_RW, 0x00000000},
>+{0x89C, "GADDR7",  "Group address register 7",            ACC_RW, 0x00000000},
>+
>+/* eTSEC DMA Attribute Registers */
>+
>+{0xBF8, "ATTR",    "Attribute register",                                  
>ACC_RW, 0x00000000},
>+{0xBFC, "ATTRELI", "Attribute extract length and extract index register", 
>ACC_RW, 0x00000000},
>+
>+
>+/* eTSEC Lossless Flow Control Registers */
>+
>+{0xC00, "RQPRM0",  "Receive Queue Parameters register 0 ", ACC_RW, 
>0x00000000},
>+{0xC04, "RQPRM1",  "Receive Queue Parameters register 1 ", ACC_RW, 
>0x00000000},
>+{0xC08, "RQPRM2",  "Receive Queue Parameters register 2 ", ACC_RW, 
>0x00000000},
>+{0xC0C, "RQPRM3",  "Receive Queue Parameters register 3 ", ACC_RW, 
>0x00000000},
>+{0xC10, "RQPRM4",  "Receive Queue Parameters register 4 ", ACC_RW, 
>0x00000000},
>+{0xC14, "RQPRM5",  "Receive Queue Parameters register 5 ", ACC_RW, 
>0x00000000},
>+{0xC18, "RQPRM6",  "Receive Queue Parameters register 6 ", ACC_RW, 
>0x00000000},
>+{0xC1C, "RQPRM7",  "Receive Queue Parameters register 7 ", ACC_RW, 
>0x00000000},
>+{0xC44, "RFBPTR0", "Last Free RxBD pointer for ring 0",    ACC_RW, 
>0x00000000},
>+{0xC4C, "RFBPTR1", "Last Free RxBD pointer for ring 1",    ACC_RW, 
>0x00000000},
>+{0xC54, "RFBPTR2", "Last Free RxBD pointer for ring 2",    ACC_RW, 
>0x00000000},
>+{0xC5C, "RFBPTR3", "Last Free RxBD pointer for ring 3",    ACC_RW, 
>0x00000000},
>+{0xC64, "RFBPTR4", "Last Free RxBD pointer for ring 4",    ACC_RW, 
>0x00000000},
>+{0xC6C, "RFBPTR5", "Last Free RxBD pointer for ring 5",    ACC_RW, 
>0x00000000},
>+{0xC74, "RFBPTR6", "Last Free RxBD pointer for ring 6",    ACC_RW, 
>0x00000000},
>+{0xC7C, "RFBPTR7", "Last Free RxBD pointer for ring 7",    ACC_RW, 
>0x00000000},
>+
>+/* eTSEC Future Expansion Space */
>+
>+/* Reserved*/
>+
>+/* eTSEC IEEE 1588 Registers */
>+
>+{0xE00, "TMR_CTRL",     "Timer control register",                          
>ACC_RW,  0x00010001},
>+{0xE04, "TMR_TEVENT",   "time stamp event register",                       
>ACC_w1c, 0x00000000},
>+{0xE08, "TMR_TEMASK",   "Timer event mask register",                       
>ACC_RW,  0x00000000},
>+{0xE0C, "TMR_PEVENT",   "time stamp event register",                       
>ACC_RW,  0x00000000},
>+{0xE10, "TMR_PEMASK",   "Timer event mask register",                       
>ACC_RW,  0x00000000},
>+{0xE14, "TMR_STAT",     "time stamp status register",                      
>ACC_RW,  0x00000000},
>+{0xE18, "TMR_CNT_H",    "timer counter high register",                     
>ACC_RW,  0x00000000},
>+{0xE1C, "TMR_CNT_L",    "timer counter low register",                      
>ACC_RW,  0x00000000},
>+{0xE20, "TMR_ADD",      "Timer drift compensation addend register",        
>ACC_RW,  0x00000000},
>+{0xE24, "TMR_ACC",      "Timer accumulator register",                      
>ACC_RW,  0x00000000},
>+{0xE28, "TMR_PRSC",     "Timer prescale",                                  
>ACC_RW,  0x00000002},
>+{0xE30, "TMROFF_H",     "Timer offset high",                               
>ACC_RW,  0x00000000},
>+{0xE34, "TMROFF_L",     "Timer offset low",                                
>ACC_RW,  0x00000000},
>+{0xE40, "TMR_ALARM1_H", "Timer alarm 1 high register",                     
>ACC_RW,  0xFFFFFFFF},
>+{0xE44, "TMR_ALARM1_L", "Timer alarm 1 high register",                     
>ACC_RW,  0xFFFFFFFF},
>+{0xE48, "TMR_ALARM2_H", "Timer alarm 2 high register",                     
>ACC_RW,  0xFFFFFFFF},
>+{0xE4C, "TMR_ALARM2_L", "Timer alarm 2 high register",                     
>ACC_RW,  0xFFFFFFFF},
>+{0xE80, "TMR_FIPER1",   "Timer fixed period interval",                     
>ACC_RW,  0xFFFFFFFF},
>+{0xE84, "TMR_FIPER2",   "Timer fixed period interval",                     
>ACC_RW,  0xFFFFFFFF},
>+{0xE88, "TMR_FIPER3",   "Timer fixed period interval",                     
>ACC_RW,  0xFFFFFFFF},
>+{0xEA0, "TMR_ETTS1_H",  "Time stamp of general purpose external trigger ", 
>ACC_RW,  0x00000000},
>+{0xEA4, "TMR_ETTS1_L",  "Time stamp of general purpose external trigger",  
>ACC_RW,  0x00000000},
>+{0xEA8, "TMR_ETTS2_H",  "Time stamp of general purpose external trigger ", 
>ACC_RW,  0x00000000},
>+{0xEAC, "TMR_ETTS2_L",  "Time stamp of general purpose external trigger",  
>ACC_RW,  0x00000000},
>+
>+/* End Of Table */
>+{0x0, 0x0, 0x0, 0x0, 0x0}
>+};
>diff --git a/hw/net/etsec_registers.h b/hw/net/etsec_registers.h
>new file mode 100644
>index 0000000..7faeaa9
>--- /dev/null
>+++ b/hw/net/etsec_registers.h
>@@ -0,0 +1,302 @@
>+/*
>+ * QEMU Freescale eTSEC Emulator
>+ *
>+ * Copyright (c) 2011-2013 AdaCore
>+ *
>+ * Permission is hereby granted, free of charge, to any person obtaining a 
>copy
>+ * of this software and associated documentation files (the "Software"), to 
>deal
>+ * in the Software without restriction, including without limitation the 
>rights
>+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>+ * copies of the Software, and to permit persons to whom the Software is
>+ * furnished to do so, subject to the following conditions:
>+ *
>+ * The above copyright notice and this permission notice shall be included in
>+ * all copies or substantial portions of the Software.
>+ *
>+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
>FROM,
>+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>+ * THE SOFTWARE.
>+ */
>+#ifndef _ETSEC_REGISTERS_H_
>+#define _ETSEC_REGISTERS_H_
>+
>+#include <stdint.h>
>+
>+typedef struct eTSEC_Register_Definition {
>+    uint32_t offset;
>+    const char *name;
>+    const char *desc;
>+    uint32_t access;
>+    uint32_t reset;
>+} eTSEC_Register_Definition;
>+
>+#define ACC_RW      1           /* Read/Write */
>+#define ACC_RO      2           /* Read Only */
>+#define ACC_WO      3           /* Write Only */
>+#define ACC_w1c     4           /* Write 1 to clear */
>+#define ACC_UNKNOWN 4           /* Unknown register*/
>+
>+extern const eTSEC_Register_Definition eTSEC_registers_def[];
>+
>+#define DMACTRL_LE  (1 << 15)
>+#define DMACTRL_GRS (1 <<  4)
>+#define DMACTRL_GTS (1 <<  3)
>+#define DMACTRL_WOP (1 <<  0)
>+
>+#define IEVENT_RXF  (1 <<  7)
>+#define IEVENT_GRSC (1 <<  8)
>+#define IEVENT_RXB  (1 << 15)
>+#define IEVENT_TXF  (1 << 20)
>+#define IEVENT_TXB  (1 << 21)
>+#define IEVENT_TXC  (1 << 23)
>+#define IEVENT_GTSC (1 << 25)
>+#define IEVENT_BSY  (1 << 29)
>+#define IEVENT_RXC  (1 << 30)
>+
>+#define IMASK_RXFEN  (1 <<  7)
>+#define IMASK_GRSCEN (1 <<  8)
>+#define IMASK_RXBEN  (1 << 15)
>+#define IMASK_TXFEN  (1 << 20)
>+#define IMASK_TXBEN  (1 << 21)
>+#define IMASK_GTSCEN (1 << 25)
>+
>+#define MACCFG1_TX_EN  (1 << 0)
>+#define MACCFG1_RX_EN  (1 << 2)
>+
>+#define MACCFG2_CRC_EN  (1 << 1)
>+#define MACCFG2_PADCRC  (1 << 2)
>+
>+#define MIIMCOM_READ (1 << 0)
>+#define MIIMCOM_SCAN (1 << 1)
>+
>+#define RCTRL_PRSDEP_MASK   (0x3)
>+#define RCTRL_PRSDEP_OFFSET (6)
>+#define RCTRL_RSF           (1 << 2)
>+
>+/* Index of each register */
>+
>+#define TSEC_ID      (0x000 / 4)
>+#define TSEC_ID2     (0x004 / 4)
>+#define IEVENT       (0x010 / 4)
>+#define IMASK        (0x014 / 4)
>+#define EDIS         (0x018 / 4)
>+#define ECNTRL       (0x020 / 4)
>+#define PTV          (0x028 / 4)
>+#define DMACTRL      (0x02C / 4)
>+#define TBIPA        (0x030 / 4)
>+#define TCTRL        (0x100 / 4)
>+#define TSTAT        (0x104 / 4)
>+#define DFVLAN       (0x108 / 4)
>+#define TXIC         (0x110 / 4)
>+#define TQUEUE       (0x114 / 4)
>+#define TR03WT       (0x140 / 4)
>+#define TR47WT       (0x144 / 4)
>+#define TBDBPH       (0x180 / 4)
>+#define TBPTR0       (0x184 / 4)
>+#define TBPTR1       (0x18C / 4)
>+#define TBPTR2       (0x194 / 4)
>+#define TBPTR3       (0x19C / 4)
>+#define TBPTR4       (0x1A4 / 4)
>+#define TBPTR5       (0x1AC / 4)
>+#define TBPTR6       (0x1B4 / 4)
>+#define TBPTR7       (0x1BC / 4)
>+#define TBASEH       (0x200 / 4)
>+#define TBASE0       (0x204 / 4)
>+#define TBASE1       (0x20C / 4)
>+#define TBASE2       (0x214 / 4)
>+#define TBASE3       (0x21C / 4)
>+#define TBASE4       (0x224 / 4)
>+#define TBASE5       (0x22C / 4)
>+#define TBASE6       (0x234 / 4)
>+#define TBASE7       (0x23C / 4)
>+#define TMR_TXTS1_ID (0x280 / 4)
>+#define TMR_TXTS2_ID (0x284 / 4)
>+#define TMR_TXTS1_H  (0x2C0 / 4)
>+#define TMR_TXTS1_L  (0x2C4 / 4)
>+#define TMR_TXTS2_H  (0x2C8 / 4)
>+#define TMR_TXTS2_L  (0x2CC / 4)
>+#define RCTRL        (0x300 / 4)
>+#define RSTAT        (0x304 / 4)
>+#define RXIC         (0x310 / 4)
>+#define RQUEUE       (0x314 / 4)
>+#define RBIFX        (0x330 / 4)
>+#define RQFAR        (0x334 / 4)
>+#define RQFCR        (0x338 / 4)
>+#define RQFPR        (0x33C / 4)
>+#define MRBLR        (0x340 / 4)
>+#define RBDBPH       (0x380 / 4)
>+#define RBPTR0       (0x384 / 4)
>+#define RBPTR1       (0x38C / 4)
>+#define RBPTR2       (0x394 / 4)
>+#define RBPTR3       (0x39C / 4)
>+#define RBPTR4       (0x3A4 / 4)
>+#define RBPTR5       (0x3AC / 4)
>+#define RBPTR6       (0x3B4 / 4)
>+#define RBPTR7       (0x3BC / 4)
>+#define RBASEH       (0x400 / 4)
>+#define RBASE0       (0x404 / 4)
>+#define RBASE1       (0x40C / 4)
>+#define RBASE2       (0x414 / 4)
>+#define RBASE3       (0x41C / 4)
>+#define RBASE4       (0x424 / 4)
>+#define RBASE5       (0x42C / 4)
>+#define RBASE6       (0x434 / 4)
>+#define RBASE7       (0x43C / 4)
>+#define TMR_RXTS_H   (0x4C0 / 4)
>+#define TMR_RXTS_L   (0x4C4 / 4)
>+#define MACCFG1      (0x500 / 4)
>+#define MACCFG2      (0x504 / 4)
>+#define IPGIFG       (0x508 / 4)
>+#define HAFDUP       (0x50C / 4)
>+#define MAXFRM       (0x510 / 4)
>+#define MIIMCFG      (0x520 / 4)
>+#define MIIMCOM      (0x524 / 4)
>+#define MIIMADD      (0x528 / 4)
>+#define MIIMCON      (0x52C / 4)
>+#define MIIMSTAT     (0x530 / 4)
>+#define MIIMIND      (0x534 / 4)
>+#define IFSTAT       (0x53C / 4)
>+#define MACSTNADDR1  (0x540 / 4)
>+#define MACSTNADDR2  (0x544 / 4)
>+#define MAC01ADDR1   (0x548 / 4)
>+#define MAC01ADDR2   (0x54C / 4)
>+#define MAC02ADDR1   (0x550 / 4)
>+#define MAC02ADDR2   (0x554 / 4)
>+#define MAC03ADDR1   (0x558 / 4)
>+#define MAC03ADDR2   (0x55C / 4)
>+#define MAC04ADDR1   (0x560 / 4)
>+#define MAC04ADDR2   (0x564 / 4)
>+#define MAC05ADDR1   (0x568 / 4)
>+#define MAC05ADDR2   (0x56C / 4)
>+#define MAC06ADDR1   (0x570 / 4)
>+#define MAC06ADDR2   (0x574 / 4)
>+#define MAC07ADDR1   (0x578 / 4)
>+#define MAC07ADDR2   (0x57C / 4)
>+#define MAC08ADDR1   (0x580 / 4)
>+#define MAC08ADDR2   (0x584 / 4)
>+#define MAC09ADDR1   (0x588 / 4)
>+#define MAC09ADDR2   (0x58C / 4)
>+#define MAC10ADDR1   (0x590 / 4)
>+#define MAC10ADDR2   (0x594 / 4)
>+#define MAC11ADDR1   (0x598 / 4)
>+#define MAC11ADDR2   (0x59C / 4)
>+#define MAC12ADDR1   (0x5A0 / 4)
>+#define MAC12ADDR2   (0x5A4 / 4)
>+#define MAC13ADDR1   (0x5A8 / 4)
>+#define MAC13ADDR2   (0x5AC / 4)
>+#define MAC14ADDR1   (0x5B0 / 4)
>+#define MAC14ADDR2   (0x5B4 / 4)
>+#define MAC15ADDR1   (0x5B8 / 4)
>+#define MAC15ADDR2   (0x5BC / 4)
>+#define TR64         (0x680 / 4)
>+#define TR127        (0x684 / 4)
>+#define TR255        (0x688 / 4)
>+#define TR511        (0x68C / 4)
>+#define TR1K         (0x690 / 4)
>+#define TRMAX        (0x694 / 4)
>+#define TRMGV        (0x698 / 4)
>+#define RBYT         (0x69C / 4)
>+#define RPKT         (0x6A0 / 4)
>+#define RFCS         (0x6A4 / 4)
>+#define RMCA         (0x6A8 / 4)
>+#define RBCA         (0x6AC / 4)
>+#define RXCF         (0x6B0 / 4)
>+#define RXPF         (0x6B4 / 4)
>+#define RXUO         (0x6B8 / 4)
>+#define RALN         (0x6BC / 4)
>+#define RFLR         (0x6C0 / 4)
>+#define RCDE         (0x6C4 / 4)
>+#define RCSE         (0x6C8 / 4)
>+#define RUND         (0x6CC / 4)
>+#define ROVR         (0x6D0 / 4)
>+#define RFRG         (0x6D4 / 4)
>+#define RJBR         (0x6D8 / 4)
>+#define RDRP         (0x6DC / 4)
>+#define TBYT         (0x6E0 / 4)
>+#define TPKT         (0x6E4 / 4)
>+#define TMCA         (0x6E8 / 4)
>+#define TBCA         (0x6EC / 4)
>+#define TXPF         (0x6F0 / 4)
>+#define TDFR         (0x6F4 / 4)
>+#define TEDF         (0x6F8 / 4)
>+#define TSCL         (0x6FC / 4)
>+#define TMCL         (0x700 / 4)
>+#define TLCL         (0x704 / 4)
>+#define TXCL         (0x708 / 4)
>+#define TNCL         (0x70C / 4)
>+#define TDRP         (0x714 / 4)
>+#define TJBR         (0x718 / 4)
>+#define TFCS         (0x71C / 4)
>+#define TXCF         (0x720 / 4)
>+#define TOVR         (0x724 / 4)
>+#define TUND         (0x728 / 4)
>+#define TFRG         (0x72C / 4)
>+#define CAR1         (0x730 / 4)
>+#define CAR2         (0x734 / 4)
>+#define CAM1         (0x738 / 4)
>+#define CAM2         (0x73C / 4)
>+#define RREJ         (0x740 / 4)
>+#define IGADDR0      (0x800 / 4)
>+#define IGADDR1      (0x804 / 4)
>+#define IGADDR2      (0x808 / 4)
>+#define IGADDR3      (0x80C / 4)
>+#define IGADDR4      (0x810 / 4)
>+#define IGADDR5      (0x814 / 4)
>+#define IGADDR6      (0x818 / 4)
>+#define IGADDR7      (0x81C / 4)
>+#define GADDR0       (0x880 / 4)
>+#define GADDR1       (0x884 / 4)
>+#define GADDR2       (0x888 / 4)
>+#define GADDR3       (0x88C / 4)
>+#define GADDR4       (0x890 / 4)
>+#define GADDR5       (0x894 / 4)
>+#define GADDR6       (0x898 / 4)
>+#define GADDR7       (0x89C / 4)
>+#define ATTR         (0xBF8 / 4)
>+#define ATTRELI      (0xBFC / 4)
>+#define RQPRM0       (0xC00 / 4)
>+#define RQPRM1       (0xC04 / 4)
>+#define RQPRM2       (0xC08 / 4)
>+#define RQPRM3       (0xC0C / 4)
>+#define RQPRM4       (0xC10 / 4)
>+#define RQPRM5       (0xC14 / 4)
>+#define RQPRM6       (0xC18 / 4)
>+#define RQPRM7       (0xC1C / 4)
>+#define RFBPTR0      (0xC44 / 4)
>+#define RFBPTR1      (0xC4C / 4)
>+#define RFBPTR2      (0xC54 / 4)
>+#define RFBPTR3      (0xC5C / 4)
>+#define RFBPTR4      (0xC64 / 4)
>+#define RFBPTR5      (0xC6C / 4)
>+#define RFBPTR6      (0xC74 / 4)
>+#define RFBPTR7      (0xC7C / 4)
>+#define TMR_CTRL     (0xE00 / 4)
>+#define TMR_TEVENT   (0xE04 / 4)
>+#define TMR_TEMASK   (0xE08 / 4)
>+#define TMR_PEVENT   (0xE0C / 4)
>+#define TMR_PEMASK   (0xE10 / 4)
>+#define TMR_STAT     (0xE14 / 4)
>+#define TMR_CNT_H    (0xE18 / 4)
>+#define TMR_CNT_L    (0xE1C / 4)
>+#define TMR_ADD      (0xE20 / 4)
>+#define TMR_ACC      (0xE24 / 4)
>+#define TMR_PRSC     (0xE28 / 4)
>+#define TMROFF_H     (0xE30 / 4)
>+#define TMROFF_L     (0xE34 / 4)
>+#define TMR_ALARM1_H (0xE40 / 4)
>+#define TMR_ALARM1_L (0xE44 / 4)
>+#define TMR_ALARM2_H (0xE48 / 4)
>+#define TMR_ALARM2_L (0xE4C / 4)
>+#define TMR_FIPER1   (0xE80 / 4)
>+#define TMR_FIPER2   (0xE84 / 4)
>+#define TMR_FIPER3   (0xE88 / 4)
>+#define TMR_ETTS1_H  (0xEA0 / 4)
>+#define TMR_ETTS1_L  (0xEA4 / 4)
>+#define TMR_ETTS2_H  (0xEA8 / 4)
>+#define TMR_ETTS2_L  (0xEAC / 4)
>+
>+#endif /* ! _ETSEC_REGISTERS_H_ */
>diff --git a/hw/net/etsec_rings.c b/hw/net/etsec_rings.c
>new file mode 100644
>index 0000000..15c0616
>--- /dev/null
>+++ b/hw/net/etsec_rings.c
>@@ -0,0 +1,673 @@
>+/*
>+ * QEMU Freescale eTSEC Emulator
>+ *
>+ * Copyright (c) 2011-2013 AdaCore
>+ *
>+ * Permission is hereby granted, free of charge, to any person obtaining a 
>copy
>+ * of this software and associated documentation files (the "Software"), to 
>deal
>+ * in the Software without restriction, including without limitation the 
>rights
>+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>+ * copies of the Software, and to permit persons to whom the Software is
>+ * furnished to do so, subject to the following conditions:
>+ *
>+ * The above copyright notice and this permission notice shall be included in
>+ * all copies or substantial portions of the Software.
>+ *
>+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
>FROM,
>+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>+ * THE SOFTWARE.
>+ */
>+#include "qemu/bswap.h"
>+#include "net/checksum.h"
>+
>+#include "etsec.h"
>+#include "etsec_registers.h"
>+
>+/* #define ETSEC_RING_DEBUG */
>+/* #define HEX_DUMP */
>+/* #define DEBUG_BD */
>+
>+#ifdef ETSEC_RING_DEBUG
>+#define RING_DEBUG(fmt, ...) printf("%s:%s " fmt, __func__ ,\
>+                                    etsec->nic->nc.name, ## __VA_ARGS__)
>+#else
>+#define RING_DEBUG(...)
>+#endif  /* ETSEC_RING_DEBUG */
>+
>+#define RING_DEBUG_A(fmt, ...) printf("%s:%s " fmt, __func__ ,\
>+                                      etsec->nic->nc.name, ## __VA_ARGS__)
>+
>+#ifdef DEBUG_BD
>+
>+static void print_tx_bd_flags(uint16_t flags)
>+{
>+    printf("      Ready: %d\n", !!(flags & BD_TX_READY));
>+    printf("      PAD/CRC: %d\n", !!(flags & BD_TX_PADCRC));
>+    printf("      Wrap: %d\n", !!(flags & BD_WRAP));
>+    printf("      Interrupt: %d\n", !!(flags & BD_INTERRUPT));
>+    printf("      Last in frame: %d\n", !!(flags & BD_LAST));
>+    printf("      Tx CRC: %d\n", !!(flags & BD_TX_TC));
>+    printf("      User-defined preamble / defer: %d\n",
>+           !!(flags & BD_TX_PREDEF));
>+    printf("      Huge frame enable / Late collision: %d\n",
>+           !!(flags & BD_TX_HFELC));
>+    printf("      Control frame / Retransmission Limit: %d\n",
>+           !!(flags & BD_TX_CFRL));
>+    printf("      Retry count: %d\n",
>+           (flags >> BD_TX_RC_OFFSET) & BD_TX_RC_MASK);
>+    printf("      Underrun / TCP/IP off-load enable: %d\n",
>+           !!(flags & BD_TX_TOEUN));
>+    printf("      Truncation: %d\n", !!(flags & BD_TX_TR));
>+}
>+
>+static void print_rx_bd_flags(uint16_t flags)
>+{
>+    printf("      Empty: %d\n", !!(flags & BD_RX_EMPTY));
>+    printf("      Receive software ownership: %d\n", !!(flags & BD_RX_RO1));
>+    printf("      Wrap: %d\n", !!(flags & BD_WRAP));
>+    printf("      Interrupt: %d\n", !!(flags & BD_INTERRUPT));
>+    printf("      Last in frame: %d\n", !!(flags & BD_LAST));
>+    printf("      First in frame: %d\n", !!(flags & BD_RX_FIRST));
>+    printf("      Miss: %d\n", !!(flags & BD_RX_MISS));
>+    printf("      Broadcast: %d\n", !!(flags & BD_RX_BROADCAST));
>+    printf("      Multicast: %d\n", !!(flags & BD_RX_MULTICAST));
>+    printf("      Rx frame length violation: %d\n", !!(flags & BD_RX_LG));
>+    printf("      Rx non-octet aligned frame: %d\n", !!(flags & BD_RX_NO));
>+    printf("      Short frame: %d\n", !!(flags & BD_RX_SH));
>+    printf("      Rx CRC Error: %d\n", !!(flags & BD_RX_CR));
>+    printf("      Overrun: %d\n", !!(flags & BD_RX_OV));
>+    printf("      Truncation: %d\n", !!(flags & BD_RX_TR));
>+}
>+
>+
>+static void print_bd(eTSEC_rxtx_bd bd, int mode, uint32_t index)
>+{
>+    printf("eTSEC %s Data Buffer Descriptor (%u)\n",
>+           mode == eTSEC_TRANSMIT ? "Transmit" : "Receive",
>+           index);
>+    printf("   Flags   : 0x%04x\n", bd.flags);
>+    if (mode == eTSEC_TRANSMIT) {
>+        print_tx_bd_flags(bd.flags);
>+    } else {
>+        print_rx_bd_flags(bd.flags);
>+    }
>+    printf("   Length  : 0x%04x\n", bd.length);
>+    printf("   Pointer : 0x%08x\n", bd.bufptr);
>+}
>+
>+#endif  /* DEBUG_BD */
>+
>+#ifdef HEX_DUMP
>+
>+static void hex_dump(FILE *f, const uint8_t *buf, int size)
>+{
>+    int len, i, j, c;
>+
>+    for (i = 0; i < size; i += 16) {
>+        len = size - i;
>+        if (len > 16) {
>+            len = 16;
>+        }
>+        fprintf(f, "%08x ", i);
>+        for (j = 0; j < 16; j++) {
>+            if (j < len) {
>+                fprintf(f, " %02x", buf[i + j]);
>+            } else {
>+                fprintf(f, "   ");
>+            }
>+        }
>+        fprintf(f, " ");
>+        for (j = 0; j < len; j++) {
>+            c = buf[i + j];
>+            if (c < ' ' || c > '~') {
>+                c = '.';
>+            }
>+            fprintf(f, "%c", c);
>+        }
>+        fprintf(f, "\n");
>+    }
>+}
>+
>+#endif
>+
>+static void read_buffer_descriptor(eTSEC         *etsec,
>+                                   hwaddr         addr,
>+                                   eTSEC_rxtx_bd *bd)
>+{
>+    assert(bd != NULL);
>+
>+    RING_DEBUG("READ Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr);
>+    cpu_physical_memory_read(addr,
>+                             bd,
>+                             sizeof(eTSEC_rxtx_bd));
>+
>+    if (etsec->regs[DMACTRL].value & DMACTRL_LE) {
>+        bd->flags  = le16_to_cpupu(&bd->flags);
>+        bd->length = le16_to_cpupu(&bd->length);
>+        bd->bufptr = le32_to_cpupu(&bd->bufptr);
>+    } else {
>+        bd->flags  = be16_to_cpupu(&bd->flags);
>+        bd->length = be16_to_cpupu(&bd->length);
>+        bd->bufptr = be32_to_cpupu(&bd->bufptr);
>+    }
>+}
>+
>+static void write_buffer_descriptor(eTSEC         *etsec,
>+                                    hwaddr         addr,
>+                                    eTSEC_rxtx_bd *bd)
>+{
>+    assert(bd != NULL);
>+
>+    if (etsec->regs[DMACTRL].value & DMACTRL_LE) {
>+        cpu_to_le16wu(&bd->flags, bd->flags);
>+        cpu_to_le16wu(&bd->length, bd->length);
>+        cpu_to_le32wu(&bd->bufptr, bd->bufptr);
>+    } else {
>+        cpu_to_be16wu(&bd->flags, bd->flags);
>+        cpu_to_be16wu(&bd->length, bd->length);
>+        cpu_to_be32wu(&bd->bufptr, bd->bufptr);
>+    }
>+
>+    RING_DEBUG("Write Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr);
>+    cpu_physical_memory_write(addr,
>+                              bd,
>+                              sizeof(eTSEC_rxtx_bd));
>+}
>+
>+static void ievent_set(eTSEC    *etsec,
>+                       uint32_t  flags)
>+{
>+    etsec->regs[IEVENT].value |= flags;
>+
>+    if ((flags & IEVENT_TXB && etsec->regs[IMASK].value & IMASK_TXBEN)
>+        || (flags & IEVENT_TXF && etsec->regs[IMASK].value & IMASK_TXFEN)) {
>+        qemu_irq_raise(etsec->tx_irq);
>+        RING_DEBUG("%s Raise Tx IRQ\n", __func__);
>+    }
>+
>+    if ((flags & IEVENT_RXB && etsec->regs[IMASK].value & IMASK_RXBEN)
>+        || (flags & IEVENT_RXF && etsec->regs[IMASK].value & IMASK_RXFEN)) {
>+        qemu_irq_pulse(etsec->rx_irq);
>+        RING_DEBUG("%s Raise Rx IRQ\n", __func__);
>+    }
>+}
>+
>+static void tx_padding_and_crc(eTSEC *etsec, uint32_t min_frame_len)
>+{
>+    int add = min_frame_len - etsec->tx_buffer_len;
>+
>+    /* Padding */
>+    if (add > 0) {
>+        RING_DEBUG("pad:%u\n", add);
>+        etsec->tx_buffer = g_realloc(etsec->tx_buffer,
>+                                        etsec->tx_buffer_len + add);
>+
>+        memset(etsec->tx_buffer + etsec->tx_buffer_len, 0x0, add);
>+        etsec->tx_buffer_len += add;
>+    }
>+
>+    /* Never add CRC in QEMU */
>+}
>+
>+static void process_tx_fcb(eTSEC *etsec)
>+{
>+    uint8_t flags = (uint8_t)(*etsec->tx_buffer);
>+    /* L3 header offset from start of frame */
>+    uint8_t l3_header_offset = (uint8_t)*(etsec->tx_buffer + 3);
>+    /* L4 header offset from start of L3 header */
>+    uint8_t l4_header_offset = (uint8_t)*(etsec->tx_buffer + 2);
>+    /* L3 header */
>+    uint8_t *l3_header = etsec->tx_buffer + 8 + l3_header_offset;
>+    /* L4 header */
>+    uint8_t *l4_header = l3_header + l4_header_offset;
>+
>+    /* if packet is IP4 and IP checksum is requested */
>+    if (flags & FCB_TX_IP && flags & FCB_TX_CIP) {
>+        /* do IP4 checksum (TODO This funtion does TCP/UDP checksum but not 
>sure
>+         * if it also does IP4 checksum. */
>+        net_checksum_calculate(etsec->tx_buffer + 8,
>+                etsec->tx_buffer_len - 8);
>+    }
>+    /* TODO Check the correct usage of the PHCS field of the FCB in case the 
>NPH
>+     * flag is on */
>+
>+    /* if packet is IP4 and TCP or UDP */
>+    if (flags & FCB_TX_IP && flags & FCB_TX_TUP) {
>+        /* if UDP */
>+        if (flags & FCB_TX_UDP) {
>+            /* if checksum is requested */
>+            if (flags & FCB_TX_CTU) {
>+                /* do UDP checksum */
>+
>+                net_checksum_calculate(etsec->tx_buffer + 8,
>+                        etsec->tx_buffer_len - 8);
>+            } else {
>+                /* set checksum field to 0 */
>+                l4_header[6] = 0;
>+                l4_header[7] = 0;
>+            }
>+        } else if (flags & FCB_TX_CTU) { /* if TCP and checksum is requested 
>*/
>+            /* do TCP checksum */
>+            net_checksum_calculate(etsec->tx_buffer + 8,
>+                                   etsec->tx_buffer_len - 8);
>+        }
>+    }
>+}
>+
>+static void process_tx_bd(eTSEC         *etsec,
>+                          eTSEC_rxtx_bd *bd)
>+{
>+    uint8_t *tmp_buff = NULL;
>+
>+    if (bd->length == 0) {
>+        /* ERROR */
>+        return;
>+    }
>+
>+    if (etsec->tx_buffer_len == 0) {
>+        /* It's the first BD */
>+        etsec->first_bd = *bd;
>+    }
>+
>+    /* TODO: if TxBD[TOE/UN] skip the Tx Frame Control Block*/
>+
>+    /* Load this Data Buffer */
>+    etsec->tx_buffer = g_realloc(etsec->tx_buffer,
>+                                    etsec->tx_buffer_len + bd->length);
>+    tmp_buff = etsec->tx_buffer + etsec->tx_buffer_len;
>+    cpu_physical_memory_read(bd->bufptr, tmp_buff, bd->length);
>+
>+    /* Update buffer length */
>+    etsec->tx_buffer_len += bd->length;
>+
>+
>+    if (etsec->tx_buffer_len != 0 && (bd->flags & BD_LAST)) {
>+        if (etsec->regs[MACCFG1].value & MACCFG1_TX_EN) {
>+            /* MAC Transmit enabled */
>+
>+            /* Process offload Tx FCB */
>+            if (etsec->first_bd.flags & BD_TX_TOEUN) {
>+                process_tx_fcb(etsec);
>+            }
>+
>+            if (etsec->first_bd.flags & BD_TX_PADCRC
>+                || etsec->regs[MACCFG2].value & MACCFG2_PADCRC) {
>+
>+                /* Padding and CRC (Padding implies CRC) */
>+                tx_padding_and_crc(etsec, 64);
>+
>+            } else if (etsec->first_bd.flags & BD_TX_TC
>+                       || etsec->regs[MACCFG2].value & MACCFG2_CRC_EN) {
>+
>+                /* Only CRC */
>+                /* Never add CRC in QEMU */
>+            }
>+
>+#if defined(HEX_DUMP)
>+            fprintf(stderr, "eTSEC Send packet size:%d\n",
>+                    etsec->tx_buffer_len);
>+            hex_dump(stderr, etsec->tx_buffer, etsec->tx_buffer_len);
>+#endif  /* ETSEC_RING_DEBUG */
>+
>+            if (etsec->first_bd.flags & BD_TX_TOEUN) {
>+                qemu_send_packet(qemu_get_queue(etsec->nic),
>+                        etsec->tx_buffer + 8,
>+                        etsec->tx_buffer_len - 8);
>+            } else {
>+                qemu_send_packet(qemu_get_queue(etsec->nic),
>+                        etsec->tx_buffer,
>+                        etsec->tx_buffer_len);
>+            }
>+
>+        }
>+
>+        etsec->tx_buffer_len = 0;
>+
>+        if (bd->flags & BD_INTERRUPT) {
>+            ievent_set(etsec, IEVENT_TXF);
>+        }
>+    } else {
>+        if (bd->flags & BD_INTERRUPT) {
>+            ievent_set(etsec, IEVENT_TXB);
>+        }
>+    }
>+
>+    /* Update DB flags */
>+
>+    /* Clear Ready */
>+    bd->flags &= ~BD_TX_READY;
>+
>+    /* Clear Defer */
>+    bd->flags &= ~BD_TX_PREDEF;
>+
>+    /* Clear Late Collision */
>+    bd->flags &= ~BD_TX_HFELC;
>+
>+    /* Clear Retransmission Limit */
>+    bd->flags &= ~BD_TX_CFRL;
>+
>+    /* Clear Retry Count */
>+    bd->flags &= ~(BD_TX_RC_MASK << BD_TX_RC_OFFSET);
>+
>+    /* Clear Underrun */
>+    bd->flags &= ~BD_TX_TOEUN;
>+
>+    /* Clear Truncation */
>+    bd->flags &= ~BD_TX_TR;
>+}
>+
>+void walk_tx_ring(eTSEC *etsec, int ring_nbr)
>+{
>+    hwaddr        ring_base = 0;
>+    hwaddr        bd_addr   = 0;
>+    eTSEC_rxtx_bd bd;
>+    uint16_t      bd_flags;
>+
>+    if (!(etsec->regs[MACCFG1].value & MACCFG1_TX_EN)) {
>+        RING_DEBUG("%s: MAC Transmit not enabled\n", __func__);
>+        return;
>+    }
>+
>+    /* ring_base = (etsec->regs[TBASEH].value & 0xF) << 32; */
>+    ring_base += etsec->regs[TBASE0 + ring_nbr].value & ~0x7;
>+    bd_addr    = etsec->regs[TBPTR0 + ring_nbr].value & ~0x7;
>+
>+    do {
>+        read_buffer_descriptor(etsec, bd_addr, &bd);
>+
>+#ifdef DEBUG_BD
>+        print_bd(bd,
>+                 eTSEC_TRANSMIT,
>+                 (bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd));
>+
>+#endif  /* DEBUG_BD */
>+
>+        /* Save flags before BD update */
>+        bd_flags = bd.flags;
>+
>+        if (bd_flags & BD_TX_READY) {
>+            process_tx_bd(etsec, &bd);
>+
>+            /* Write back BD after update */
>+            write_buffer_descriptor(etsec, bd_addr, &bd);
>+        }
>+
>+        /* Wrap or next BD */
>+        if (bd_flags & BD_WRAP) {
>+            bd_addr = ring_base;
>+        } else {
>+            bd_addr += sizeof(eTSEC_rxtx_bd);
>+        }
>+
>+    } while (bd_addr != ring_base);
>+
>+    bd_addr = ring_base;
>+
>+    /* Save the Buffer Descriptor Pointers to current bd */
>+    etsec->regs[TBPTR0 + ring_nbr].value = bd_addr;
>+
>+    /* Set transmit halt THLTx */
>+    etsec->regs[TSTAT].value |= 1 << (31 - ring_nbr);
>+}
>+
>+static void fill_rx_bd(eTSEC          *etsec,
>+                       eTSEC_rxtx_bd  *bd,
>+                       const uint8_t **buf,
>+                       size_t         *size)
>+{
>+    uint16_t to_write = MIN(etsec->rx_fcb_size + *size - etsec->rx_padding,
>+                            etsec->regs[MRBLR].value);
>+    uint32_t bufptr   = bd->bufptr;
>+    uint8_t  padd[etsec->rx_padding];
>+    uint8_t  rem;
>+
>+    RING_DEBUG("eTSEC fill Rx buffer @ 0x%08x"
>+               " size:%u(padding + crc:%u) + fcb:%u\n",
>+               bufptr, *size, etsec->rx_padding, etsec->rx_fcb_size);
>+
>+    bd->length = 0;
>+    if (etsec->rx_fcb_size != 0) {
>+        cpu_physical_memory_write(bufptr, etsec->rx_fcb, etsec->rx_fcb_size);
>+
>+        bufptr             += etsec->rx_fcb_size;
>+        bd->length         += etsec->rx_fcb_size;
>+        to_write           -= etsec->rx_fcb_size;
>+        etsec->rx_fcb_size  = 0;
>+
>+    }
>+
>+    if (to_write > 0) {
>+        cpu_physical_memory_write(bufptr, *buf, to_write);
>+
>+        *buf   += to_write;
>+        bufptr += to_write;
>+        *size  -= to_write;
>+
>+        bd->flags  &= ~BD_RX_EMPTY;
>+        bd->length += to_write;
>+    }
>+
>+    if (*size == etsec->rx_padding) {
>+        /* The remaining bytes are for padding which is not actually allocated
>+           in the buffer */
>+
>+        rem = MIN(etsec->regs[MRBLR].value - bd->length, etsec->rx_padding);
>+
>+        if (rem > 0) {
>+            memset(padd, 0x0, sizeof(padd));
>+            etsec->rx_padding -= rem;
>+            *size             -= rem;
>+            bd->length        += rem;
>+            cpu_physical_memory_write(bufptr, padd, rem);
>+        }
>+    }
>+}
>+
>+static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size)
>+{
>+    uint32_t fcb_size = 0;
>+    uint8_t  prsdep   = (etsec->regs[RCTRL].value >> RCTRL_PRSDEP_OFFSET)
>+        & RCTRL_PRSDEP_MASK;
>+
>+    if (prsdep != 0) {
>+        /* Prepend FCB */
>+        fcb_size = 8 + 2;          /* FCB size + align */
>+        /* I can't find this 2 bytes alignement in fsl documentation but 
>VxWorks
>+           expects them */
>+
>+        etsec->rx_fcb_size = fcb_size;
>+
>+        /* TODO: fill_FCB(etsec); */
>+        memset(etsec->rx_fcb, 0x0, sizeof(etsec->rx_fcb));
>+
>+    } else {
>+        etsec->rx_fcb_size = 0;
>+    }
>+
>+    if (etsec->rx_buffer != NULL) {
>+        g_free(etsec->rx_buffer);
>+    }
>+
>+    /* Do not copy the frame for now */
>+    etsec->rx_buffer     = (uint8_t *)buf;
>+    etsec->rx_buffer_len = size;
>+    etsec->rx_padding    = 4;
>+
>+    if (size < 60) {
>+        etsec->rx_padding += 60 - size;
>+    }
>+
>+    etsec->rx_first_in_frame = 1;
>+    etsec->rx_remaining_data = etsec->rx_buffer_len;
>+    RING_DEBUG("%s: rx_buffer_len:%u rx_padding+crc:%u\n", __func__,
>+               etsec->rx_buffer_len, etsec->rx_padding);
>+}
>+
>+void rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size)
>+{
>+    int ring_nbr = 0;           /* Always use ring0 (no filer) */
>+
>+    if (etsec->rx_buffer_len != 0) {
>+        RING_DEBUG("%s: We can't receive now,"
>+                   " a buffer is already in the pipe\n", __func__);
>+        return;
>+    }
>+
>+    if (etsec->regs[RSTAT].value & 1 << (23 - ring_nbr)) {
>+        RING_DEBUG("%s: The ring is halted\n", __func__);
>+        return;
>+    }
>+
>+    if (etsec->regs[DMACTRL].value & DMACTRL_GRS) {
>+        RING_DEBUG("%s: Graceful receive stop\n", __func__);
>+        return;
>+    }
>+
>+    if (!(etsec->regs[MACCFG1].value & MACCFG1_RX_EN)) {
>+        RING_DEBUG("%s: MAC Receive not enabled\n", __func__);
>+        return;
>+    }
>+
>+    /* Don't drop short packets, just add padding (later) */
>+
>+    rx_init_frame(etsec, buf, size);
>+
>+    walk_rx_ring(etsec, ring_nbr);
>+}
>+
>+void walk_rx_ring(eTSEC *etsec, int ring_nbr)
>+{
>+    hwaddr         ring_base     = 0;
>+    hwaddr         bd_addr       = 0;
>+    hwaddr         start_bd_addr = 0;
>+    eTSEC_rxtx_bd  bd;
>+    uint16_t       bd_flags;
>+    size_t         remaining_data;
>+    const uint8_t *buf;
>+    uint8_t       *tmp_buf;
>+    size_t         size;
>+
>+    if (etsec->rx_buffer_len == 0) {
>+        /* No frame to send */
>+        RING_DEBUG("No frame to send\n");
>+        return;
>+    }
>+
>+    remaining_data = etsec->rx_remaining_data + etsec->rx_padding;
>+    buf            = etsec->rx_buffer
>+        + (etsec->rx_buffer_len - etsec->rx_remaining_data);
>+    size           = etsec->rx_buffer_len + etsec->rx_padding;
>+
>+    /* ring_base = (etsec->regs[RBASEH].value & 0xF) << 32; */
>+    ring_base     += etsec->regs[RBASE0 + ring_nbr].value & ~0x7;
>+    start_bd_addr  = bd_addr = etsec->regs[RBPTR0 + ring_nbr].value & ~0x7;
>+
>+    do {
>+        read_buffer_descriptor(etsec, bd_addr, &bd);
>+
>+#ifdef DEBUG_BD
>+        print_bd(bd,
>+                 eTSEC_RECEIVE,
>+                 (bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd));
>+
>+#endif  /* DEBUG_BD */
>+
>+        /* Save flags before BD update */
>+        bd_flags = bd.flags;
>+
>+        if (bd_flags & BD_RX_EMPTY) {
>+            fill_rx_bd(etsec, &bd, &buf, &remaining_data);
>+
>+            if (etsec->rx_first_in_frame) {
>+                bd.flags |= BD_RX_FIRST;
>+                etsec->rx_first_in_frame = 0;
>+                etsec->rx_first_bd = bd;
>+            }
>+
>+            /* Last in frame */
>+            if (remaining_data == 0) {
>+
>+                /* Clear flags */
>+
>+                bd.flags &= ~0x7ff;
>+
>+                bd.flags |= BD_LAST;
>+
>+                /* NOTE: non-octet aligned frame is impossible in qemu */
>+
>+                if (size >= etsec->regs[MAXFRM].value) {
>+                    /* frame length violation */
>+                    printf("%s frame length violation: size:%d MAXFRM:%d\n",
>+                           __func__, size, etsec->regs[MAXFRM].value);
>+
>+                    bd.flags |= BD_RX_LG;
>+                }
>+
>+                if (size  < 64) {
>+                    /* Short frame */
>+                    printf("%s Short frame: %d\n", __func__, size);
>+                    bd.flags |= BD_RX_SH;
>+                }
>+
>+                /* TODO: Broadcast and Multicast */
>+
>+                if (bd.flags | BD_INTERRUPT) {
>+                    /* Set RXFx */
>+                    etsec->regs[RSTAT].value |= 1 << (7 - ring_nbr);
>+
>+                    /* Set IEVENT */
>+                    ievent_set(etsec, IEVENT_RXF);
>+                }
>+
>+            } else {
>+                if (bd.flags | BD_INTERRUPT) {
>+                    /* Set IEVENT */
>+                    ievent_set(etsec, IEVENT_RXB);
>+                }
>+            }
>+
>+            /* Write back BD after update */
>+            write_buffer_descriptor(etsec, bd_addr, &bd);
>+        }
>+
>+        /* Wrap or next BD */
>+        if (bd_flags & BD_WRAP) {
>+            bd_addr = ring_base;
>+        } else {
>+            bd_addr += sizeof(eTSEC_rxtx_bd);
>+        }
>+    } while (remaining_data != 0
>+             && (bd_flags & BD_RX_EMPTY)
>+             && bd_addr != start_bd_addr);
>+
>+    /* Reset ring ptr */
>+    etsec->regs[RBPTR0 + ring_nbr].value = bd_addr;
>+
>+    /* The frame is too large to fit in the Rx ring */
>+    if (remaining_data > 0) {
>+
>+        /* Set RSTAT[QHLTx] */
>+        etsec->regs[RSTAT].value |= 1 << (23 - ring_nbr);
>+
>+        /* Save remaining data to send the end of the frame when the ring will
>+         * be restarted
>+         */
>+        etsec->rx_remaining_data = remaining_data;
>+
>+        /* Copy the frame */
>+        tmp_buf = g_malloc(size);
>+        memcpy(tmp_buf, etsec->rx_buffer, size);
>+        etsec->rx_buffer = tmp_buf;
>+
>+        RING_DEBUG("no empty RxBD available any more\n");
>+    } else {
>+        etsec->rx_buffer_len = 0;
>+        etsec->rx_buffer     = NULL;
>+    }
>+
>+    RING_DEBUG("eTSEC End of ring_write: remaining_data:%u\n", 
>remaining_data);
>+}
>-- 
>1.7.9.5
>
>
Hi:
        I'm very interesting in it, but I don't know how to create a eTSEC 
device, I did a test as below:

for(i = 0; i < nb_nics; i++) {
     NICInfo *nd = &nd_table[i];
     if (!nd->model) {
         nd->model = g_strdup("eTSEC");
     }
     if(strcmp(nd->model, "eTSEC") == 0) {
          etsec_create(ETSEC0_REGS_OFFSET, ccsr_addr_space, nd,
          mpic[0x1d], mpic[0x1e], mpic[0x22]);
     }
}

When I start the qemu, an error exists" qemu-system-ppc: Unsupported NIC model: 
eTSEC" .
Could you tell me how to create a eTSEC device?

Thank you!

--------------------------------------------------                       
2013-07-15



reply via email to

[Prev in Thread] Current Thread [Next in Thread]