All of lore.kernel.org
 help / color / mirror / Atom feed
From: Scott Wood <scottwood@freescale.com>
To: Fabien Chouteau <chouteau@adacore.com>
Cc: qemu-ppc@nongnu.org, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [Qemu-ppc] [PATCH 2/2] Add Enhanced Three-Speed Ethernet Controller (eTSEC)
Date: Mon, 15 Jul 2013 21:06:17 -0500	[thread overview]
Message-ID: <20130716020617.GA22542@home.buserror.net> (raw)
In-Reply-To: <1373476202-11277-3-git-send-email-chouteau@adacore.com>

On 07/10/2013 12:10:02 PM, Fabien Chouteau wrote:
> This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
> 
> Signed-off-by: Fabien Chouteau <chouteau@adacore.com>

>From the code comments I gather this has been tested on VxWorks.  Has it
been tested on Linux, or anywhere else?

> ---
>  default-configs/ppc-softmmu.mak |    1 +
>  hw/net/Makefile.objs            |    1 +
>  hw/net/etsec.c                  |  472 +++++++++++++++++++++++++++
>  hw/net/etsec.h                  |  169 ++++++++++
>  hw/net/etsec_miim.c             |  146 +++++++++
>  hw/net/etsec_registers.c        |  295 +++++++++++++++++
>  hw/net/etsec_registers.h        |  302 ++++++++++++++++++
>  hw/net/etsec_rings.c            |  673 +++++++++++++++++++++++++++++++++++++++
>  8 files changed, 2059 insertions(+)
>  create mode 100644 hw/net/etsec.c
>  create mode 100644 hw/uuunet/etsec.h
>  create mode 100644 hw/net/etsec_miim.c
>  create mode 100644 hw/net/etsec_registers.c
>  create mode 100644 hw/net/etsec_registers.h
>  create mode 100644 hw/net/etsec_rings.c

This should probably be namespaced as something like fsl_etsec.

> diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
> index 73e4cc5..c7541cf 100644
> --- a/default-configs/ppc-softmmu.mak
> +++ b/default-configs/ppc-softmmu.mak
> @@ -46,3 +46,4 @@ CONFIG_E500=y
>  CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
>  # For PReP
>  CONFIG_MC146818RTC=y
> +CONFIG_ETSEC=y
> diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
> index 951cca3..ca03c3f 100644
> --- a/hw/net/Makefile.objs
> +++ b/hw/net/Makefile.objs
> @@ -28,6 +28,7 @@ obj-$(CONFIG_COLDFIRE) += mcf_fec.o
>  obj-$(CONFIG_MILKYMIST) += milkymist-minimac2.o
>  obj-$(CONFIG_PSERIES) += spapr_llan.o
>  obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
> +obj-$(CONFIG_ETSEC) += etsec.o etsec_registers.o etsec_rings.o etsec_miim.o

Maybe an fsl_etsec directory?

> +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;

It's always awkward when QEMU's type naming convention collides with
names that have pre-existing significant capitalization, but I suspect
this ought to be Etsec and EtsecRegister.  Or maybe ETSEC and
ETSECRegister?  Oh well.

> +    assert(reg_index < REG_NUMBER);
> +
> +    reg = &etsec->regs[reg_index];
> +
> +
> +    switch (reg->access) {
> +    case ACC_WO:
> +        ret = 0x00000000;
> +        break;
> +
> +    case ACC_RW:
> +    case ACC_w1c:
> +    case ACC_RO:
> +    default:
> +        ret = reg->value;
> +        break;
> +    }

Why is "w1c" lowercase when the rest are uppercase?  I realize the
hardware docs do that, but in this case I don't think that takes
precedence over consistent coding style for #defines.

> +#ifdef DEBUG_REGISTER
> +    printf("Read  0x%08x @ 0x" TARGET_FMT_plx
> +           "                            : %s (%s)\n",
> +           ret, addr, reg->name, reg->desc);
> +#endif

This is likely to bitrot -- please consider doing something similar to DPRINTF in hw/intc/openpic.c.

> +static void write_ievent(eTSEC          *etsec,
> +                         eTSEC_Register *reg,
> +                         uint32_t        reg_index,
> +                         uint32_t        value)
> +{
> +    if (value & IEVENT_TXF) {
> +        qemu_irq_lower(etsec->tx_irq);
> +    }
> +    if (value & IEVENT_RXF) {
> +        qemu_irq_lower(etsec->rx_irq);
> +    }
> +
> +    /* Write 1 to clear */
> +    reg->value &= ~value;
> +}

What about the error interrupt?  You raise it but never lower it that I
can see.

TXB/RXB should also be included, and you should only lower the interrupt
if neither ?XB nor ?XF are set for a particular direction.

