xref: /openbmc/qemu/hw/net/xilinx_axienet.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * QEMU model of Xilinx AXI-Ethernet.
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2011 Edgar E. Iglesias.
549ab747fSPaolo Bonzini  *
649ab747fSPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
749ab747fSPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
849ab747fSPaolo Bonzini  * in the Software without restriction, including without limitation the rights
949ab747fSPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1049ab747fSPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1149ab747fSPaolo Bonzini  * furnished to do so, subject to the following conditions:
1249ab747fSPaolo Bonzini  *
1349ab747fSPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1449ab747fSPaolo Bonzini  * all copies or substantial portions of the Software.
1549ab747fSPaolo Bonzini  *
1649ab747fSPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1749ab747fSPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1849ab747fSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1949ab747fSPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2049ab747fSPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2149ab747fSPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2249ab747fSPaolo Bonzini  * THE SOFTWARE.
2349ab747fSPaolo Bonzini  */
2449ab747fSPaolo Bonzini 
25e8d40465SPeter Maydell #include "qemu/osdep.h"
26a27bd6c7SMarkus Armbruster #include "hw/hw.h"
2749ab747fSPaolo Bonzini #include "hw/sysbus.h"
28da34e65cSMarkus Armbruster #include "qapi/error.h"
2949ab747fSPaolo Bonzini #include "qemu/log.h"
300b8fa32fSMarkus Armbruster #include "qemu/module.h"
3149ab747fSPaolo Bonzini #include "net/net.h"
3249ab747fSPaolo Bonzini #include "net/checksum.h"
3349ab747fSPaolo Bonzini 
3464552b6bSMarkus Armbruster #include "hw/irq.h"
35a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
3649ab747fSPaolo Bonzini #include "hw/stream.h"
37db1015e9SEduardo Habkost #include "qom/object.h"
3849ab747fSPaolo Bonzini 
3949ab747fSPaolo Bonzini #define DPHY(x)
4049ab747fSPaolo Bonzini 
41f0e7a81cSPeter Crosthwaite #define TYPE_XILINX_AXI_ENET "xlnx.axi-ethernet"
4255b3e0c2SPeter Crosthwaite #define TYPE_XILINX_AXI_ENET_DATA_STREAM "xilinx-axienet-data-stream"
4342bb9c91SPeter Crosthwaite #define TYPE_XILINX_AXI_ENET_CONTROL_STREAM "xilinx-axienet-control-stream"
44f0e7a81cSPeter Crosthwaite 
458063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(XilinxAXIEnet, XILINX_AXI_ENET)
46f0e7a81cSPeter Crosthwaite 
47357088b1SPhilippe Mathieu-Daudé typedef struct XilinxAXIEnetStreamSink XilinxAXIEnetStreamSink;
48357088b1SPhilippe Mathieu-Daudé DECLARE_INSTANCE_CHECKER(XilinxAXIEnetStreamSink, XILINX_AXI_ENET_DATA_STREAM,
4955b3e0c2SPeter Crosthwaite                          TYPE_XILINX_AXI_ENET_DATA_STREAM)
5055b3e0c2SPeter Crosthwaite 
51357088b1SPhilippe Mathieu-Daudé DECLARE_INSTANCE_CHECKER(XilinxAXIEnetStreamSink, XILINX_AXI_ENET_CONTROL_STREAM,
5242bb9c91SPeter Crosthwaite                          TYPE_XILINX_AXI_ENET_CONTROL_STREAM)
5342bb9c91SPeter Crosthwaite 
5449ab747fSPaolo Bonzini /* Advertisement control register. */
5549ab747fSPaolo Bonzini #define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
5649ab747fSPaolo Bonzini #define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
5749ab747fSPaolo Bonzini #define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
5849ab747fSPaolo Bonzini 
5942bb9c91SPeter Crosthwaite #define CONTROL_PAYLOAD_WORDS 5
6042bb9c91SPeter Crosthwaite #define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t)))
6142bb9c91SPeter Crosthwaite 
6249ab747fSPaolo Bonzini struct PHY {
6349ab747fSPaolo Bonzini     uint32_t regs[32];
6449ab747fSPaolo Bonzini 
6549ab747fSPaolo Bonzini     int link;
6649ab747fSPaolo Bonzini 
6749ab747fSPaolo Bonzini     unsigned int (*read)(struct PHY *phy, unsigned int req);
6849ab747fSPaolo Bonzini     void (*write)(struct PHY *phy, unsigned int req,
6949ab747fSPaolo Bonzini                   unsigned int data);
7049ab747fSPaolo Bonzini };
7149ab747fSPaolo Bonzini 
tdk_read(struct PHY * phy,unsigned int req)7249ab747fSPaolo Bonzini static unsigned int tdk_read(struct PHY *phy, unsigned int req)
7349ab747fSPaolo Bonzini {
7449ab747fSPaolo Bonzini     int regnum;
7549ab747fSPaolo Bonzini     unsigned r = 0;
7649ab747fSPaolo Bonzini 
7749ab747fSPaolo Bonzini     regnum = req & 0x1f;
7849ab747fSPaolo Bonzini 
7949ab747fSPaolo Bonzini     switch (regnum) {
8049ab747fSPaolo Bonzini         case 1:
8149ab747fSPaolo Bonzini             if (!phy->link) {
8249ab747fSPaolo Bonzini                 break;
8349ab747fSPaolo Bonzini             }
8449ab747fSPaolo Bonzini             /* MR1.  */
8549ab747fSPaolo Bonzini             /* Speeds and modes.  */
8649ab747fSPaolo Bonzini             r |= (1 << 13) | (1 << 14);
8749ab747fSPaolo Bonzini             r |= (1 << 11) | (1 << 12);
8849ab747fSPaolo Bonzini             r |= (1 << 5); /* Autoneg complete.  */
8949ab747fSPaolo Bonzini             r |= (1 << 3); /* Autoneg able.  */
9049ab747fSPaolo Bonzini             r |= (1 << 2); /* link.  */
9149ab747fSPaolo Bonzini             r |= (1 << 1); /* link.  */
9249ab747fSPaolo Bonzini             break;
9349ab747fSPaolo Bonzini         case 5:
9449ab747fSPaolo Bonzini             /* Link partner ability.
9549ab747fSPaolo Bonzini                We are kind; always agree with whatever best mode
9649ab747fSPaolo Bonzini                the guest advertises.  */
9749ab747fSPaolo Bonzini             r = 1 << 14; /* Success.  */
9849ab747fSPaolo Bonzini             /* Copy advertised modes.  */
9949ab747fSPaolo Bonzini             r |= phy->regs[4] & (15 << 5);
10049ab747fSPaolo Bonzini             /* Autoneg support.  */
10149ab747fSPaolo Bonzini             r |= 1;
10249ab747fSPaolo Bonzini             break;
10349ab747fSPaolo Bonzini         case 17:
10424c12b79SStefan Weil             /* Marvell PHY on many xilinx boards.  */
10549ab747fSPaolo Bonzini             r = 0x8000; /* 1000Mb  */
10649ab747fSPaolo Bonzini             break;
10749ab747fSPaolo Bonzini         case 18:
10849ab747fSPaolo Bonzini             {
10949ab747fSPaolo Bonzini                 /* Diagnostics reg.  */
11049ab747fSPaolo Bonzini                 int duplex = 0;
11149ab747fSPaolo Bonzini                 int speed_100 = 0;
11249ab747fSPaolo Bonzini 
11349ab747fSPaolo Bonzini                 if (!phy->link) {
11449ab747fSPaolo Bonzini                     break;
11549ab747fSPaolo Bonzini                 }
11649ab747fSPaolo Bonzini 
11749ab747fSPaolo Bonzini                 /* Are we advertising 100 half or 100 duplex ? */
11849ab747fSPaolo Bonzini                 speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
11949ab747fSPaolo Bonzini                 speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
12049ab747fSPaolo Bonzini 
12149ab747fSPaolo Bonzini                 /* Are we advertising 10 duplex or 100 duplex ? */
12249ab747fSPaolo Bonzini                 duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
12349ab747fSPaolo Bonzini                 duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
12449ab747fSPaolo Bonzini                 r = (speed_100 << 10) | (duplex << 11);
12549ab747fSPaolo Bonzini             }
12649ab747fSPaolo Bonzini             break;
12749ab747fSPaolo Bonzini 
12849ab747fSPaolo Bonzini         default:
12949ab747fSPaolo Bonzini             r = phy->regs[regnum];
13049ab747fSPaolo Bonzini             break;
13149ab747fSPaolo Bonzini     }
13249ab747fSPaolo Bonzini     DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum));
13349ab747fSPaolo Bonzini     return r;
13449ab747fSPaolo Bonzini }
13549ab747fSPaolo Bonzini 
13649ab747fSPaolo Bonzini static void
tdk_write(struct PHY * phy,unsigned int req,unsigned int data)13749ab747fSPaolo Bonzini tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
13849ab747fSPaolo Bonzini {
13949ab747fSPaolo Bonzini     int regnum;
14049ab747fSPaolo Bonzini 
14149ab747fSPaolo Bonzini     regnum = req & 0x1f;
14249ab747fSPaolo Bonzini     DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data));
14349ab747fSPaolo Bonzini     switch (regnum) {
14449ab747fSPaolo Bonzini         default:
14549ab747fSPaolo Bonzini             phy->regs[regnum] = data;
14649ab747fSPaolo Bonzini             break;
14749ab747fSPaolo Bonzini     }
148f663faacSNathan Rossi 
1493e2a0cb9SEdgar E. Iglesias     /* Unconditionally clear regs[BMCR][BMCR_RESET] and auto-neg */
1503e2a0cb9SEdgar E. Iglesias     phy->regs[0] &= ~0x8200;
15149ab747fSPaolo Bonzini }
15249ab747fSPaolo Bonzini 
15349ab747fSPaolo Bonzini static void
tdk_init(struct PHY * phy)15449ab747fSPaolo Bonzini tdk_init(struct PHY *phy)
15549ab747fSPaolo Bonzini {
15649ab747fSPaolo Bonzini     phy->regs[0] = 0x3100;
15749ab747fSPaolo Bonzini     /* PHY Id.  */
15849ab747fSPaolo Bonzini     phy->regs[2] = 0x0300;
15949ab747fSPaolo Bonzini     phy->regs[3] = 0xe400;
16049ab747fSPaolo Bonzini     /* Autonegotiation advertisement reg.  */
16149ab747fSPaolo Bonzini     phy->regs[4] = 0x01E1;
16249ab747fSPaolo Bonzini     phy->link = 1;
16349ab747fSPaolo Bonzini 
16449ab747fSPaolo Bonzini     phy->read = tdk_read;
16549ab747fSPaolo Bonzini     phy->write = tdk_write;
16649ab747fSPaolo Bonzini }
16749ab747fSPaolo Bonzini 
16849ab747fSPaolo Bonzini struct MDIOBus {
16949ab747fSPaolo Bonzini     struct PHY *devs[32];
17049ab747fSPaolo Bonzini };
17149ab747fSPaolo Bonzini 
17249ab747fSPaolo Bonzini static void
mdio_attach(struct MDIOBus * bus,struct PHY * phy,unsigned int addr)17349ab747fSPaolo Bonzini mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
17449ab747fSPaolo Bonzini {
17549ab747fSPaolo Bonzini     bus->devs[addr & 0x1f] = phy;
17649ab747fSPaolo Bonzini }
17749ab747fSPaolo Bonzini 
17849ab747fSPaolo Bonzini #ifdef USE_THIS_DEAD_CODE
17949ab747fSPaolo Bonzini static void
mdio_detach(struct MDIOBus * bus,struct PHY * phy,unsigned int addr)18049ab747fSPaolo Bonzini mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
18149ab747fSPaolo Bonzini {
18249ab747fSPaolo Bonzini     bus->devs[addr & 0x1f] = NULL;
18349ab747fSPaolo Bonzini }
18449ab747fSPaolo Bonzini #endif
18549ab747fSPaolo Bonzini 
mdio_read_req(struct MDIOBus * bus,unsigned int addr,unsigned int reg)18649ab747fSPaolo Bonzini static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr,
18749ab747fSPaolo Bonzini                   unsigned int reg)
18849ab747fSPaolo Bonzini {
18949ab747fSPaolo Bonzini     struct PHY *phy;
19049ab747fSPaolo Bonzini     uint16_t data;
19149ab747fSPaolo Bonzini 
19249ab747fSPaolo Bonzini     phy = bus->devs[addr];
19349ab747fSPaolo Bonzini     if (phy && phy->read) {
19449ab747fSPaolo Bonzini         data = phy->read(phy, reg);
19549ab747fSPaolo Bonzini     } else {
19649ab747fSPaolo Bonzini         data = 0xffff;
19749ab747fSPaolo Bonzini     }
19849ab747fSPaolo Bonzini     DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
19949ab747fSPaolo Bonzini     return data;
20049ab747fSPaolo Bonzini }
20149ab747fSPaolo Bonzini 
mdio_write_req(struct MDIOBus * bus,unsigned int addr,unsigned int reg,uint16_t data)20249ab747fSPaolo Bonzini static void mdio_write_req(struct MDIOBus *bus, unsigned int addr,
20349ab747fSPaolo Bonzini                unsigned int reg, uint16_t data)
20449ab747fSPaolo Bonzini {
20549ab747fSPaolo Bonzini     struct PHY *phy;
20649ab747fSPaolo Bonzini 
20749ab747fSPaolo Bonzini     DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
20849ab747fSPaolo Bonzini     phy = bus->devs[addr];
20949ab747fSPaolo Bonzini     if (phy && phy->write) {
21049ab747fSPaolo Bonzini         phy->write(phy, reg, data);
21149ab747fSPaolo Bonzini     }
21249ab747fSPaolo Bonzini }
21349ab747fSPaolo Bonzini 
21449ab747fSPaolo Bonzini #define DENET(x)
21549ab747fSPaolo Bonzini 
21649ab747fSPaolo Bonzini #define R_RAF      (0x000 / 4)
21749ab747fSPaolo Bonzini enum {
21849ab747fSPaolo Bonzini     RAF_MCAST_REJ = (1 << 1),
21949ab747fSPaolo Bonzini     RAF_BCAST_REJ = (1 << 2),
22049ab747fSPaolo Bonzini     RAF_EMCF_EN = (1 << 12),
22149ab747fSPaolo Bonzini     RAF_NEWFUNC_EN = (1 << 11)
22249ab747fSPaolo Bonzini };
22349ab747fSPaolo Bonzini 
22449ab747fSPaolo Bonzini #define R_IS       (0x00C / 4)
22549ab747fSPaolo Bonzini enum {
22649ab747fSPaolo Bonzini     IS_HARD_ACCESS_COMPLETE = 1,
22749ab747fSPaolo Bonzini     IS_AUTONEG = (1 << 1),
22849ab747fSPaolo Bonzini     IS_RX_COMPLETE = (1 << 2),
22949ab747fSPaolo Bonzini     IS_RX_REJECT = (1 << 3),
23049ab747fSPaolo Bonzini     IS_TX_COMPLETE = (1 << 5),
23149ab747fSPaolo Bonzini     IS_RX_DCM_LOCK = (1 << 6),
23249ab747fSPaolo Bonzini     IS_MGM_RDY = (1 << 7),
23349ab747fSPaolo Bonzini     IS_PHY_RST_DONE = (1 << 8),
23449ab747fSPaolo Bonzini };
23549ab747fSPaolo Bonzini 
23649ab747fSPaolo Bonzini #define R_IP       (0x010 / 4)
23749ab747fSPaolo Bonzini #define R_IE       (0x014 / 4)
23849ab747fSPaolo Bonzini #define R_UAWL     (0x020 / 4)
23949ab747fSPaolo Bonzini #define R_UAWU     (0x024 / 4)
24049ab747fSPaolo Bonzini #define R_PPST     (0x030 / 4)
24149ab747fSPaolo Bonzini enum {
24249ab747fSPaolo Bonzini     PPST_LINKSTATUS = (1 << 0),
24349ab747fSPaolo Bonzini     PPST_PHY_LINKSTATUS = (1 << 7),
24449ab747fSPaolo Bonzini };
24549ab747fSPaolo Bonzini 
24649ab747fSPaolo Bonzini #define R_STATS_RX_BYTESL (0x200 / 4)
24749ab747fSPaolo Bonzini #define R_STATS_RX_BYTESH (0x204 / 4)
24849ab747fSPaolo Bonzini #define R_STATS_TX_BYTESL (0x208 / 4)
24949ab747fSPaolo Bonzini #define R_STATS_TX_BYTESH (0x20C / 4)
25049ab747fSPaolo Bonzini #define R_STATS_RXL       (0x290 / 4)
25149ab747fSPaolo Bonzini #define R_STATS_RXH       (0x294 / 4)
25249ab747fSPaolo Bonzini #define R_STATS_RX_BCASTL (0x2a0 / 4)
25349ab747fSPaolo Bonzini #define R_STATS_RX_BCASTH (0x2a4 / 4)
25449ab747fSPaolo Bonzini #define R_STATS_RX_MCASTL (0x2a8 / 4)
25549ab747fSPaolo Bonzini #define R_STATS_RX_MCASTH (0x2ac / 4)
25649ab747fSPaolo Bonzini 
25749ab747fSPaolo Bonzini #define R_RCW0     (0x400 / 4)
25849ab747fSPaolo Bonzini #define R_RCW1     (0x404 / 4)
25949ab747fSPaolo Bonzini enum {
26049ab747fSPaolo Bonzini     RCW1_VLAN = (1 << 27),
26149ab747fSPaolo Bonzini     RCW1_RX   = (1 << 28),
26249ab747fSPaolo Bonzini     RCW1_FCS  = (1 << 29),
26349ab747fSPaolo Bonzini     RCW1_JUM  = (1 << 30),
26449ab747fSPaolo Bonzini     RCW1_RST  = (1 << 31),
26549ab747fSPaolo Bonzini };
26649ab747fSPaolo Bonzini 
26749ab747fSPaolo Bonzini #define R_TC       (0x408 / 4)
26849ab747fSPaolo Bonzini enum {
26949ab747fSPaolo Bonzini     TC_VLAN = (1 << 27),
27049ab747fSPaolo Bonzini     TC_TX   = (1 << 28),
27149ab747fSPaolo Bonzini     TC_FCS  = (1 << 29),
27249ab747fSPaolo Bonzini     TC_JUM  = (1 << 30),
27349ab747fSPaolo Bonzini     TC_RST  = (1 << 31),
27449ab747fSPaolo Bonzini };
27549ab747fSPaolo Bonzini 
27649ab747fSPaolo Bonzini #define R_EMMC     (0x410 / 4)
27749ab747fSPaolo Bonzini enum {
27849ab747fSPaolo Bonzini     EMMC_LINKSPEED_10MB = (0 << 30),
27949ab747fSPaolo Bonzini     EMMC_LINKSPEED_100MB = (1 << 30),
28049ab747fSPaolo Bonzini     EMMC_LINKSPEED_1000MB = (2 << 30),
28149ab747fSPaolo Bonzini };
28249ab747fSPaolo Bonzini 
28349ab747fSPaolo Bonzini #define R_PHYC     (0x414 / 4)
28449ab747fSPaolo Bonzini 
28549ab747fSPaolo Bonzini #define R_MC       (0x500 / 4)
28649ab747fSPaolo Bonzini #define MC_EN      (1 << 6)
28749ab747fSPaolo Bonzini 
28849ab747fSPaolo Bonzini #define R_MCR      (0x504 / 4)
28949ab747fSPaolo Bonzini #define R_MWD      (0x508 / 4)
29049ab747fSPaolo Bonzini #define R_MRD      (0x50c / 4)
29149ab747fSPaolo Bonzini #define R_MIS      (0x600 / 4)
29249ab747fSPaolo Bonzini #define R_MIP      (0x620 / 4)
29349ab747fSPaolo Bonzini #define R_MIE      (0x640 / 4)
29449ab747fSPaolo Bonzini #define R_MIC      (0x640 / 4)
29549ab747fSPaolo Bonzini 
29649ab747fSPaolo Bonzini #define R_UAW0     (0x700 / 4)
29749ab747fSPaolo Bonzini #define R_UAW1     (0x704 / 4)
29849ab747fSPaolo Bonzini #define R_FMI      (0x708 / 4)
29949ab747fSPaolo Bonzini #define R_AF0      (0x710 / 4)
30049ab747fSPaolo Bonzini #define R_AF1      (0x714 / 4)
30149ab747fSPaolo Bonzini #define R_MAX      (0x34 / 4)
30249ab747fSPaolo Bonzini 
30349ab747fSPaolo Bonzini /* Indirect registers.  */
30449ab747fSPaolo Bonzini struct TEMAC  {
30549ab747fSPaolo Bonzini     struct MDIOBus mdio_bus;
30649ab747fSPaolo Bonzini     struct PHY phy;
30749ab747fSPaolo Bonzini 
30849ab747fSPaolo Bonzini     void *parent;
30949ab747fSPaolo Bonzini };
31049ab747fSPaolo Bonzini 
311545129e5SPeter Crosthwaite 
312357088b1SPhilippe Mathieu-Daudé struct XilinxAXIEnetStreamSink {
31355b3e0c2SPeter Crosthwaite     Object parent;
31455b3e0c2SPeter Crosthwaite 
31555b3e0c2SPeter Crosthwaite     struct XilinxAXIEnet *enet;
31655b3e0c2SPeter Crosthwaite } ;
31755b3e0c2SPeter Crosthwaite 
31849ab747fSPaolo Bonzini struct XilinxAXIEnet {
31949ab747fSPaolo Bonzini     SysBusDevice busdev;
32049ab747fSPaolo Bonzini     MemoryRegion iomem;
32149ab747fSPaolo Bonzini     qemu_irq irq;
322cfbef3f4SPhilippe Mathieu-Daudé     StreamSink *tx_data_dev;
323cfbef3f4SPhilippe Mathieu-Daudé     StreamSink *tx_control_dev;
324357088b1SPhilippe Mathieu-Daudé     XilinxAXIEnetStreamSink rx_data_dev;
325357088b1SPhilippe Mathieu-Daudé     XilinxAXIEnetStreamSink rx_control_dev;
32649ab747fSPaolo Bonzini     NICState *nic;
32749ab747fSPaolo Bonzini     NICConf conf;
32849ab747fSPaolo Bonzini 
32949ab747fSPaolo Bonzini 
33049ab747fSPaolo Bonzini     uint32_t c_rxmem;
33149ab747fSPaolo Bonzini     uint32_t c_txmem;
33249ab747fSPaolo Bonzini     uint32_t c_phyaddr;
33349ab747fSPaolo Bonzini 
33449ab747fSPaolo Bonzini     struct TEMAC TEMAC;
33549ab747fSPaolo Bonzini 
33649ab747fSPaolo Bonzini     /* MII regs.  */
33749ab747fSPaolo Bonzini     union {
33849ab747fSPaolo Bonzini         uint32_t regs[4];
33949ab747fSPaolo Bonzini         struct {
34049ab747fSPaolo Bonzini             uint32_t mc;
34149ab747fSPaolo Bonzini             uint32_t mcr;
34249ab747fSPaolo Bonzini             uint32_t mwd;
34349ab747fSPaolo Bonzini             uint32_t mrd;
34449ab747fSPaolo Bonzini         };
34549ab747fSPaolo Bonzini     } mii;
34649ab747fSPaolo Bonzini 
34749ab747fSPaolo Bonzini     struct {
34849ab747fSPaolo Bonzini         uint64_t rx_bytes;
34949ab747fSPaolo Bonzini         uint64_t tx_bytes;
35049ab747fSPaolo Bonzini 
35149ab747fSPaolo Bonzini         uint64_t rx;
35249ab747fSPaolo Bonzini         uint64_t rx_bcast;
35349ab747fSPaolo Bonzini         uint64_t rx_mcast;
35449ab747fSPaolo Bonzini     } stats;
35549ab747fSPaolo Bonzini 
35649ab747fSPaolo Bonzini     /* Receive configuration words.  */
35749ab747fSPaolo Bonzini     uint32_t rcw[2];
35849ab747fSPaolo Bonzini     /* Transmit config.  */
35949ab747fSPaolo Bonzini     uint32_t tc;
36049ab747fSPaolo Bonzini     uint32_t emmc;
36149ab747fSPaolo Bonzini     uint32_t phyc;
36249ab747fSPaolo Bonzini 
36349ab747fSPaolo Bonzini     /* Unicast Address Word.  */
36449ab747fSPaolo Bonzini     uint32_t uaw[2];
36549ab747fSPaolo Bonzini     /* Unicast address filter used with extended mcast.  */
36649ab747fSPaolo Bonzini     uint32_t ext_uaw[2];
36749ab747fSPaolo Bonzini     uint32_t fmi;
36849ab747fSPaolo Bonzini 
36949ab747fSPaolo Bonzini     uint32_t regs[R_MAX];
37049ab747fSPaolo Bonzini 
37149ab747fSPaolo Bonzini     /* Multicast filter addrs.  */
37249ab747fSPaolo Bonzini     uint32_t maddr[4][2];
37349ab747fSPaolo Bonzini     /* 32K x 1 lookup filter.  */
37449ab747fSPaolo Bonzini     uint32_t ext_mtable[1024];
37549ab747fSPaolo Bonzini 
37642bb9c91SPeter Crosthwaite     uint32_t hdr[CONTROL_PAYLOAD_WORDS];
37749ab747fSPaolo Bonzini 
3782a4f2635SEdgar E. Iglesias     uint8_t *txmem;
3792a4f2635SEdgar E. Iglesias     uint32_t txpos;
3802a4f2635SEdgar E. Iglesias 
38149ab747fSPaolo Bonzini     uint8_t *rxmem;
3823630ae95SPeter Crosthwaite     uint32_t rxsize;
3833630ae95SPeter Crosthwaite     uint32_t rxpos;
38442bb9c91SPeter Crosthwaite 
38542bb9c91SPeter Crosthwaite     uint8_t rxapp[CONTROL_PAYLOAD_SIZE];
38642bb9c91SPeter Crosthwaite     uint32_t rxappsize;
387f9f7492eSFam Zheng 
388f9f7492eSFam Zheng     /* Whether axienet_eth_rx_notify should flush incoming queue. */
389f9f7492eSFam Zheng     bool need_flush;
39049ab747fSPaolo Bonzini };
39149ab747fSPaolo Bonzini 
axienet_rx_reset(XilinxAXIEnet * s)392545129e5SPeter Crosthwaite static void axienet_rx_reset(XilinxAXIEnet *s)
39349ab747fSPaolo Bonzini {
39449ab747fSPaolo Bonzini     s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN;
39549ab747fSPaolo Bonzini }
39649ab747fSPaolo Bonzini 
axienet_tx_reset(XilinxAXIEnet * s)397545129e5SPeter Crosthwaite static void axienet_tx_reset(XilinxAXIEnet *s)
39849ab747fSPaolo Bonzini {
39949ab747fSPaolo Bonzini     s->tc = TC_JUM | TC_TX | TC_VLAN;
4002a4f2635SEdgar E. Iglesias     s->txpos = 0;
40149ab747fSPaolo Bonzini }
40249ab747fSPaolo Bonzini 
axienet_rx_resetting(XilinxAXIEnet * s)403545129e5SPeter Crosthwaite static inline int axienet_rx_resetting(XilinxAXIEnet *s)
40449ab747fSPaolo Bonzini {
40549ab747fSPaolo Bonzini     return s->rcw[1] & RCW1_RST;
40649ab747fSPaolo Bonzini }
40749ab747fSPaolo Bonzini 
axienet_rx_enabled(XilinxAXIEnet * s)408545129e5SPeter Crosthwaite static inline int axienet_rx_enabled(XilinxAXIEnet *s)
40949ab747fSPaolo Bonzini {
41049ab747fSPaolo Bonzini     return s->rcw[1] & RCW1_RX;
41149ab747fSPaolo Bonzini }
41249ab747fSPaolo Bonzini 
axienet_extmcf_enabled(XilinxAXIEnet * s)413545129e5SPeter Crosthwaite static inline int axienet_extmcf_enabled(XilinxAXIEnet *s)
41449ab747fSPaolo Bonzini {
41549ab747fSPaolo Bonzini     return !!(s->regs[R_RAF] & RAF_EMCF_EN);
41649ab747fSPaolo Bonzini }
41749ab747fSPaolo Bonzini 
axienet_newfunc_enabled(XilinxAXIEnet * s)418545129e5SPeter Crosthwaite static inline int axienet_newfunc_enabled(XilinxAXIEnet *s)
41949ab747fSPaolo Bonzini {
42049ab747fSPaolo Bonzini     return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN);
42149ab747fSPaolo Bonzini }
42249ab747fSPaolo Bonzini 
xilinx_axienet_reset(DeviceState * d)4239ee0ceb7SPeter Crosthwaite static void xilinx_axienet_reset(DeviceState *d)
42449ab747fSPaolo Bonzini {
4259ee0ceb7SPeter Crosthwaite     XilinxAXIEnet *s = XILINX_AXI_ENET(d);
4269ee0ceb7SPeter Crosthwaite 
42749ab747fSPaolo Bonzini     axienet_rx_reset(s);
42849ab747fSPaolo Bonzini     axienet_tx_reset(s);
42949ab747fSPaolo Bonzini 
43049ab747fSPaolo Bonzini     s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS;
43149ab747fSPaolo Bonzini     s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE;
43249ab747fSPaolo Bonzini 
43349ab747fSPaolo Bonzini     s->emmc = EMMC_LINKSPEED_100MB;
43449ab747fSPaolo Bonzini }
43549ab747fSPaolo Bonzini 
enet_update_irq(XilinxAXIEnet * s)436545129e5SPeter Crosthwaite static void enet_update_irq(XilinxAXIEnet *s)
43749ab747fSPaolo Bonzini {
43849ab747fSPaolo Bonzini     s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE];
43949ab747fSPaolo Bonzini     qemu_set_irq(s->irq, !!s->regs[R_IP]);
44049ab747fSPaolo Bonzini }
44149ab747fSPaolo Bonzini 
enet_read(void * opaque,hwaddr addr,unsigned size)44249ab747fSPaolo Bonzini static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size)
44349ab747fSPaolo Bonzini {
444545129e5SPeter Crosthwaite     XilinxAXIEnet *s = opaque;
44549ab747fSPaolo Bonzini     uint32_t r = 0;
44649ab747fSPaolo Bonzini     addr >>= 2;
44749ab747fSPaolo Bonzini 
44849ab747fSPaolo Bonzini     switch (addr) {
44949ab747fSPaolo Bonzini         case R_RCW0:
45049ab747fSPaolo Bonzini         case R_RCW1:
45149ab747fSPaolo Bonzini             r = s->rcw[addr & 1];
45249ab747fSPaolo Bonzini             break;
45349ab747fSPaolo Bonzini 
45449ab747fSPaolo Bonzini         case R_TC:
45549ab747fSPaolo Bonzini             r = s->tc;
45649ab747fSPaolo Bonzini             break;
45749ab747fSPaolo Bonzini 
45849ab747fSPaolo Bonzini         case R_EMMC:
45949ab747fSPaolo Bonzini             r = s->emmc;
46049ab747fSPaolo Bonzini             break;
46149ab747fSPaolo Bonzini 
46249ab747fSPaolo Bonzini         case R_PHYC:
46349ab747fSPaolo Bonzini             r = s->phyc;
46449ab747fSPaolo Bonzini             break;
46549ab747fSPaolo Bonzini 
46649ab747fSPaolo Bonzini         case R_MCR:
46749ab747fSPaolo Bonzini             r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready.  */
46849ab747fSPaolo Bonzini             break;
46949ab747fSPaolo Bonzini 
47049ab747fSPaolo Bonzini         case R_STATS_RX_BYTESL:
47149ab747fSPaolo Bonzini         case R_STATS_RX_BYTESH:
47249ab747fSPaolo Bonzini             r = s->stats.rx_bytes >> (32 * (addr & 1));
47349ab747fSPaolo Bonzini             break;
47449ab747fSPaolo Bonzini 
47549ab747fSPaolo Bonzini         case R_STATS_TX_BYTESL:
47649ab747fSPaolo Bonzini         case R_STATS_TX_BYTESH:
47749ab747fSPaolo Bonzini             r = s->stats.tx_bytes >> (32 * (addr & 1));
47849ab747fSPaolo Bonzini             break;
47949ab747fSPaolo Bonzini 
48049ab747fSPaolo Bonzini         case R_STATS_RXL:
48149ab747fSPaolo Bonzini         case R_STATS_RXH:
48249ab747fSPaolo Bonzini             r = s->stats.rx >> (32 * (addr & 1));
48349ab747fSPaolo Bonzini             break;
48449ab747fSPaolo Bonzini         case R_STATS_RX_BCASTL:
48549ab747fSPaolo Bonzini         case R_STATS_RX_BCASTH:
48649ab747fSPaolo Bonzini             r = s->stats.rx_bcast >> (32 * (addr & 1));
48749ab747fSPaolo Bonzini             break;
48849ab747fSPaolo Bonzini         case R_STATS_RX_MCASTL:
48949ab747fSPaolo Bonzini         case R_STATS_RX_MCASTH:
49049ab747fSPaolo Bonzini             r = s->stats.rx_mcast >> (32 * (addr & 1));
49149ab747fSPaolo Bonzini             break;
49249ab747fSPaolo Bonzini 
49349ab747fSPaolo Bonzini         case R_MC:
49449ab747fSPaolo Bonzini         case R_MWD:
49549ab747fSPaolo Bonzini         case R_MRD:
49649ab747fSPaolo Bonzini             r = s->mii.regs[addr & 3];
49749ab747fSPaolo Bonzini             break;
49849ab747fSPaolo Bonzini 
49949ab747fSPaolo Bonzini         case R_UAW0:
50049ab747fSPaolo Bonzini         case R_UAW1:
50149ab747fSPaolo Bonzini             r = s->uaw[addr & 1];
50249ab747fSPaolo Bonzini             break;
50349ab747fSPaolo Bonzini 
50449ab747fSPaolo Bonzini         case R_UAWU:
50549ab747fSPaolo Bonzini         case R_UAWL:
50649ab747fSPaolo Bonzini             r = s->ext_uaw[addr & 1];
50749ab747fSPaolo Bonzini             break;
50849ab747fSPaolo Bonzini 
50949ab747fSPaolo Bonzini         case R_FMI:
51049ab747fSPaolo Bonzini             r = s->fmi;
51149ab747fSPaolo Bonzini             break;
51249ab747fSPaolo Bonzini 
51349ab747fSPaolo Bonzini         case R_AF0:
51449ab747fSPaolo Bonzini         case R_AF1:
51549ab747fSPaolo Bonzini             r = s->maddr[s->fmi & 3][addr & 1];
51649ab747fSPaolo Bonzini             break;
51749ab747fSPaolo Bonzini 
51849ab747fSPaolo Bonzini         case 0x8000 ... 0x83ff:
51949ab747fSPaolo Bonzini             r = s->ext_mtable[addr - 0x8000];
52049ab747fSPaolo Bonzini             break;
52149ab747fSPaolo Bonzini 
52249ab747fSPaolo Bonzini         default:
52349ab747fSPaolo Bonzini             if (addr < ARRAY_SIZE(s->regs)) {
52449ab747fSPaolo Bonzini                 r = s->regs[addr];
52549ab747fSPaolo Bonzini             }
526883f2c59SPhilippe Mathieu-Daudé             DENET(qemu_log("%s addr=" HWADDR_FMT_plx " v=%x\n",
52749ab747fSPaolo Bonzini                             __func__, addr * 4, r));
52849ab747fSPaolo Bonzini             break;
52949ab747fSPaolo Bonzini     }
53049ab747fSPaolo Bonzini     return r;
53149ab747fSPaolo Bonzini }
53249ab747fSPaolo Bonzini 
enet_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)53349ab747fSPaolo Bonzini static void enet_write(void *opaque, hwaddr addr,
53449ab747fSPaolo Bonzini                        uint64_t value, unsigned size)
53549ab747fSPaolo Bonzini {
536545129e5SPeter Crosthwaite     XilinxAXIEnet *s = opaque;
53749ab747fSPaolo Bonzini     struct TEMAC *t = &s->TEMAC;
53849ab747fSPaolo Bonzini 
53949ab747fSPaolo Bonzini     addr >>= 2;
54049ab747fSPaolo Bonzini     switch (addr) {
54149ab747fSPaolo Bonzini         case R_RCW0:
54249ab747fSPaolo Bonzini         case R_RCW1:
54349ab747fSPaolo Bonzini             s->rcw[addr & 1] = value;
54449ab747fSPaolo Bonzini             if ((addr & 1) && value & RCW1_RST) {
54549ab747fSPaolo Bonzini                 axienet_rx_reset(s);
54649ab747fSPaolo Bonzini             } else {
54749ab747fSPaolo Bonzini                 qemu_flush_queued_packets(qemu_get_queue(s->nic));
54849ab747fSPaolo Bonzini             }
54949ab747fSPaolo Bonzini             break;
55049ab747fSPaolo Bonzini 
55149ab747fSPaolo Bonzini         case R_TC:
55249ab747fSPaolo Bonzini             s->tc = value;
55349ab747fSPaolo Bonzini             if (value & TC_RST) {
55449ab747fSPaolo Bonzini                 axienet_tx_reset(s);
55549ab747fSPaolo Bonzini             }
55649ab747fSPaolo Bonzini             break;
55749ab747fSPaolo Bonzini 
55849ab747fSPaolo Bonzini         case R_EMMC:
55949ab747fSPaolo Bonzini             s->emmc = value;
56049ab747fSPaolo Bonzini             break;
56149ab747fSPaolo Bonzini 
56249ab747fSPaolo Bonzini         case R_PHYC:
56349ab747fSPaolo Bonzini             s->phyc = value;
56449ab747fSPaolo Bonzini             break;
56549ab747fSPaolo Bonzini 
56649ab747fSPaolo Bonzini         case R_MC:
5674e298e46SStefan Weil              value &= ((1 << 7) - 1);
56849ab747fSPaolo Bonzini 
56949ab747fSPaolo Bonzini              /* Enable the MII.  */
57049ab747fSPaolo Bonzini              if (value & MC_EN) {
57149ab747fSPaolo Bonzini                  unsigned int miiclkdiv = value & ((1 << 6) - 1);
57249ab747fSPaolo Bonzini                  if (!miiclkdiv) {
57349ab747fSPaolo Bonzini                      qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n");
57449ab747fSPaolo Bonzini                  }
57549ab747fSPaolo Bonzini              }
57649ab747fSPaolo Bonzini              s->mii.mc = value;
57749ab747fSPaolo Bonzini              break;
57849ab747fSPaolo Bonzini 
57949ab747fSPaolo Bonzini         case R_MCR: {
58049ab747fSPaolo Bonzini              unsigned int phyaddr = (value >> 24) & 0x1f;
58149ab747fSPaolo Bonzini              unsigned int regaddr = (value >> 16) & 0x1f;
58249ab747fSPaolo Bonzini              unsigned int op = (value >> 14) & 3;
58349ab747fSPaolo Bonzini              unsigned int initiate = (value >> 11) & 1;
58449ab747fSPaolo Bonzini 
58549ab747fSPaolo Bonzini              if (initiate) {
58649ab747fSPaolo Bonzini                  if (op == 1) {
58749ab747fSPaolo Bonzini                      mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd);
58849ab747fSPaolo Bonzini                  } else if (op == 2) {
58949ab747fSPaolo Bonzini                      s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr);
59049ab747fSPaolo Bonzini                  } else {
59149ab747fSPaolo Bonzini                      qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op);
59249ab747fSPaolo Bonzini                  }
59349ab747fSPaolo Bonzini              }
59449ab747fSPaolo Bonzini              s->mii.mcr = value;
59549ab747fSPaolo Bonzini              break;
59649ab747fSPaolo Bonzini         }
59749ab747fSPaolo Bonzini 
59849ab747fSPaolo Bonzini         case R_MWD:
59949ab747fSPaolo Bonzini         case R_MRD:
60049ab747fSPaolo Bonzini              s->mii.regs[addr & 3] = value;
60149ab747fSPaolo Bonzini              break;
60249ab747fSPaolo Bonzini 
60349ab747fSPaolo Bonzini 
60449ab747fSPaolo Bonzini         case R_UAW0:
60549ab747fSPaolo Bonzini         case R_UAW1:
60649ab747fSPaolo Bonzini             s->uaw[addr & 1] = value;
60749ab747fSPaolo Bonzini             break;
60849ab747fSPaolo Bonzini 
60949ab747fSPaolo Bonzini         case R_UAWL:
61049ab747fSPaolo Bonzini         case R_UAWU:
61149ab747fSPaolo Bonzini             s->ext_uaw[addr & 1] = value;
61249ab747fSPaolo Bonzini             break;
61349ab747fSPaolo Bonzini 
61449ab747fSPaolo Bonzini         case R_FMI:
61549ab747fSPaolo Bonzini             s->fmi = value;
61649ab747fSPaolo Bonzini             break;
61749ab747fSPaolo Bonzini 
61849ab747fSPaolo Bonzini         case R_AF0:
61949ab747fSPaolo Bonzini         case R_AF1:
62049ab747fSPaolo Bonzini             s->maddr[s->fmi & 3][addr & 1] = value;
62149ab747fSPaolo Bonzini             break;
62249ab747fSPaolo Bonzini 
62349ab747fSPaolo Bonzini         case R_IS:
62449ab747fSPaolo Bonzini             s->regs[addr] &= ~value;
62549ab747fSPaolo Bonzini             break;
62649ab747fSPaolo Bonzini 
62749ab747fSPaolo Bonzini         case 0x8000 ... 0x83ff:
62849ab747fSPaolo Bonzini             s->ext_mtable[addr - 0x8000] = value;
62949ab747fSPaolo Bonzini             break;
63049ab747fSPaolo Bonzini 
63149ab747fSPaolo Bonzini         default:
632883f2c59SPhilippe Mathieu-Daudé             DENET(qemu_log("%s addr=" HWADDR_FMT_plx " v=%x\n",
63349ab747fSPaolo Bonzini                            __func__, addr * 4, (unsigned)value));
63449ab747fSPaolo Bonzini             if (addr < ARRAY_SIZE(s->regs)) {
63549ab747fSPaolo Bonzini                 s->regs[addr] = value;
63649ab747fSPaolo Bonzini             }
63749ab747fSPaolo Bonzini             break;
63849ab747fSPaolo Bonzini     }
63949ab747fSPaolo Bonzini     enet_update_irq(s);
64049ab747fSPaolo Bonzini }
64149ab747fSPaolo Bonzini 
64249ab747fSPaolo Bonzini static const MemoryRegionOps enet_ops = {
64349ab747fSPaolo Bonzini     .read = enet_read,
64449ab747fSPaolo Bonzini     .write = enet_write,
64549ab747fSPaolo Bonzini     .endianness = DEVICE_LITTLE_ENDIAN,
64649ab747fSPaolo Bonzini };
64749ab747fSPaolo Bonzini 
eth_can_rx(XilinxAXIEnet * s)648f9f7492eSFam Zheng static int eth_can_rx(XilinxAXIEnet *s)
64949ab747fSPaolo Bonzini {
65049ab747fSPaolo Bonzini     /* RX enabled?  */
6513630ae95SPeter Crosthwaite     return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s);
65249ab747fSPaolo Bonzini }
65349ab747fSPaolo Bonzini 
enet_match_addr(const uint8_t * buf,uint32_t f0,uint32_t f1)65449ab747fSPaolo Bonzini static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1)
65549ab747fSPaolo Bonzini {
65649ab747fSPaolo Bonzini     int match = 1;
65749ab747fSPaolo Bonzini 
65849ab747fSPaolo Bonzini     if (memcmp(buf, &f0, 4)) {
65949ab747fSPaolo Bonzini         match = 0;
66049ab747fSPaolo Bonzini     }
66149ab747fSPaolo Bonzini 
66249ab747fSPaolo Bonzini     if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) {
66349ab747fSPaolo Bonzini         match = 0;
66449ab747fSPaolo Bonzini     }
66549ab747fSPaolo Bonzini 
66649ab747fSPaolo Bonzini     return match;
66749ab747fSPaolo Bonzini }
66849ab747fSPaolo Bonzini 
axienet_eth_rx_notify(void * opaque)6693630ae95SPeter Crosthwaite static void axienet_eth_rx_notify(void *opaque)
6703630ae95SPeter Crosthwaite {
6713630ae95SPeter Crosthwaite     XilinxAXIEnet *s = XILINX_AXI_ENET(opaque);
6723630ae95SPeter Crosthwaite 
67342bb9c91SPeter Crosthwaite     while (s->rxappsize && stream_can_push(s->tx_control_dev,
67442bb9c91SPeter Crosthwaite                                            axienet_eth_rx_notify, s)) {
67542bb9c91SPeter Crosthwaite         size_t ret = stream_push(s->tx_control_dev,
67642bb9c91SPeter Crosthwaite                                  (void *)s->rxapp + CONTROL_PAYLOAD_SIZE
67751b19950SEdgar E. Iglesias                                  - s->rxappsize, s->rxappsize, true);
67842bb9c91SPeter Crosthwaite         s->rxappsize -= ret;
67942bb9c91SPeter Crosthwaite     }
68042bb9c91SPeter Crosthwaite 
68142bb9c91SPeter Crosthwaite     while (s->rxsize && stream_can_push(s->tx_data_dev,
68242bb9c91SPeter Crosthwaite                                         axienet_eth_rx_notify, s)) {
68342bb9c91SPeter Crosthwaite         size_t ret = stream_push(s->tx_data_dev, (void *)s->rxmem + s->rxpos,
68451b19950SEdgar E. Iglesias                                  s->rxsize, true);
6853630ae95SPeter Crosthwaite         s->rxsize -= ret;
6863630ae95SPeter Crosthwaite         s->rxpos += ret;
6873630ae95SPeter Crosthwaite         if (!s->rxsize) {
6883630ae95SPeter Crosthwaite             s->regs[R_IS] |= IS_RX_COMPLETE;
689f9f7492eSFam Zheng             if (s->need_flush) {
690f9f7492eSFam Zheng                 s->need_flush = false;
691f9f7492eSFam Zheng                 qemu_flush_queued_packets(qemu_get_queue(s->nic));
692f9f7492eSFam Zheng             }
6933630ae95SPeter Crosthwaite         }
6943630ae95SPeter Crosthwaite     }
6953630ae95SPeter Crosthwaite     enet_update_irq(s);
6963630ae95SPeter Crosthwaite }
6973630ae95SPeter Crosthwaite 
eth_rx(NetClientState * nc,const uint8_t * buf,size_t size)69849ab747fSPaolo Bonzini static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
69949ab747fSPaolo Bonzini {
700545129e5SPeter Crosthwaite     XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
70149ab747fSPaolo Bonzini     static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
70249ab747fSPaolo Bonzini                                               0xff, 0xff, 0xff};
70349ab747fSPaolo Bonzini     static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52};
70442bb9c91SPeter Crosthwaite     uint32_t app[CONTROL_PAYLOAD_WORDS] = {0};
70549ab747fSPaolo Bonzini     int promisc = s->fmi & (1 << 31);
70649ab747fSPaolo Bonzini     int unicast, broadcast, multicast, ip_multicast = 0;
70749ab747fSPaolo Bonzini     uint32_t csum32;
70849ab747fSPaolo Bonzini     uint16_t csum16;
70949ab747fSPaolo Bonzini     int i;
71049ab747fSPaolo Bonzini 
71149ab747fSPaolo Bonzini     DENET(qemu_log("%s: %zd bytes\n", __func__, size));
71249ab747fSPaolo Bonzini 
713f9f7492eSFam Zheng     if (!eth_can_rx(s)) {
714f9f7492eSFam Zheng         s->need_flush = true;
715f9f7492eSFam Zheng         return 0;
716f9f7492eSFam Zheng     }
717f9f7492eSFam Zheng 
71849ab747fSPaolo Bonzini     unicast = ~buf[0] & 0x1;
71949ab747fSPaolo Bonzini     broadcast = memcmp(buf, sa_bcast, 6) == 0;
72049ab747fSPaolo Bonzini     multicast = !unicast && !broadcast;
72149ab747fSPaolo Bonzini     if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) {
72249ab747fSPaolo Bonzini         ip_multicast = 1;
72349ab747fSPaolo Bonzini     }
72449ab747fSPaolo Bonzini 
72549ab747fSPaolo Bonzini     /* Jumbo or vlan sizes ?  */
72649ab747fSPaolo Bonzini     if (!(s->rcw[1] & RCW1_JUM)) {
72749ab747fSPaolo Bonzini         if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) {
72849ab747fSPaolo Bonzini             return size;
72949ab747fSPaolo Bonzini         }
73049ab747fSPaolo Bonzini     }
73149ab747fSPaolo Bonzini 
73249ab747fSPaolo Bonzini     /* Basic Address filters.  If you want to use the extended filters
73349ab747fSPaolo Bonzini        you'll generally have to place the ethernet mac into promiscuous mode
73449ab747fSPaolo Bonzini        to avoid the basic filtering from dropping most frames.  */
73549ab747fSPaolo Bonzini     if (!promisc) {
73649ab747fSPaolo Bonzini         if (unicast) {
73749ab747fSPaolo Bonzini             if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) {
73849ab747fSPaolo Bonzini                 return size;
73949ab747fSPaolo Bonzini             }
74049ab747fSPaolo Bonzini         } else {
74149ab747fSPaolo Bonzini             if (broadcast) {
74249ab747fSPaolo Bonzini                 /* Broadcast.  */
74349ab747fSPaolo Bonzini                 if (s->regs[R_RAF] & RAF_BCAST_REJ) {
74449ab747fSPaolo Bonzini                     return size;
74549ab747fSPaolo Bonzini                 }
74649ab747fSPaolo Bonzini             } else {
74749ab747fSPaolo Bonzini                 int drop = 1;
74849ab747fSPaolo Bonzini 
74949ab747fSPaolo Bonzini                 /* Multicast.  */
75049ab747fSPaolo Bonzini                 if (s->regs[R_RAF] & RAF_MCAST_REJ) {
75149ab747fSPaolo Bonzini                     return size;
75249ab747fSPaolo Bonzini                 }
75349ab747fSPaolo Bonzini 
75449ab747fSPaolo Bonzini                 for (i = 0; i < 4; i++) {
75549ab747fSPaolo Bonzini                     if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) {
75649ab747fSPaolo Bonzini                         drop = 0;
75749ab747fSPaolo Bonzini                         break;
75849ab747fSPaolo Bonzini                     }
75949ab747fSPaolo Bonzini                 }
76049ab747fSPaolo Bonzini 
76149ab747fSPaolo Bonzini                 if (drop) {
76249ab747fSPaolo Bonzini                     return size;
76349ab747fSPaolo Bonzini                 }
76449ab747fSPaolo Bonzini             }
76549ab747fSPaolo Bonzini         }
76649ab747fSPaolo Bonzini     }
76749ab747fSPaolo Bonzini 
76849ab747fSPaolo Bonzini     /* Extended mcast filtering enabled?  */
76949ab747fSPaolo Bonzini     if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) {
77049ab747fSPaolo Bonzini         if (unicast) {
77149ab747fSPaolo Bonzini             if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) {
77249ab747fSPaolo Bonzini                 return size;
77349ab747fSPaolo Bonzini             }
77449ab747fSPaolo Bonzini         } else {
77549ab747fSPaolo Bonzini             if (broadcast) {
77649ab747fSPaolo Bonzini                 /* Broadcast. ???  */
77749ab747fSPaolo Bonzini                 if (s->regs[R_RAF] & RAF_BCAST_REJ) {
77849ab747fSPaolo Bonzini                     return size;
77949ab747fSPaolo Bonzini                 }
78049ab747fSPaolo Bonzini             } else {
78149ab747fSPaolo Bonzini                 int idx, bit;
78249ab747fSPaolo Bonzini 
78349ab747fSPaolo Bonzini                 /* Multicast.  */
78449ab747fSPaolo Bonzini                 if (!memcmp(buf, sa_ipmcast, 3)) {
78549ab747fSPaolo Bonzini                     return size;
78649ab747fSPaolo Bonzini                 }
78749ab747fSPaolo Bonzini 
78849ab747fSPaolo Bonzini                 idx  = (buf[4] & 0x7f) << 8;
78949ab747fSPaolo Bonzini                 idx |= buf[5];
79049ab747fSPaolo Bonzini 
79149ab747fSPaolo Bonzini                 bit = 1 << (idx & 0x1f);
79249ab747fSPaolo Bonzini                 idx >>= 5;
79349ab747fSPaolo Bonzini 
79449ab747fSPaolo Bonzini                 if (!(s->ext_mtable[idx] & bit)) {
79549ab747fSPaolo Bonzini                     return size;
79649ab747fSPaolo Bonzini                 }
79749ab747fSPaolo Bonzini             }
79849ab747fSPaolo Bonzini         }
79949ab747fSPaolo Bonzini     }
80049ab747fSPaolo Bonzini 
80149ab747fSPaolo Bonzini     if (size < 12) {
80249ab747fSPaolo Bonzini         s->regs[R_IS] |= IS_RX_REJECT;
80349ab747fSPaolo Bonzini         enet_update_irq(s);
80449ab747fSPaolo Bonzini         return -1;
80549ab747fSPaolo Bonzini     }
80649ab747fSPaolo Bonzini 
80749ab747fSPaolo Bonzini     if (size > (s->c_rxmem - 4)) {
80849ab747fSPaolo Bonzini         size = s->c_rxmem - 4;
80949ab747fSPaolo Bonzini     }
81049ab747fSPaolo Bonzini 
81149ab747fSPaolo Bonzini     memcpy(s->rxmem, buf, size);
81249ab747fSPaolo Bonzini     memset(s->rxmem + size, 0, 4); /* Clear the FCS.  */
81349ab747fSPaolo Bonzini 
81449ab747fSPaolo Bonzini     if (s->rcw[1] & RCW1_FCS) {
81549ab747fSPaolo Bonzini         size += 4; /* fcs is inband.  */
81649ab747fSPaolo Bonzini     }
81749ab747fSPaolo Bonzini 
81849ab747fSPaolo Bonzini     app[0] = 5 << 28;
81949ab747fSPaolo Bonzini     csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14);
82049ab747fSPaolo Bonzini     /* Fold it once.  */
82149ab747fSPaolo Bonzini     csum32 = (csum32 & 0xffff) + (csum32 >> 16);
82249ab747fSPaolo Bonzini     /* And twice to get rid of possible carries.  */
82349ab747fSPaolo Bonzini     csum16 = (csum32 & 0xffff) + (csum32 >> 16);
82449ab747fSPaolo Bonzini     app[3] = csum16;
82549ab747fSPaolo Bonzini     app[4] = size & 0xffff;
82649ab747fSPaolo Bonzini 
82749ab747fSPaolo Bonzini     s->stats.rx_bytes += size;
82849ab747fSPaolo Bonzini     s->stats.rx++;
82949ab747fSPaolo Bonzini     if (multicast) {
83049ab747fSPaolo Bonzini         s->stats.rx_mcast++;
83149ab747fSPaolo Bonzini         app[2] |= 1 | (ip_multicast << 1);
83249ab747fSPaolo Bonzini     } else if (broadcast) {
83349ab747fSPaolo Bonzini         s->stats.rx_bcast++;
83449ab747fSPaolo Bonzini         app[2] |= 1 << 3;
83549ab747fSPaolo Bonzini     }
83649ab747fSPaolo Bonzini 
83749ab747fSPaolo Bonzini     /* Good frame.  */
83849ab747fSPaolo Bonzini     app[2] |= 1 << 6;
83949ab747fSPaolo Bonzini 
8403630ae95SPeter Crosthwaite     s->rxsize = size;
8413630ae95SPeter Crosthwaite     s->rxpos = 0;
84242bb9c91SPeter Crosthwaite     for (i = 0; i < ARRAY_SIZE(app); ++i) {
84342bb9c91SPeter Crosthwaite         app[i] = cpu_to_le32(app[i]);
84442bb9c91SPeter Crosthwaite     }
84542bb9c91SPeter Crosthwaite     s->rxappsize = CONTROL_PAYLOAD_SIZE;
84642bb9c91SPeter Crosthwaite     memcpy(s->rxapp, app, s->rxappsize);
8473630ae95SPeter Crosthwaite     axienet_eth_rx_notify(s);
84849ab747fSPaolo Bonzini 
84949ab747fSPaolo Bonzini     enet_update_irq(s);
8503a6d374bSFea.Wang     return s->rxpos;
85149ab747fSPaolo Bonzini }
85249ab747fSPaolo Bonzini 
85335e60bfdSPeter Crosthwaite static size_t
xilinx_axienet_control_stream_push(StreamSink * obj,uint8_t * buf,size_t len,bool eop)854cfbef3f4SPhilippe Mathieu-Daudé xilinx_axienet_control_stream_push(StreamSink *obj, uint8_t *buf, size_t len,
85551b19950SEdgar E. Iglesias                                    bool eop)
85642bb9c91SPeter Crosthwaite {
85742bb9c91SPeter Crosthwaite     int i;
858357088b1SPhilippe Mathieu-Daudé     XilinxAXIEnetStreamSink *cs = XILINX_AXI_ENET_CONTROL_STREAM(obj);
85942bb9c91SPeter Crosthwaite     XilinxAXIEnet *s = cs->enet;
86042bb9c91SPeter Crosthwaite 
86151b19950SEdgar E. Iglesias     assert(eop);
86242bb9c91SPeter Crosthwaite     if (len != CONTROL_PAYLOAD_SIZE) {
86342bb9c91SPeter Crosthwaite         hw_error("AXI Enet requires %d byte control stream payload\n",
86442bb9c91SPeter Crosthwaite                  (int)CONTROL_PAYLOAD_SIZE);
86542bb9c91SPeter Crosthwaite     }
86642bb9c91SPeter Crosthwaite 
86742bb9c91SPeter Crosthwaite     memcpy(s->hdr, buf, len);
86842bb9c91SPeter Crosthwaite 
86942bb9c91SPeter Crosthwaite     for (i = 0; i < ARRAY_SIZE(s->hdr); ++i) {
87042bb9c91SPeter Crosthwaite         s->hdr[i] = le32_to_cpu(s->hdr[i]);
87142bb9c91SPeter Crosthwaite     }
87242bb9c91SPeter Crosthwaite     return len;
87342bb9c91SPeter Crosthwaite }
87442bb9c91SPeter Crosthwaite 
87542bb9c91SPeter Crosthwaite static size_t
xilinx_axienet_data_stream_push(StreamSink * obj,uint8_t * buf,size_t size,bool eop)876cfbef3f4SPhilippe Mathieu-Daudé xilinx_axienet_data_stream_push(StreamSink *obj, uint8_t *buf, size_t size,
87751b19950SEdgar E. Iglesias                                 bool eop)
87849ab747fSPaolo Bonzini {
879357088b1SPhilippe Mathieu-Daudé     XilinxAXIEnetStreamSink *ds = XILINX_AXI_ENET_DATA_STREAM(obj);
88055b3e0c2SPeter Crosthwaite     XilinxAXIEnet *s = ds->enet;
88149ab747fSPaolo Bonzini 
88249ab747fSPaolo Bonzini     /* TX enable ?  */
88349ab747fSPaolo Bonzini     if (!(s->tc & TC_TX)) {
88435e60bfdSPeter Crosthwaite         return size;
88549ab747fSPaolo Bonzini     }
88649ab747fSPaolo Bonzini 
8872a4f2635SEdgar E. Iglesias     if (s->txpos + size > s->c_txmem) {
8882a4f2635SEdgar E. Iglesias         qemu_log_mask(LOG_GUEST_ERROR, "%s: Packet larger than txmem\n",
8892a4f2635SEdgar E. Iglesias                       TYPE_XILINX_AXI_ENET);
8902a4f2635SEdgar E. Iglesias         s->txpos = 0;
8912a4f2635SEdgar E. Iglesias         return size;
8922a4f2635SEdgar E. Iglesias     }
8932a4f2635SEdgar E. Iglesias 
8942a4f2635SEdgar E. Iglesias     if (s->txpos == 0 && eop) {
8952a4f2635SEdgar E. Iglesias         /* Fast path single fragment.  */
8962a4f2635SEdgar E. Iglesias         s->txpos = size;
8972a4f2635SEdgar E. Iglesias     } else {
8982a4f2635SEdgar E. Iglesias         memcpy(s->txmem + s->txpos, buf, size);
8992a4f2635SEdgar E. Iglesias         buf = s->txmem;
9002a4f2635SEdgar E. Iglesias         s->txpos += size;
9012a4f2635SEdgar E. Iglesias 
9022a4f2635SEdgar E. Iglesias         if (!eop) {
9032a4f2635SEdgar E. Iglesias             return size;
9042a4f2635SEdgar E. Iglesias         }
9052a4f2635SEdgar E. Iglesias     }
9062a4f2635SEdgar E. Iglesias 
90749ab747fSPaolo Bonzini     /* Jumbo or vlan sizes ?  */
90849ab747fSPaolo Bonzini     if (!(s->tc & TC_JUM)) {
9092a4f2635SEdgar E. Iglesias         if (s->txpos > 1518 && s->txpos <= 1522 && !(s->tc & TC_VLAN)) {
9102a4f2635SEdgar E. Iglesias             s->txpos = 0;
91135e60bfdSPeter Crosthwaite             return size;
91249ab747fSPaolo Bonzini         }
91349ab747fSPaolo Bonzini     }
91449ab747fSPaolo Bonzini 
91542bb9c91SPeter Crosthwaite     if (s->hdr[0] & 1) {
91642bb9c91SPeter Crosthwaite         unsigned int start_off = s->hdr[1] >> 16;
91742bb9c91SPeter Crosthwaite         unsigned int write_off = s->hdr[1] & 0xffff;
91849ab747fSPaolo Bonzini         uint32_t tmp_csum;
91949ab747fSPaolo Bonzini         uint16_t csum;
92049ab747fSPaolo Bonzini 
9212a4f2635SEdgar E. Iglesias         tmp_csum = net_checksum_add(s->txpos - start_off,
922da59e178SEdgar E. Iglesias                                     buf + start_off);
92349ab747fSPaolo Bonzini         /* Accumulate the seed.  */
92442bb9c91SPeter Crosthwaite         tmp_csum += s->hdr[2] & 0xffff;
92549ab747fSPaolo Bonzini 
92649ab747fSPaolo Bonzini         /* Fold the 32bit partial checksum.  */
92749ab747fSPaolo Bonzini         csum = net_checksum_finish(tmp_csum);
92849ab747fSPaolo Bonzini 
92949ab747fSPaolo Bonzini         /* Writeback.  */
93049ab747fSPaolo Bonzini         buf[write_off] = csum >> 8;
93149ab747fSPaolo Bonzini         buf[write_off + 1] = csum & 0xff;
93249ab747fSPaolo Bonzini     }
93349ab747fSPaolo Bonzini 
9342a4f2635SEdgar E. Iglesias     qemu_send_packet(qemu_get_queue(s->nic), buf, s->txpos);
93549ab747fSPaolo Bonzini 
9362a4f2635SEdgar E. Iglesias     s->stats.tx_bytes += s->txpos;
93749ab747fSPaolo Bonzini     s->regs[R_IS] |= IS_TX_COMPLETE;
93849ab747fSPaolo Bonzini     enet_update_irq(s);
93935e60bfdSPeter Crosthwaite 
9402a4f2635SEdgar E. Iglesias     s->txpos = 0;
94135e60bfdSPeter Crosthwaite     return size;
94249ab747fSPaolo Bonzini }
94349ab747fSPaolo Bonzini 
94449ab747fSPaolo Bonzini static NetClientInfo net_xilinx_enet_info = {
945f394b2e2SEric Blake     .type = NET_CLIENT_DRIVER_NIC,
94649ab747fSPaolo Bonzini     .size = sizeof(NICState),
94749ab747fSPaolo Bonzini     .receive = eth_rx,
94849ab747fSPaolo Bonzini };
94949ab747fSPaolo Bonzini 
xilinx_enet_realize(DeviceState * dev,Error ** errp)950b2d9dfe9SPeter Crosthwaite static void xilinx_enet_realize(DeviceState *dev, Error **errp)
95149ab747fSPaolo Bonzini {
952f0e7a81cSPeter Crosthwaite     XilinxAXIEnet *s = XILINX_AXI_ENET(dev);
953357088b1SPhilippe Mathieu-Daudé     XilinxAXIEnetStreamSink *ds = XILINX_AXI_ENET_DATA_STREAM(&s->rx_data_dev);
954357088b1SPhilippe Mathieu-Daudé     XilinxAXIEnetStreamSink *cs = XILINX_AXI_ENET_CONTROL_STREAM(
95542bb9c91SPeter Crosthwaite                                                             &s->rx_control_dev);
95655b3e0c2SPeter Crosthwaite 
95755b3e0c2SPeter Crosthwaite     object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet",
9589561fda8SStefan Hajnoczi                              (Object **) &ds->enet,
95939f72ef9SStefan Hajnoczi                              object_property_allow_set_link,
960d2623129SMarkus Armbruster                              OBJ_PROP_LINK_STRONG);
96142bb9c91SPeter Crosthwaite     object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet",
9629561fda8SStefan Hajnoczi                              (Object **) &cs->enet,
96339f72ef9SStefan Hajnoczi                              object_property_allow_set_link,
964d2623129SMarkus Armbruster                              OBJ_PROP_LINK_STRONG);
9655325cc34SMarkus Armbruster     object_property_set_link(OBJECT(ds), "enet", OBJECT(s), &error_abort);
9665325cc34SMarkus Armbruster     object_property_set_link(OBJECT(cs), "enet", OBJECT(s), &error_abort);
96749ab747fSPaolo Bonzini 
96849ab747fSPaolo Bonzini     qemu_macaddr_default_if_unset(&s->conf.macaddr);
96949ab747fSPaolo Bonzini     s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
9707d0fefdfSAkihiko Odaki                           object_get_typename(OBJECT(dev)), dev->id,
9717d0fefdfSAkihiko Odaki                           &dev->mem_reentrancy_guard, s);
97249ab747fSPaolo Bonzini     qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
97349ab747fSPaolo Bonzini 
97449ab747fSPaolo Bonzini     tdk_init(&s->TEMAC.phy);
97549ab747fSPaolo Bonzini     mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr);
97649ab747fSPaolo Bonzini 
97749ab747fSPaolo Bonzini     s->TEMAC.parent = s;
97849ab747fSPaolo Bonzini 
97949ab747fSPaolo Bonzini     s->rxmem = g_malloc(s->c_rxmem);
9802a4f2635SEdgar E. Iglesias     s->txmem = g_malloc(s->c_txmem);
98149ab747fSPaolo Bonzini }
98249ab747fSPaolo Bonzini 
xilinx_enet_init(Object * obj)983b2d9dfe9SPeter Crosthwaite static void xilinx_enet_init(Object *obj)
98449ab747fSPaolo Bonzini {
985f0e7a81cSPeter Crosthwaite     XilinxAXIEnet *s = XILINX_AXI_ENET(obj);
986b2d9dfe9SPeter Crosthwaite     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
98749ab747fSPaolo Bonzini 
98865da9142SPhilippe Mathieu-Daudé     object_initialize_child(OBJECT(s), "axistream-connected-target",
9899fc7fc4dSMarkus Armbruster                             &s->rx_data_dev, TYPE_XILINX_AXI_ENET_DATA_STREAM);
99065da9142SPhilippe Mathieu-Daudé     object_initialize_child(OBJECT(s), "axistream-control-connected-target",
9919fc7fc4dSMarkus Armbruster                             &s->rx_control_dev,
9929fc7fc4dSMarkus Armbruster                             TYPE_XILINX_AXI_ENET_CONTROL_STREAM);
993b2d9dfe9SPeter Crosthwaite     sysbus_init_irq(sbd, &s->irq);
994b2d9dfe9SPeter Crosthwaite 
995eedfac6fSPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &enet_ops, s, "enet", 0x40000);
996b2d9dfe9SPeter Crosthwaite     sysbus_init_mmio(sbd, &s->iomem);
99749ab747fSPaolo Bonzini }
99849ab747fSPaolo Bonzini 
99949ab747fSPaolo Bonzini static Property xilinx_enet_properties[] = {
1000545129e5SPeter Crosthwaite     DEFINE_PROP_UINT32("phyaddr", XilinxAXIEnet, c_phyaddr, 7),
1001545129e5SPeter Crosthwaite     DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000),
1002545129e5SPeter Crosthwaite     DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000),
1003545129e5SPeter Crosthwaite     DEFINE_NIC_PROPERTIES(XilinxAXIEnet, conf),
100426cfb11fSFam Zheng     DEFINE_PROP_LINK("axistream-connected", XilinxAXIEnet,
1005cfbef3f4SPhilippe Mathieu-Daudé                      tx_data_dev, TYPE_STREAM_SINK, StreamSink *),
100626cfb11fSFam Zheng     DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIEnet,
1007cfbef3f4SPhilippe Mathieu-Daudé                      tx_control_dev, TYPE_STREAM_SINK, StreamSink *),
100849ab747fSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
100949ab747fSPaolo Bonzini };
101049ab747fSPaolo Bonzini 
xilinx_enet_class_init(ObjectClass * klass,void * data)101149ab747fSPaolo Bonzini static void xilinx_enet_class_init(ObjectClass *klass, void *data)
101249ab747fSPaolo Bonzini {
101349ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
101449ab747fSPaolo Bonzini 
1015b2d9dfe9SPeter Crosthwaite     dc->realize = xilinx_enet_realize;
10164f67d30bSMarc-André Lureau     device_class_set_props(dc, xilinx_enet_properties);
1017*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, xilinx_axienet_reset);
101855b3e0c2SPeter Crosthwaite }
101955b3e0c2SPeter Crosthwaite 
xilinx_enet_control_stream_class_init(ObjectClass * klass,void * data)10200d9047c4SEdgar E. Iglesias static void xilinx_enet_control_stream_class_init(ObjectClass *klass,
10210d9047c4SEdgar E. Iglesias                                                   void *data)
102255b3e0c2SPeter Crosthwaite {
1023cfbef3f4SPhilippe Mathieu-Daudé     StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
102455b3e0c2SPeter Crosthwaite 
10250d9047c4SEdgar E. Iglesias     ssc->push = xilinx_axienet_control_stream_push;
10260d9047c4SEdgar E. Iglesias }
10270d9047c4SEdgar E. Iglesias 
xilinx_enet_data_stream_class_init(ObjectClass * klass,void * data)10280d9047c4SEdgar E. Iglesias static void xilinx_enet_data_stream_class_init(ObjectClass *klass, void *data)
10290d9047c4SEdgar E. Iglesias {
1030cfbef3f4SPhilippe Mathieu-Daudé     StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
10310d9047c4SEdgar E. Iglesias 
10320d9047c4SEdgar E. Iglesias     ssc->push = xilinx_axienet_data_stream_push;
103349ab747fSPaolo Bonzini }
103449ab747fSPaolo Bonzini 
103549ab747fSPaolo Bonzini static const TypeInfo xilinx_enet_info = {
1036f0e7a81cSPeter Crosthwaite     .name          = TYPE_XILINX_AXI_ENET,
103749ab747fSPaolo Bonzini     .parent        = TYPE_SYS_BUS_DEVICE,
1038545129e5SPeter Crosthwaite     .instance_size = sizeof(XilinxAXIEnet),
103949ab747fSPaolo Bonzini     .class_init    = xilinx_enet_class_init,
1040b2d9dfe9SPeter Crosthwaite     .instance_init = xilinx_enet_init,
104155b3e0c2SPeter Crosthwaite };
104255b3e0c2SPeter Crosthwaite 
104355b3e0c2SPeter Crosthwaite static const TypeInfo xilinx_enet_data_stream_info = {
104455b3e0c2SPeter Crosthwaite     .name          = TYPE_XILINX_AXI_ENET_DATA_STREAM,
104555b3e0c2SPeter Crosthwaite     .parent        = TYPE_OBJECT,
1046357088b1SPhilippe Mathieu-Daudé     .instance_size = sizeof(XilinxAXIEnetStreamSink),
10470d9047c4SEdgar E. Iglesias     .class_init    = xilinx_enet_data_stream_class_init,
104849ab747fSPaolo Bonzini     .interfaces = (InterfaceInfo[]) {
1049cfbef3f4SPhilippe Mathieu-Daudé             { TYPE_STREAM_SINK },
105049ab747fSPaolo Bonzini             { }
105149ab747fSPaolo Bonzini     }
105249ab747fSPaolo Bonzini };
105349ab747fSPaolo Bonzini 
105442bb9c91SPeter Crosthwaite static const TypeInfo xilinx_enet_control_stream_info = {
105542bb9c91SPeter Crosthwaite     .name          = TYPE_XILINX_AXI_ENET_CONTROL_STREAM,
105642bb9c91SPeter Crosthwaite     .parent        = TYPE_OBJECT,
1057357088b1SPhilippe Mathieu-Daudé     .instance_size = sizeof(XilinxAXIEnetStreamSink),
10580d9047c4SEdgar E. Iglesias     .class_init    = xilinx_enet_control_stream_class_init,
105942bb9c91SPeter Crosthwaite     .interfaces = (InterfaceInfo[]) {
1060cfbef3f4SPhilippe Mathieu-Daudé             { TYPE_STREAM_SINK },
106142bb9c91SPeter Crosthwaite             { }
106242bb9c91SPeter Crosthwaite     }
106342bb9c91SPeter Crosthwaite };
106442bb9c91SPeter Crosthwaite 
xilinx_enet_register_types(void)106549ab747fSPaolo Bonzini static void xilinx_enet_register_types(void)
106649ab747fSPaolo Bonzini {
106749ab747fSPaolo Bonzini     type_register_static(&xilinx_enet_info);
106855b3e0c2SPeter Crosthwaite     type_register_static(&xilinx_enet_data_stream_info);
106942bb9c91SPeter Crosthwaite     type_register_static(&xilinx_enet_control_stream_info);
107049ab747fSPaolo Bonzini }
107149ab747fSPaolo Bonzini 
107249ab747fSPaolo Bonzini type_init(xilinx_enet_register_types)
1073