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