Patchwork [1/3] net/bitbang_mdio: Generalize etraxfs MDIO bitbanging emulation

login
register
mail settings
Submitter Grant Likely
Date Jan. 19, 2013, 10:28 p.m.
Message ID <1358634492-22627-2-git-send-email-grant.likely@secretlab.ca>
Download mbox | patch
Permalink /patch/213892/
State New
Headers show

Comments

Grant Likely - Jan. 19, 2013, 10:28 p.m.
The etraxfs Ethernet model implements quite a nice bitbanging core. The
change splits it out into a separate .c file. There are no functional
changes here, just movement of code and reformatting to match qemu
coding standards.

Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Paul Brook <paul@codesourcery.com>
Cc: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---
 hw/bitbang_mdio.c     |  263 +++++++++++++++++++++++++++++++++++++++++++++++
 hw/bitbang_mdio.h     |   72 +++++++++++++
 hw/cris/Makefile.objs |    1 +
 hw/etraxfs_eth.c      |  273 +------------------------------------------------
 4 files changed, 337 insertions(+), 272 deletions(-)
 create mode 100644 hw/bitbang_mdio.c
 create mode 100644 hw/bitbang_mdio.h
Andreas Färber - Jan. 20, 2013, 5:29 p.m.
Am 19.01.2013 23:28, schrieb Grant Likely:
> The etraxfs Ethernet model implements quite a nice bitbanging core. The
> change splits it out into a separate .c file. There are no functional
> changes here, just movement of code and reformatting to match qemu
> coding standards.
> 
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Paul Brook <paul@codesourcery.com>
> Cc: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> Cc: Anthony Liguori <aliguori@us.ibm.com>
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>  hw/bitbang_mdio.c     |  263 +++++++++++++++++++++++++++++++++++++++++++++++
>  hw/bitbang_mdio.h     |   72 +++++++++++++
>  hw/cris/Makefile.objs |    1 +
>  hw/etraxfs_eth.c      |  273 +------------------------------------------------
>  4 files changed, 337 insertions(+), 272 deletions(-)
>  create mode 100644 hw/bitbang_mdio.c
>  create mode 100644 hw/bitbang_mdio.h

If you fix coding style issues in the original file first this helps
git's copy detection. Looks like either you have it disabled for patches
or it's not detecting it at all... I would expect some "similarity N%"
notice.

Cheers,
Andreas
Edgar Iglesias - Jan. 21, 2013, 12:51 p.m.
On Sat, Jan 19, 2013 at 06:28:10PM -0400, Grant Likely wrote:
> The etraxfs Ethernet model implements quite a nice bitbanging core. The
> change splits it out into a separate .c file. There are no functional
> changes here, just movement of code and reformatting to match qemu
> coding standards.

Hi Grant!

It makes sense to move it out.

A few comments:
* Maybe we could separate the phy models from the bus model/infrastructure.
I.e, the qemu_mdio parts into one file and the qemu_phy into another one.
That way we can add other phy models and keep things separated.

* Not sure bitbang_ makes sense in the naming, the abstraction supports
both the bit twiddeling model with MDIO cycles but also a higher level
transactional version (mdio_write_req etc) that bypass the cycle accuracy.
The latter is useful for modeling NICs that have MDIO support in hw, e.g
like the hw/xilinx_axienet.c while beeing able to reuse the PHY models.

I realize I should have done this split when doing the axienet model, sorry..

Best regards,
Edgar


