[{"id":1865284,"web_url":"http://patchwork.ozlabs.org/comment/1865284/","msgid":"<CAKmqyKPK9qCkZC0V_UpZrYVhK2GXj53MkUwNhM2SMRfeH=RMjg@mail.gmail.com>","list_archive_url":null,"date":"2018-02-27T22:30:36","subject":"Re: [Qemu-devel] [PATCH v5 1/7] hw/mdio: Generalize etraxfs MDIO\n\tbitbanging emulation","submitter":{"id":47878,"url":"http://patchwork.ozlabs.org/api/people/47878/","name":"Alistair Francis","email":"alistair.francis@xilinx.com"},"content":"On Fri, Sep 22, 2017 at 10:13 AM, Philippe Mathieu-Daudé\n<f4bug@amsat.org> wrote:\n> From: Grant Likely <grant.likely@arm.com>\n>\n> The etraxfs and Xilinx axienet Ethernet models implement quite a nice\n> MDIO core that supports both bitbanging and direct register access. This\n> change factors the common code out into a separate file. There are no\n> functional changes here, just movement of code.\n>\n> The etraxfs and axienet are slightly different. The etraxfs version\n> includes the bitbang state processing, but the axienet version has a\n> minor enhancement for read/write of phy registers without using bitbang\n> state variables.  This patch generalizes the etraxfs version, with the\n> axienet change backported in.\n>\n> Signed-off-by: Grant Likely <grant.likely@arm.com>\n> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>\n> [PMD: rebased with a minor checkpatch fix]\n> ---\n>  include/hw/net/mdio.h   |  76 +++++++++++++\n>  hw/net/etraxfs_eth.c    | 278 +-----------------------------------------------\n>  hw/net/mdio.c           | 262 +++++++++++++++++++++++++++++++++++++++++++++\n>  hw/net/xilinx_axienet.c | 187 +-------------------------------\n>  hw/net/Makefile.objs    |   2 +\n>  5 files changed, 344 insertions(+), 461 deletions(-)\n>  create mode 100644 include/hw/net/mdio.h\n>  create mode 100644 hw/net/mdio.c\n>\n> diff --git a/include/hw/net/mdio.h b/include/hw/net/mdio.h\n> new file mode 100644\n> index 0000000000..ac36aed3c3\n> --- /dev/null\n> +++ b/include/hw/net/mdio.h\n> @@ -0,0 +1,76 @@\n> +#ifndef BITBANG_MDIO_H\n> +#define BITBANG_MDIO_H\n> +\n> +/*\n> + * QEMU Bitbang Ethernet MDIO bus & PHY controllers.\n> + *\n> + * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.\n> + *\n> + * Permission is hereby granted, free of charge, to any person obtaining a copy\n> + * of this software and associated documentation files (the \"Software\"), to deal\n> + * in the Software without restriction, including without limitation the rights\n> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n> + * copies of the Software, and to permit persons to whom the Software is\n> + * furnished to do so, subject to the following conditions:\n> + *\n> + * The above copyright notice and this permission notice shall be included in\n> + * all copies or substantial portions of the Software.\n> + *\n> + * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n> + * THE SOFTWARE.\n> + */\n> +\n> +/* PHY Advertisement control register */\n> +#define PHY_ADVERTISE_10HALF    0x0020  /* Try for 10mbps half-duplex  */\n> +#define PHY_ADVERTISE_10FULL    0x0040  /* Try for 10mbps full-duplex  */\n> +#define PHY_ADVERTISE_100HALF   0x0080  /* Try for 100mbps half-duplex */\n> +#define PHY_ADVERTISE_100FULL   0x0100  /* Try for 100mbps full-duplex */\n> +\n> +struct qemu_phy {\n> +    uint32_t regs[32];\n> +\n> +    int link;\n> +\n> +    unsigned int (*read)(struct qemu_phy *phy, unsigned int req);\n> +    void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);\n> +};\n> +\n> +struct qemu_mdio {\n> +    /* bus. */\n> +    int mdc;\n> +    int mdio;\n> +\n> +    /* decoder.  */\n> +    enum {\n> +        PREAMBLE,\n> +        SOF,\n> +        OPC,\n> +        ADDR,\n> +        REQ,\n> +        TURNAROUND,\n> +        DATA\n> +    } state;\n> +    unsigned int drive;\n> +\n> +    unsigned int cnt;\n> +    unsigned int addr;\n> +    unsigned int opc;\n> +    unsigned int req;\n> +    unsigned int data;\n> +\n> +    struct qemu_phy *devs[32];\n> +};\n> +\n> +void tdk_init(struct qemu_phy *phy);\n> +void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy,\n> +                 unsigned int addr);\n> +uint16_t mdio_read_req(struct qemu_mdio *bus, uint8_t addr, uint8_t req);\n> +void mdio_write_req(struct qemu_mdio *bus, uint8_t addr, uint8_t req, uint16_t data);\n> +void mdio_cycle(struct qemu_mdio *bus);\n> +\n> +#endif\n> diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c\n> index 013c8d0a41..f8d8f8441d 100644\n> --- a/hw/net/etraxfs_eth.c\n> +++ b/hw/net/etraxfs_eth.c\n> @@ -26,287 +26,11 @@\n>  #include \"hw/sysbus.h\"\n>  #include \"net/net.h\"\n>  #include \"hw/cris/etraxfs.h\"\n> +#include \"hw/net/mdio.h\"\n>  #include \"qemu/error-report.h\"\n>\n>  #define D(x)\n>\n> -/* Advertisement control register. */\n> -#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */\n> -#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */\n> -#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */\n> -#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */\n> -\n> -/*\n> - * The MDIO extensions in the TDK PHY model were reversed engineered from the\n> - * linux driver (PHYID and Diagnostics reg).\n> - * TODO: Add friendly names for the register nums.\n> - */\n> -struct qemu_phy\n> -{\n> -    uint32_t regs[32];\n> -\n> -    int link;\n> -\n> -    unsigned int (*read)(struct qemu_phy *phy, unsigned int req);\n> -    void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);\n> -};\n> -\n> -static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)\n> -{\n> -    int regnum;\n> -    unsigned r = 0;\n> -\n> -    regnum = req & 0x1f;\n> -\n> -    switch (regnum) {\n> -    case 1:\n> -        if (!phy->link) {\n> -            break;\n> -        }\n> -        /* MR1.     */\n> -        /* Speeds and modes.  */\n> -        r |= (1 << 13) | (1 << 14);\n> -        r |= (1 << 11) | (1 << 12);\n> -        r |= (1 << 5); /* Autoneg complete.  */\n> -        r |= (1 << 3); /* Autoneg able.     */\n> -        r |= (1 << 2); /* link.     */\n> -        break;\n> -    case 5:\n> -        /* Link partner ability.\n> -           We are kind; always agree with whatever best mode\n> -           the guest advertises.  */\n> -        r = 1 << 14; /* Success.  */\n> -        /* Copy advertised modes.  */\n> -        r |= phy->regs[4] & (15 << 5);\n> -        /* Autoneg support.  */\n> -        r |= 1;\n> -        break;\n> -    case 18:\n> -    {\n> -        /* Diagnostics reg.  */\n> -        int duplex = 0;\n> -        int speed_100 = 0;\n> -\n> -        if (!phy->link) {\n> -            break;\n> -        }\n> -\n> -        /* Are we advertising 100 half or 100 duplex ? */\n> -        speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);\n> -        speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);\n> -\n> -        /* Are we advertising 10 duplex or 100 duplex ? */\n> -        duplex = !!(phy->regs[4] & ADVERTISE_100FULL);\n> -        duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);\n> -        r = (speed_100 << 10) | (duplex << 11);\n> -    }\n> -    break;\n> -\n> -    default:\n> -        r = phy->regs[regnum];\n> -        break;\n> -    }\n> -    D(printf(\"\\n%s %x = reg[%d]\\n\", __func__, r, regnum));\n> -    return r;\n> -}\n> -\n> -static void\n> -tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)\n> -{\n> -    int regnum;\n> -\n> -    regnum = req & 0x1f;\n> -    D(printf(\"%s reg[%d] = %x\\n\", __func__, regnum, data));\n> -    switch (regnum) {\n> -    default:\n> -        phy->regs[regnum] = data;\n> -        break;\n> -    }\n> -}\n> -\n> -static void\n> -tdk_init(struct qemu_phy *phy)\n> -{\n> -    phy->regs[0] = 0x3100;\n> -    /* PHY Id.  */\n> -    phy->regs[2] = 0x0300;\n> -    phy->regs[3] = 0xe400;\n> -    /* Autonegotiation advertisement reg.  */\n> -    phy->regs[4] = 0x01E1;\n> -    phy->link = 1;\n> -\n> -    phy->read = tdk_read;\n> -    phy->write = tdk_write;\n> -}\n> -\n> -struct qemu_mdio\n> -{\n> -    /* bus.     */\n> -    int mdc;\n> -    int mdio;\n> -\n> -    /* decoder.  */\n> -    enum {\n> -        PREAMBLE,\n> -        SOF,\n> -        OPC,\n> -        ADDR,\n> -        REQ,\n> -        TURNAROUND,\n> -        DATA\n> -    } state;\n> -    unsigned int drive;\n> -\n> -    unsigned int cnt;\n> -    unsigned int addr;\n> -    unsigned int opc;\n> -    unsigned int req;\n> -    unsigned int data;\n> -\n> -    struct qemu_phy *devs[32];\n> -};\n> -\n> -static void\n> -mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)\n> -{\n> -    bus->devs[addr & 0x1f] = phy;\n> -}\n> -\n> -#ifdef USE_THIS_DEAD_CODE\n> -static void\n> -mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)\n> -{\n> -    bus->devs[addr & 0x1f] = NULL;\n> -}\n> -#endif\n> -\n> -static void mdio_read_req(struct qemu_mdio *bus)\n> -{\n> -    struct qemu_phy *phy;\n> -\n> -    phy = bus->devs[bus->addr];\n> -    if (phy && phy->read) {\n> -        bus->data = phy->read(phy, bus->req);\n> -    } else {\n> -        bus->data = 0xffff;\n> -    }\n> -}\n> -\n> -static void mdio_write_req(struct qemu_mdio *bus)\n> -{\n> -    struct qemu_phy *phy;\n> -\n> -    phy = bus->devs[bus->addr];\n> -    if (phy && phy->write) {\n> -        phy->write(phy, bus->req, bus->data);\n> -    }\n> -}\n> -\n> -static void mdio_cycle(struct qemu_mdio *bus)\n> -{\n> -    bus->cnt++;\n> -\n> -    D(printf(\"mdc=%d mdio=%d state=%d cnt=%d drv=%d\\n\",\n> -        bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));\n> -#if 0\n> -    if (bus->mdc) {\n> -        printf(\"%d\", bus->mdio);\n> -    }\n> -#endif\n> -    switch (bus->state) {\n> -    case PREAMBLE:\n> -        if (bus->mdc) {\n> -            if (bus->cnt >= (32 * 2) && !bus->mdio) {\n> -                bus->cnt = 0;\n> -                bus->state = SOF;\n> -                bus->data = 0;\n> -            }\n> -        }\n> -        break;\n> -    case SOF:\n> -        if (bus->mdc) {\n> -            if (bus->mdio != 1) {\n> -                printf(\"WARNING: no SOF\\n\");\n> -            }\n> -            if (bus->cnt == 1*2) {\n> -                bus->cnt = 0;\n> -                bus->opc = 0;\n> -                bus->state = OPC;\n> -            }\n> -        }\n> -        break;\n> -    case OPC:\n> -        if (bus->mdc) {\n> -            bus->opc <<= 1;\n> -            bus->opc |= bus->mdio & 1;\n> -            if (bus->cnt == 2*2) {\n> -                bus->cnt = 0;\n> -                bus->addr = 0;\n> -                bus->state = ADDR;\n> -            }\n> -        }\n> -        break;\n> -    case ADDR:\n> -        if (bus->mdc) {\n> -            bus->addr <<= 1;\n> -            bus->addr |= bus->mdio & 1;\n> -\n> -            if (bus->cnt == 5*2) {\n> -                bus->cnt = 0;\n> -                bus->req = 0;\n> -                bus->state = REQ;\n> -            }\n> -        }\n> -        break;\n> -    case REQ:\n> -        if (bus->mdc) {\n> -            bus->req <<= 1;\n> -            bus->req |= bus->mdio & 1;\n> -            if (bus->cnt == 5*2) {\n> -                bus->cnt = 0;\n> -                bus->state = TURNAROUND;\n> -            }\n> -        }\n> -        break;\n> -    case TURNAROUND:\n> -        if (bus->mdc && bus->cnt == 2*2) {\n> -            bus->mdio = 0;\n> -            bus->cnt = 0;\n> -\n> -            if (bus->opc == 2) {\n> -                bus->drive = 1;\n> -                mdio_read_req(bus);\n> -                bus->mdio = bus->data & 1;\n> -            }\n> -            bus->state = DATA;\n> -        }\n> -        break;\n> -    case DATA:\n> -        if (!bus->mdc) {\n> -            if (bus->drive) {\n> -                bus->mdio = !!(bus->data & (1 << 15));\n> -                bus->data <<= 1;\n> -            }\n> -        } else {\n> -            if (!bus->drive) {\n> -                bus->data <<= 1;\n> -                bus->data |= bus->mdio;\n> -            }\n> -            if (bus->cnt == 16 * 2) {\n> -                bus->cnt = 0;\n> -                bus->state = PREAMBLE;\n> -                if (!bus->drive) {\n> -                    mdio_write_req(bus);\n> -                }\n> -                bus->drive = 0;\n> -            }\n> -        }\n> -        break;\n> -    default:\n> -        break;\n> -    }\n> -}\n> -\n>  /* ETRAX-FS Ethernet MAC block starts here.  */\n>\n>  #define RW_MA0_LO      0x00\n> diff --git a/hw/net/mdio.c b/hw/net/mdio.c\n> new file mode 100644\n> index 0000000000..3763fcc8af\n> --- /dev/null\n> +++ b/hw/net/mdio.c\n> @@ -0,0 +1,262 @@\n> +/*\n> + * QEMU Ethernet MDIO bus & PHY models\n> + *\n> + * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.\n> + *\n> + * Permission is hereby granted, free of charge, to any person obtaining a copy\n> + * of this software and associated documentation files (the \"Software\"), to deal\n> + * in the Software without restriction, including without limitation the rights\n> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n> + * copies of the Software, and to permit persons to whom the Software is\n> + * furnished to do so, subject to the following conditions:\n> + *\n> + * The above copyright notice and this permission notice shall be included in\n> + * all copies or substantial portions of the Software.\n> + *\n> + * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n> + * THE SOFTWARE.\n> + *\n> + * This is a generic MDIO implementation.\n> + *\n> + * TODO:\n> + * - Split PHYs out as separate device models so they can be defined and\n> + *   instantiated separately from the MDIO bus.\n> + * - Split out bitbang state machine into a separate model. Mostly this consists\n> + *   of the mdio_cycle() routine and the bitbang state data in struct qemu_mdio\n> + * - Use the GPIO interface for driving bitbang\n> + */\n> +\n> +#include \"qemu/osdep.h\"\n> +#include \"qemu-common.h\"\n> +#include \"qemu/log.h\"\n> +#include \"hw/net/mdio.h\"\n> +\n> +#define D(x)\n\nThis should be updated to the new way to handle QEMU logging.\n\nOtherwise this patch looks fine to me.\n\nAlistair\n\n> +\n> +/*\n> + * The MDIO extensions in the TDK PHY model were reversed engineered from the\n> + * linux driver (PHYID and Diagnostics reg).\n> + * TODO: Add friendly names for the register nums.\n> + */\n> +static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)\n> +{\n> +    int regnum;\n> +    unsigned r = 0;\n> +\n> +    regnum = req & 0x1f;\n> +\n> +    switch (regnum) {\n> +    case 1:\n> +        if (!phy->link) {\n> +            break;\n> +        }\n> +        /* MR1.     */\n> +        /* Speeds and modes.  */\n> +        r |= (1 << 13) | (1 << 14);\n> +        r |= (1 << 11) | (1 << 12);\n> +        r |= (1 << 5); /* Autoneg complete.  */\n> +        r |= (1 << 3); /* Autoneg able.     */\n> +        r |= (1 << 2); /* link.     */\n> +        r |= (1 << 1); /* link.     */\n> +        break;\n> +    case 5:\n> +        /* Link partner ability.\n> +           We are kind; always agree with whatever best mode\n> +           the guest advertises.  */\n> +        r = 1 << 14; /* Success.  */\n> +        /* Copy advertised modes.  */\n> +        r |= phy->regs[4] & (15 << 5);\n> +        /* Autoneg support.  */\n> +        r |= 1;\n> +        break;\n> +    case 17:\n> +        /* Marvel PHY on many xilinx boards. */\n> +        r = 0x8000; /* 1000Mb */\n> +        break;\n> +    case 18:\n> +    {\n> +        /* Diagnostics reg.  */\n> +        int duplex = 0;\n> +        int speed_100 = 0;\n> +\n> +        if (!phy->link) {\n> +            break;\n> +        }\n> +\n> +        /* Are we advertising 100 half or 100 duplex ? */\n> +        speed_100 = !!(phy->regs[4] & PHY_ADVERTISE_100HALF);\n> +        speed_100 |= !!(phy->regs[4] & PHY_ADVERTISE_100FULL);\n> +\n> +        /* Are we advertising 10 duplex or 100 duplex ? */\n> +        duplex = !!(phy->regs[4] & PHY_ADVERTISE_100FULL);\n> +        duplex |= !!(phy->regs[4] & PHY_ADVERTISE_10FULL);\n> +        r = (speed_100 << 10) | (duplex << 11);\n> +    }\n> +    break;\n> +\n> +    default:\n> +        r = phy->regs[regnum];\n> +        break;\n> +    }\n> +    D(printf(\"\\n%s %x = reg[%d]\\n\", __func__, r, regnum));\n> +    return r;\n> +}\n> +\n> +static void tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)\n> +{\n> +    int regnum;\n> +\n> +    regnum = req & 0x1f;\n> +    D(printf(\"%s reg[%d] = %x\\n\", __func__, regnum, data));\n> +    switch (regnum) {\n> +    default:\n> +        phy->regs[regnum] = data;\n> +        break;\n> +    }\n> +}\n> +\n> +void tdk_init(struct qemu_phy *phy)\n> +{\n> +    phy->regs[0] = 0x3100;\n> +    /* PHY Id. */\n> +    phy->regs[2] = 0x0300;\n> +    phy->regs[3] = 0xe400;\n> +    /* Autonegotiation advertisement reg. */\n> +    phy->regs[4] = 0x01e1;\n> +    phy->link = 1;\n> +\n> +    phy->read = tdk_read;\n> +    phy->write = tdk_write;\n> +}\n> +\n> +void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)\n> +{\n> +    bus->devs[addr & 0x1f] = phy;\n> +}\n> +\n> +uint16_t mdio_read_req(struct qemu_mdio *bus, uint8_t addr, uint8_t req)\n> +{\n> +    struct qemu_phy *phy;\n> +\n> +    phy = bus->devs[bus->addr];\n> +    if (phy && phy->read) {\n> +        return phy->read(phy, req);\n> +    }\n> +    return 0xffff;\n> +}\n> +\n> +void mdio_write_req(struct qemu_mdio *bus, uint8_t addr, uint8_t req,\n> +                    uint16_t data)\n> +{\n> +    struct qemu_phy *phy;\n> +\n> +    phy = bus->devs[bus->addr];\n> +    if (phy && phy->write) {\n> +        phy->write(phy, req, data);\n> +    }\n> +}\n> +\n> +void mdio_cycle(struct qemu_mdio *bus)\n> +{\n> +    bus->cnt++;\n> +\n> +    D(printf(\"mdc=%d mdio=%d state=%d cnt=%d drv=%d\\n\",\n> +             bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));\n> +    switch (bus->state) {\n> +    case PREAMBLE:\n> +        if (bus->mdc) {\n> +            if (bus->cnt >= (32 * 2) && !bus->mdio) {\n> +                bus->cnt = 0;\n> +                bus->state = SOF;\n> +                bus->data = 0;\n> +            }\n> +        }\n> +        break;\n> +    case SOF:\n> +        if (bus->mdc) {\n> +            if (bus->mdio != 1) {\n> +                printf(\"WARNING: no SOF\\n\");\n> +            }\n> +            if (bus->cnt == 1 * 2) {\n> +                bus->cnt = 0;\n> +                bus->opc = 0;\n> +                bus->state = OPC;\n> +            }\n> +        }\n> +        break;\n> +    case OPC:\n> +        if (bus->mdc) {\n> +            bus->opc <<= 1;\n> +            bus->opc |= bus->mdio & 1;\n> +            if (bus->cnt == 2 * 2) {\n> +                bus->cnt = 0;\n> +                bus->addr = 0;\n> +                bus->state = ADDR;\n> +            }\n> +        }\n> +        break;\n> +    case ADDR:\n> +        if (bus->mdc) {\n> +            bus->addr <<= 1;\n> +            bus->addr |= bus->mdio & 1;\n> +\n> +            if (bus->cnt == 5 * 2) {\n> +                bus->cnt = 0;\n> +                bus->req = 0;\n> +                bus->state = REQ;\n> +            }\n> +        }\n> +        break;\n> +    case REQ:\n> +        if (bus->mdc) {\n> +            bus->req <<= 1;\n> +            bus->req |= bus->mdio & 1;\n> +            if (bus->cnt == 5 * 2) {\n> +                bus->cnt = 0;\n> +                bus->state = TURNAROUND;\n> +            }\n> +        }\n> +        break;\n> +    case TURNAROUND:\n> +        if (bus->mdc && bus->cnt == 2 * 2) {\n> +            bus->mdio = 0;\n> +            bus->cnt = 0;\n> +\n> +            if (bus->opc == 2) {\n> +                bus->drive = 1;\n> +                bus->data = mdio_read_req(bus, bus->addr, bus->req);\n> +                bus->mdio = bus->data & 1;\n> +            }\n> +            bus->state = DATA;\n> +        }\n> +        break;\n> +    case DATA:\n> +        if (!bus->mdc) {\n> +            if (bus->drive) {\n> +                bus->mdio = !!(bus->data & (1 << 15));\n> +                bus->data <<= 1;\n> +            }\n> +        } else {\n> +            if (!bus->drive) {\n> +                bus->data <<= 1;\n> +                bus->data |= bus->mdio;\n> +            }\n> +            if (bus->cnt == 16 * 2) {\n> +                bus->cnt = 0;\n> +                bus->state = PREAMBLE;\n> +                if (!bus->drive) {\n> +                    mdio_write_req(bus, bus->addr, bus->req, bus->data);\n> +                }\n> +                bus->drive = 0;\n> +            }\n> +        }\n> +        break;\n> +    default:\n> +        break;\n> +    }\n> +}\n> diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c\n> index d4c2c89dc1..1e859fdaae 100644\n> --- a/hw/net/xilinx_axienet.c\n> +++ b/hw/net/xilinx_axienet.c\n> @@ -26,13 +26,12 @@\n>  #include \"hw/sysbus.h\"\n>  #include \"qapi/error.h\"\n>  #include \"qemu/log.h\"\n> +#include \"hw/net/mdio.h\"\n>  #include \"net/net.h\"\n>  #include \"net/checksum.h\"\n>\n>  #include \"hw/stream.h\"\n>\n> -#define DPHY(x)\n> -\n>  #define TYPE_XILINX_AXI_ENET \"xlnx.axi-ethernet\"\n>  #define TYPE_XILINX_AXI_ENET_DATA_STREAM \"xilinx-axienet-data-stream\"\n>  #define TYPE_XILINX_AXI_ENET_CONTROL_STREAM \"xilinx-axienet-control-stream\"\n> @@ -48,189 +47,9 @@\n>       OBJECT_CHECK(XilinxAXIEnetStreamSlave, (obj),\\\n>       TYPE_XILINX_AXI_ENET_CONTROL_STREAM)\n>\n> -/* Advertisement control register. */\n> -#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */\n> -#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */\n> -#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */\n> -#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */\n> -\n>  #define CONTROL_PAYLOAD_WORDS 5\n>  #define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t)))\n>\n> -struct PHY {\n> -    uint32_t regs[32];\n> -\n> -    int link;\n> -\n> -    unsigned int (*read)(struct PHY *phy, unsigned int req);\n> -    void (*write)(struct PHY *phy, unsigned int req,\n> -                  unsigned int data);\n> -};\n> -\n> -static unsigned int tdk_read(struct PHY *phy, unsigned int req)\n> -{\n> -    int regnum;\n> -    unsigned r = 0;\n> -\n> -    regnum = req & 0x1f;\n> -\n> -    switch (regnum) {\n> -        case 1:\n> -            if (!phy->link) {\n> -                break;\n> -            }\n> -            /* MR1.  */\n> -            /* Speeds and modes.  */\n> -            r |= (1 << 13) | (1 << 14);\n> -            r |= (1 << 11) | (1 << 12);\n> -            r |= (1 << 5); /* Autoneg complete.  */\n> -            r |= (1 << 3); /* Autoneg able.  */\n> -            r |= (1 << 2); /* link.  */\n> -            r |= (1 << 1); /* link.  */\n> -            break;\n> -        case 5:\n> -            /* Link partner ability.\n> -               We are kind; always agree with whatever best mode\n> -               the guest advertises.  */\n> -            r = 1 << 14; /* Success.  */\n> -            /* Copy advertised modes.  */\n> -            r |= phy->regs[4] & (15 << 5);\n> -            /* Autoneg support.  */\n> -            r |= 1;\n> -            break;\n> -        case 17:\n> -            /* Marvell PHY on many xilinx boards.  */\n> -            r = 0x8000; /* 1000Mb  */\n> -            break;\n> -        case 18:\n> -            {\n> -                /* Diagnostics reg.  */\n> -                int duplex = 0;\n> -                int speed_100 = 0;\n> -\n> -                if (!phy->link) {\n> -                    break;\n> -                }\n> -\n> -                /* Are we advertising 100 half or 100 duplex ? */\n> -                speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);\n> -                speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);\n> -\n> -                /* Are we advertising 10 duplex or 100 duplex ? */\n> -                duplex = !!(phy->regs[4] & ADVERTISE_100FULL);\n> -                duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);\n> -                r = (speed_100 << 10) | (duplex << 11);\n> -            }\n> -            break;\n> -\n> -        default:\n> -            r = phy->regs[regnum];\n> -            break;\n> -    }\n> -    DPHY(qemu_log(\"\\n%s %x = reg[%d]\\n\", __func__, r, regnum));\n> -    return r;\n> -}\n> -\n> -static void\n> -tdk_write(struct PHY *phy, unsigned int req, unsigned int data)\n> -{\n> -    int regnum;\n> -\n> -    regnum = req & 0x1f;\n> -    DPHY(qemu_log(\"%s reg[%d] = %x\\n\", __func__, regnum, data));\n> -    switch (regnum) {\n> -        default:\n> -            phy->regs[regnum] = data;\n> -            break;\n> -    }\n> -\n> -    /* Unconditionally clear regs[BMCR][BMCR_RESET] */\n> -    phy->regs[0] &= ~0x8000;\n> -}\n> -\n> -static void\n> -tdk_init(struct PHY *phy)\n> -{\n> -    phy->regs[0] = 0x3100;\n> -    /* PHY Id.  */\n> -    phy->regs[2] = 0x0300;\n> -    phy->regs[3] = 0xe400;\n> -    /* Autonegotiation advertisement reg.  */\n> -    phy->regs[4] = 0x01E1;\n> -    phy->link = 1;\n> -\n> -    phy->read = tdk_read;\n> -    phy->write = tdk_write;\n> -}\n> -\n> -struct MDIOBus {\n> -    /* bus.  */\n> -    int mdc;\n> -    int mdio;\n> -\n> -    /* decoder.  */\n> -    enum {\n> -        PREAMBLE,\n> -        SOF,\n> -        OPC,\n> -        ADDR,\n> -        REQ,\n> -        TURNAROUND,\n> -        DATA\n> -    } state;\n> -    unsigned int drive;\n> -\n> -    unsigned int cnt;\n> -    unsigned int addr;\n> -    unsigned int opc;\n> -    unsigned int req;\n> -    unsigned int data;\n> -\n> -    struct PHY *devs[32];\n> -};\n> -\n> -static void\n> -mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)\n> -{\n> -    bus->devs[addr & 0x1f] = phy;\n> -}\n> -\n> -#ifdef USE_THIS_DEAD_CODE\n> -static void\n> -mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)\n> -{\n> -    bus->devs[addr & 0x1f] = NULL;\n> -}\n> -#endif\n> -\n> -static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr,\n> -                  unsigned int reg)\n> -{\n> -    struct PHY *phy;\n> -    uint16_t data;\n> -\n> -    phy = bus->devs[addr];\n> -    if (phy && phy->read) {\n> -        data = phy->read(phy, reg);\n> -    } else {\n> -        data = 0xffff;\n> -    }\n> -    DPHY(qemu_log(\"%s addr=%d reg=%d data=%x\\n\", __func__, addr, reg, data));\n> -    return data;\n> -}\n> -\n> -static void mdio_write_req(struct MDIOBus *bus, unsigned int addr,\n> -               unsigned int reg, uint16_t data)\n> -{\n> -    struct PHY *phy;\n> -\n> -    DPHY(qemu_log(\"%s addr=%d reg=%d data=%x\\n\", __func__, addr, reg, data));\n> -    phy = bus->devs[addr];\n> -    if (phy && phy->write) {\n> -        phy->write(phy, reg, data);\n> -    }\n> -}\n> -\n>  #define DENET(x)\n>\n>  #define R_RAF      (0x000 / 4)\n> @@ -322,8 +141,8 @@ enum {\n>\n>  /* Indirect registers.  */\n>  struct TEMAC  {\n> -    struct MDIOBus mdio_bus;\n> -    struct PHY phy;\n> +    struct qemu_mdio mdio_bus;\n> +    struct qemu_phy phy;\n>\n>      void *parent;\n>  };\n> diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs\n> index 4171af0b5d..a020963d10 100644\n> --- a/hw/net/Makefile.objs\n> +++ b/hw/net/Makefile.objs\n> @@ -30,6 +30,8 @@ common-obj-$(CONFIG_SUNHME) += sunhme.o\n>  common-obj-$(CONFIG_FTGMAC100) += ftgmac100.o\n>  common-obj-$(CONFIG_SUNGEM) += sungem.o\n>\n> +common-obj-y += mdio.o\n> +\n>  obj-$(CONFIG_ETRAXFS) += etraxfs_eth.o\n>  obj-$(CONFIG_COLDFIRE) += mcf_fec.o\n>  obj-$(CONFIG_MILKYMIST) += milkymist-minimac2.o\n> --\n> 2.14.1\n>\n>","headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdmarc=none (p=none dis=none) header.from=xilinx.com","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"STJBN9FN\"; dkim-atps=neutral"],"Received":["from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3zrYMr2v9tz9s19\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 28 Feb 2018 09:31:52 +1100 (AEDT)","from localhost ([::1]:40462 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1eqnmo-00008F-IF\n\tfor incoming@patchwork.ozlabs.org; Tue, 27 Feb 2018 17:31:50 -0500","from eggs.gnu.org ([2001:4830:134:3::10]:47461)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <alistair23@gmail.com>) id 1eqnmI-00004t-CX\n\tfor qemu-devel@nongnu.org; Tue, 27 Feb 2018 17:31:21 -0500","from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <alistair23@gmail.com>) id 1eqnmF-0001xT-MF\n\tfor qemu-devel@nongnu.org; Tue, 27 Feb 2018 17:31:18 -0500","from mail-lf0-x244.google.com ([2a00:1450:4010:c07::244]:41677)\n\tby eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16)\n\t(Exim 4.71) (envelope-from <alistair23@gmail.com>)\n\tid 1eqnm9-0001pX-0X; Tue, 27 Feb 2018 17:31:09 -0500","by mail-lf0-x244.google.com with SMTP id m69so612548lfe.8;\n\tTue, 27 Feb 2018 14:31:08 -0800 (PST)","by 10.46.32.215 with HTTP; Tue, 27 Feb 2018 14:30:36 -0800 (PST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=mime-version:sender:in-reply-to:references:from:date:message-id\n\t:subject:to:cc:content-transfer-encoding;\n\tbh=dcrbLUEgi7mF/jaOya4/XcFfr2mI/jHP8CiNeqKyXjg=;\n\tb=STJBN9FNWhUXL7Qyt9SKCUz1ZyUJNi8L6HacxwlwnH+S/XpOebwosvFFCCCj/jawJw\n\tXqco6+Qkp8P5y4HGUiRoCU5sTiS606NbRDHXU5rwal14Zs/0C2QGah1CCSRjaoiv+dq3\n\tN5/+t5a/AGnPrpCIvIGj2ZV6rJkWS6YAnZJ+MlAnP8Z1THk2tQlsLR9/5NVXPpSYvEqQ\n\tHcEU6qc7dkiplfYWSWCdCBZdxzhmMiFqYOzZ+Kl8rt+Gnz2VdBybCWpHOXtqAYu8tQiy\n\tMTS/i90f1tEgQc2URaZyy4Cp0QNIpY5x9JUCpuFe+HlZPrTSJxzdNCBzqKuLAWnnMugd\n\t6WEQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:mime-version:sender:in-reply-to:references:from\n\t:date:message-id:subject:to:cc:content-transfer-encoding;\n\tbh=dcrbLUEgi7mF/jaOya4/XcFfr2mI/jHP8CiNeqKyXjg=;\n\tb=dWWPLB8lv9tQ4bhdXLx1ZJJ2dRSt2xLfeI8Q1XFELcl0vPWbeywQcm0GpFZGTg5MGr\n\tQs6amZUzsst0XshyK2Bla874fqa11lpmFrzGSqd4DvSSyYYzkaflgyH/G3FCfZYoM2Jj\n\thQQbt8fbyIysEi4q7D5zpDeqp2tuc6FPv88iSGFO8T0BniUjLsJ9gUteIKXRFapqicKw\n\ttGdBmU1YS2qqpgKqS/PVw91ajup4/8xO6YzgzWx6EPftnmdvPul38l/HktELuBVYmHYu\n\tn0nXMyq4KkT0ST+Cp+kRBrprYWm0e34jr/roeUFasnBEJEU4a4AHKDTJT/6YKIENN5ug\n\tIbNg==","X-Gm-Message-State":"APf1xPC5U/3aCQoDn/L35nn4FlcwS5VR1rHnoMc/JeMm/7jeMpQd4Tfv\n\tm1+9bP3C5LCA8zurU+4dcu1vWZcrNFariMOrMZI=","X-Google-Smtp-Source":"AG47ELu47Vyhx871TQ9wtv+zBX2Vx+N7zqGrQvRc3kUDmS14J9KVJAxxP7ZhBUpv4L8DVhtqtKf2H+YqvElHmBSWL1E=","X-Received":"by 10.25.170.144 with SMTP id t138mr2990453lfe.71.1519770667214; \n\tTue, 27 Feb 2018 14:31:07 -0800 (PST)","MIME-Version":"1.0","In-Reply-To":"<20170922171323.10348-2-f4bug@amsat.org>","References":"<20170922171323.10348-1-f4bug@amsat.org>\n\t<20170922171323.10348-2-f4bug@amsat.org>","From":"Alistair Francis <alistair.francis@xilinx.com>","Date":"Tue, 27 Feb 2018 14:30:36 -0800","X-Google-Sender-Auth":"UAAG7YEK6V00IRbHaY-MDzbS2Ik","Message-ID":"<CAKmqyKPK9qCkZC0V_UpZrYVhK2GXj53MkUwNhM2SMRfeH=RMjg@mail.gmail.com>","To":"=?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= <f4bug@amsat.org>","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","X-detected-operating-system":"by eggs.gnu.org: Genre and OS details not\n\trecognized.","X-Received-From":"2a00:1450:4010:c07::244","Subject":"Re: [Qemu-devel] [PATCH v5 1/7] hw/mdio: Generalize etraxfs MDIO\n\tbitbanging emulation","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"<qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<http://lists.nongnu.org/archive/html/qemu-devel/>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Cc":"Peter Maydell <peter.maydell@linaro.org>, Fam Zheng <famz@redhat.com>,\n\tJason Wang <jasowang@redhat.com>, \"qemu-devel@nongnu.org Developers\"\n\t<qemu-devel@nongnu.org>, \n\tAlistair Francis <alistair.francis@xilinx.com>, Grant Likely\n\t<grant.likely@arm.com>, qemu-arm <qemu-arm@nongnu.org>, \"Edgar E.\n\tIglesias\" <edgar.iglesias@gmail.com>, =?utf-8?q?Andreas_F=C3=A4rber?=\n\t<afaerber@suse.de>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>"}}]