Add Enhanced Three-Speed Ethernet Controller (eTSEC)
This implementation doesn't include ring priority, TCP/IP Off-Load, QoS. Signed-off-by: Fabien Chouteau <chouteau@adacore.com> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
		
							parent
							
								
									b36f100e17
								
							
						
					
					
						commit
						eb1e7c3e51
					
				@ -47,4 +47,5 @@ CONFIG_E500=y
 | 
			
		||||
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
 | 
			
		||||
# For PReP
 | 
			
		||||
CONFIG_MC146818RTC=y
 | 
			
		||||
CONFIG_ETSEC=y
 | 
			
		||||
CONFIG_ISA_TESTDEV=y
 | 
			
		||||
 | 
			
		||||
@ -32,3 +32,6 @@ obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_VIRTIO) += virtio-net.o
 | 
			
		||||
obj-y += vhost_net.o
 | 
			
		||||
 | 
			
		||||
obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
 | 
			
		||||
			fsl_etsec/rings.o fsl_etsec/miim.o
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										465
									
								
								hw/net/fsl_etsec/etsec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										465
									
								
								hw/net/fsl_etsec/etsec.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,465 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "sysemu/sysemu.h"
 | 
			
		||||
#include "hw/sysbus.h"
 | 
			
		||||
#include "trace.h"
 | 
			
		||||
#include "hw/ptimer.h"
 | 
			
		||||
#include "etsec.h"
 | 
			
		||||
#include "registers.h"
 | 
			
		||||
 | 
			
		||||
/* #define HEX_DUMP */
 | 
			
		||||
/* #define DEBUG_REGISTER */
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_REGISTER
 | 
			
		||||
static const int debug_etsec = 1;
 | 
			
		||||
#else
 | 
			
		||||