> 
> Cc: Peter Maydell <peter.maydell@linaro.org>
> Cc: Paul Brook <paul@codesourcery.com>
> Cc: Edgar E. Iglesias <edgar.iglesias@gmail.com>
> Cc: Anthony Liguori <aliguori@us.ibm.com>
> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
> ---
>  hw/bitbang_mdio.c     |  263 +++++++++++++++++++++++++++++++++++++++++++++++
>  hw/bitbang_mdio.h     |   72 +++++++++++++
>  hw/cris/Makefile.objs |    1 +
>  hw/etraxfs_eth.c      |  273 +------------------------------------------------
>  4 files changed, 337 insertions(+), 272 deletions(-)
>  create mode 100644 hw/bitbang_mdio.c
>  create mode 100644 hw/bitbang_mdio.h
> 
> diff --git a/hw/bitbang_mdio.c b/hw/bitbang_mdio.c
> new file mode 100644
> index 0000000..f0ee6af
> --- /dev/null
> +++ b/hw/bitbang_mdio.c
> @@ -0,0 +1,263 @@
> +/*
> + * QEMU Bitbang Ethernet MDIO bus & PHY controllers.
> + *
> + * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
> + *
> + * 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 <stdio.h>
> +#include "qemu-common.h"
> +#include "qemu/log.h"
> +#include "bitbang_mdio.h"
> +
> +#define D(x)
> +
> +/* Advertisement control register. */
> +#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
> +#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
> +#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
> +#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
> +
> +/*
> + * The MDIO extensions in the TDK PHY model were reversed engineered from the
> + * linux driver (PHYID and Diagnostics reg).
> + * TODO: Add friendly names for the register nums.
> + */
> +static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
> +{
> +    int regnum;
> +    unsigned r = 0;
> +
> +    regnum = req & 0x1f;
> +
> +    switch (regnum) {
> +    case 1:
> +        if (!phy->link) {
> +            break;
> +        }
> +        /* MR1.     */
> +        /* Speeds and modes.  */
> +        r |= (1 << 13) | (1 << 14);
> +        r |= (1 << 11) | (1 << 12);
> +        r |= (1 << 5); /* Autoneg complete.  */
> +        r |= (1 << 3); /* Autoneg able.     */
> +        r |= (1 << 2); /* link.     */
> +        break;
> +    case 5:
> +        /* Link partner ability.
> +           We are kind; always agree with whatever best mode
> +           the guest advertises.  */
> +        r = 1 << 14; /* Success.  */
> +        /* Copy advertised modes.  */
> +        r |= phy->regs[4] & (15 << 5);
> +        /* Autoneg support.  */
> +        r |= 1;
> +        break;
> +    case 18:
> +    {
> +        /* Diagnostics reg.  */
> +        int duplex = 0;
> +        int speed_100 = 0;
> +
> +        if (!phy->link) {
> +            break;
> +        }
> +
> +        /* Are we advertising 100 half or 100 duplex ? */
> +        speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
> +        speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
> +
> +        /* Are we advertising 10 duplex or 100 duplex ? */
> +        duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
> +        duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
> +        r = (speed_100 << 10) | (duplex << 11);
> +    }
> +    break;
> +
> +    default:
> +        r = phy->regs[regnum];
> +        break;
> +    }
> +    D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
> +    return r;
> +}
> +
> +static void tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
> +{
> +    int regnum;
> +
> +    regnum = req & 0x1f;
> +    D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
> +    switch (regnum) {
> +    default:
> +        phy->regs[regnum] = data;
> +        break;
> +    }
> +}
> +
> +void tdk_init(struct qemu_phy *phy)
> +{
> +    phy->regs[0] = 0x3100;
> +    /* PHY Id. */
> +    phy->regs[2] = 0x0300;
> +    phy->regs[3] = 0xe400;
> +    /* Autonegotiation advertisement reg. */
> +    phy->regs[4] = 0x01e1;
> +    phy->link = 1;
> +
> +    phy->read = tdk_read;
> +    phy->write = tdk_write;
> +}
> +
> +void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
> +{
> +    bus->devs[addr & 0x1f] = phy;
> +}
> +
> +#ifdef USE_THIS_DEAD_CODE
> +void mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
> +{
> +    bus->devs[addr & 0x1f] = NULL;
> +}
> +#endif
> +
> +void mdio_read_req(struct qemu_mdio *bus)
> +{
> +    struct qemu_phy *phy;
> +
> +    phy = bus->devs[bus->addr];
> +    if (phy && phy->read) {
> +        bus->data = phy->read(phy, bus->req);
> +    } else {
> +        bus->data = 0xffff;
> +    }
> +    D(qemu_log("%s addr=%d reg=%d data=%x\n", __func__,
> +               bus->addr, bus->req, bus->data));
> +}
> +
> +void mdio_write_req(struct qemu_mdio *bus)
> +{
> +    struct qemu_phy *phy;
> +
> +    phy = bus->devs[bus->addr];
> +    if (phy && phy->write) {
> +        phy->write(phy, bus->req, bus->data);
> +    }
> +}
> +
> +void mdio_cycle(struct qemu_mdio *bus)
> +{
> +    bus->cnt++;
> +
> +    D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
> +             bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
> +    switch (bus->state) {
> +    case PREAMBLE:
> +        if (bus->mdc) {
> +            if (bus->cnt >= (32 * 2) && !bus->mdio) {
> +                bus->cnt = 0;
> +                bus->state = SOF;
> +                bus->data = 0;
> +            }
> +        }
> +        break;
> +    case SOF:
> +        if (bus->mdc) {
> +            if (bus->mdio != 1) {
> +                printf("WARNING: no SOF\n");
> +            }
> +            if (bus->cnt == 1*2) {
> +                bus->cnt = 0;
> +                bus->opc = 0;
> +                bus->state = OPC;
> +            }
> +        }
> +        break;
> +    case OPC:
> +        if (bus->mdc) {
> +            bus->opc <<= 1;
> +            bus->opc |= bus->mdio & 1;
> +            if (bus->cnt == 2*2) {
> +                bus->cnt = 0;
> +                bus->addr = 0;
> +                bus->state = ADDR;
> +            }
> +        }
> +        break;
> +    case ADDR:
> +        if (bus->mdc) {
> +            bus->addr <<= 1;
> +            bus->addr |= bus->mdio & 1;
> +
> +            if (bus->cnt == 5*2) {
> +                bus->cnt = 0;
> +                bus->req = 0;
> +                bus->state = REQ;
> +            }
> +        }
> +        break;
> +    case REQ:
> +        if (bus->mdc) {
> +            bus->req <<= 1;
> +            bus->req |= bus->mdio & 1;
> +            if (bus->cnt == 5*2) {
> +                bus->cnt = 0;
> +                bus->state = TURNAROUND;
> +            }
> +        }
> +        break;
> +    case TURNAROUND:
> +        if (bus->mdc && bus->cnt == 2*2) {
> +            bus->mdio = 0;
> +            bus->cnt = 0;
> +
> +            if (bus->opc == 2) {
> +                bus->drive = 1;
> +                mdio_read_req(bus);
> +                bus->mdio = bus->data & 1;
> +            }
> +            bus->state = DATA;
> +        }
> +        break;
> +    case DATA:
> +        if (!bus->mdc) {
> +            if (bus->drive) {
> +                bus->mdio = !!(bus->data & (1 << 15));
> +                bus->data <<= 1;
> +            }
> +        } else {
> +            if (!bus->drive) {
> +                bus->data <<= 1;
> +                bus->data |= bus->mdio;
> +            }
> +            if (bus->cnt == 16 * 2) {
> +                bus->cnt = 0;
> +                bus->state = PREAMBLE;
> +                if (!bus->drive) {
> +                    mdio_write_req(bus);
> +                }
> +                bus->drive = 0;
> +            }
> +        }
> +        break;
> +    default:
> +        break;
> +    }
> +}
> diff --git a/hw/bitbang_mdio.h b/hw/bitbang_mdio.h
> new file mode 100644
> index 0000000..3484aba
> --- /dev/null
> +++ b/hw/bitbang_mdio.h
> @@ -0,0 +1,72 @@
> +#ifndef BITBANG_MDIO_H
> +#define BITBANG_MDIO_H
> +
> +/*
> + * QEMU Bitbang Ethernet MDIO bus & PHY controllers.
> + *
> + * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
> + *
> + * 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 <stdint.h>
> +
> +struct qemu_phy {
> +    uint32_t regs[32];
> +
> +    int link;
> +
> +    unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
> +    void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
> +};
> +
> +struct qemu_mdio {
> +    /* bus. */
> +    int mdc;
> +    int mdio;
> +
> +    /* decoder.  */
> +    enum {
> +        PREAMBLE,
> +        SOF,
> +        OPC,
> +        ADDR,
> +        REQ,
> +        TURNAROUND,
> +        DATA
> +    } state;
> +    unsigned int drive;
> +
> +    unsigned int cnt;
> +    unsigned int addr;
> +    unsigned int opc;
> +    unsigned int req;
> +    unsigned int data;
> +
> +    struct qemu_phy *devs[32];
> +};
> +
> +void tdk_init(struct qemu_phy *phy);
> +void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy,
> +                 unsigned int addr);
> +void mdio_read_req(struct qemu_mdio *bus);
> +void mdio_write_req(struct qemu_mdio *bus);
> +void mdio_cycle(struct qemu_mdio *bus);
> +
> +#endif
> diff --git a/hw/cris/Makefile.objs b/hw/cris/Makefile.objs
> index aa9298a..86759a3 100644
> --- a/hw/cris/Makefile.objs
> +++ b/hw/cris/Makefile.objs
> @@ -9,5 +9,6 @@ obj-y += etraxfs_pic.o
>  obj-y += etraxfs_eth.o
>  obj-y += etraxfs_timer.o
>  obj-y += etraxfs_ser.o
> +obj-y += bitbang_mdio.o
>  
>  obj-y := $(addprefix ../,$(obj-y))
> diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
> index ec23fa6..67b4797 100644
> --- a/hw/etraxfs_eth.c
> +++ b/hw/etraxfs_eth.c
> @@ -26,281 +26,10 @@
>  #include "sysbus.h"
>  #include "net/net.h"
>  #include "etraxfs.h"
> +#include "bitbang_mdio.h"
>  
>  #define D(x)
>  
> -/* Advertisement control register. */
> -#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
> -#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
> -#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
> -#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
> -
> -/* 
> - * The MDIO extensions in the TDK PHY model were reversed engineered from the 
> - * linux driver (PHYID and Diagnostics reg).
> - * TODO: Add friendly names for the register nums.
> - */
> -struct qemu_phy
> -{
> -	uint32_t regs[32];
> -
> -	int link;
> -
> -	unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
> -	void (*write)(struct qemu_phy *phy, unsigned int req, 
> -		      unsigned int data);
> -};
> -
> -static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
> -{
> -	int regnum;
> -	unsigned r = 0;
> -
> -	regnum = req & 0x1f;
> -
> -	switch (regnum) {
> -		case 1:
> -			if (!phy->link)
> -				break;
> -			/* MR1.	 */
> -			/* Speeds and modes.  */
> -			r |= (1 << 13) | (1 << 14);
> -			r |= (1 << 11) | (1 << 12);
> -			r |= (1 << 5); /* Autoneg complete.  */
> -			r |= (1 << 3); /* Autoneg able.	 */
> -			r |= (1 << 2); /* link.	 */
> -			break;
> -		case 5:
> -			/* Link partner ability.
> -			   We are kind; always agree with whatever best mode
> -			   the guest advertises.  */
> -			r = 1 << 14; /* Success.  */
> -			/* Copy advertised modes.  */
> -			r |= phy->regs[4] & (15 << 5);
> -			/* Autoneg support.  */
> -			r |= 1;
> -			break;
> -		case 18:
> -		{
> -			/* Diagnostics reg.  */
> -			int duplex = 0;
> -			int speed_100 = 0;
> -
> -			if (!phy->link)
> -				break;
> -
> -			/* Are we advertising 100 half or 100 duplex ? */
> -			speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
> -			speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
> -
> -			/* Are we advertising 10 duplex or 100 duplex ? */
> -			duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
> -			duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
> -			r = (speed_100 << 10) | (duplex << 11);
> -		}
> -		break;
> -
> -		default:
> -			r = phy->regs[regnum];
> -			break;
> -	}
> -	D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
> -	return r;
> -}
> -
> -static void 
> -tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
> -{
> -	int regnum;
> -
> -	regnum = req & 0x1f;
> -	D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
> -	switch (regnum) {
> -		default:
> -			phy->regs[regnum] = data;
> -			break;
> -	}
> -}
> -
> -static void 
> -tdk_init(struct qemu_phy *phy)
> -{
> -	phy->regs[0] = 0x3100;
> -	/* PHY Id.  */
> -	phy->regs[2] = 0x0300;
> -	phy->regs[3] = 0xe400;
> -	/* Autonegotiation advertisement reg.  */
> -	phy->regs[4] = 0x01E1;
> -	phy->link = 1;
> -
> -	phy->read = tdk_read;
> -	phy->write = tdk_write;
> -}
> -
> -struct qemu_mdio
> -{
> -	/* bus.	 */
> -	int mdc;
> -	int mdio;
> -
> -	/* decoder.  */
> -	enum {
> -		PREAMBLE,
> -		SOF,
> -		OPC,
> -		ADDR,
> -		REQ,
> -		TURNAROUND,
> -		DATA
> -	} state;
> -	unsigned int drive;
> -
> -	unsigned int cnt;
> -	unsigned int addr;
> -	unsigned int opc;
> -	unsigned int req;
> -	unsigned int data;
> -
> -	struct qemu_phy *devs[32];
> -};
> -
> -static void 
> -mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
> -{
> -	bus->devs[addr & 0x1f] = phy;
> -}
> -
> -#ifdef USE_THIS_DEAD_CODE
> -static void 
> -mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
> -{
> -	bus->devs[addr & 0x1f] = NULL;	
> -}
> -#endif
> -
> -static void mdio_read_req(struct qemu_mdio *bus)
> -{
> -	struct qemu_phy *phy;
> -
> -	phy = bus->devs[bus->addr];
> -	if (phy && phy->read)
> -		bus->data = phy->read(phy, bus->req);
> -	else 
> -		bus->data = 0xffff;
> -}
> -
> -static void mdio_write_req(struct qemu_mdio *bus)
> -{
> -	struct qemu_phy *phy;
> -
> -	phy = bus->devs[bus->addr];
> -	if (phy && phy->write)
> -		phy->write(phy, bus->req, bus->data);
> -}
> -
> -static void mdio_cycle(struct qemu_mdio *bus)
> -{
> -	bus->cnt++;
> -
> -	D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
> -		bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
> -#if 0
> -	if (bus->mdc)
> -		printf("%d", bus->mdio);
> -#endif
> -	switch (bus->state)
> -	{
> -		case PREAMBLE:
> -			if (bus->mdc) {
> -				if (bus->cnt >= (32 * 2) && !bus->mdio) {
> -					bus->cnt = 0;
> -					bus->state = SOF;
> -					bus->data = 0;
> -				}
> -			}
> -			break;
> -		case SOF:
> -			if (bus->mdc) {
> -				if (bus->mdio != 1)
> -					printf("WARNING: no SOF\n");
> -				if (bus->cnt == 1*2) {
> -					bus->cnt = 0;
> -					bus->opc = 0;
> -					bus->state = OPC;
> -				}
> -			}
> -			break;
> -		case OPC:
> -			if (bus->mdc) {
> -				bus->opc <<= 1;
> -				bus->opc |= bus->mdio & 1;
> -				if (bus->cnt == 2*2) {
> -					bus->cnt = 0;
> -					bus->addr = 0;
> -					bus->state = ADDR;
> -				}
> -			}
> -			break;
> -		case ADDR:
> -			if (bus->mdc) {
> -				bus->addr <<= 1;
> -				bus->addr |= bus->mdio & 1;
> -
> -				if (bus->cnt == 5*2) {
> -					bus->cnt = 0;
> -					bus->req = 0;
> -					bus->state = REQ;
> -				}
> -			}
> -			break;
> -		case REQ:
> -			if (bus->mdc) {
> -				bus->req <<= 1;
> -				bus->req |= bus->mdio & 1;
> -				if (bus->cnt == 5*2) {
> -					bus->cnt = 0;
> -					bus->state = TURNAROUND;
> -				}
> -			}
> -			break;
> -		case TURNAROUND:
> -			if (bus->mdc && bus->cnt == 2*2) {
> -				bus->mdio = 0;
> -				bus->cnt = 0;
> -
> -				if (bus->opc == 2) {
> -					bus->drive = 1;
> -					mdio_read_req(bus);
> -					bus->mdio = bus->data & 1;
> -				}
> -				bus->state = DATA;
> -			}
> -			break;
> -		case DATA:			
> -			if (!bus->mdc) {
> -				if (bus->drive) {
> -					bus->mdio = !!(bus->data & (1 << 15));
> -					bus->data <<= 1;
> -				}
> -			} else {
> -				if (!bus->drive) {
> -					bus->data <<= 1;
> -					bus->data |= bus->mdio;
> -				}
> -				if (bus->cnt == 16 * 2) {
> -					bus->cnt = 0;
> -					bus->state = PREAMBLE;
> -					if (!bus->drive)
> -						mdio_write_req(bus);
> -					bus->drive = 0;
> -				}
> -			}
> -			break;
> -		default:
> -			break;
> -	}
> -}
> -
>  /* ETRAX-FS Ethernet MAC block starts here.  */
>  
>  #define RW_MA0_LO	  0x00
> -- 
> 1.7.10.4
>
Grant Likely - Jan. 21, 2013, 1:21 p.m.
On Mon, 21 Jan 2013 13:51:02 +0100, "Edgar E. Iglesias" <edgar.iglesias@gmail.com> wrote:
> On Sat, Jan 19, 2013 at 06:28:10PM -0400, Grant Likely wrote:
> > The etraxfs Ethernet model implements quite a nice bitbanging core. The
> > change splits it out into a separate .c file. There are no functional
> > changes here, just movement of code and reformatting to match qemu
> > coding standards.
> 
> Hi Grant!
> 
> It makes sense to move it out.
> 
> A few comments:
> * Maybe we could separate the phy models from the bus model/infrastructure.
> I.e, the qemu_mdio parts into one file and the qemu_phy into another one.
> That way we can add other phy models and keep things separated.

