xref: /qemu/hw/net/xilinx_axienet.c (revision db1015e92e04835c9eb50c29625fe566d1202dbd)
193f1e401SEdgar E. Iglesias /*
293f1e401SEdgar E. Iglesias  * QEMU model of Xilinx AXI-Ethernet.
393f1e401SEdgar E. Iglesias  *
493f1e401SEdgar E. Iglesias  * Copyright (c) 2011 Edgar E. Iglesias.
593f1e401SEdgar E. Iglesias  *
693f1e401SEdgar E. Iglesias  * Permission is hereby granted, free of charge, to any person obtaining a copy
793f1e401SEdgar E. Iglesias  * of this software and associated documentation files (the "Software"), to deal
893f1e401SEdgar E. Iglesias  * in the Software without restriction, including without limitation the rights
993f1e401SEdgar E. Iglesias  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1093f1e401SEdgar E. Iglesias  * copies of the Software, and to permit persons to whom the Software is
1193f1e401SEdgar E. Iglesias  * furnished to do so, subject to the following conditions:
1293f1e401SEdgar E. Iglesias  *
1393f1e401SEdgar E. Iglesias  * The above copyright notice and this permission notice shall be included in
1493f1e401SEdgar E. Iglesias  * all copies or substantial portions of the Software.
1593f1e401SEdgar E. Iglesias  *
1693f1e401SEdgar E. Iglesias  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1793f1e401SEdgar E. Iglesias  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1893f1e401SEdgar E. Iglesias  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1993f1e401SEdgar E. Iglesias  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2093f1e401SEdgar E. Iglesias  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2193f1e401SEdgar E. Iglesias  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2293f1e401SEdgar E. Iglesias  * THE SOFTWARE.
2393f1e401SEdgar E. Iglesias  */
2493f1e401SEdgar E. Iglesias 
25e8d40465SPeter Maydell #include "qemu/osdep.h"
26a27bd6c7SMarkus Armbruster #include "hw/hw.h"
2783c9f4caSPaolo Bonzini #include "hw/sysbus.h"
28da34e65cSMarkus Armbruster #include "qapi/error.h"
291de7afc9SPaolo Bonzini #include "qemu/log.h"
300b8fa32fSMarkus Armbruster #include "qemu/module.h"
311422e32dSPaolo Bonzini #include "net/net.h"
3293f1e401SEdgar E. Iglesias #include "net/checksum.h"
3393f1e401SEdgar E. Iglesias 
34650d103dSMarkus Armbruster #include "hw/hw.h"
3564552b6bSMarkus Armbruster #include "hw/irq.h"
36a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
3783c9f4caSPaolo Bonzini #include "hw/stream.h"
38*db1015e9SEduardo Habkost #include "qom/object.h"
3993f1e401SEdgar E. Iglesias 
4093f1e401SEdgar E. Iglesias #define DPHY(x)
4193f1e401SEdgar E. Iglesias 
42f0e7a81cSPeter Crosthwaite #define TYPE_XILINX_AXI_ENET "xlnx.axi-ethernet"
4355b3e0c2SPeter Crosthwaite #define TYPE_XILINX_AXI_ENET_DATA_STREAM "xilinx-axienet-data-stream"
4442bb9c91SPeter Crosthwaite #define TYPE_XILINX_AXI_ENET_CONTROL_STREAM "xilinx-axienet-control-stream"
45f0e7a81cSPeter Crosthwaite 
46*db1015e9SEduardo Habkost typedef struct XilinxAXIEnet XilinxAXIEnet;
47f0e7a81cSPeter Crosthwaite #define XILINX_AXI_ENET(obj) \
48f0e7a81cSPeter Crosthwaite      OBJECT_CHECK(XilinxAXIEnet, (obj), TYPE_XILINX_AXI_ENET)
49f0e7a81cSPeter Crosthwaite 
50*db1015e9SEduardo Habkost typedef struct XilinxAXIEnetStreamSlave XilinxAXIEnetStreamSlave;
5155b3e0c2SPeter Crosthwaite #define XILINX_AXI_ENET_DATA_STREAM(obj) \
5255b3e0c2SPeter Crosthwaite      OBJECT_CHECK(XilinxAXIEnetStreamSlave, (obj),\
5355b3e0c2SPeter Crosthwaite      TYPE_XILINX_AXI_ENET_DATA_STREAM)
5455b3e0c2SPeter Crosthwaite 
5542bb9c91SPeter Crosthwaite #define XILINX_AXI_ENET_CONTROL_STREAM(obj) \
5642bb9c91SPeter Crosthwaite      OBJECT_CHECK(XilinxAXIEnetStreamSlave, (obj),\
5742bb9c91SPeter Crosthwaite      TYPE_XILINX_AXI_ENET_CONTROL_STREAM)
5842bb9c91SPeter Crosthwaite 
5993f1e401SEdgar E. Iglesias /* Advertisement control register. */
6093f1e401SEdgar E. Iglesias #define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
6193f1e401SEdgar E. Iglesias #define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
6293f1e401SEdgar E. Iglesias #define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
6393f1e401SEdgar E. Iglesias 
6442bb9c91SPeter Crosthwaite #define CONTROL_PAYLOAD_WORDS 5
6542bb9c91SPeter Crosthwaite #define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t)))
6642bb9c91SPeter Crosthwaite 
6793f1e401SEdgar E. Iglesias struct PHY {
6893f1e401SEdgar E. Iglesias     uint32_t regs[32];
6993f1e401SEdgar E. Iglesias 
7093f1e401SEdgar E. Iglesias     int link;
7193f1e401SEdgar E. Iglesias 
7293f1e401SEdgar E. Iglesias     unsigned int (*read)(struct PHY *phy, unsigned int req);
7393f1e401SEdgar E. Iglesias     void (*write)(struct PHY *phy, unsigned int req,
7493f1e401SEdgar E. Iglesias                   unsigned int data);
7593f1e401SEdgar E. Iglesias };
7693f1e401SEdgar E. Iglesias 
7793f1e401SEdgar E. Iglesias static unsigned int tdk_read(struct PHY *phy, unsigned int req)
7893f1e401SEdgar E. Iglesias {
7993f1e401SEdgar E. Iglesias     int regnum;
8093f1e401SEdgar E. Iglesias     unsigned r = 0;
8193f1e401SEdgar E. Iglesias 
8293f1e401SEdgar E. Iglesias     regnum = req & 0x1f;
8393f1e401SEdgar E. Iglesias 
8493f1e401SEdgar E. Iglesias     switch (regnum) {
8593f1e401SEdgar E. Iglesias         case 1:
8693f1e401SEdgar E. Iglesias             if (!phy->link) {
8793f1e401SEdgar E. Iglesias                 break;
8893f1e401SEdgar E. Iglesias             }
8993f1e401SEdgar E. Iglesias             /* MR1.  */
9093f1e401SEdgar E. Iglesias             /* Speeds and modes.  */
9193f1e401SEdgar E. Iglesias             r |= (1 << 13) | (1 << 14);
9293f1e401SEdgar E. Iglesias             r |= (1 << 11) | (1 << 12);
9393f1e401SEdgar E. Iglesias             r |= (1 << 5); /* Autoneg complete.  */
9493f1e401SEdgar E. Iglesias             r |= (1 << 3); /* Autoneg able.  */
9593f1e401SEdgar E. Iglesias             r |= (1 << 2); /* link.  */
9693f1e401SEdgar E. Iglesias             r |= (1 << 1); /* link.  */
9793f1e401SEdgar E. Iglesias             break;
9893f1e401SEdgar E. Iglesias         case 5:
9993f1e401SEdgar E. Iglesias             /* Link partner ability.
10093f1e401SEdgar E. Iglesias                We are kind; always agree with whatever best mode
10193f1e401SEdgar E. Iglesias                the guest advertises.  */
10293f1e401SEdgar E. Iglesias             r = 1 << 14; /* Success.  */
10393f1e401SEdgar E. Iglesias             /* Copy advertised modes.  */
10493f1e401SEdgar E. Iglesias             r |= phy->regs[4] & (15 << 5);
10593f1e401SEdgar E. Iglesias             /* Autoneg support.  */
10693f1e401SEdgar E. Iglesias             r |= 1;
10793f1e401SEdgar E. Iglesias             break;
10893f1e401SEdgar E. Iglesias         case 17:
10924c12b79SStefan Weil             /* Marvell PHY on many xilinx boards.  */
11093f1e401SEdgar E. Iglesias             r = 0x8000; /* 1000Mb  */
11193f1e401SEdgar E. Iglesias             break;
11293f1e401SEdgar E. Iglesias         case 18:
11393f1e401SEdgar E. Iglesias             {
11493f1e401SEdgar E. Iglesias                 /* Diagnostics reg.  */
11593f1e401SEdgar E. Iglesias                 int duplex = 0;
11693f1e401SEdgar E. Iglesias                 int speed_100 = 0;
11793f1e401SEdgar E. Iglesias 
11893f1e401SEdgar E. Iglesias                 if (!phy->link) {
11993f1e401SEdgar E. Iglesias                     break;
12093f1e401SEdgar E. Iglesias                 }
12193f1e401SEdgar E. Iglesias 
12293f1e401SEdgar E. Iglesias                 /* Are we advertising 100 half or 100 duplex ? */
12393f1e401SEdgar E. Iglesias                 speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
12493f1e401SEdgar E. Iglesias                 speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
12593f1e401SEdgar E. Iglesias 
12693f1e401SEdgar E. Iglesias                 /* Are we advertising 10 duplex or 100 duplex ? */
12793f1e401SEdgar E. Iglesias                 duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
12893f1e401SEdgar E. Iglesias                 duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
12993f1e401SEdgar E. Iglesias                 r = (speed_100 << 10) | (duplex << 11);
13093f1e401SEdgar E. Iglesias             }
13193f1e401SEdgar E. Iglesias             break;
13293f1e401SEdgar E. Iglesias 
13393f1e401SEdgar E. Iglesias         default:
13493f1e401SEdgar E. Iglesias             r = phy->regs[regnum];
13593f1e401SEdgar E. Iglesias             break;
13693f1e401SEdgar E. Iglesias     }
13793f1e401SEdgar E. Iglesias     DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum));
13893f1e401SEdgar E. Iglesias     return r;
13993f1e401SEdgar E. Iglesias }
14093f1e401SEdgar E. Iglesias 
14193f1e401SEdgar E. Iglesias static void
14293f1e401SEdgar E. Iglesias tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
14393f1e401SEdgar E. Iglesias {
14493f1e401SEdgar E. Iglesias     int regnum;
14593f1e401SEdgar E. Iglesias 
14693f1e401SEdgar E. Iglesias     regnum = req & 0x1f;
14793f1e401SEdgar E. Iglesias     DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data));
14893f1e401SEdgar E. Iglesias     switch (regnum) {
14993f1e401SEdgar E. Iglesias         default:
15093f1e401SEdgar E. Iglesias             phy->regs[regnum] = data;
15193f1e401SEdgar E. Iglesias             break;
15293f1e401SEdgar E. Iglesias     }
153f663faacSNathan Rossi 
1543e2a0cb9SEdgar E. Iglesias     /* Unconditionally clear regs[BMCR][BMCR_RESET] and auto-neg */
1553e2a0cb9SEdgar E. Iglesias     phy->regs[0] &= ~0x8200;
15693f1e401SEdgar E. Iglesias }
15793f1e401SEdgar E. Iglesias 
15893f1e401SEdgar E. Iglesias static void
15993f1e401SEdgar E. Iglesias tdk_init(struct PHY *phy)
16093f1e401SEdgar E. Iglesias {
16193f1e401SEdgar E. Iglesias     phy->regs[0] = 0x3100;
16293f1e401SEdgar E. Iglesias     /* PHY Id.  */
16393f1e401SEdgar E. Iglesias     phy->regs[2] = 0x0300;
16493f1e401SEdgar E. Iglesias     phy->regs[3] = 0xe400;
16593f1e401SEdgar E. Iglesias     /* Autonegotiation advertisement reg.  */
16693f1e401SEdgar E. Iglesias     phy->regs[4] = 0x01E1;
16793f1e401SEdgar E. Iglesias     phy->link = 1;
16893f1e401SEdgar E. Iglesias 
16993f1e401SEdgar E. Iglesias     phy->read = tdk_read;
17093f1e401SEdgar E. Iglesias     phy->write = tdk_write;
17193f1e401SEdgar E. Iglesias }
17293f1e401SEdgar E. Iglesias 
17393f1e401SEdgar E. Iglesias struct MDIOBus {
17493f1e401SEdgar E. Iglesias     struct PHY *devs[32];
17593f1e401SEdgar E. Iglesias };
17693f1e401SEdgar E. Iglesias 
17793f1e401SEdgar E. Iglesias static void
17893f1e401SEdgar E. Iglesias mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
17993f1e401SEdgar E. Iglesias {
18093f1e401SEdgar E. Iglesias     bus->devs[addr & 0x1f] = phy;
18193f1e401SEdgar E. Iglesias }
18293f1e401SEdgar E. Iglesias 
18393f1e401SEdgar E. Iglesias #ifdef USE_THIS_DEAD_CODE
18493f1e401SEdgar E. Iglesias static void
18593f1e401SEdgar E. Iglesias mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
18693f1e401SEdgar E. Iglesias {
18793f1e401SEdgar E. Iglesias     bus->devs[addr & 0x1f] = NULL;
18893f1e401SEdgar E. Iglesias }
18993f1e401SEdgar E. Iglesias #endif
19093f1e401SEdgar E. Iglesias 
19193f1e401SEdgar E. Iglesias static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr,
19293f1e401SEdgar E. Iglesias                   unsigned int reg)
19393f1e401SEdgar E. Iglesias {
19493f1e401SEdgar E. Iglesias     struct PHY *phy;
19593f1e401SEdgar E. Iglesias     uint16_t data;
19693f1e401SEdgar E. Iglesias 
19793f1e401SEdgar E. Iglesias     phy = bus->devs[addr];
19893f1e401SEdgar E. Iglesias     if (phy && phy->read) {
19993f1e401SEdgar E. Iglesias         data = phy->read(phy, reg);
20093f1e401SEdgar E. Iglesias     } else {
20193f1e401SEdgar E. Iglesias         data = 0xffff;
20293f1e401SEdgar E. Iglesias     }
20393f1e401SEdgar E. Iglesias     DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
20493f1e401SEdgar E. Iglesias     return data;
20593f1e401SEdgar E. Iglesias }
20693f1e401SEdgar E. Iglesias 
20793f1e401SEdgar E. Iglesias static void mdio_write_req(struct MDIOBus *bus, unsigned int addr,
20893f1e401SEdgar E. Iglesias                unsigned int reg, uint16_t data)
20993f1e401SEdgar E. Iglesias {
21093f1e401SEdgar E. Iglesias     struct PHY *phy;
21193f1e401SEdgar E. Iglesias 
21293f1e401SEdgar E. Iglesias     DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
21393f1e401SEdgar E. Iglesias     phy = bus->devs[addr];
21493f1e401SEdgar E. Iglesias     if (phy && phy->write) {
21593f1e401SEdgar E. Iglesias         phy->write(phy, reg, data);
21693f1e401SEdgar E. Iglesias     }
21793f1e401SEdgar E. Iglesias }
21893f1e401SEdgar E. Iglesias 
21993f1e401SEdgar E. Iglesias #define DENET(x)
22093f1e401SEdgar E. Iglesias 
22193f1e401SEdgar E. Iglesias #define R_RAF      (0x000 / 4)
22293f1e401SEdgar E. Iglesias enum {
22393f1e401SEdgar E. Iglesias     RAF_MCAST_REJ = (1 << 1),
22493f1e401SEdgar E. Iglesias     RAF_BCAST_REJ = (1 << 2),
22593f1e401SEdgar E. Iglesias     RAF_EMCF_EN = (1 << 12),
22693f1e401SEdgar E. Iglesias     RAF_NEWFUNC_EN = (1 << 11)
22793f1e401SEdgar E. Iglesias };
22893f1e401SEdgar E. Iglesias 
22993f1e401SEdgar E. Iglesias #define R_IS       (0x00C / 4)
23093f1e401SEdgar E. Iglesias enum {
23193f1e401SEdgar E. Iglesias     IS_HARD_ACCESS_COMPLETE = 1,
23293f1e401SEdgar E. Iglesias     IS_AUTONEG = (1 << 1),
23393f1e401SEdgar E. Iglesias     IS_RX_COMPLETE = (1 << 2),
23493f1e401SEdgar E. Iglesias     IS_RX_REJECT = (1 << 3),
23593f1e401SEdgar E. Iglesias     IS_TX_COMPLETE = (1 << 5),
23693f1e401SEdgar E. Iglesias     IS_RX_DCM_LOCK = (1 << 6),
23793f1e401SEdgar E. Iglesias     IS_MGM_RDY = (1 << 7),
23893f1e401SEdgar E. Iglesias     IS_PHY_RST_DONE = (1 << 8),
23993f1e401SEdgar E. Iglesias };
24093f1e401SEdgar E. Iglesias 
24193f1e401SEdgar E. Iglesias #define R_IP       (0x010 / 4)
24293f1e401SEdgar E. Iglesias #define R_IE       (0x014 / 4)
24393f1e401SEdgar E. Iglesias #define R_UAWL     (0x020 / 4)
24493f1e401SEdgar E. Iglesias #define R_UAWU     (0x024 / 4)
24593f1e401SEdgar E. Iglesias #define R_PPST     (0x030 / 4)
24693f1e401SEdgar E. Iglesias enum {
24793f1e401SEdgar E. Iglesias     PPST_LINKSTATUS = (1 << 0),
24893f1e401SEdgar E. Iglesias     PPST_PHY_LINKSTATUS = (1 << 7),
24993f1e401SEdgar E. Iglesias };
25093f1e401SEdgar E. Iglesias 
25193f1e401SEdgar E. Iglesias #define R_STATS_RX_BYTESL (0x200 / 4)
25293f1e401SEdgar E. Iglesias #define R_STATS_RX_BYTESH (0x204 / 4)
25393f1e401SEdgar E. Iglesias #define R_STATS_TX_BYTESL (0x208 / 4)
25493f1e401SEdgar E. Iglesias #define R_STATS_TX_BYTESH (0x20C / 4)
25593f1e401SEdgar E. Iglesias #define R_STATS_RXL       (0x290 / 4)
25693f1e401SEdgar E. Iglesias #define R_STATS_RXH       (0x294 / 4)
25793f1e401SEdgar E. Iglesias #define R_STATS_RX_BCASTL (0x2a0 / 4)
25893f1e401SEdgar E. Iglesias #define R_STATS_RX_BCASTH (0x2a4 / 4)
25993f1e401SEdgar E. Iglesias #define R_STATS_RX_MCASTL (0x2a8 / 4)
26093f1e401SEdgar E. Iglesias #define R_STATS_RX_MCASTH (0x2ac / 4)
26193f1e401SEdgar E. Iglesias 
26293f1e401SEdgar E. Iglesias #define R_RCW0     (0x400 / 4)
26393f1e401SEdgar E. Iglesias #define R_RCW1     (0x404 / 4)
26493f1e401SEdgar E. Iglesias enum {
26593f1e401SEdgar E. Iglesias     RCW1_VLAN = (1 << 27),
26693f1e401SEdgar E. Iglesias     RCW1_RX   = (1 << 28),
26793f1e401SEdgar E. Iglesias     RCW1_FCS  = (1 << 29),
26893f1e401SEdgar E. Iglesias     RCW1_JUM  = (1 << 30),
26993f1e401SEdgar E. Iglesias     RCW1_RST  = (1 << 31),
27093f1e401SEdgar E. Iglesias };
27193f1e401SEdgar E. Iglesias 
27293f1e401SEdgar E. Iglesias #define R_TC       (0x408 / 4)
27393f1e401SEdgar E. Iglesias enum {
27493f1e401SEdgar E. Iglesias     TC_VLAN = (1 << 27),
27593f1e401SEdgar E. Iglesias     TC_TX   = (1 << 28),
27693f1e401SEdgar E. Iglesias     TC_FCS  = (1 << 29),
27793f1e401SEdgar E. Iglesias     TC_JUM  = (1 << 30),
27893f1e401SEdgar E. Iglesias     TC_RST  = (1 << 31),
27993f1e401SEdgar E. Iglesias };
28093f1e401SEdgar E. Iglesias 
28193f1e401SEdgar E. Iglesias #define R_EMMC     (0x410 / 4)
28293f1e401SEdgar E. Iglesias enum {
28393f1e401SEdgar E. Iglesias     EMMC_LINKSPEED_10MB = (0 << 30),
28493f1e401SEdgar E. Iglesias     EMMC_LINKSPEED_100MB = (1 << 30),
28593f1e401SEdgar E. Iglesias     EMMC_LINKSPEED_1000MB = (2 << 30),
28693f1e401SEdgar E. Iglesias };
28793f1e401SEdgar E. Iglesias 
28893f1e401SEdgar E. Iglesias #define R_PHYC     (0x414 / 4)
28993f1e401SEdgar E. Iglesias 
29093f1e401SEdgar E. Iglesias #define R_MC       (0x500 / 4)
29193f1e401SEdgar E. Iglesias #define MC_EN      (1 << 6)
29293f1e401SEdgar E. Iglesias 
29393f1e401SEdgar E. Iglesias #define R_MCR      (0x504 / 4)
29493f1e401SEdgar E. Iglesias #define R_MWD      (0x508 / 4)
29593f1e401SEdgar E. Iglesias #define R_MRD      (0x50c / 4)
29693f1e401SEdgar E. Iglesias #define R_MIS      (0x600 / 4)
29793f1e401SEdgar E. Iglesias #define R_MIP      (0x620 / 4)
29893f1e401SEdgar E. Iglesias #define R_MIE      (0x640 / 4)
29993f1e401SEdgar E. Iglesias #define R_MIC      (0x640 / 4)
30093f1e401SEdgar E. Iglesias 
30193f1e401SEdgar E. Iglesias #define R_UAW0     (0x700 / 4)
30293f1e401SEdgar E. Iglesias #define R_UAW1     (0x704 / 4)
30393f1e401SEdgar E. Iglesias #define R_FMI      (0x708 / 4)
30493f1e401SEdgar E. Iglesias #define R_AF0      (0x710 / 4)
30593f1e401SEdgar E. Iglesias #define R_AF1      (0x714 / 4)
30693f1e401SEdgar E. Iglesias #define R_MAX      (0x34 / 4)
30793f1e401SEdgar E. Iglesias 
30893f1e401SEdgar E. Iglesias /* Indirect registers.  */
30993f1e401SEdgar E. Iglesias struct TEMAC  {
31093f1e401SEdgar E. Iglesias     struct MDIOBus mdio_bus;
31193f1e401SEdgar E. Iglesias     struct PHY phy;
31293f1e401SEdgar E. Iglesias 
31393f1e401SEdgar E. Iglesias     void *parent;
31493f1e401SEdgar E. Iglesias };
31593f1e401SEdgar E. Iglesias 
316545129e5SPeter Crosthwaite 
31755b3e0c2SPeter Crosthwaite struct XilinxAXIEnetStreamSlave {
31855b3e0c2SPeter Crosthwaite     Object parent;
31955b3e0c2SPeter Crosthwaite 
32055b3e0c2SPeter Crosthwaite     struct XilinxAXIEnet *enet;
32155b3e0c2SPeter Crosthwaite } ;
32255b3e0c2SPeter Crosthwaite 
32393f1e401SEdgar E. Iglesias struct XilinxAXIEnet {
32493f1e401SEdgar E. Iglesias     SysBusDevice busdev;
3250dc31f3bSAvi Kivity     MemoryRegion iomem;
32693f1e401SEdgar E. Iglesias     qemu_irq irq;
32742bb9c91SPeter Crosthwaite     StreamSlave *tx_data_dev;
32842bb9c91SPeter Crosthwaite     StreamSlave *tx_control_dev;
32955b3e0c2SPeter Crosthwaite     XilinxAXIEnetStreamSlave rx_data_dev;
33042bb9c91SPeter Crosthwaite     XilinxAXIEnetStreamSlave rx_control_dev;
33193f1e401SEdgar E. Iglesias     NICState *nic;
33293f1e401SEdgar E. Iglesias     NICConf conf;
33393f1e401SEdgar E. Iglesias 
33493f1e401SEdgar E. Iglesias 
33593f1e401SEdgar E. Iglesias     uint32_t c_rxmem;
33693f1e401SEdgar E. Iglesias     uint32_t c_txmem;
33793f1e401SEdgar E. Iglesias     uint32_t c_phyaddr;
33893f1e401SEdgar E. Iglesias 
33993f1e401SEdgar E. Iglesias     struct TEMAC TEMAC;
34093f1e401SEdgar E. Iglesias 
34193f1e401SEdgar E. Iglesias     /* MII regs.  */
34293f1e401SEdgar E. Iglesias     union {
34393f1e401SEdgar E. Iglesias         uint32_t regs[4];
34493f1e401SEdgar E. Iglesias         struct {
34593f1e401SEdgar E. Iglesias             uint32_t mc;
34693f1e401SEdgar E. Iglesias             uint32_t mcr;
34793f1e401SEdgar E. Iglesias             uint32_t mwd;
34893f1e401SEdgar E. Iglesias             uint32_t mrd;
34993f1e401SEdgar E. Iglesias         };
35093f1e401SEdgar E. Iglesias     } mii;
35193f1e401SEdgar E. Iglesias 
35293f1e401SEdgar E. Iglesias     struct {
35393f1e401SEdgar E. Iglesias         uint64_t rx_bytes;
35493f1e401SEdgar E. Iglesias         uint64_t tx_bytes;
35593f1e401SEdgar E. Iglesias 
35693f1e401SEdgar E. Iglesias         uint64_t rx;
35793f1e401SEdgar E. Iglesias         uint64_t rx_bcast;
35893f1e401SEdgar E. Iglesias         uint64_t rx_mcast;
35993f1e401SEdgar E. Iglesias     } stats;
36093f1e401SEdgar E. Iglesias 
36193f1e401SEdgar E. Iglesias     /* Receive configuration words.  */
36293f1e401SEdgar E. Iglesias     uint32_t rcw[2];
36393f1e401SEdgar E. Iglesias     /* Transmit config.  */
36493f1e401SEdgar E. Iglesias     uint32_t tc;
36593f1e401SEdgar E. Iglesias     uint32_t emmc;
36693f1e401SEdgar E. Iglesias     uint32_t phyc;
36793f1e401SEdgar E. Iglesias 
36893f1e401SEdgar E. Iglesias     /* Unicast Address Word.  */
36993f1e401SEdgar E. Iglesias     uint32_t uaw[2];
37093f1e401SEdgar E. Iglesias     /* Unicast address filter used with extended mcast.  */
37193f1e401SEdgar E. Iglesias     uint32_t ext_uaw[2];
37293f1e401SEdgar E. Iglesias     uint32_t fmi;
37393f1e401SEdgar E. Iglesias 
37493f1e401SEdgar E. Iglesias     uint32_t regs[R_MAX];
37593f1e401SEdgar E. Iglesias 
37693f1e401SEdgar E. Iglesias     /* Multicast filter addrs.  */
37793f1e401SEdgar E. Iglesias     uint32_t maddr[4][2];
37893f1e401SEdgar E. Iglesias     /* 32K x 1 lookup filter.  */
37993f1e401SEdgar E. Iglesias     uint32_t ext_mtable[1024];
38093f1e401SEdgar E. Iglesias 
38142bb9c91SPeter Crosthwaite     uint32_t hdr[CONTROL_PAYLOAD_WORDS];
38293f1e401SEdgar E. Iglesias 
3832a4f2635SEdgar E. Iglesias     uint8_t *txmem;
3842a4f2635SEdgar E. Iglesias     uint32_t txpos;
3852a4f2635SEdgar E. Iglesias 
38693f1e401SEdgar E. Iglesias     uint8_t *rxmem;
3873630ae95SPeter Crosthwaite     uint32_t rxsize;
3883630ae95SPeter Crosthwaite     uint32_t rxpos;
38942bb9c91SPeter Crosthwaite 
39042bb9c91SPeter Crosthwaite     uint8_t rxapp[CONTROL_PAYLOAD_SIZE];
39142bb9c91SPeter Crosthwaite     uint32_t rxappsize;
392f9f7492eSFam Zheng 
393f9f7492eSFam Zheng     /* Whether axienet_eth_rx_notify should flush incoming queue. */
394f9f7492eSFam Zheng     bool need_flush;
39593f1e401SEdgar E. Iglesias };
39693f1e401SEdgar E. Iglesias 
397545129e5SPeter Crosthwaite static void axienet_rx_reset(XilinxAXIEnet *s)
39893f1e401SEdgar E. Iglesias {
39993f1e401SEdgar E. Iglesias     s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN;
40093f1e401SEdgar E. Iglesias }
40193f1e401SEdgar E. Iglesias 
402545129e5SPeter Crosthwaite static void axienet_tx_reset(XilinxAXIEnet *s)
40393f1e401SEdgar E. Iglesias {
40493f1e401SEdgar E. Iglesias     s->tc = TC_JUM | TC_TX | TC_VLAN;
4052a4f2635SEdgar E. Iglesias     s->txpos = 0;
40693f1e401SEdgar E. Iglesias }
40793f1e401SEdgar E. Iglesias 
408545129e5SPeter Crosthwaite static inline int axienet_rx_resetting(XilinxAXIEnet *s)
40993f1e401SEdgar E. Iglesias {
41093f1e401SEdgar E. Iglesias     return s->rcw[1] & RCW1_RST;
41193f1e401SEdgar E. Iglesias }
41293f1e401SEdgar E. Iglesias 
413545129e5SPeter Crosthwaite static inline int axienet_rx_enabled(XilinxAXIEnet *s)
41493f1e401SEdgar E. Iglesias {
41593f1e401SEdgar E. Iglesias     return s->rcw[1] & RCW1_RX;
41693f1e401SEdgar E. Iglesias }
41793f1e401SEdgar E. Iglesias 
418545129e5SPeter Crosthwaite static inline int axienet_extmcf_enabled(XilinxAXIEnet *s)
41993f1e401SEdgar E. Iglesias {
42093f1e401SEdgar E. Iglesias     return !!(s->regs[R_RAF] & RAF_EMCF_EN);
42193f1e401SEdgar E. Iglesias }
42293f1e401SEdgar E. Iglesias 
423545129e5SPeter Crosthwaite static inline int axienet_newfunc_enabled(XilinxAXIEnet *s)
42493f1e401SEdgar E. Iglesias {
42593f1e401SEdgar E. Iglesias     return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN);
42693f1e401SEdgar E. Iglesias }
42793f1e401SEdgar E. Iglesias 
4289ee0ceb7SPeter Crosthwaite static void xilinx_axienet_reset(DeviceState *d)
42993f1e401SEdgar E. Iglesias {
4309ee0ceb7SPeter Crosthwaite     XilinxAXIEnet *s = XILINX_AXI_ENET(d);
4319ee0ceb7SPeter Crosthwaite 
43293f1e401SEdgar E. Iglesias     axienet_rx_reset(s);
43393f1e401SEdgar E. Iglesias     axienet_tx_reset(s);
43493f1e401SEdgar E. Iglesias 
43593f1e401SEdgar E. Iglesias     s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS;
43693f1e401SEdgar E. Iglesias     s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE;
43793f1e401SEdgar E. Iglesias 
43893f1e401SEdgar E. Iglesias     s->emmc = EMMC_LINKSPEED_100MB;
43993f1e401SEdgar E. Iglesias }
44093f1e401SEdgar E. Iglesias 
441545129e5SPeter Crosthwaite static void enet_update_irq(XilinxAXIEnet *s)
44293f1e401SEdgar E. Iglesias {
44393f1e401SEdgar E. Iglesias     s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE];
44493f1e401SEdgar E. Iglesias     qemu_set_irq(s->irq, !!s->regs[R_IP]);
44593f1e401SEdgar E. Iglesias }
44693f1e401SEdgar E. Iglesias 
447a8170e5eSAvi Kivity static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size)
44893f1e401SEdgar E. Iglesias {
449545129e5SPeter Crosthwaite     XilinxAXIEnet *s = opaque;
45093f1e401SEdgar E. Iglesias     uint32_t r = 0;
45193f1e401SEdgar E. Iglesias     addr >>= 2;
45293f1e401SEdgar E. Iglesias 
45393f1e401SEdgar E. Iglesias     switch (addr) {
45493f1e401SEdgar E. Iglesias         case R_RCW0:
45593f1e401SEdgar E. Iglesias         case R_RCW1:
45693f1e401SEdgar E. Iglesias             r = s->rcw[addr & 1];
45793f1e401SEdgar E. Iglesias             break;
45893f1e401SEdgar E. Iglesias 
45993f1e401SEdgar E. Iglesias         case R_TC:
46093f1e401SEdgar E. Iglesias             r = s->tc;
46193f1e401SEdgar E. Iglesias             break;
46293f1e401SEdgar E. Iglesias 
46393f1e401SEdgar E. Iglesias         case R_EMMC:
46493f1e401SEdgar E. Iglesias             r = s->emmc;
46593f1e401SEdgar E. Iglesias             break;
46693f1e401SEdgar E. Iglesias 
46793f1e401SEdgar E. Iglesias         case R_PHYC:
46893f1e401SEdgar E. Iglesias             r = s->phyc;
46993f1e401SEdgar E. Iglesias             break;
47093f1e401SEdgar E. Iglesias 
47193f1e401SEdgar E. Iglesias         case R_MCR:
47293f1e401SEdgar E. Iglesias             r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready.  */
47393f1e401SEdgar E. Iglesias             break;
47493f1e401SEdgar E. Iglesias 
47593f1e401SEdgar E. Iglesias         case R_STATS_RX_BYTESL:
47693f1e401SEdgar E. Iglesias         case R_STATS_RX_BYTESH:
47793f1e401SEdgar E. Iglesias             r = s->stats.rx_bytes >> (32 * (addr & 1));
47893f1e401SEdgar E. Iglesias             break;
47993f1e401SEdgar E. Iglesias 
48093f1e401SEdgar E. Iglesias         case R_STATS_TX_BYTESL:
48193f1e401SEdgar E. Iglesias         case R_STATS_TX_BYTESH:
48293f1e401SEdgar E. Iglesias             r = s->stats.tx_bytes >> (32 * (addr & 1));
48393f1e401SEdgar E. Iglesias             break;
48493f1e401SEdgar E. Iglesias 
48593f1e401SEdgar E. Iglesias         case R_STATS_RXL:
48693f1e401SEdgar E. Iglesias         case R_STATS_RXH:
48793f1e401SEdgar E. Iglesias             r = s->stats.rx >> (32 * (addr & 1));
48893f1e401SEdgar E. Iglesias             break;
48993f1e401SEdgar E. Iglesias         case R_STATS_RX_BCASTL:
49093f1e401SEdgar E. Iglesias         case R_STATS_RX_BCASTH:
49193f1e401SEdgar E. Iglesias             r = s->stats.rx_bcast >> (32 * (addr & 1));
49293f1e401SEdgar E. Iglesias             break;
49393f1e401SEdgar E. Iglesias         case R_STATS_RX_MCASTL:
49493f1e401SEdgar E. Iglesias         case R_STATS_RX_MCASTH:
49593f1e401SEdgar E. Iglesias             r = s->stats.rx_mcast >> (32 * (addr & 1));
49693f1e401SEdgar E. Iglesias             break;
49793f1e401SEdgar E. Iglesias 
49893f1e401SEdgar E. Iglesias         case R_MC:
49993f1e401SEdgar E. Iglesias         case R_MWD:
50093f1e401SEdgar E. Iglesias         case R_MRD:
50193f1e401SEdgar E. Iglesias             r = s->mii.regs[addr & 3];
50293f1e401SEdgar E. Iglesias             break;
50393f1e401SEdgar E. Iglesias 
50493f1e401SEdgar E. Iglesias         case R_UAW0:
50593f1e401SEdgar E. Iglesias         case R_UAW1:
50693f1e401SEdgar E. Iglesias             r = s->uaw[addr & 1];
50793f1e401SEdgar E. Iglesias             break;
50893f1e401SEdgar E. Iglesias 
50993f1e401SEdgar E. Iglesias         case R_UAWU:
51093f1e401SEdgar E. Iglesias         case R_UAWL:
51193f1e401SEdgar E. Iglesias             r = s->ext_uaw[addr & 1];
51293f1e401SEdgar E. Iglesias             break;
51393f1e401SEdgar E. Iglesias 
51493f1e401SEdgar E. Iglesias         case R_FMI:
51593f1e401SEdgar E. Iglesias             r = s->fmi;
51693f1e401SEdgar E. Iglesias             break;
51793f1e401SEdgar E. Iglesias 
51893f1e401SEdgar E. Iglesias         case R_AF0:
51993f1e401SEdgar E. Iglesias         case R_AF1:
52093f1e401SEdgar E. Iglesias             r = s->maddr[s->fmi & 3][addr & 1];
52193f1e401SEdgar E. Iglesias             break;
52293f1e401SEdgar E. Iglesias 
52393f1e401SEdgar E. Iglesias         case 0x8000 ... 0x83ff:
52493f1e401SEdgar E. Iglesias             r = s->ext_mtable[addr - 0x8000];
52593f1e401SEdgar E. Iglesias             break;
52693f1e401SEdgar E. Iglesias 
52793f1e401SEdgar E. Iglesias         default:
52893f1e401SEdgar E. Iglesias             if (addr < ARRAY_SIZE(s->regs)) {
52993f1e401SEdgar E. Iglesias                 r = s->regs[addr];
53093f1e401SEdgar E. Iglesias             }
53193f1e401SEdgar E. Iglesias             DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
53293f1e401SEdgar E. Iglesias                             __func__, addr * 4, r));
53393f1e401SEdgar E. Iglesias             break;
53493f1e401SEdgar E. Iglesias     }
53593f1e401SEdgar E. Iglesias     return r;
53693f1e401SEdgar E. Iglesias }
53793f1e401SEdgar E. Iglesias 
538a8170e5eSAvi Kivity static void enet_write(void *opaque, hwaddr addr,
5390dc31f3bSAvi Kivity                        uint64_t value, unsigned size)
54093f1e401SEdgar E. Iglesias {
541545129e5SPeter Crosthwaite     XilinxAXIEnet *s = opaque;
54293f1e401SEdgar E. Iglesias     struct TEMAC *t = &s->TEMAC;
54393f1e401SEdgar E. Iglesias 
54493f1e401SEdgar E. Iglesias     addr >>= 2;
54593f1e401SEdgar E. Iglesias     switch (addr) {
54693f1e401SEdgar E. Iglesias         case R_RCW0:
54793f1e401SEdgar E. Iglesias         case R_RCW1:
54893f1e401SEdgar E. Iglesias             s->rcw[addr & 1] = value;
54993f1e401SEdgar E. Iglesias             if ((addr & 1) && value & RCW1_RST) {
55093f1e401SEdgar E. Iglesias                 axienet_rx_reset(s);
5514dbb9ed3SPeter Crosthwaite             } else {
5524dbb9ed3SPeter Crosthwaite                 qemu_flush_queued_packets(qemu_get_queue(s->nic));
55393f1e401SEdgar E. Iglesias             }
55493f1e401SEdgar E. Iglesias             break;
55593f1e401SEdgar E. Iglesias 
55693f1e401SEdgar E. Iglesias         case R_TC:
55793f1e401SEdgar E. Iglesias             s->tc = value;
55893f1e401SEdgar E. Iglesias             if (value & TC_RST) {
55993f1e401SEdgar E. Iglesias                 axienet_tx_reset(s);
56093f1e401SEdgar E. Iglesias             }
56193f1e401SEdgar E. Iglesias             break;
56293f1e401SEdgar E. Iglesias 
56393f1e401SEdgar E. Iglesias         case R_EMMC:
56493f1e401SEdgar E. Iglesias             s->emmc = value;
56593f1e401SEdgar E. Iglesias             break;
56693f1e401SEdgar E. Iglesias 
56793f1e401SEdgar E. Iglesias         case R_PHYC:
56893f1e401SEdgar E. Iglesias             s->phyc = value;
56993f1e401SEdgar E. Iglesias             break;
57093f1e401SEdgar E. Iglesias 
57193f1e401SEdgar E. Iglesias         case R_MC:
5724e298e46SStefan Weil              value &= ((1 << 7) - 1);
57393f1e401SEdgar E. Iglesias 
57493f1e401SEdgar E. Iglesias              /* Enable the MII.  */
57593f1e401SEdgar E. Iglesias              if (value & MC_EN) {
57693f1e401SEdgar E. Iglesias                  unsigned int miiclkdiv = value & ((1 << 6) - 1);
57793f1e401SEdgar E. Iglesias                  if (!miiclkdiv) {
57893f1e401SEdgar E. Iglesias                      qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n");
57993f1e401SEdgar E. Iglesias                  }
58093f1e401SEdgar E. Iglesias              }
58193f1e401SEdgar E. Iglesias              s->mii.mc = value;
58293f1e401SEdgar E. Iglesias              break;
58393f1e401SEdgar E. Iglesias 
58493f1e401SEdgar E. Iglesias         case R_MCR: {
58593f1e401SEdgar E. Iglesias              unsigned int phyaddr = (value >> 24) & 0x1f;
58693f1e401SEdgar E. Iglesias              unsigned int regaddr = (value >> 16) & 0x1f;
58793f1e401SEdgar E. Iglesias              unsigned int op = (value >> 14) & 3;
58893f1e401SEdgar E. Iglesias              unsigned int initiate = (value >> 11) & 1;
58993f1e401SEdgar E. Iglesias 
59093f1e401SEdgar E. Iglesias              if (initiate) {
59193f1e401SEdgar E. Iglesias                  if (op == 1) {
59293f1e401SEdgar E. Iglesias                      mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd);
59393f1e401SEdgar E. Iglesias                  } else if (op == 2) {
59493f1e401SEdgar E. Iglesias                      s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr);
59593f1e401SEdgar E. Iglesias                  } else {
59693f1e401SEdgar E. Iglesias                      qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op);
59793f1e401SEdgar E. Iglesias                  }
59893f1e401SEdgar E. Iglesias              }
59993f1e401SEdgar E. Iglesias              s->mii.mcr = value;
60093f1e401SEdgar E. Iglesias              break;
60193f1e401SEdgar E. Iglesias         }
60293f1e401SEdgar E. Iglesias 
60393f1e401SEdgar E. Iglesias         case R_MWD:
60493f1e401SEdgar E. Iglesias         case R_MRD:
60593f1e401SEdgar E. Iglesias              s->mii.regs[addr & 3] = value;
60693f1e401SEdgar E. Iglesias              break;
60793f1e401SEdgar E. Iglesias 
60893f1e401SEdgar E. Iglesias 
60993f1e401SEdgar E. Iglesias         case R_UAW0:
61093f1e401SEdgar E. Iglesias         case R_UAW1:
61193f1e401SEdgar E. Iglesias             s->uaw[addr & 1] = value;
61293f1e401SEdgar E. Iglesias             break;
61393f1e401SEdgar E. Iglesias 
61493f1e401SEdgar E. Iglesias         case R_UAWL:
61593f1e401SEdgar E. Iglesias         case R_UAWU:
61693f1e401SEdgar E. Iglesias             s->ext_uaw[addr & 1] = value;
61793f1e401SEdgar E. Iglesias             break;
61893f1e401SEdgar E. Iglesias 
61993f1e401SEdgar E. Iglesias         case R_FMI:
62093f1e401SEdgar E. Iglesias             s->fmi = value;
62193f1e401SEdgar E. Iglesias             break;
62293f1e401SEdgar E. Iglesias 
62393f1e401SEdgar E. Iglesias         case R_AF0:
62493f1e401SEdgar E. Iglesias         case R_AF1:
62593f1e401SEdgar E. Iglesias             s->maddr[s->fmi & 3][addr & 1] = value;
62693f1e401SEdgar E. Iglesias             break;
62793f1e401SEdgar E. Iglesias 
628d4d230daSPeter Crosthwaite         case R_IS:
629d4d230daSPeter Crosthwaite             s->regs[addr] &= ~value;
630d4d230daSPeter Crosthwaite             break;
631d4d230daSPeter Crosthwaite 
63293f1e401SEdgar E. Iglesias         case 0x8000 ... 0x83ff:
63393f1e401SEdgar E. Iglesias             s->ext_mtable[addr - 0x8000] = value;
63493f1e401SEdgar E. Iglesias             break;
63593f1e401SEdgar E. Iglesias 
63693f1e401SEdgar E. Iglesias         default:
63793f1e401SEdgar E. Iglesias             DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
6380dc31f3bSAvi Kivity                            __func__, addr * 4, (unsigned)value));
63993f1e401SEdgar E. Iglesias             if (addr < ARRAY_SIZE(s->regs)) {
64093f1e401SEdgar E. Iglesias                 s->regs[addr] = value;
64193f1e401SEdgar E. Iglesias             }
64293f1e401SEdgar E. Iglesias             break;
64393f1e401SEdgar E. Iglesias     }
64493f1e401SEdgar E. Iglesias     enet_update_irq(s);
64593f1e401SEdgar E. Iglesias }
64693f1e401SEdgar E. Iglesias 
6470dc31f3bSAvi Kivity static const MemoryRegionOps enet_ops = {
6480dc31f3bSAvi Kivity     .read = enet_read,
6490dc31f3bSAvi Kivity     .write = enet_write,
6500dc31f3bSAvi Kivity     .endianness = DEVICE_LITTLE_ENDIAN,
65193f1e401SEdgar E. Iglesias };
65293f1e401SEdgar E. Iglesias 
653f9f7492eSFam Zheng static int eth_can_rx(XilinxAXIEnet *s)
65493f1e401SEdgar E. Iglesias {
65593f1e401SEdgar E. Iglesias     /* RX enabled?  */
6563630ae95SPeter Crosthwaite     return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s);
65793f1e401SEdgar E. Iglesias }
65893f1e401SEdgar E. Iglesias 
65993f1e401SEdgar E. Iglesias static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1)
66093f1e401SEdgar E. Iglesias {
66193f1e401SEdgar E. Iglesias     int match = 1;
66293f1e401SEdgar E. Iglesias 
66393f1e401SEdgar E. Iglesias     if (memcmp(buf, &f0, 4)) {
66493f1e401SEdgar E. Iglesias         match = 0;
66593f1e401SEdgar E. Iglesias     }
66693f1e401SEdgar E. Iglesias 
66793f1e401SEdgar E. Iglesias     if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) {
66893f1e401SEdgar E. Iglesias         match = 0;
66993f1e401SEdgar E. Iglesias     }
67093f1e401SEdgar E. Iglesias 
67193f1e401SEdgar E. Iglesias     return match;
67293f1e401SEdgar E. Iglesias }
67393f1e401SEdgar E. Iglesias 
6743630ae95SPeter Crosthwaite static void axienet_eth_rx_notify(void *opaque)
6753630ae95SPeter Crosthwaite {
6763630ae95SPeter Crosthwaite     XilinxAXIEnet *s = XILINX_AXI_ENET(opaque);
6773630ae95SPeter Crosthwaite 
67842bb9c91SPeter Crosthwaite     while (s->rxappsize && stream_can_push(s->tx_control_dev,
67942bb9c91SPeter Crosthwaite                                            axienet_eth_rx_notify, s)) {
68042bb9c91SPeter Crosthwaite         size_t ret = stream_push(s->tx_control_dev,
68142bb9c91SPeter Crosthwaite                                  (void *)s->rxapp + CONTROL_PAYLOAD_SIZE
68251b19950SEdgar E. Iglesias                                  - s->rxappsize, s->rxappsize, true);
68342bb9c91SPeter Crosthwaite         s->rxappsize -= ret;
68442bb9c91SPeter Crosthwaite     }
68542bb9c91SPeter Crosthwaite 
68642bb9c91SPeter Crosthwaite     while (s->rxsize && stream_can_push(s->tx_data_dev,
68742bb9c91SPeter Crosthwaite                                         axienet_eth_rx_notify, s)) {
68842bb9c91SPeter Crosthwaite         size_t ret = stream_push(s->tx_data_dev, (void *)s->rxmem + s->rxpos,
68951b19950SEdgar E. Iglesias                                  s->rxsize, true);
6903630ae95SPeter Crosthwaite         s->rxsize -= ret;
6913630ae95SPeter Crosthwaite         s->rxpos += ret;
6923630ae95SPeter Crosthwaite         if (!s->rxsize) {
6933630ae95SPeter Crosthwaite             s->regs[R_IS] |= IS_RX_COMPLETE;
694f9f7492eSFam Zheng             if (s->need_flush) {
695f9f7492eSFam Zheng                 s->need_flush = false;
696f9f7492eSFam Zheng                 qemu_flush_queued_packets(qemu_get_queue(s->nic));
697f9f7492eSFam Zheng             }
6983630ae95SPeter Crosthwaite         }
6993630ae95SPeter Crosthwaite     }
7003630ae95SPeter Crosthwaite     enet_update_irq(s);
7013630ae95SPeter Crosthwaite }
7023630ae95SPeter Crosthwaite 
7034e68f7a0SStefan Hajnoczi static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
70493f1e401SEdgar E. Iglesias {
705545129e5SPeter Crosthwaite     XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
70693f1e401SEdgar E. Iglesias     static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
70793f1e401SEdgar E. Iglesias                                               0xff, 0xff, 0xff};
70893f1e401SEdgar E. Iglesias     static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52};
70942bb9c91SPeter Crosthwaite     uint32_t app[CONTROL_PAYLOAD_WORDS] = {0};
71093f1e401SEdgar E. Iglesias     int promisc = s->fmi & (1 << 31);
71193f1e401SEdgar E. Iglesias     int unicast, broadcast, multicast, ip_multicast = 0;
71293f1e401SEdgar E. Iglesias     uint32_t csum32;
71393f1e401SEdgar E. Iglesias     uint16_t csum16;
71493f1e401SEdgar E. Iglesias     int i;
71593f1e401SEdgar E. Iglesias 
71693f1e401SEdgar E. Iglesias     DENET(qemu_log("%s: %zd bytes\n", __func__, size));
71793f1e401SEdgar E. Iglesias 
718f9f7492eSFam Zheng     if (!eth_can_rx(s)) {
719f9f7492eSFam Zheng         s->need_flush = true;
720f9f7492eSFam Zheng         return 0;
721f9f7492eSFam Zheng     }
722f9f7492eSFam Zheng 
72393f1e401SEdgar E. Iglesias     unicast = ~buf[0] & 0x1;
72493f1e401SEdgar E. Iglesias     broadcast = memcmp(buf, sa_bcast, 6) == 0;
72593f1e401SEdgar E. Iglesias     multicast = !unicast && !broadcast;
72693f1e401SEdgar E. Iglesias     if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) {
72793f1e401SEdgar E. Iglesias         ip_multicast = 1;
72893f1e401SEdgar E. Iglesias     }
72993f1e401SEdgar E. Iglesias 
73093f1e401SEdgar E. Iglesias     /* Jumbo or vlan sizes ?  */
73193f1e401SEdgar E. Iglesias     if (!(s->rcw[1] & RCW1_JUM)) {
73293f1e401SEdgar E. Iglesias         if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) {
73393f1e401SEdgar E. Iglesias             return size;
73493f1e401SEdgar E. Iglesias         }
73593f1e401SEdgar E. Iglesias     }
73693f1e401SEdgar E. Iglesias 
73793f1e401SEdgar E. Iglesias     /* Basic Address filters.  If you want to use the extended filters
73893f1e401SEdgar E. Iglesias        you'll generally have to place the ethernet mac into promiscuous mode
73993f1e401SEdgar E. Iglesias        to avoid the basic filtering from dropping most frames.  */
74093f1e401SEdgar E. Iglesias     if (!promisc) {
74193f1e401SEdgar E. Iglesias         if (unicast) {
74293f1e401SEdgar E. Iglesias             if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) {
74393f1e401SEdgar E. Iglesias                 return size;
74493f1e401SEdgar E. Iglesias             }
74593f1e401SEdgar E. Iglesias         } else {
74693f1e401SEdgar E. Iglesias             if (broadcast) {
74793f1e401SEdgar E. Iglesias                 /* Broadcast.  */
74893f1e401SEdgar E. Iglesias                 if (s->regs[R_RAF] & RAF_BCAST_REJ) {
74993f1e401SEdgar E. Iglesias                     return size;
75093f1e401SEdgar E. Iglesias                 }
75193f1e401SEdgar E. Iglesias             } else {
75293f1e401SEdgar E. Iglesias                 int drop = 1;
75393f1e401SEdgar E. Iglesias 
75493f1e401SEdgar E. Iglesias                 /* Multicast.  */
75593f1e401SEdgar E. Iglesias                 if (s->regs[R_RAF] & RAF_MCAST_REJ) {
75693f1e401SEdgar E. Iglesias                     return size;
75793f1e401SEdgar E. Iglesias                 }
75893f1e401SEdgar E. Iglesias 
75993f1e401SEdgar E. Iglesias                 for (i = 0; i < 4; i++) {
76093f1e401SEdgar E. Iglesias                     if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) {
76193f1e401SEdgar E. Iglesias                         drop = 0;
76293f1e401SEdgar E. Iglesias                         break;
76393f1e401SEdgar E. Iglesias                     }
76493f1e401SEdgar E. Iglesias                 }
76593f1e401SEdgar E. Iglesias 
76693f1e401SEdgar E. Iglesias                 if (drop) {
76793f1e401SEdgar E. Iglesias                     return size;
76893f1e401SEdgar E. Iglesias                 }
76993f1e401SEdgar E. Iglesias             }
77093f1e401SEdgar E. Iglesias         }
77193f1e401SEdgar E. Iglesias     }
77293f1e401SEdgar E. Iglesias 
77393f1e401SEdgar E. Iglesias     /* Extended mcast filtering enabled?  */
77493f1e401SEdgar E. Iglesias     if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) {
77593f1e401SEdgar E. Iglesias         if (unicast) {
77693f1e401SEdgar E. Iglesias             if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) {
77793f1e401SEdgar E. Iglesias                 return size;
77893f1e401SEdgar E. Iglesias             }
77993f1e401SEdgar E. Iglesias         } else {
78093f1e401SEdgar E. Iglesias             if (broadcast) {
78193f1e401SEdgar E. Iglesias                 /* Broadcast. ???  */
78293f1e401SEdgar E. Iglesias                 if (s->regs[R_RAF] & RAF_BCAST_REJ) {
78393f1e401SEdgar E. Iglesias                     return size;
78493f1e401SEdgar E. Iglesias                 }
78593f1e401SEdgar E. Iglesias             } else {
78693f1e401SEdgar E. Iglesias                 int idx, bit;
78793f1e401SEdgar E. Iglesias 
78893f1e401SEdgar E. Iglesias                 /* Multicast.  */
78993f1e401SEdgar E. Iglesias                 if (!memcmp(buf, sa_ipmcast, 3)) {
79093f1e401SEdgar E. Iglesias                     return size;
79193f1e401SEdgar E. Iglesias                 }
79293f1e401SEdgar E. Iglesias 
79393f1e401SEdgar E. Iglesias                 idx  = (buf[4] & 0x7f) << 8;
79493f1e401SEdgar E. Iglesias                 idx |= buf[5];
79593f1e401SEdgar E. Iglesias 
79693f1e401SEdgar E. Iglesias                 bit = 1 << (idx & 0x1f);
79793f1e401SEdgar E. Iglesias                 idx >>= 5;
79893f1e401SEdgar E. Iglesias 
79993f1e401SEdgar E. Iglesias                 if (!(s->ext_mtable[idx] & bit)) {
80093f1e401SEdgar E. Iglesias                     return size;
80193f1e401SEdgar E. Iglesias                 }
80293f1e401SEdgar E. Iglesias             }
80393f1e401SEdgar E. Iglesias         }
80493f1e401SEdgar E. Iglesias     }
80593f1e401SEdgar E. Iglesias 
80693f1e401SEdgar E. Iglesias     if (size < 12) {
80793f1e401SEdgar E. Iglesias         s->regs[R_IS] |= IS_RX_REJECT;
80893f1e401SEdgar E. Iglesias         enet_update_irq(s);
80993f1e401SEdgar E. Iglesias         return -1;
81093f1e401SEdgar E. Iglesias     }
81193f1e401SEdgar E. Iglesias 
81293f1e401SEdgar E. Iglesias     if (size > (s->c_rxmem - 4)) {
81393f1e401SEdgar E. Iglesias         size = s->c_rxmem - 4;
81493f1e401SEdgar E. Iglesias     }
81593f1e401SEdgar E. Iglesias 
81693f1e401SEdgar E. Iglesias     memcpy(s->rxmem, buf, size);
81793f1e401SEdgar E. Iglesias     memset(s->rxmem + size, 0, 4); /* Clear the FCS.  */
81893f1e401SEdgar E. Iglesias 
81993f1e401SEdgar E. Iglesias     if (s->rcw[1] & RCW1_FCS) {
82093f1e401SEdgar E. Iglesias         size += 4; /* fcs is inband.  */
82193f1e401SEdgar E. Iglesias     }
82293f1e401SEdgar E. Iglesias 
82393f1e401SEdgar E. Iglesias     app[0] = 5 << 28;
82493f1e401SEdgar E. Iglesias     csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14);
82593f1e401SEdgar E. Iglesias     /* Fold it once.  */
82693f1e401SEdgar E. Iglesias     csum32 = (csum32 & 0xffff) + (csum32 >> 16);
82793f1e401SEdgar E. Iglesias     /* And twice to get rid of possible carries.  */
82893f1e401SEdgar E. Iglesias     csum16 = (csum32 & 0xffff) + (csum32 >> 16);
82993f1e401SEdgar E. Iglesias     app[3] = csum16;
83093f1e401SEdgar E. Iglesias     app[4] = size & 0xffff;
83193f1e401SEdgar E. Iglesias 
83293f1e401SEdgar E. Iglesias     s->stats.rx_bytes += size;
83393f1e401SEdgar E. Iglesias     s->stats.rx++;
83493f1e401SEdgar E. Iglesias     if (multicast) {
83593f1e401SEdgar E. Iglesias         s->stats.rx_mcast++;
83693f1e401SEdgar E. Iglesias         app[2] |= 1 | (ip_multicast << 1);
83793f1e401SEdgar E. Iglesias     } else if (broadcast) {
83893f1e401SEdgar E. Iglesias         s->stats.rx_bcast++;
83993f1e401SEdgar E. Iglesias         app[2] |= 1 << 3;
84093f1e401SEdgar E. Iglesias     }
84193f1e401SEdgar E. Iglesias 
84293f1e401SEdgar E. Iglesias     /* Good frame.  */
84393f1e401SEdgar E. Iglesias     app[2] |= 1 << 6;
84493f1e401SEdgar E. Iglesias 
8453630ae95SPeter Crosthwaite     s->rxsize = size;
8463630ae95SPeter Crosthwaite     s->rxpos = 0;
84742bb9c91SPeter Crosthwaite     for (i = 0; i < ARRAY_SIZE(app); ++i) {
84842bb9c91SPeter Crosthwaite         app[i] = cpu_to_le32(app[i]);
84942bb9c91SPeter Crosthwaite     }
85042bb9c91SPeter Crosthwaite     s->rxappsize = CONTROL_PAYLOAD_SIZE;
85142bb9c91SPeter Crosthwaite     memcpy(s->rxapp, app, s->rxappsize);
8523630ae95SPeter Crosthwaite     axienet_eth_rx_notify(s);
85393f1e401SEdgar E. Iglesias 
85493f1e401SEdgar E. Iglesias     enet_update_irq(s);
85593f1e401SEdgar E. Iglesias     return size;
85693f1e401SEdgar E. Iglesias }
85793f1e401SEdgar E. Iglesias 
85835e60bfdSPeter Crosthwaite static size_t
85951b19950SEdgar E. Iglesias xilinx_axienet_control_stream_push(StreamSlave *obj, uint8_t *buf, size_t len,
86051b19950SEdgar E. Iglesias                                    bool eop)
86142bb9c91SPeter Crosthwaite {
86242bb9c91SPeter Crosthwaite     int i;
86342bb9c91SPeter Crosthwaite     XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM(obj);
86442bb9c91SPeter Crosthwaite     XilinxAXIEnet *s = cs->enet;
86542bb9c91SPeter Crosthwaite 
86651b19950SEdgar E. Iglesias     assert(eop);
86742bb9c91SPeter Crosthwaite     if (len != CONTROL_PAYLOAD_SIZE) {
86842bb9c91SPeter Crosthwaite         hw_error("AXI Enet requires %d byte control stream payload\n",
86942bb9c91SPeter Crosthwaite                  (int)CONTROL_PAYLOAD_SIZE);
87042bb9c91SPeter Crosthwaite     }
87142bb9c91SPeter Crosthwaite 
87242bb9c91SPeter Crosthwaite     memcpy(s->hdr, buf, len);
87342bb9c91SPeter Crosthwaite 
87442bb9c91SPeter Crosthwaite     for (i = 0; i < ARRAY_SIZE(s->hdr); ++i) {
87542bb9c91SPeter Crosthwaite         s->hdr[i] = le32_to_cpu(s->hdr[i]);
87642bb9c91SPeter Crosthwaite     }
87742bb9c91SPeter Crosthwaite     return len;
87842bb9c91SPeter Crosthwaite }
87942bb9c91SPeter Crosthwaite 
88042bb9c91SPeter Crosthwaite static size_t
88151b19950SEdgar E. Iglesias xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size,
88251b19950SEdgar E. Iglesias                                 bool eop)
88393f1e401SEdgar E. Iglesias {
88455b3e0c2SPeter Crosthwaite     XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(obj);
88555b3e0c2SPeter Crosthwaite     XilinxAXIEnet *s = ds->enet;
88693f1e401SEdgar E. Iglesias 
88793f1e401SEdgar E. Iglesias     /* TX enable ?  */
88893f1e401SEdgar E. Iglesias     if (!(s->tc & TC_TX)) {
88935e60bfdSPeter Crosthwaite         return size;
89093f1e401SEdgar E. Iglesias     }
89193f1e401SEdgar E. Iglesias 
8922a4f2635SEdgar E. Iglesias     if (s->txpos + size > s->c_txmem) {
8932a4f2635SEdgar E. Iglesias         qemu_log_mask(LOG_GUEST_ERROR, "%s: Packet larger than txmem\n",
8942a4f2635SEdgar E. Iglesias                       TYPE_XILINX_AXI_ENET);
8952a4f2635SEdgar E. Iglesias         s->txpos = 0;
8962a4f2635SEdgar E. Iglesias         return size;
8972a4f2635SEdgar E. Iglesias     }
8982a4f2635SEdgar E. Iglesias 
8992a4f2635SEdgar E. Iglesias     if (s->txpos == 0 && eop) {
9002a4f2635SEdgar E. Iglesias         /* Fast path single fragment.  */
9012a4f2635SEdgar E. Iglesias         s->txpos = size;
9022a4f2635SEdgar E. Iglesias     } else {
9032a4f2635SEdgar E. Iglesias         memcpy(s->txmem + s->txpos, buf, size);
9042a4f2635SEdgar E. Iglesias         buf = s->txmem;
9052a4f2635SEdgar E. Iglesias         s->txpos += size;
9062a4f2635SEdgar E. Iglesias 
9072a4f2635SEdgar E. Iglesias         if (!eop) {
9082a4f2635SEdgar E. Iglesias             return size;
9092a4f2635SEdgar E. Iglesias         }
9102a4f2635SEdgar E. Iglesias     }
9112a4f2635SEdgar E. Iglesias 
91293f1e401SEdgar E. Iglesias     /* Jumbo or vlan sizes ?  */
91393f1e401SEdgar E. Iglesias     if (!(s->tc & TC_JUM)) {
9142a4f2635SEdgar E. Iglesias         if (s->txpos > 1518 && s->txpos <= 1522 && !(s->tc & TC_VLAN)) {
9152a4f2635SEdgar E. Iglesias             s->txpos = 0;
91635e60bfdSPeter Crosthwaite             return size;
91793f1e401SEdgar E. Iglesias         }
91893f1e401SEdgar E. Iglesias     }
91993f1e401SEdgar E. Iglesias 
92042bb9c91SPeter Crosthwaite     if (s->hdr[0] & 1) {
92142bb9c91SPeter Crosthwaite         unsigned int start_off = s->hdr[1] >> 16;
92242bb9c91SPeter Crosthwaite         unsigned int write_off = s->hdr[1] & 0xffff;
92393f1e401SEdgar E. Iglesias         uint32_t tmp_csum;
92493f1e401SEdgar E. Iglesias         uint16_t csum;
92593f1e401SEdgar E. Iglesias 
9262a4f2635SEdgar E. Iglesias         tmp_csum = net_checksum_add(s->txpos - start_off,
927da59e178SEdgar E. Iglesias                                     buf + start_off);
92893f1e401SEdgar E. Iglesias         /* Accumulate the seed.  */
92942bb9c91SPeter Crosthwaite         tmp_csum += s->hdr[2] & 0xffff;
93093f1e401SEdgar E. Iglesias 
93193f1e401SEdgar E. Iglesias         /* Fold the 32bit partial checksum.  */
93293f1e401SEdgar E. Iglesias         csum = net_checksum_finish(tmp_csum);
93393f1e401SEdgar E. Iglesias 
93493f1e401SEdgar E. Iglesias         /* Writeback.  */
93593f1e401SEdgar E. Iglesias         buf[write_off] = csum >> 8;
93693f1e401SEdgar E. Iglesias         buf[write_off + 1] = csum & 0xff;
93793f1e401SEdgar E. Iglesias     }
93893f1e401SEdgar E. Iglesias 
9392a4f2635SEdgar E. Iglesias     qemu_send_packet(qemu_get_queue(s->nic), buf, s->txpos);
94093f1e401SEdgar E. Iglesias 
9412a4f2635SEdgar E. Iglesias     s->stats.tx_bytes += s->txpos;
94293f1e401SEdgar E. Iglesias     s->regs[R_IS] |= IS_TX_COMPLETE;
94393f1e401SEdgar E. Iglesias     enet_update_irq(s);
94435e60bfdSPeter Crosthwaite 
9452a4f2635SEdgar E. Iglesias     s->txpos = 0;
94635e60bfdSPeter Crosthwaite     return size;
94793f1e401SEdgar E. Iglesias }
94893f1e401SEdgar E. Iglesias 
94993f1e401SEdgar E. Iglesias static NetClientInfo net_xilinx_enet_info = {
950f394b2e2SEric Blake     .type = NET_CLIENT_DRIVER_NIC,
95193f1e401SEdgar E. Iglesias     .size = sizeof(NICState),
95293f1e401SEdgar E. Iglesias     .receive = eth_rx,
95393f1e401SEdgar E. Iglesias };
95493f1e401SEdgar E. Iglesias 
955b2d9dfe9SPeter Crosthwaite static void xilinx_enet_realize(DeviceState *dev, Error **errp)
95693f1e401SEdgar E. Iglesias {
957f0e7a81cSPeter Crosthwaite     XilinxAXIEnet *s = XILINX_AXI_ENET(dev);
95855b3e0c2SPeter Crosthwaite     XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(&s->rx_data_dev);
95942bb9c91SPeter Crosthwaite     XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM(
96042bb9c91SPeter Crosthwaite                                                             &s->rx_control_dev);
96155b3e0c2SPeter Crosthwaite 
96255b3e0c2SPeter Crosthwaite     object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet",
9639561fda8SStefan Hajnoczi                              (Object **) &ds->enet,
96439f72ef9SStefan Hajnoczi                              object_property_allow_set_link,
965d2623129SMarkus Armbruster                              OBJ_PROP_LINK_STRONG);
96642bb9c91SPeter Crosthwaite     object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet",
9679561fda8SStefan Hajnoczi                              (Object **) &cs->enet,
96839f72ef9SStefan Hajnoczi                              object_property_allow_set_link,
969d2623129SMarkus Armbruster                              OBJ_PROP_LINK_STRONG);
9705325cc34SMarkus Armbruster     object_property_set_link(OBJECT(ds), "enet", OBJECT(s), &error_abort);
9715325cc34SMarkus Armbruster     object_property_set_link(OBJECT(cs), "enet", OBJECT(s), &error_abort);
97293f1e401SEdgar E. Iglesias 
97393f1e401SEdgar E. Iglesias     qemu_macaddr_default_if_unset(&s->conf.macaddr);
97493f1e401SEdgar E. Iglesias     s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
975b2d9dfe9SPeter Crosthwaite                           object_get_typename(OBJECT(dev)), dev->id, s);
976b356f76dSJason Wang     qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
97793f1e401SEdgar E. Iglesias 
97893f1e401SEdgar E. Iglesias     tdk_init(&s->TEMAC.phy);
97993f1e401SEdgar E. Iglesias     mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr);
98093f1e401SEdgar E. Iglesias 
98193f1e401SEdgar E. Iglesias     s->TEMAC.parent = s;
98293f1e401SEdgar E. Iglesias 
9837267c094SAnthony Liguori     s->rxmem = g_malloc(s->c_rxmem);
9842a4f2635SEdgar E. Iglesias     s->txmem = g_malloc(s->c_txmem);
98593f1e401SEdgar E. Iglesias }
98693f1e401SEdgar E. Iglesias 
987b2d9dfe9SPeter Crosthwaite static void xilinx_enet_init(Object *obj)
988669b4983SPeter A. G. Crosthwaite {
989f0e7a81cSPeter Crosthwaite     XilinxAXIEnet *s = XILINX_AXI_ENET(obj);
990b2d9dfe9SPeter Crosthwaite     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
991669b4983SPeter A. G. Crosthwaite 
99265da9142SPhilippe Mathieu-Daudé     object_initialize_child(OBJECT(s), "axistream-connected-target",
9939fc7fc4dSMarkus Armbruster                             &s->rx_data_dev, TYPE_XILINX_AXI_ENET_DATA_STREAM);
99465da9142SPhilippe Mathieu-Daudé     object_initialize_child(OBJECT(s), "axistream-control-connected-target",
9959fc7fc4dSMarkus Armbruster                             &s->rx_control_dev,
9969fc7fc4dSMarkus Armbruster                             TYPE_XILINX_AXI_ENET_CONTROL_STREAM);
997b2d9dfe9SPeter Crosthwaite     sysbus_init_irq(sbd, &s->irq);
998b2d9dfe9SPeter Crosthwaite 
999eedfac6fSPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &enet_ops, s, "enet", 0x40000);
1000b2d9dfe9SPeter Crosthwaite     sysbus_init_mmio(sbd, &s->iomem);
1001669b4983SPeter A. G. Crosthwaite }
1002669b4983SPeter A. G. Crosthwaite 
1003999e12bbSAnthony Liguori static Property xilinx_enet_properties[] = {
1004545129e5SPeter Crosthwaite     DEFINE_PROP_UINT32("phyaddr", XilinxAXIEnet, c_phyaddr, 7),
1005545129e5SPeter Crosthwaite     DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000),
1006545129e5SPeter Crosthwaite     DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000),
1007545129e5SPeter Crosthwaite     DEFINE_NIC_PROPERTIES(XilinxAXIEnet, conf),
100826cfb11fSFam Zheng     DEFINE_PROP_LINK("axistream-connected", XilinxAXIEnet,
100926cfb11fSFam Zheng                      tx_data_dev, TYPE_STREAM_SLAVE, StreamSlave *),
101026cfb11fSFam Zheng     DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIEnet,
101126cfb11fSFam Zheng                      tx_control_dev, TYPE_STREAM_SLAVE, StreamSlave *),
101293f1e401SEdgar E. Iglesias     DEFINE_PROP_END_OF_LIST(),
1013999e12bbSAnthony Liguori };
1014999e12bbSAnthony Liguori 
1015999e12bbSAnthony Liguori static void xilinx_enet_class_init(ObjectClass *klass, void *data)
1016999e12bbSAnthony Liguori {
101739bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
1018999e12bbSAnthony Liguori 
1019b2d9dfe9SPeter Crosthwaite     dc->realize = xilinx_enet_realize;
10204f67d30bSMarc-André Lureau     device_class_set_props(dc, xilinx_enet_properties);
10219ee0ceb7SPeter Crosthwaite     dc->reset = xilinx_axienet_reset;
102255b3e0c2SPeter Crosthwaite }
102355b3e0c2SPeter Crosthwaite 
10240d9047c4SEdgar E. Iglesias static void xilinx_enet_control_stream_class_init(ObjectClass *klass,
10250d9047c4SEdgar E. Iglesias                                                   void *data)
102655b3e0c2SPeter Crosthwaite {
102755b3e0c2SPeter Crosthwaite     StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
102855b3e0c2SPeter Crosthwaite 
10290d9047c4SEdgar E. Iglesias     ssc->push = xilinx_axienet_control_stream_push;
10300d9047c4SEdgar E. Iglesias }
10310d9047c4SEdgar E. Iglesias 
10320d9047c4SEdgar E. Iglesias static void xilinx_enet_data_stream_class_init(ObjectClass *klass, void *data)
10330d9047c4SEdgar E. Iglesias {
10340d9047c4SEdgar E. Iglesias     StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
10350d9047c4SEdgar E. Iglesias 
10360d9047c4SEdgar E. Iglesias     ssc->push = xilinx_axienet_data_stream_push;
103793f1e401SEdgar E. Iglesias }
1038999e12bbSAnthony Liguori 
10398c43a6f0SAndreas Färber static const TypeInfo xilinx_enet_info = {
1040f0e7a81cSPeter Crosthwaite     .name          = TYPE_XILINX_AXI_ENET,
104139bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
1042545129e5SPeter Crosthwaite     .instance_size = sizeof(XilinxAXIEnet),
1043999e12bbSAnthony Liguori     .class_init    = xilinx_enet_class_init,
1044b2d9dfe9SPeter Crosthwaite     .instance_init = xilinx_enet_init,
104555b3e0c2SPeter Crosthwaite };
104655b3e0c2SPeter Crosthwaite 
104755b3e0c2SPeter Crosthwaite static const TypeInfo xilinx_enet_data_stream_info = {
104855b3e0c2SPeter Crosthwaite     .name          = TYPE_XILINX_AXI_ENET_DATA_STREAM,
104955b3e0c2SPeter Crosthwaite     .parent        = TYPE_OBJECT,
105055b3e0c2SPeter Crosthwaite     .instance_size = sizeof(struct XilinxAXIEnetStreamSlave),
10510d9047c4SEdgar E. Iglesias     .class_init    = xilinx_enet_data_stream_class_init,
1052669b4983SPeter A. G. Crosthwaite     .interfaces = (InterfaceInfo[]) {
1053669b4983SPeter A. G. Crosthwaite             { TYPE_STREAM_SLAVE },
1054669b4983SPeter A. G. Crosthwaite             { }
1055669b4983SPeter A. G. Crosthwaite     }
105693f1e401SEdgar E. Iglesias };
105783f7d43aSAndreas Färber 
105842bb9c91SPeter Crosthwaite static const TypeInfo xilinx_enet_control_stream_info = {
105942bb9c91SPeter Crosthwaite     .name          = TYPE_XILINX_AXI_ENET_CONTROL_STREAM,
106042bb9c91SPeter Crosthwaite     .parent        = TYPE_OBJECT,
106142bb9c91SPeter Crosthwaite     .instance_size = sizeof(struct XilinxAXIEnetStreamSlave),
10620d9047c4SEdgar E. Iglesias     .class_init    = xilinx_enet_control_stream_class_init,
106342bb9c91SPeter Crosthwaite     .interfaces = (InterfaceInfo[]) {
106442bb9c91SPeter Crosthwaite             { TYPE_STREAM_SLAVE },
106542bb9c91SPeter Crosthwaite             { }
106642bb9c91SPeter Crosthwaite     }
106742bb9c91SPeter Crosthwaite };
106842bb9c91SPeter Crosthwaite 
106983f7d43aSAndreas Färber static void xilinx_enet_register_types(void)
107093f1e401SEdgar E. Iglesias {
107139bffca2SAnthony Liguori     type_register_static(&xilinx_enet_info);
107255b3e0c2SPeter Crosthwaite     type_register_static(&xilinx_enet_data_stream_info);
107342bb9c91SPeter Crosthwaite     type_register_static(&xilinx_enet_control_stream_info);
107493f1e401SEdgar E. Iglesias }
107593f1e401SEdgar E. Iglesias 
107683f7d43aSAndreas Färber type_init(xilinx_enet_register_types)
1077