static const int debug_etsec;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DPRINTF(fmt, ...) do {                 \
 | 
			
		||||
    if (debug_etsec) {                         \
 | 
			
		||||
        qemu_log(fmt , ## __VA_ARGS__);        \
 | 
			
		||||
    }                                          \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
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 < ETSEC_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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DPRINTF("Read  0x%08x @ 0x" TARGET_FMT_plx
 | 
			
		||||
            "                            : %s (%s)\n",
 | 
			
		||||
            ret, addr, reg->name, reg->desc);
 | 
			
		||||
 | 
			
		||||
    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))) {
 | 
			
		||||
            etsec_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)))) {
 | 
			
		||||
            etsec_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)
 | 
			
		||||
{
 | 
			
		||||
    /* Write 1 to clear */
 | 
			
		||||
    reg->value &= ~value;
 | 
			
		||||
 | 
			
		||||
    if (!(reg->value & (IEVENT_TXF | IEVENT_TXF))) {
 | 
			
		||||
        qemu_irq_lower(etsec->tx_irq);
 | 
			
		||||
    }
 | 
			
		||||
    if (!(reg->value & (IEVENT_RXF | IEVENT_RXF))) {
 | 
			
		||||
        qemu_irq_lower(etsec->rx_irq);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!(reg->value & (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC |
 | 
			
		||||
                        IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC |
 | 
			
		||||
                        IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ |
 | 
			
		||||
                        IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE |
 | 
			
		||||
                        IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD |
 | 
			
		||||
                        IEVENT_MMRW))) {
 | 
			
		||||
        qemu_irq_lower(etsec->err_irq);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 < ETSEC_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:
 | 
			
		||||
        etsec_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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DPRINTF("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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)) {
 | 
			
		||||
            etsec_walk_tx_ring(etsec, 0);
 | 
			
		||||
        }
 | 
			
		||||
        ptimer_set_count(etsec->ptimer, 1);
 | 
			
		||||
        ptimer_run(etsec->ptimer, 1);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void etsec_reset(DeviceState *d)
 | 
			
		||||
{
 | 
			
		||||
    eTSEC *etsec = ETSEC_COMMON(d);
 | 
			
		||||
    int i = 0;
 | 
			
		||||
    int reg_index = 0;
 | 
			
		||||
 | 
			
		||||
    /* Default value for all registers */
 | 
			
		||||
    for (i = 0; i < ETSEC_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)
 | 
			
		||||
{
 | 
			
		||||
    /* qemu_log("eTSEC cleanup\n"); */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int etsec_can_receive(NetClientState *nc)
 | 
			
		||||
{
 | 
			
		||||
    eTSEC *etsec = qemu_get_nic_opaque(nc);
 | 
			
		||||
 | 
			
		||||
    return etsec->rx_buffer_len == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
    qemu_hexdump(buf, stderr, "", size);
 | 
			
		||||
#endif
 | 
			
		||||
    etsec_rx_ring_write(etsec, buf, size);
 | 
			
		||||
    return size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void etsec_set_link_status(NetClientState *nc)
 | 
			
		||||
{
 | 
			
		||||
    eTSEC *etsec = qemu_get_nic_opaque(nc);
 | 
			
		||||
 | 
			
		||||
    etsec_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 void etsec_realize(DeviceState *dev, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    eTSEC        *etsec = ETSEC_COMMON(dev);
 | 
			
		||||
 | 
			
		||||
    etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf,
 | 
			
		||||
                              object_get_typename(OBJECT(dev)), dev->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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void etsec_instance_init(Object *obj)
 | 
			
		||||
{
 | 
			
		||||
    eTSEC        *etsec = ETSEC_COMMON(obj);
 | 
			
		||||
    SysBusDevice *sbd   = SYS_BUS_DEVICE(obj);
 | 
			
		||||
 | 
			
		||||
    memory_region_init_io(&etsec->io_area, OBJECT(etsec), &etsec_ops, etsec,
 | 
			
		||||
                          "eTSEC", 0x1000);
 | 
			
		||||
    sysbus_init_mmio(sbd, &etsec->io_area);
 | 
			
		||||
 | 
			
		||||
    sysbus_init_irq(sbd, &etsec->tx_irq);
 | 
			
		||||
    sysbus_init_irq(sbd, &etsec->rx_irq);
 | 
			
		||||
    sysbus_init_irq(sbd, &etsec->err_irq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
    dc->realize = etsec_realize;
 | 
			
		||||
    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,
 | 
			
		||||
    .instance_init         = etsec_instance_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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										174
									
								
								hw/net/fsl_etsec/etsec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								hw/net/fsl_etsec/etsec.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,174 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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 */
 | 
			
		||||
 | 
			
		||||
/* Number of register in the device */
 | 
			
		||||
#define ETSEC_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[ETSEC_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 TYPE_ETSEC_COMMON "eTSEC"
 | 
			
		||||
#define ETSEC_COMMON(obj) \
 | 
			
		||||
     OBJECT_CHECK(eTSEC, (obj), TYPE_ETSEC_COMMON)
 | 
			
		||||
 | 
			
		||||
#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 etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr);
 | 
			
		||||
void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr);
 | 
			
		||||
void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size);
 | 
			
		||||
 | 
			
		||||
void etsec_write_miim(eTSEC          *etsec,
 | 
			
		||||
                      eTSEC_Register *reg,
 | 
			
		||||
                      uint32_t        reg_index,
 | 
			
		||||
                      uint32_t        value);
 | 
			
		||||
 | 
			
		||||
void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc);
 | 
			
		||||
 | 
			
		||||
#endif /* ! _ETSEC_H_ */
 | 
			
		||||
							
								
								
									
										146
									
								
								hw/net/fsl_etsec/miim.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								hw/net/fsl_etsec/miim.c
									
									
									
									
									
										Normal file
									
								
							@ -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 "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
 | 
			
		||||
    qemu_log("%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
 | 
			
		||||
    qemu_log("%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 etsec_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 etsec_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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										295
									
								
								hw/net/fsl_etsec/registers.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								hw/net/fsl_etsec/registers.c
									
									
									
									
									
										Normal file
									
								
							@ -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 "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}
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										320
									
								
								hw/net/fsl_etsec/registers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										320
									
								
								hw/net/fsl_etsec/registers.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,320 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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>
 | 
			
		||||
 | 
			
		||||
enum eTSEC_Register_Access_Type {
 | 
			
		||||
    ACC_RW      = 1,            /* Read/Write */
 | 
			
		||||
    ACC_RO      = 2,            /* Read Only */
 | 
			
		||||
    ACC_WO      = 3,            /* Write Only */
 | 
			
		||||
    ACC_W1C     = 4,            /* Write 1 to clear */
 | 
			
		||||
    ACC_UNKNOWN = 5             /* Unknown register*/
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct eTSEC_Register_Definition {
 | 
			
		||||
    uint32_t                         offset;
 | 
			
		||||
    const char                      *name;
 | 
			
		||||
    const char                      *desc;
 | 
			
		||||
    enum eTSEC_Register_Access_Type  access;
 | 
			
		||||
    uint32_t                         reset;
 | 
			
		||||
} eTSEC_Register_Definition;
 | 
			
		||||
 | 
			
		||||
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_PERR  (1 <<  0)
 | 
			
		||||
#define IEVENT_DPE   (1 <<  1)
 | 
			
		||||
#define IEVENT_FIQ   (1 <<  2)
 | 
			
		||||
#define IEVENT_FIR   (1 <<  3)
 | 
			
		||||
#define IEVENT_FGPI  (1 <<  4)
 | 
			
		||||
#define IEVENT_RXF   (1 <<  7)
 | 
			
		||||
#define IEVENT_GRSC  (1 <<  8)
 | 
			
		||||
#define IEVENT_MMRW  (1 <<  9)
 | 
			
		||||
#define IEVENT_MMRD  (1 << 10)
 | 
			
		||||
#define IEVENT_MAG   (1 << 11)
 | 
			
		||||
#define IEVENT_RXB   (1 << 15)
 | 
			
		||||
#define IEVENT_XFUN  (1 << 16)
 | 
			
		||||
#define IEVENT_CRL   (1 << 17)
 | 
			
		||||
#define IEVENT_LC    (1 << 18)
 | 
			
		||||
#define IEVENT_TXF   (1 << 20)
 | 
			
		||||
#define IEVENT_TXB   (1 << 21)
 | 
			
		||||
#define IEVENT_TXE   (1 << 22)
 | 
			
		||||
#define IEVENT_TXC   (1 << 23)
 | 
			
		||||
#define IEVENT_BABT  (1 << 24)
 | 
			
		||||
#define IEVENT_GTSC  (1 << 25)
 | 
			
		||||
#define IEVENT_MSRO  (1 << 26)
 | 
			
		||||
#define IEVENT_EBERR (1 << 28)
 | 
			
		||||
#define IEVENT_BSY   (1 << 29)
 | 
			
		||||
#define IEVENT_RXC   (1 << 30)
 | 
			
		||||
#define IEVENT_BABR  (1 << 31)
 | 
			
		||||
 | 
			
		||||
#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_ */
 | 
			
		||||
							
								
								
									
										650
									
								
								hw/net/fsl_etsec/rings.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										650
									
								
								hw/net/fsl_etsec/rings.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,650 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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 "net/checksum.h"
 | 
			
		||||
 | 
			
		||||
#include "etsec.h"
 | 
			
		||||
#include "registers.h"
 | 
			
		||||
 | 
			
		||||
/* #define ETSEC_RING_DEBUG */
 | 
			
		||||
/* #define HEX_DUMP */
 | 
			
		||||
/* #define DEBUG_BD */
 | 
			
		||||
 | 
			
		||||
#ifdef ETSEC_RING_DEBUG
 | 
			
		||||
static const int debug_etsec = 1;
 | 
			
		||||
#else
 | 
			
		||||
static const int debug_etsec;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define RING_DEBUG(fmt, ...) do {              \
 | 
			
		||||
 if (debug_etsec) {                            \
 | 
			
		||||
        qemu_log(fmt , ## __VA_ARGS__);        \
 | 
			
		||||
    }                                          \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_BD
 | 
			
		||||
 | 
			
		||||
static void print_tx_bd_flags(uint16_t flags)
 | 
			
		||||
{
 | 
			
		||||
    qemu_log("      Ready: %d\n", !!(flags & BD_TX_READY));
 | 
			
		||||
    qemu_log("      PAD/CRC: %d\n", !!(flags & BD_TX_PADCRC));
 | 
			
		||||
    qemu_log("      Wrap: %d\n", !!(flags & BD_WRAP));
 | 
			
		||||
    qemu_log("      Interrupt: %d\n", !!(flags & BD_INTERRUPT));
 | 
			
		||||
    qemu_log("      Last in frame: %d\n", !!(flags & BD_LAST));
 | 
			
		||||
    qemu_log("      Tx CRC: %d\n", !!(flags & BD_TX_TC));
 | 
			
		||||
    qemu_log("      User-defined preamble / defer: %d\n",
 | 
			
		||||
           !!(flags & BD_TX_PREDEF));
 | 
			
		||||
    qemu_log("      Huge frame enable / Late collision: %d\n",
 | 
			
		||||
           !!(flags & BD_TX_HFELC));
 | 
			
		||||
    qemu_log("      Control frame / Retransmission Limit: %d\n",
 | 
			
		||||
           !!(flags & BD_TX_CFRL));
 | 
			
		||||
    qemu_log("      Retry count: %d\n",
 | 
			
		||||
           (flags >> BD_TX_RC_OFFSET) & BD_TX_RC_MASK);
 | 
			
		||||
    qemu_log("      Underrun / TCP/IP off-load enable: %d\n",
 | 
			
		||||
           !!(flags & BD_TX_TOEUN));
 | 
			
		||||
    qemu_log("      Truncation: %d\n", !!(flags & BD_TX_TR));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_rx_bd_flags(uint16_t flags)
 | 
			
		||||
{
 | 
			
		||||
    qemu_log("      Empty: %d\n", !!(flags & BD_RX_EMPTY));
 | 
			
		||||
    qemu_log("      Receive software ownership: %d\n", !!(flags & BD_RX_RO1));
 | 
			
		||||
    qemu_log("      Wrap: %d\n", !!(flags & BD_WRAP));
 | 
			
		||||
    qemu_log("      Interrupt: %d\n", !!(flags & BD_INTERRUPT));
 | 
			
		||||
    qemu_log("      Last in frame: %d\n", !!(flags & BD_LAST));
 | 
			
		||||
    qemu_log("      First in frame: %d\n", !!(flags & BD_RX_FIRST));
 | 
			
		||||
    qemu_log("      Miss: %d\n", !!(flags & BD_RX_MISS));
 | 
			
		||||
    qemu_log("      Broadcast: %d\n", !!(flags & BD_RX_BROADCAST));
 | 
			
		||||
    qemu_log("      Multicast: %d\n", !!(flags & BD_RX_MULTICAST));
 | 
			
		||||
    qemu_log("      Rx frame length violation: %d\n", !!(flags & BD_RX_LG));
 | 
			
		||||
    qemu_log("      Rx non-octet aligned frame: %d\n", !!(flags & BD_RX_NO));
 | 
			
		||||
    qemu_log("      Short frame: %d\n", !!(flags & BD_RX_SH));
 | 
			
		||||
    qemu_log("      Rx CRC Error: %d\n", !!(flags & BD_RX_CR));
 | 
			
		||||
    qemu_log("      Overrun: %d\n", !!(flags & BD_RX_OV));
 | 
			
		||||
    qemu_log("      Truncation: %d\n", !!(flags & BD_RX_TR));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void print_bd(eTSEC_rxtx_bd bd, int mode, uint32_t index)
 | 
			
		||||
{
 | 
			
		||||
    qemu_log("eTSEC %s Data Buffer Descriptor (%u)\n",
 | 
			
		||||
           mode == eTSEC_TRANSMIT ? "Transmit" : "Receive",
 | 
			
		||||
           index);
 | 
			
		||||
    qemu_log("   Flags   : 0x%04x\n", bd.flags);
 | 
			
		||||
    if (mode == eTSEC_TRANSMIT) {
 | 
			
		||||
        print_tx_bd_flags(bd.flags);
 | 
			
		||||
    } else {
 | 
			
		||||
        print_rx_bd_flags(bd.flags);
 | 
			
		||||
    }
 | 
			
		||||
    qemu_log("   Length  : 0x%04x\n", bd.length);
 | 
			
		||||
    qemu_log("   Pointer : 0x%08x\n", bd.bufptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif  /* DEBUG_BD */
 | 
			
		||||
 | 
			
		||||
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  = lduw_le_p(&bd->flags);
 | 
			
		||||
        bd->length = lduw_le_p(&bd->length);
 | 
			
		||||
        bd->bufptr = ldl_le_p(&bd->bufptr);
 | 
			
		||||
    } else {
 | 
			
		||||
        bd->flags  = lduw_be_p(&bd->flags);
 | 
			
		||||
        bd->length = lduw_be_p(&bd->length);
 | 
			
		||||
        bd->bufptr = ldl_be_p(&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) {
 | 
			
		||||
        stw_le_p(&bd->flags, bd->flags);
 | 
			
		||||
        stw_le_p(&bd->length, bd->length);
 | 
			
		||||
        stl_le_p(&bd->bufptr, bd->bufptr);
 | 
			
		||||
    } else {
 | 
			
		||||
        stw_be_p(&bd->flags, bd->flags);
 | 
			
		||||
        stw_be_p(&bd->length, bd->length);
 | 
			
		||||
        stl_be_p(&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;
 | 
			
		||||
    hwaddr tbdbth     = (hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32;
 | 
			
		||||
 | 
			
		||||
    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 + tbdbth, 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)
 | 
			
		||||
            qemu_log("eTSEC Send packet size:%d\n", etsec->tx_buffer_len);
 | 
			
		||||
            qemu_hexdump(etsec->tx_buffer, stderr, "", 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 etsec_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 = (hwaddr)(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;
 | 
			
		||||
    hwaddr   bufptr = bd->bufptr +
 | 
			
		||||
        ((hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32);
 | 
			
		||||
    uint8_t  padd[etsec->rx_padding];
 | 
			
		||||
    uint8_t  rem;
 | 
			
		||||
 | 
			
		||||
    RING_DEBUG("eTSEC fill Rx buffer @ 0x%016" HWADDR_PRIx
 | 
			
		||||
               " size:%zu(padding + crc:%u) + fcb:%u\n",
 | 
			
		||||
               bufptr, *size, etsec->rx_padding, etsec->rx_fcb_size);
 | 
			
		||||
 | 
			
		||||
    bd->length = 0;
 | 
			
		||||
 | 
			
		||||
    /* This operation will only write FCB */
 | 
			
		||||
    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;
 | 
			
		||||
        etsec->rx_fcb_size  = 0;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* We remove padding from the computation of to_write because it is not
 | 
			
		||||
     * allocated in the buffer.
 | 
			
		||||
     */
 | 
			
		||||
    to_write = MIN(*size - etsec->rx_padding,
 | 
			
		||||
                   etsec->regs[MRBLR].value - etsec->rx_fcb_size);
 | 
			
		||||
 | 
			
		||||
    /* This operation can only write packet data and no padding */
 | 
			
		||||
    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 only for padding which is not actually
 | 
			
		||||
         * allocated in the data 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 + RCTRL[PAL]) */
 | 
			
		||||
        fcb_size = 8 + ((etsec->regs[RCTRL].value >> 16) & 0x1F);
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
    /* CRC padding (We don't have to compute the CRC) */
 | 
			
		||||
    etsec->rx_padding = 4;
 | 
			
		||||
 | 
			
		||||
    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 etsec_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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((etsec->regs[RCTRL].value & RCTRL_RSF) && (size < 60)) {
 | 
			
		||||
        /* CRC is not in the packet yet, so short frame is below 60 bytes */
 | 
			
		||||
        RING_DEBUG("%s: Drop short frame\n", __func__);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rx_init_frame(etsec, buf, size);
 | 
			
		||||
 | 
			
		||||
    etsec_walk_rx_ring(etsec, ring_nbr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void etsec_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 = (hwaddr)(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 */
 | 
			
		||||
                    qemu_log("%s frame length violation: size:%zu MAXFRM:%d\n",
 | 
			
		||||
                           __func__, size, etsec->regs[MAXFRM].value);
 | 
			
		||||
 | 
			
		||||
                    bd.flags |= BD_RX_LG;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (size  < 64) {
 | 
			
		||||
                    /* Short frame */
 | 
			
		||||
                    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:%zu\n", remaining_data);
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user