That makes sense too, but it should be done as a follow on patch. That
keeps the factoring out as a single logical block of code.

> * Not sure bitbang_ makes sense in the naming, the abstraction supports
> both the bit twiddeling model with MDIO cycles but also a higher level
> transactional version (mdio_write_req etc) that bypass the cycle accuracy.
> The latter is useful for modeling NICs that have MDIO support in hw, e.g
> like the hw/xilinx_axienet.c while beeing able to reuse the PHY models.

axienet and etraxfs implementations are subtely different (as you know).
I originally was going to do both, but I didn't want to mix
functionality changes in with the factoring out. Doing both at the same
time would have required (slight) behavour changes in one of the models,
so instead I decided to do only one to keep it simple with the other
being a follow-on.

> I realize I should have done this split when doing the axienet model, sorry..

Can you help me out with a patch that migrates axienet to the new common
code?

Thanks,
g.
Edgar Iglesias - Jan. 21, 2013, 3:08 p.m.
On Mon, Jan 21, 2013 at 09:21:43AM -0400, Grant Likely wrote:
> On Mon, 21 Jan 2013 13:51:02 +0100, "Edgar E. Iglesias" <edgar.iglesias@gmail.com> wrote:
> > On Sat, Jan 19, 2013 at 06:28:10PM -0400, Grant Likely wrote:
> > > The etraxfs Ethernet model implements quite a nice bitbanging core. The
> > > change splits it out into a separate .c file. There are no functional
> > > changes here, just movement of code and reformatting to match qemu
> > > coding standards.
> > 
> > Hi Grant!
> > 
> > It makes sense to move it out.
> > 
> > A few comments:
> > * Maybe we could separate the phy models from the bus model/infrastructure.
> > I.e, the qemu_mdio parts into one file and the qemu_phy into another one.
> > That way we can add other phy models and keep things separated.
> 
> That makes sense too, but it should be done as a follow on patch. That
> keeps the factoring out as a single logical block of code.
> 
> > * Not sure bitbang_ makes sense in the naming, the abstraction supports
> > both the bit twiddeling model with MDIO cycles but also a higher level
> > transactional version (mdio_write_req etc) that bypass the cycle accuracy.
> > The latter is useful for modeling NICs that have MDIO support in hw, e.g
> > like the hw/xilinx_axienet.c while beeing able to reuse the PHY models.
> 
> axienet and etraxfs implementations are subtely different (as you know).
> I originally was going to do both, but I didn't want to mix
> functionality changes in with the factoring out. Doing both at the same
> time would have required (slight) behavour changes in one of the models,
> so instead I decided to do only one to keep it simple with the other
> being a follow-on.
> 
> > I realize I should have done this split when doing the axienet model, sorry..
> 
> Can you help me out with a patch that migrates axienet to the new common
> code?