> +#ifdef HEX_DUMP
> +static void hex_dump(FILE *f, const uint8_t *buf, int size)
> +{
> +    int len, i, j, c;
> +
> +    for (i = 0; i < size; i += 16) {
> +        len = size - i;
> +        if (len > 16) {
> +            len = 16;
> +        }
> +        fprintf(f, "%08x ", i);
> +        for (j = 0; j < 16; j++) {
> +            if (j < len) {
> +                fprintf(f, " %02x", buf[i + j]);
> +            } else {
> +                fprintf(f, "   ");
> +            }
> +        }
> +        fprintf(f, " ");
> +        for (j = 0; j < len; j++) {
> +            c = buf[i + j];
> +            if (c < ' ' || c > '~') {
> +                c = '.';
> +            }
> +            fprintf(f, "%c", c);
> +        }
> +        fprintf(f, "\n");
> +    }
> +}
> +#endif

qemu_hexdump()

> +static int etsec_init(SysBusDevice *dev)
> +{
> +    eTSEC *etsec = FROM_SYSBUS(typeof(*etsec), dev);

I was recently yelled at for using FROM_SYSBUS and related
deprecated infrastructure -- see http://wiki.qemu.org/QOMConventions

> +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;
> +}

Do you plan to update hw/ppc/e500.c (or maybe some other platform?) to
call this?

If you're centralizing this part of device creation, how about the device
tree bits as well?

> +/* eTSEC */
> +
> +#define REG_NUMBER 1024

This is pretty vague.

> +DeviceState *etsec_create(hwaddr        base,
> +                          MemoryRegion *mr,
> +                          NICInfo      *nd,
> +                          qemu_irq      tx_irq,
> +                          qemu_irq      rx_irq,
> +                          qemu_irq      err_irq);

You've got stuff in this file that isn't properly namespaced for
inclusion by arbitrary QEMU code (especially board code that needs to
include headers for several devices), such as REG_NUMBER, yet you declare
etsec_create here which has to be called from board code.

> +#ifdef ETSEC_RING_DEBUG
> +#define RING_DEBUG(fmt, ...) printf("%s:%s " fmt, __func__ ,\
> +                                    etsec->nic->nc.name, ## __VA_ARGS__)
> +#else
> +#define RING_DEBUG(...)
> +#endif  /* ETSEC_RING_DEBUG */

