From: Beniamino Galvani <b.galvani@gmail.com>
To: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Cc: Peter Maydell <peter.maydell@linaro.org>,
"qemu-devel@nongnu.org Developers" <qemu-devel@nongnu.org>,
Li Guang <lig.fnst@cn.fujitsu.com>,
Stefan Hajnoczi <stefanha@gmail.com>
Subject: Re: [Qemu-devel] [PATCH v3 1/2] hw/net: add support for Allwinner EMAC Fast Ethernet controller
Date: Sat, 25 Jan 2014 14:37:12 +0100 [thread overview]
Message-ID: <20140125133711.GA15341@gmail.com> (raw)
In-Reply-To: <CAEgOgz4_SnLwaSvkx+VKRNfbYbL1FYq14wZUJq_pNb2_-7PL2w@mail.gmail.com>
On Thu, Jan 23, 2014 at 11:04:32PM +1000, Peter Crosthwaite wrote:
> On Mon, Jan 20, 2014 at 9:25 AM, Beniamino Galvani <b.galvani@gmail.com> wrote:
> > This patch adds support for the Fast Ethernet MAC found on Allwinner
> > SoCs, together with a basic emulation of Realtek RTL8201CP PHY.
> >
> > Since there is no public documentation of the Allwinner controller, the
> > implementation is based on Linux kernel driver.
> >
> > Signed-off-by: Beniamino Galvani <b.galvani@gmail.com>
> > ---
> > default-configs/arm-softmmu.mak | 1 +
> > hw/net/Makefile.objs | 1 +
> > hw/net/allwinner_emac.c | 589 +++++++++++++++++++++++++++++++++++++++
> > include/hw/net/allwinner_emac.h | 222 +++++++++++++++
> > 4 files changed, 813 insertions(+)
> > create mode 100644 hw/net/allwinner_emac.c
> > create mode 100644 include/hw/net/allwinner_emac.h
> >
> > diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> > index ce1d620..f3513fa 100644
> > --- a/default-configs/arm-softmmu.mak
> > +++ b/default-configs/arm-softmmu.mak
> > @@ -27,6 +27,7 @@ CONFIG_SSI_SD=y
> > CONFIG_SSI_M25P80=y
> > CONFIG_LAN9118=y
> > CONFIG_SMC91C111=y
> > +CONFIG_ALLWINNER_EMAC=y
> > CONFIG_DS1338=y
> > CONFIG_PFLASH_CFI01=y
> > CONFIG_PFLASH_CFI02=y
> > diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
> > index 951cca3..75e80c2 100644
> > --- a/hw/net/Makefile.objs
> > +++ b/hw/net/Makefile.objs
> > @@ -18,6 +18,7 @@ common-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o
> > common-obj-$(CONFIG_XGMAC) += xgmac.o
> > common-obj-$(CONFIG_MIPSNET) += mipsnet.o
> > common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
> > +common-obj-$(CONFIG_ALLWINNER_EMAC) += allwinner_emac.o
> >
> > common-obj-$(CONFIG_CADENCE) += cadence_gem.o
> > common-obj-$(CONFIG_STELLARIS_ENET) += stellaris_enet.o
> > diff --git a/hw/net/allwinner_emac.c b/hw/net/allwinner_emac.c
> > new file mode 100644
> > index 0000000..4cad7e0
> > --- /dev/null
> > +++ b/hw/net/allwinner_emac.c
> > @@ -0,0 +1,589 @@
> > +/*
> > + * Emulation of Allwinner EMAC Fast Ethernet controller and
> > + * Realtek RTL8201CP PHY
> > + *
> > + * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + */
> > +#include "hw/sysbus.h"
> > +#include "net/net.h"
> > +#include "hw/net/allwinner_emac.h"
> > +#include <zlib.h>
> > +
> > +static uint8_t padding[60];
> > +
> > +static void mii_set_link(RTL8201CPState *mii, bool link_ok)
> > +{
> > + if (link_ok) {
> > + mii->bmsr |= MII_BMSR_LINK_ST;
> > + mii->anlpar |= MII_ANAR_TXFD | MII_ANAR_10FD | MII_ANAR_10 |
> > + MII_ANAR_CSMACD;
> > + } else {
> > + mii->bmsr &= ~MII_BMSR_LINK_ST;
> > + mii->anlpar = MII_ANAR_TX;
> > + }
> > +}
> > +
> > +static void mii_reset(RTL8201CPState *mii, bool link_ok)
> > +{
> > + mii->bmcr = MII_BMCR_FD | MII_BMCR_AUTOEN | MII_BMCR_SPEED;
> > + mii->bmsr = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD |
> > + MII_BMSR_10T_HD | MII_BMSR_MFPS | MII_BMSR_AUTONEG;
> > + mii->anar = MII_ANAR_TXFD | MII_ANAR_TX | MII_ANAR_10FD | MII_ANAR_10 |
> > + MII_ANAR_CSMACD;
> > + mii->anlpar = MII_ANAR_TX;
> > +
> > + mii_set_link(mii, link_ok);
> > +}
> > +
> > +static uint16_t aw_emac_mdio_read(AwEmacState *s, uint8_t addr, uint8_t reg)
>
> Drop the AW reference here (replace with "RTL8201").
>
> > +{
> > + RTL8201CPState *mii = &s->mii;
> > + uint16_t ret = 0xffff;
> > +
> > + if (addr == s->phy_addr) {
> > + switch (reg) {
> > + case MII_BMCR:
> > + return mii->bmcr;
> > + case MII_BMSR:
> > + return mii->bmsr;
> > + case MII_PHYID1:
> > + return RTL8201CP_PHYID1;
> > + case MII_PHYID2:
> > + return RTL8201CP_PHYID2;
> > + case MII_ANAR:
> > + return mii->anar;
> > + case MII_ANLPAR:
> > + return mii->anlpar;
> > + case MII_ANER:
> > + case MII_NSR:
> > + case MII_LBREMR:
> > + case MII_REC:
> > + case MII_SNRDR:
> > + case MII_TEST:
> > + qemu_log_mask(LOG_UNIMP,
> > + "allwinner_emac: read from unimpl. mii reg 0x%x\n",
> > + reg);
> > + return 0;
> > + default:
> > + qemu_log_mask(LOG_GUEST_ERROR,
> > + "allwinner_emac: read from invalid mii reg 0x%x\n",
> > + reg);
> > + return 0;
> > + }
> > + }
> > + return ret;
> > +}
> > +
> > +static void aw_emac_mdio_write(AwEmacState *s, uint8_t addr, uint8_t reg,
> > + uint16_t value)
> > +{
> > + RTL8201CPState *mii = &s->mii;
> > + NetClientState *nc;
> > +
> > + if (addr == s->phy_addr) {
> > + switch (reg) {
> > + case MII_BMCR:
> > + if (value & MII_BMCR_RESET) {
> > + nc = qemu_get_queue(s->nic);
> > + mii_reset(mii, !nc->link_down);
> > + } else {
> > + mii->bmcr = value;
> > + }
> > + break;
> > + case MII_ANAR:
> > + mii->anar = value;
> > + break;
> > + case MII_BMSR:
> > + case MII_PHYID1:
> > + case MII_PHYID2:
> > + case MII_ANLPAR:
> > + case MII_ANER:
> > + qemu_log_mask(LOG_GUEST_ERROR,
> > + "allwinner_emac: write to read-only mii reg 0x%x\n",
> > + reg);
> > + break;
>
> Theres plenty of precedent for not bothering making the distinction
> between read_only and out of range if you just want to collapse into
> the one GUEST_ERROR message. Either way though.
>
> > + case MII_NSR:
> > + case MII_LBREMR:
> > + case MII_REC:
> > + case MII_SNRDR:
> > + case MII_TEST:
> > + qemu_log_mask(LOG_UNIMP,
> > + "allwinner_emac: write to unimpl. mii reg 0x%x\n",
> > + reg);
> > + break;
> > + default:
> > + qemu_log_mask(LOG_GUEST_ERROR,
> > + "allwinner_emac: write to invalid mii reg 0x%x\n",
> > + reg);
> > + }
> > + }
> > +}
> > +
> > +static void aw_emac_update_irq(AwEmacState *s)
> > +{
> > + qemu_set_irq(s->irq, (s->int_sta & s->int_ctl) != 0);
> > +}
> > +
> > +static void aw_emac_tx_reset(AwEmacTxFifo *fifo)
> > +{
> > + fifo->length = 0;
> > + fifo->offset = 0;
> > +}
> > +
> > +static int aw_emac_tx_has_space(AwEmacTxFifo *fifo, int n)
> > +{
> > + return fifo->offset + n <= TX_FIFO_SIZE;
> > +}
> > +
> > +static void aw_emac_tx_pushw(AwEmacTxFifo *fifo, uint32_t val)
> > +{
> > + assert(fifo->offset + 4 <= TX_FIFO_SIZE);
> > + fifo->data[fifo->offset++] = val;
> > + fifo->data[fifo->offset++] = val >> 8;
> > + fifo->data[fifo->offset++] = val >> 16;
> > + fifo->data[fifo->offset++] = val >> 24;
> > +}
> > +
> > +static void aw_emac_rx_reset(AwEmacRxFifo *fifo)
> > +{
> > + fifo->head = 0;
> > + fifo->num = 0;
> > + fifo->num_packets = 0;
> > + fifo->packet_size = 0;
> > + fifo->packet_pos = 0;
> > +}
> > +
> > +static int aw_emac_rx_has_space(AwEmacRxFifo *fifo, int n)
> > +{
> > + return fifo->num + n <= RX_FIFO_SIZE;
> > +}
> > +
> > +static void aw_emac_rx_push(AwEmacRxFifo *fifo, const uint8_t *data, int size)
>
> This is pretty much exactly the proposed addition to the fifo API to
> solve the no-buffer-write incompletness. I'm happy to ACK a patch to
> that API with this implementation, especially if it means you can
> collapse use for the rx fifo here to save on the ring-buffer
> boilerplate.
Should I base the patch on top of your proposed generalisation to
different element widths or on current master?
>
> > +{
> > + int index;
> > +
> > + assert(fifo->num + size <= RX_FIFO_SIZE);
> > + index = (fifo->head + fifo->num) % RX_FIFO_SIZE;
> > +
> > + if (index + size <= RX_FIFO_SIZE) {
> > + memcpy(&fifo->data[index], data, size);
> > + } else {
> > + memcpy(&fifo->data[index], data, RX_FIFO_SIZE - index);
> > + memcpy(&fifo->data[0], &data[RX_FIFO_SIZE - index],
> > + size - RX_FIFO_SIZE + index);
> > + }
> > +
> > + fifo->num += size;
> > +}
> > +
> > +static void aw_emac_rx_pushb(AwEmacRxFifo *fifo, uint8_t val)
> > +{
> > + return aw_emac_rx_push(fifo, &val, 1);
> > +}
> > +
> > +static void aw_emac_rx_pushw(AwEmacRxFifo *fifo, uint32_t val)
> > +{
> > + aw_emac_rx_pushb(fifo, val);
> > + aw_emac_rx_pushb(fifo, val >> 8);
> > + aw_emac_rx_pushb(fifo, val >> 16);
> > + aw_emac_rx_pushb(fifo, val >> 24);
> > +}
> > +
> > +static uint8_t aw_emac_rx_popb(AwEmacRxFifo *fifo)
> > +{
> > + uint8_t ret;
> > +
> > + assert(fifo->num > 0);
> > + ret = fifo->data[fifo->head];
> > + fifo->head = (fifo->head + 1) % RX_FIFO_SIZE;
> > + fifo->num--;
> > +
> > + return ret;
> > +}
> > +
> > +static uint32_t aw_emac_rx_popw(AwEmacRxFifo *fifo)
> > +{
> > + uint32_t ret;
> > +
> > + ret = aw_emac_rx_popb(fifo);
> > + ret |= aw_emac_rx_popb(fifo) << 8;
> > + ret |= aw_emac_rx_popb(fifo) << 16;
> > + ret |= aw_emac_rx_popb(fifo) << 24;
> > +
> > + return ret;
> > +}
> > +
> > +static int aw_emac_can_receive(NetClientState *nc)
> > +{
> > + AwEmacState *s = qemu_get_nic_opaque(nc);
> > +
> > + return s->ctl & EMAC_CTL_RX_EN;
>
> So I'm not a fan of ethernets that just drop all packets on a full
> fifo (they tend to have very poor tftp performance esp. when using
> u-boot as a guest). Since we completely fabricated the size of the rx
> fifo (due to no specs), you could just make a conservative assumption
> that you need a full frames-worth of space spare before you accept a
> packet of any size. There simple is no known or specified behaviour to
> preserve here WRT to fifo occupancy, so having some form of fifo-full
> awareness will at least give you good performance.
Ok, I will add this check in next version.
Beniamino
next prev parent reply other threads:[~2014-01-25 13:38 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-01-19 23:25 [Qemu-devel] [PATCH v3 0/2] hw/arm: add ethernet support to Allwinner A10 Beniamino Galvani
2014-01-19 23:25 ` [Qemu-devel] [PATCH v3 1/2] hw/net: add support for Allwinner EMAC Fast Ethernet controller Beniamino Galvani
2014-01-23 13:04 ` Peter Crosthwaite
2014-01-25 13:37 ` Beniamino Galvani [this message]
2014-01-25 23:58 ` Peter Crosthwaite
2014-01-19 23:25 ` [Qemu-devel] [PATCH v3 2/2] hw/arm/allwinner-a10: initialize EMAC Beniamino Galvani
2014-01-23 13:06 ` Peter Crosthwaite
2014-01-25 23:42 ` Andreas Färber
2014-01-26 21:25 ` Beniamino Galvani
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=20140125133711.GA15341@gmail.com \
--to=b.galvani@gmail.com \
--cc=lig.fnst@cn.fujitsu.com \
--cc=peter.crosthwaite@xilinx.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.