Yes, I can do that part once the new common code is in place.

Cheers,
Edgar

Patch

diff --git a/hw/bitbang_mdio.c b/hw/bitbang_mdio.c
new file mode 100644
index 0000000..f0ee6af
--- /dev/null
+++ b/hw/bitbang_mdio.c
@@ -0,0 +1,263 @@ 
+/*
+ * QEMU Bitbang Ethernet MDIO bus & PHY controllers.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 <stdio.h>
+#include "qemu-common.h"
+#include "qemu/log.h"
+#include "bitbang_mdio.h"
+
+#define D(x)
+
+/* Advertisement control register. */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+
+/*
+ * The MDIO extensions in the TDK PHY model were reversed engineered from the
+ * linux driver (PHYID and Diagnostics reg).
+ * TODO: Add friendly names for the register nums.
+ */
+static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
+{
+    int regnum;
+    unsigned r = 0;
+
+    regnum = req & 0x1f;
+
+    switch (regnum) {
+    case 1:
+        if (!phy->link) {
+            break;
+        }
+        /* MR1.     */
+        /* Speeds and modes.  */
+        r |= (1 << 13) | (1 << 14);
+        r |= (1 << 11) | (1 << 12);
+        r |= (1 << 5); /* Autoneg complete.  */
+        r |= (1 << 3); /* Autoneg able.     */
+        r |= (1 << 2); /* link.     */
+        break;
+    case 5:
+        /* Link partner ability.
+           We are kind; always agree with whatever best mode
+           the guest advertises.  */
+        r = 1 << 14; /* Success.  */
+        /* Copy advertised modes.  */
+        r |= phy->regs[4] & (15 << 5);
+        /* Autoneg support.  */
+        r |= 1;
+        break;
+    case 18:
+    {
+        /* Diagnostics reg.  */
+        int duplex = 0;
+        int speed_100 = 0;
+
+        if (!phy->link) {
+            break;
+        }
+
+        /* Are we advertising 100 half or 100 duplex ? */
+        speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
+        speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
+
+        /* Are we advertising 10 duplex or 100 duplex ? */
+        duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
+        duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
+        r = (speed_100 << 10) | (duplex << 11);
+    }
+    break;
+
+    default:
+        r = phy->regs[regnum];
+        break;
+    }
+    D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
+    return r;
+}
+
+static void tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
+{
+    int regnum;
+
+    regnum = req & 0x1f;
+    D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
+    switch (regnum) {
+    default:
+        phy->regs[regnum] = data;
+        break;
+    }
+}
+
+void tdk_init(struct qemu_phy *phy)
+{
+    phy->regs[0] = 0x3100;
+    /* PHY Id. */
+    phy->regs[2] = 0x0300;
+    phy->regs[3] = 0xe400;
+    /* Autonegotiation advertisement reg. */
+    phy->regs[4] = 0x01e1;
+    phy->link = 1;
+
+    phy->read = tdk_read;
+    phy->write = tdk_write;
+}
+
+void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = phy;
+}
+
+#ifdef USE_THIS_DEAD_CODE
+void mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = NULL;
+}
+#endif
+
+void mdio_read_req(struct qemu_mdio *bus)
+{
+    struct qemu_phy *phy;
+
+    phy = bus->devs[bus->addr];
+    if (phy && phy->read) {
+        bus->data = phy->read(phy, bus->req);
+    } else {
+        bus->data = 0xffff;
+    }
+    D(qemu_log("%s addr=%d reg=%d data=%x\n", __func__,
+               bus->addr, bus->req, bus->data));
+}
+
+void mdio_write_req(struct qemu_mdio *bus)
+{
+    struct qemu_phy *phy;
+
+    phy = bus->devs[bus->addr];
+    if (phy && phy->write) {
+        phy->write(phy, bus->req, bus->data);
+    }
+}
+
+void mdio_cycle(struct qemu_mdio *bus)
+{
+    bus->cnt++;
+
+    D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
+             bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
+    switch (bus->state) {
+    case PREAMBLE:
+        if (bus->mdc) {
+            if (bus->cnt >= (32 * 2) && !bus->mdio) {
+                bus->cnt = 0;
+                bus->state = SOF;
+                bus->data = 0;
+            }
+        }
+        break;
+    case SOF:
+        if (bus->mdc) {
+            if (bus->mdio != 1) {
+                printf("WARNING: no SOF\n");
+            }
+            if (bus->cnt == 1*2) {
+                bus->cnt = 0;
+                bus->opc = 0;
+                bus->state = OPC;
+            }
+        }
+        break;
+    case OPC:
+        if (bus->mdc) {
+            bus->opc <<= 1;
+            bus->opc |= bus->mdio & 1;
+            if (bus->cnt == 2*2) {
+                bus->cnt = 0;
+                bus->addr = 0;
+                bus->state = ADDR;
+            }
+        }
+        break;
+    case ADDR:
+        if (bus->mdc) {
+            bus->addr <<= 1;
+            bus->addr |= bus->mdio & 1;
+
+            if (bus->cnt == 5*2) {
+                bus->cnt = 0;
+                bus->req = 0;
+                bus->state = REQ;
+            }
+        }
+        break;
+    case REQ:
+        if (bus->mdc) {
+            bus->req <<= 1;
+            bus->req |= bus->mdio & 1;
+            if (bus->cnt == 5*2) {
+                bus->cnt = 0;
+                bus->state = TURNAROUND;
+            }
+        }
+        break;
+    case TURNAROUND:
+        if (bus->mdc && bus->cnt == 2*2) {
+            bus->mdio = 0;
+            bus->cnt = 0;
+
+            if (bus->opc == 2) {
+                bus->drive = 1;
+                mdio_read_req(bus);
+                bus->mdio = bus->data & 1;
+            }
+            bus->state = DATA;
+        }
+        break;
+    case DATA:
+        if (!bus->mdc) {
+            if (bus->drive) {
+                bus->mdio = !!(bus->data & (1 << 15));
+                bus->data <<= 1;
+            }
+        } else {
+            if (!bus->drive) {
+                bus->data <<= 1;
+                bus->data |= bus->mdio;
+            }
+            if (bus->cnt == 16 * 2) {
+                bus->cnt = 0;
+                bus->state = PREAMBLE;
+                if (!bus->drive) {
+                    mdio_write_req(bus);
+                }
+                bus->drive = 0;
+            }
+        }
+        break;
+    default:
+        break;
+    }
+}
diff --git a/hw/bitbang_mdio.h b/hw/bitbang_mdio.h
new file mode 100644
index 0000000..3484aba
--- /dev/null
+++ b/hw/bitbang_mdio.h
@@ -0,0 +1,72 @@ 
+#ifndef BITBANG_MDIO_H
+#define BITBANG_MDIO_H
+
+/*
+ * QEMU Bitbang Ethernet MDIO bus & PHY controllers.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 <stdint.h>
+
+struct qemu_phy {
+    uint32_t regs[32];
+
+    int link;
+
+    unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
+    void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
+};
+
+struct qemu_mdio {
+    /* bus. */
+    int mdc;
+    int mdio;
+
+    /* decoder.  */
+    enum {
+        PREAMBLE,
+        SOF,
+        OPC,
+        ADDR,
+        REQ,
+        TURNAROUND,
+        DATA
+    } state;
+    unsigned int drive;
+
+    unsigned int cnt;
+    unsigned int addr;
+    unsigned int opc;
+    unsigned int req;
+    unsigned int data;
+
+    struct qemu_phy *devs[32];
+};
+
+void tdk_init(struct qemu_phy *phy);
+void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy,
+                 unsigned int addr);
+void mdio_read_req(struct qemu_mdio *bus);
+void mdio_write_req(struct qemu_mdio *bus);
+void mdio_cycle(struct qemu_mdio *bus);
+
+#endif
diff --git a/hw/cris/Makefile.objs b/hw/cris/Makefile.objs
index aa9298a..86759a3 100644
--- a/hw/cris/Makefile.objs
+++ b/hw/cris/Makefile.objs
@@ -9,5 +9,6 @@  obj-y += etraxfs_pic.o
 obj-y += etraxfs_eth.o
 obj-y += etraxfs_timer.o
 obj-y += etraxfs_ser.o