Please consume the arguments even if debug output is not enabled (so you
don't get unused variable warnings), and ideally do a printf inside an
if-statement (on a constant so it will be optimized away) so you still
get format checking -- again, similar to DPRINTF in hw/intc/openpic.c.

> +#define RING_DEBUG_A(fmt, ...) printf("%s:%s " fmt, __func__ ,\
> +                                      etsec->nic->nc.name, ## __VA_ARGS__)

"A"?

If this means "always", why not define RING_DEBUG in terms of this?

> +#ifdef HEX_DUMP
> +
> +static void hex_dump(FILE *f, const uint8_t *buf, int size)
> +{
> +    int len, i, j, c;
> +
> +    for (i = 0; i < size; i += 16) {
> +        len = size - i;
> +        if (len > 16) {
> +            len = 16;
> +        }
> +        fprintf(f, "%08x ", i);
> +        for (j = 0; j < 16; j++) {
> +            if (j < len) {
> +                fprintf(f, " %02x", buf[i + j]);
> +            } else {
> +                fprintf(f, "   ");
> +            }
> +        }
> +        fprintf(f, " ");
> +        for (j = 0; j < len; j++) {
> +            c = buf[i + j];
> +            if (c < ' ' || c > '~') {
> +                c = '.';
> +            }
> +            fprintf(f, "%c", c);
> +        }
> +        fprintf(f, "\n");
> +    }
> +}
> +
> +#endif

Two instances of this even in the same driver?

> +static void fill_rx_bd(eTSEC          *etsec,
> +                       eTSEC_rxtx_bd  *bd,
> +                       const uint8_t **buf,
> +                       size_t         *size)
> +{
> +    uint16_t to_write = MIN(etsec->rx_fcb_size + *size - etsec->rx_padding,
> +                            etsec->regs[MRBLR].value);
> +    uint32_t bufptr   = bd->bufptr;
> +    uint8_t  padd[etsec->rx_padding];
> +    uint8_t  rem;
> +
> +    RING_DEBUG("eTSEC fill Rx buffer @ 0x%08x"
> +               " size:%u(padding + crc:%u) + fcb:%u\n",
> +               bufptr, *size, etsec->rx_padding, etsec->rx_fcb_size);
> +
> +    bd->length = 0;
> +    if (etsec->rx_fcb_size != 0) {
> +        cpu_physical_memory_write(bufptr, etsec->rx_fcb, etsec->rx_fcb_size);
> +
> +        bufptr             += etsec->rx_fcb_size;
> +        bd->length         += etsec->rx_fcb_size;
> +        to_write           -= etsec->rx_fcb_size;
> +        etsec->rx_fcb_size  = 0;
> +
> +    }
> +
> +    if (to_write > 0) {
> +        cpu_physical_memory_write(bufptr, *buf, to_write);
> +
> +        *buf   += to_write;
> +        bufptr += to_write;
> +        *size  -= to_write;
> +
> +        bd->flags  &= ~BD_RX_EMPTY;
> +        bd->length += to_write;
> +    }
> +
> +    if (*size == etsec->rx_padding) {
> +        /* The remaining bytes are for padding which is not actually allocated
> +           in the buffer */
> +
> +        rem = MIN(etsec->regs[MRBLR].value - bd->length, etsec->rx_padding);
> +
> +        if (rem > 0) {
> +            memset(padd, 0x0, sizeof(padd));
> +            etsec->rx_padding -= rem;
> +            *size             -= rem;
> +            bd->length        += rem;
> +            cpu_physical_memory_write(bufptr, padd, rem);
> +        }
> +    }

What if *size > 0 && *size < etsec->rx_padding?

> +static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size)
> +{
> +    uint32_t fcb_size = 0;
> +    uint8_t  prsdep   = (etsec->regs[RCTRL].value >> RCTRL_PRSDEP_OFFSET)
> +        & RCTRL_PRSDEP_MASK;
> +
> +    if (prsdep != 0) {
> +        /* Prepend FCB */
> +        fcb_size = 8 + 2;          /* FCB size + align */
> +        /* I can't find this 2 bytes alignement in fsl documentation but VxWorks
> +           expects them */

Could these 2 bytes be from RCTRL[PAD], which you seem to ignore?

> +    etsec->rx_padding    = 4;
> +    if (size < 60) {
> +        etsec->rx_padding += 60 - size;
> +    }

Could you explain what you're doing with rx_padding?

> +    /* ring_base = (etsec->regs[RBASEH].value & 0xF) << 32; */
> +    ring_base     += etsec->regs[RBASE0 + ring_nbr].value & ~0x7;
> +    start_bd_addr  = bd_addr = etsec->regs[RBPTR0 + ring_nbr].value & ~0x7;

What about RBDBPH (upper bits of physical address)?  Likewise for TX.

> +                /* NOTE: non-octet aligned frame is impossible in qemu */

Is it possible in eTSEC?

-Scott

  parent reply	other threads:[~2013-07-16  2:06 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-07-10 17:10 [Qemu-devel] [PATCH 0/2] Enhanced Three Speed Ethernet Controller (eTSEC) Fabien Chouteau
2013-07-10 17:10 ` [Qemu-devel] [PATCH 1/2] Add be16_to_cpupu function Fabien Chouteau
2013-07-10 17:25   ` Peter Maydell
2013-07-12  9:57     ` Fabien Chouteau
2013-07-10 17:10 ` [Qemu-devel] [PATCH 2/2] Add Enhanced Three-Speed Ethernet Controller (eTSEC) Fabien Chouteau
     [not found]   ` <201307110955092430409@cn.fujitsu.com>
2013-07-15  1:25     ` [Qemu-devel] Fw: [PATCH 2/2] Add Enhanced Three-Speed EthernetController (eTSEC) Yao Xingtao
2013-07-15 10:19       ` Fabien Chouteau
2013-07-15  2:00   ` [Qemu-devel] [PATCH 2/2] Add Enhanced Three-Speed Ethernet Controller (eTSEC) Peter Crosthwaite
2013-07-15 14:23     ` Fabien Chouteau
2013-07-16  1:06       ` Peter Crosthwaite
2013-07-16  8:35         ` Fabien Chouteau
2013-07-16  2:06   ` Scott Wood [this message]
2013-07-16 15:28     ` [Qemu-devel] [Qemu-ppc] " Fabien Chouteau
2013-07-16 15:37       ` Alexander Graf
2013-07-16 16:15         ` Fabien Chouteau
2013-07-16 16:54           ` Scott Wood
2013-07-17  8:24             ` Fabien Chouteau
2013-07-17  8:29               ` Alexander Graf
2013-07-17 10:27                 ` Fabien Chouteau
2013-07-16 17:50       ` Scott Wood
2013-07-17 10:17         ` Fabien Chouteau
2013-07-17 10:22           ` Alexander Graf
2013-07-17 10:43             ` Fabien Chouteau
2013-07-17 21:02           ` Scott Wood
2013-07-18  9:27             ` Fabien Chouteau
2013-07-18 20:37               ` Scott Wood
2013-07-19  9:22                 ` Fabien Chouteau
2013-07-19 17:19                   ` Scott Wood
2013-07-22  9:00                     ` Fabien Chouteau

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20130716020617.GA22542@home.buserror.net \
    --to=scottwood@freescale.com \
    --cc=chouteau@adacore.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    /path/to/YOUR_REPLY

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

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.