+obj-y += bitbang_mdio.o
 
 obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index ec23fa6..67b4797 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -26,281 +26,10 @@ 
 #include "sysbus.h"
 #include "net/net.h"
 #include "etraxfs.h"
+#include "bitbang_mdio.h"
 
 #define D(x)
 
-/* Advertisement control register. */
-#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
-#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
-#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
-#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
-
-/* 
- * The MDIO extensions in the TDK PHY model were reversed engineered from the 
- * linux driver (PHYID and Diagnostics reg).
- * TODO: Add friendly names for the register nums.
- */
-struct qemu_phy
-{
-	uint32_t regs[32];
-
-	int link;
-
-	unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
-	void (*write)(struct qemu_phy *phy, unsigned int req, 
-		      unsigned int data);
-};
-
-static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
-{
-	int regnum;
-	unsigned r = 0;
-
-	regnum = req & 0x1f;
-
-	switch (regnum) {
-		case 1:
-			if (!phy->link)
-				break;
-			/* MR1.	 */
-			/* Speeds and modes.  */
-			r |= (1 << 13) | (1 << 14);
-			r |= (1 << 11) | (1 << 12);
-			r |= (1 << 5); /* Autoneg complete.  */
-			r |= (1 << 3); /* Autoneg able.	 */
-			r |= (1 << 2); /* link.	 */
-			break;
-		case 5:
-			/* Link partner ability.
-			   We are kind; always agree with whatever best mode
-			   the guest advertises.  */
-			r = 1 << 14; /* Success.  */
-			/* Copy advertised modes.  */
-			r |= phy->regs[4] & (15 << 5);
-			/* Autoneg support.  */
-			r |= 1;
-			break;
-		case 18:
-		{
-			/* Diagnostics reg.  */
-			int duplex = 0;
-			int speed_100 = 0;
-
-			if (!phy->link)
-				break;
-
-			/* Are we advertising 100 half or 100 duplex ? */
-			speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
-			speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
-
-			/* Are we advertising 10 duplex or 100 duplex ? */
-			duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
-			duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
-			r = (speed_100 << 10) | (duplex << 11);
-		}
-		break;
-
-		default:
-			r = phy->regs[regnum];
-			break;
-	}
-	D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
-	return r;
-}
-
-static void 
-tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
-{
-	int regnum;
-
-	regnum = req & 0x1f;
-	D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
-	switch (regnum) {
-		default:
-			phy->regs[regnum] = data;
-			break;
-	}
-}
-
-static void 
-tdk_init(struct qemu_phy *phy)
-{
-	phy->regs[0] = 0x3100;
-	/* PHY Id.  */
-	phy->regs[2] = 0x0300;
-	phy->regs[3] = 0xe400;
-	/* Autonegotiation advertisement reg.  */
-	phy->regs[4] = 0x01E1;
-	phy->link = 1;
-
-	phy->read = tdk_read;
-	phy->write = tdk_write;
-}
-
-struct qemu_mdio
-{
-	/* bus.	 */
-	int mdc;
-	int mdio;
-
-	/* decoder.  */
-	enum {
-		PREAMBLE,
-		SOF,
-		OPC,
-		ADDR,
-		REQ,
-		TURNAROUND,
-		DATA
-	} state;
-	unsigned int drive;
-
-	unsigned int cnt;
-	unsigned int addr;
-	unsigned int opc;
-	unsigned int req;
-	unsigned int data;
-
-	struct qemu_phy *devs[32];
-};
-
-static void 
-mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
-	bus->devs[addr & 0x1f] = phy;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void 
-mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
-	bus->devs[addr & 0x1f] = NULL;	
-}
-#endif
-
-static void mdio_read_req(struct qemu_mdio *bus)
-{
-	struct qemu_phy *phy;
-
-	phy = bus->devs[bus->addr];
-	if (phy && phy->read)
-		bus->data = phy->read(phy, bus->req);
-	else 
-		bus->data = 0xffff;
-}
-
-static void mdio_write_req(struct qemu_mdio *bus)
-{
-	struct qemu_phy *phy;
-
-	phy = bus->devs[bus->addr];
-	if (phy && phy->write)
-		phy->write(phy, bus->req, bus->data);
-}
-
-static void mdio_cycle(struct qemu_mdio *bus)
-{
-	bus->cnt++;
-
-	D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
-		bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
-#if 0
-	if (bus->mdc)
-		printf("%d", bus->mdio);
-#endif
-	switch (bus->state)
-	{
-		case PREAMBLE:
-			if (bus->mdc) {
-				if (bus->cnt >= (32 * 2) && !bus->mdio) {
-					bus->cnt = 0;
-					bus->state = SOF;
-					bus->data = 0;
-				}
-			}
-			break;
-		case SOF:
-			if (bus->mdc) {
-				if (bus->mdio != 1)
-					printf("WARNING: no SOF\n");
-				if (bus->cnt == 1*2) {
-					bus->cnt = 0;
-					bus->opc = 0;
-					bus->state = OPC;
-				}
-			}
-			break;
-		case OPC:
-			if (bus->mdc) {
-				bus->opc <<= 1;
-				bus->opc |= bus->mdio & 1;
-				if (bus->cnt == 2*2) {
-					bus->cnt = 0;
-					bus->addr = 0;
-					bus->state = ADDR;
-				}
-			}
-			break;
-		case ADDR:
-			if (bus->mdc) {
-				bus->addr <<= 1;
-				bus->addr |= bus->mdio & 1;
-
-				if (bus->cnt == 5*2) {
-					bus->cnt = 0;
-					bus->req = 0;
-					bus->state = REQ;
-				}
-			}
-			break;
-		case REQ:
-			if (bus->mdc) {
-				bus->req <<= 1;
-				bus->req |= bus->mdio & 1;
-				if (bus->cnt == 5*2) {
-					bus->cnt = 0;
-					bus->state = TURNAROUND;
-				}
-			}
-			break;
-		case TURNAROUND:
-			if (bus->mdc && bus->cnt == 2*2) {
-				bus->mdio = 0;
-				bus->cnt = 0;
-
-				if (bus->opc == 2) {
-					bus->drive = 1;
-					mdio_read_req(bus);
-					bus->mdio = bus->data & 1;
-				}
-				bus->state = DATA;
-			}
-			break;
-		case DATA:			
-			if (!bus->mdc) {
-				if (bus->drive) {
-					bus->mdio = !!(bus->data & (1 << 15));
-					bus->data <<= 1;
-				}
-			} else {
-				if (!bus->drive) {
-					bus->data <<= 1;
-					bus->data |= bus->mdio;
-				}
-				if (bus->cnt == 16 * 2) {
-					bus->cnt = 0;
-					bus->state = PREAMBLE;
-					if (!bus->drive)
-						mdio_write_req(bus);
-					bus->drive = 0;
-				}
-			}
-			break;
-		default:
-			break;
-	}
-}
-
 /* ETRAX-FS Ethernet MAC block starts here.  */
 
 #define RW_MA0_LO	  0x00