193f1e401SEdgar E. Iglesias /*
293f1e401SEdgar E. Iglesias * QEMU model of Xilinx AXI-Ethernet.
393f1e401SEdgar E. Iglesias *
493f1e401SEdgar E. Iglesias * Copyright (c) 2011 Edgar E. Iglesias.
593f1e401SEdgar E. Iglesias *
693f1e401SEdgar E. Iglesias * Permission is hereby granted, free of charge, to any person obtaining a copy
793f1e401SEdgar E. Iglesias * of this software and associated documentation files (the "Software"), to deal
893f1e401SEdgar E. Iglesias * in the Software without restriction, including without limitation the rights
993f1e401SEdgar E. Iglesias * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1093f1e401SEdgar E. Iglesias * copies of the Software, and to permit persons to whom the Software is
1193f1e401SEdgar E. Iglesias * furnished to do so, subject to the following conditions:
1293f1e401SEdgar E. Iglesias *
1393f1e401SEdgar E. Iglesias * The above copyright notice and this permission notice shall be included in
1493f1e401SEdgar E. Iglesias * all copies or substantial portions of the Software.
1593f1e401SEdgar E. Iglesias *
1693f1e401SEdgar E. Iglesias * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1793f1e401SEdgar E. Iglesias * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1893f1e401SEdgar E. Iglesias * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1993f1e401SEdgar E. Iglesias * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2093f1e401SEdgar E. Iglesias * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2193f1e401SEdgar E. Iglesias * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2293f1e401SEdgar E. Iglesias * THE SOFTWARE.
2393f1e401SEdgar E. Iglesias */
2493f1e401SEdgar E. Iglesias
25e8d40465SPeter Maydell #include "qemu/osdep.h"
26a27bd6c7SMarkus Armbruster #include "hw/hw.h"
2783c9f4caSPaolo Bonzini #include "hw/sysbus.h"
28da34e65cSMarkus Armbruster #include "qapi/error.h"
291de7afc9SPaolo Bonzini #include "qemu/log.h"
300b8fa32fSMarkus Armbruster #include "qemu/module.h"
311422e32dSPaolo Bonzini #include "net/net.h"
3293f1e401SEdgar E. Iglesias #include "net/checksum.h"
3393f1e401SEdgar E. Iglesias
3464552b6bSMarkus Armbruster #include "hw/irq.h"
35a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
3683c9f4caSPaolo Bonzini #include "hw/stream.h"
37db1015e9SEduardo Habkost #include "qom/object.h"
3893f1e401SEdgar E. Iglesias
3993f1e401SEdgar E. Iglesias #define DPHY(x)
4093f1e401SEdgar E. Iglesias
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
5493f1e401SEdgar E. Iglesias /* Advertisement control register. */
5593f1e401SEdgar E. Iglesias #define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
5693f1e401SEdgar E. Iglesias #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
5793f1e401SEdgar E. Iglesias #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
5893f1e401SEdgar E. Iglesias
5942bb9c91SPeter Crosthwaite #define CONTROL_PAYLOAD_WORDS 5
6042bb9c91SPeter Crosthwaite #define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t)))
6142bb9c91SPeter Crosthwaite
6293f1e401SEdgar E. Iglesias struct PHY {
6393f1e401SEdgar E. Iglesias uint32_t regs[32];
6493f1e401SEdgar E. Iglesias
6593f1e401SEdgar E. Iglesias int link;
6693f1e401SEdgar E. Iglesias
6793f1e401SEdgar E. Iglesias unsigned int (*read)(struct PHY *phy, unsigned int req);
6893f1e401SEdgar E. Iglesias void (*write)(struct PHY *phy, unsigned int req,
6993f1e401SEdgar E. Iglesias unsigned int data);
7093f1e401SEdgar E. Iglesias };
7193f1e401SEdgar E. Iglesias
tdk_read(struct PHY * phy,unsigned int req)7293f1e401SEdgar E. Iglesias static unsigned int tdk_read(struct PHY *phy, unsigned int req)
7393f1e401SEdgar E. Iglesias {
7493f1e401SEdgar E. Iglesias int regnum;
7593f1e401SEdgar E. Iglesias unsigned r = 0;
7693f1e401SEdgar E. Iglesias
7793f1e401SEdgar E. Iglesias regnum = req & 0x1f;
7893f1e401SEdgar E. Iglesias
7993f1e401SEdgar E. Iglesias switch (regnum) {
8093f1e401SEdgar E. Iglesias case 1:
8193f1e401SEdgar E. Iglesias if (!phy->link) {
8293f1e401SEdgar E. Iglesias break;
8393f1e401SEdgar E. Iglesias }
8493f1e401SEdgar E. Iglesias /* MR1. */
8593f1e401SEdgar E. Iglesias /* Speeds and modes. */
8693f1e401SEdgar E. Iglesias r |= (1 << 13) | (1 << 14);
8793f1e401SEdgar E. Iglesias r |= (1 << 11) | (1 << 12);
8893f1e401SEdgar E. Iglesias r |= (1 << 5); /* Autoneg complete. */
8993f1e401SEdgar E. Iglesias r |= (1 << 3); /* Autoneg able. */
9093f1e401SEdgar E. Iglesias r |= (1 << 2); /* link. */
9193f1e401SEdgar E. Iglesias r |= (1 << 1); /* link. */
9293f1e401SEdgar E. Iglesias break;
9393f1e401SEdgar E. Iglesias case 5:
9493f1e401SEdgar E. Iglesias /* Link partner ability.
9593f1e401SEdgar E. Iglesias We are kind; always agree with whatever best mode
9693f1e401SEdgar E. Iglesias the guest advertises. */
9793f1e401SEdgar E. Iglesias r = 1 << 14; /* Success. */
9893f1e401SEdgar E. Iglesias /* Copy advertised modes. */
9993f1e401SEdgar E. Iglesias r |= phy->regs[4] & (15 << 5);
10093f1e401SEdgar E. Iglesias /* Autoneg support. */
10193f1e401SEdgar E. Iglesias r |= 1;
10293f1e401SEdgar E. Iglesias break;
10393f1e401SEdgar E. Iglesias case 17:
10424c12b79SStefan Weil /* Marvell PHY on many xilinx boards. */
10593f1e401SEdgar E. Iglesias r = 0x8000; /* 1000Mb */
10693f1e401SEdgar E. Iglesias break;
10793f1e401SEdgar E. Iglesias case 18:
10893f1e401SEdgar E. Iglesias {
10993f1e401SEdgar E. Iglesias /* Diagnostics reg. */
11093f1e401SEdgar E. Iglesias int duplex = 0;
11193f1e401SEdgar E. Iglesias int speed_100 = 0;
11293f1e401SEdgar E. Iglesias
11393f1e401SEdgar E. Iglesias if (!phy->link) {
11493f1e401SEdgar E. Iglesias break;
11593f1e401SEdgar E. Iglesias }
11693f1e401SEdgar E. Iglesias
11793f1e401SEdgar E. Iglesias /* Are we advertising 100 half or 100 duplex ? */
11893f1e401SEdgar E. Iglesias speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
11993f1e401SEdgar E. Iglesias speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
12093f1e401SEdgar E. Iglesias
12193f1e401SEdgar E. Iglesias /* Are we advertising 10 duplex or 100 duplex ? */
12293f1e401SEdgar E. Iglesias duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
12393f1e401SEdgar E. Iglesias duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
12493f1e401SEdgar E. Iglesias r = (speed_100 << 10) | (duplex << 11);
12593f1e401SEdgar E. Iglesias }
12693f1e401SEdgar E. Iglesias break;
12793f1e401SEdgar E. Iglesias
12893f1e401SEdgar E. Iglesias default:
12993f1e401SEdgar E. Iglesias r = phy->regs[regnum];
13093f1e401SEdgar E. Iglesias break;
13193f1e401SEdgar E. Iglesias }
13293f1e401SEdgar E. Iglesias DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum));
13393f1e401SEdgar E. Iglesias return r;
13493f1e401SEdgar E. Iglesias }
13593f1e401SEdgar E. Iglesias
13693f1e401SEdgar E. Iglesias static void
tdk_write(struct PHY * phy,unsigned int req,unsigned int data)13793f1e401SEdgar E. Iglesias tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
13893f1e401SEdgar E. Iglesias {
13993f1e401SEdgar E. Iglesias int regnum;
14093f1e401SEdgar E. Iglesias
14193f1e401SEdgar E. Iglesias regnum = req & 0x1f;
14293f1e401SEdgar E. Iglesias DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data));
14393f1e401SEdgar E. Iglesias switch (regnum) {
14493f1e401SEdgar E. Iglesias default:
14593f1e401SEdgar E. Iglesias phy->regs[regnum] = data;
14693f1e401SEdgar E. Iglesias break;
14793f1e401SEdgar E. Iglesias }
148f663faacSNathan Rossi
1493e2a0cb9SEdgar E. Iglesias /* Unconditionally clear regs[BMCR][BMCR_RESET] and auto-neg */
1503e2a0cb9SEdgar E. Iglesias phy->regs[0] &= ~0x8200;
15193f1e401SEdgar E. Iglesias }
15293f1e401SEdgar E. Iglesias
15393f1e401SEdgar E. Iglesias static void
tdk_init(struct PHY * phy)15493f1e401SEdgar E. Iglesias tdk_init(struct PHY *phy)
15593f1e401SEdgar E. Iglesias {
15693f1e401SEdgar E. Iglesias phy->regs[0] = 0x3100;
15793f1e401SEdgar E. Iglesias /* PHY Id. */
15893f1e401SEdgar E. Iglesias phy->regs[2] = 0x0300;
15993f1e401SEdgar E. Iglesias phy->regs[3] = 0xe400;
16093f1e401SEdgar E. Iglesias /* Autonegotiation advertisement reg. */
16193f1e401SEdgar E. Iglesias phy->regs[4] = 0x01E1;
16293f1e401SEdgar E. Iglesias phy->link = 1;
16393f1e401SEdgar E. Iglesias
16493f1e401SEdgar E. Iglesias phy->read = tdk_read;
16593f1e401SEdgar E. Iglesias phy->write = tdk_write;
16693f1e401SEdgar E. Iglesias }
16793f1e401SEdgar E. Iglesias
16893f1e401SEdgar E. Iglesias struct MDIOBus {
16993f1e401SEdgar E. Iglesias struct PHY *devs[32];
17093f1e401SEdgar E. Iglesias };
17193f1e401SEdgar E. Iglesias
17293f1e401SEdgar E. Iglesias static void
mdio_attach(struct MDIOBus * bus,struct PHY * phy,unsigned int addr)17393f1e401SEdgar E. Iglesias mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
17493f1e401SEdgar E. Iglesias {
17593f1e401SEdgar E. Iglesias bus->devs[addr & 0x1f] = phy;
17693f1e401SEdgar E. Iglesias }
17793f1e401SEdgar E. Iglesias
17893f1e401SEdgar E. Iglesias #ifdef USE_THIS_DEAD_CODE
17993f1e401SEdgar E. Iglesias static void
mdio_detach(struct MDIOBus * bus,struct PHY * phy,unsigned int addr)18093f1e401SEdgar E. Iglesias mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
18193f1e401SEdgar E. Iglesias {
18293f1e401SEdgar E. Iglesias bus->devs[addr & 0x1f] = NULL;
18393f1e401SEdgar E. Iglesias }
18493f1e401SEdgar E. Iglesias #endif
18593f1e401SEdgar E. Iglesias
mdio_read_req(struct MDIOBus * bus,unsigned int addr,unsigned int reg)18693f1e401SEdgar E. Iglesias static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr,
18793f1e401SEdgar E. Iglesias unsigned int reg)
18893f1e401SEdgar E. Iglesias {
18993f1e401SEdgar E. Iglesias struct PHY *phy;
19093f1e401SEdgar E. Iglesias uint16_t data;
19193f1e401SEdgar E. Iglesias
19293f1e401SEdgar E. Iglesias phy = bus->devs[addr];
19393f1e401SEdgar E. Iglesias if (phy && phy->read) {
19493f1e401SEdgar E. Iglesias data = phy->read(phy, reg);
19593f1e401SEdgar E. Iglesias } else {
19693f1e401SEdgar E. Iglesias data = 0xffff;
19793f1e401SEdgar E. Iglesias }
19893f1e401SEdgar E. Iglesias DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
19993f1e401SEdgar E. Iglesias return data;
20093f1e401SEdgar E. Iglesias }
20193f1e401SEdgar E. Iglesias
mdio_write_req(struct MDIOBus * bus,unsigned int addr,unsigned int reg,uint16_t data)20293f1e401SEdgar E. Iglesias static void mdio_write_req(struct MDIOBus *bus, unsigned int addr,
20393f1e401SEdgar E. Iglesias unsigned int reg, uint16_t data)
20493f1e401SEdgar E. Iglesias {
20593f1e401SEdgar E. Iglesias struct PHY *phy;
20693f1e401SEdgar E. Iglesias
20793f1e401SEdgar E. Iglesias DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
20893f1e401SEdgar E. Iglesias phy = bus->devs[addr];
20993f1e401SEdgar E. Iglesias if (phy && phy->write) {
21093f1e401SEdgar E. Iglesias phy->write(phy, reg, data);
21193f1e401SEdgar E. Iglesias }
21293f1e401SEdgar E. Iglesias }
21393f1e401SEdgar E. Iglesias
21493f1e401SEdgar E. Iglesias #define DENET(x)
21593f1e401SEdgar E. Iglesias
21693f1e401SEdgar E. Iglesias #define R_RAF (0x000 / 4)
21793f1e401SEdgar E. Iglesias enum {
21893f1e401SEdgar E. Iglesias RAF_MCAST_REJ = (1 << 1),
21993f1e401SEdgar E. Iglesias RAF_BCAST_REJ = (1 << 2),
22093f1e401SEdgar E. Iglesias RAF_EMCF_EN = (1 << 12),
22193f1e401SEdgar E. Iglesias RAF_NEWFUNC_EN = (1 << 11)
22293f1e401SEdgar E. Iglesias };
22393f1e401SEdgar E. Iglesias
22493f1e401SEdgar E. Iglesias #define R_IS (0x00C / 4)
22593f1e401SEdgar E. Iglesias enum {
22693f1e401SEdgar E. Iglesias IS_HARD_ACCESS_COMPLETE = 1,
22793f1e401SEdgar E. Iglesias IS_AUTONEG = (1 << 1),
22893f1e401SEdgar E. Iglesias IS_RX_COMPLETE = (1 << 2),
22993f1e401SEdgar E. Iglesias IS_RX_REJECT = (1 << 3),
23093f1e401SEdgar E. Iglesias IS_TX_COMPLETE = (1 << 5),
23193f1e401SEdgar E. Iglesias IS_RX_DCM_LOCK = (1 << 6),
23293f1e401SEdgar E. Iglesias IS_MGM_RDY = (1 << 7),
23393f1e401SEdgar E. Iglesias IS_PHY_RST_DONE = (1 << 8),
23493f1e401SEdgar E. Iglesias };
23593f1e401SEdgar E. Iglesias
23693f1e401SEdgar E. Iglesias #define R_IP (0x010 / 4)
23793f1e401SEdgar E. Iglesias #define R_IE (0x014 / 4)
23893f1e401SEdgar E. Iglesias #define R_UAWL (0x020 / 4)
23993f1e401SEdgar E. Iglesias #define R_UAWU (0x024 / 4)
24093f1e401SEdgar E. Iglesias #define R_PPST (0x030 / 4)
24193f1e401SEdgar E. Iglesias enum {
24293f1e401SEdgar E. Iglesias PPST_LINKSTATUS = (1 << 0),
24393f1e401SEdgar E. Iglesias PPST_PHY_LINKSTATUS = (1 << 7),
24493f1e401SEdgar E. Iglesias };
24593f1e401SEdgar E. Iglesias
24693f1e401SEdgar E. Iglesias #define R_STATS_RX_BYTESL (0x200 / 4)
24793f1e401SEdgar E. Iglesias #define R_STATS_RX_BYTESH (0x204 / 4)
24893f1e401SEdgar E. Iglesias #define R_STATS_TX_BYTESL (0x208 / 4)
24993f1e401SEdgar E. Iglesias #define R_STATS_TX_BYTESH (0x20C / 4)
25093f1e401SEdgar E. Iglesias #define R_STATS_RXL (0x290 / 4)
25193f1e401SEdgar E. Iglesias #define R_STATS_RXH (0x294 / 4)
25293f1e401SEdgar E. Iglesias #define R_STATS_RX_BCASTL (0x2a0 / 4)
25393f1e401SEdgar E. Iglesias #define R_STATS_RX_BCASTH (0x2a4 / 4)
25493f1e401SEdgar E. Iglesias #define R_STATS_RX_MCASTL (0x2a8 / 4)
25593f1e401SEdgar E. Iglesias #define R_STATS_RX_MCASTH (0x2ac / 4)
25693f1e401SEdgar E. Iglesias
25793f1e401SEdgar E. Iglesias #define R_RCW0 (0x400 / 4)
25893f1e401SEdgar E. Iglesias #define R_RCW1 (0x404 / 4)
25993f1e401SEdgar E. Iglesias enum {
26093f1e401SEdgar E. Iglesias RCW1_VLAN = (1 << 27),
26193f1e401SEdgar E. Iglesias RCW1_RX = (1 << 28),
26293f1e401SEdgar E. Iglesias RCW1_FCS = (1 << 29),
26393f1e401SEdgar E. Iglesias RCW1_JUM = (1 << 30),
26493f1e401SEdgar E. Iglesias RCW1_RST = (1 << 31),
26593f1e401SEdgar E. Iglesias };
26693f1e401SEdgar E. Iglesias
26793f1e401SEdgar E. Iglesias #define R_TC (0x408 / 4)
26893f1e401SEdgar E. Iglesias enum {
26993f1e401SEdgar E. Iglesias TC_VLAN = (1 << 27),
27093f1e401SEdgar E. Iglesias TC_TX = (1 << 28),
27193f1e401SEdgar E. Iglesias TC_FCS = (1 << 29),
27293f1e401SEdgar E. Iglesias TC_JUM = (1 << 30),
27393f1e401SEdgar E. Iglesias TC_RST = (1 << 31),
27493f1e401SEdgar E. Iglesias };
27593f1e401SEdgar E. Iglesias
27693f1e401SEdgar E. Iglesias #define R_EMMC (0x410 / 4)
27793f1e401SEdgar E. Iglesias enum {
27893f1e401SEdgar E. Iglesias EMMC_LINKSPEED_10MB = (0 << 30),
27993f1e401SEdgar E. Iglesias EMMC_LINKSPEED_100MB = (1 << 30),
28093f1e401SEdgar E. Iglesias EMMC_LINKSPEED_1000MB = (2 << 30),
28193f1e401SEdgar E. Iglesias };
28293f1e401SEdgar E. Iglesias
28393f1e401SEdgar E. Iglesias #define R_PHYC (0x414 / 4)
28493f1e401SEdgar E. Iglesias
28593f1e401SEdgar E. Iglesias #define R_MC (0x500 / 4)
28693f1e401SEdgar E. Iglesias #define MC_EN (1 << 6)
28793f1e401SEdgar E. Iglesias
28893f1e401SEdgar E. Iglesias #define R_MCR (0x504 / 4)
28993f1e401SEdgar E. Iglesias #define R_MWD (0x508 / 4)
29093f1e401SEdgar E. Iglesias #define R_MRD (0x50c / 4)
29193f1e401SEdgar E. Iglesias #define R_MIS (0x600 / 4)
29293f1e401SEdgar E. Iglesias #define R_MIP (0x620 / 4)
29393f1e401SEdgar E. Iglesias #define R_MIE (0x640 / 4)
29493f1e401SEdgar E. Iglesias #define R_MIC (0x640 / 4)
29593f1e401SEdgar E. Iglesias
29693f1e401SEdgar E. Iglesias #define R_UAW0 (0x700 / 4)
29793f1e401SEdgar E. Iglesias #define R_UAW1 (0x704 / 4)
29893f1e401SEdgar E. Iglesias #define R_FMI (0x708 / 4)
29993f1e401SEdgar E. Iglesias #define R_AF0 (0x710 / 4)
30093f1e401SEdgar E. Iglesias #define R_AF1 (0x714 / 4)
30193f1e401SEdgar E. Iglesias #define R_MAX (0x34 / 4)
30293f1e401SEdgar E. Iglesias
30393f1e401SEdgar E. Iglesias /* Indirect registers. */
30493f1e401SEdgar E. Iglesias struct TEMAC {
30593f1e401SEdgar E. Iglesias struct MDIOBus mdio_bus;
30693f1e401SEdgar E. Iglesias struct PHY phy;
30793f1e401SEdgar E. Iglesias
30893f1e401SEdgar E. Iglesias void *parent;
30993f1e401SEdgar E. Iglesias };
31093f1e401SEdgar E. Iglesias
311545129e5SPeter Crosthwaite
312357088b1SPhilippe Mathieu-Daudé struct XilinxAXIEnetStreamSink {
31355b3e0c2SPeter Crosthwaite Object parent;
31455b3e0c2SPeter Crosthwaite
31555b3e0c2SPeter Crosthwaite struct XilinxAXIEnet *enet;
31655b3e0c2SPeter Crosthwaite } ;
31755b3e0c2SPeter Crosthwaite
31893f1e401SEdgar E. Iglesias struct XilinxAXIEnet {
31993f1e401SEdgar E. Iglesias SysBusDevice busdev;
3200dc31f3bSAvi Kivity MemoryRegion iomem;
32193f1e401SEdgar E. Iglesias 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;
32693f1e401SEdgar E. Iglesias NICState *nic;
32793f1e401SEdgar E. Iglesias NICConf conf;
32893f1e401SEdgar E. Iglesias
32993f1e401SEdgar E. Iglesias
33093f1e401SEdgar E. Iglesias uint32_t c_rxmem;
33193f1e401SEdgar E. Iglesias uint32_t c_txmem;
33293f1e401SEdgar E. Iglesias uint32_t c_phyaddr;
33393f1e401SEdgar E. Iglesias
33493f1e401SEdgar E. Iglesias struct TEMAC TEMAC;
33593f1e401SEdgar E. Iglesias
33693f1e401SEdgar E. Iglesias /* MII regs. */
33793f1e401SEdgar E. Iglesias union {
33893f1e401SEdgar E. Iglesias uint32_t regs[4];
33993f1e401SEdgar E. Iglesias struct {
34093f1e401SEdgar E. Iglesias uint32_t mc;
34193f1e401SEdgar E. Iglesias uint32_t mcr;
34293f1e401SEdgar E. Iglesias uint32_t mwd;
34393f1e401SEdgar E. Iglesias uint32_t mrd;
34493f1e401SEdgar E. Iglesias };
34593f1e401SEdgar E. Iglesias } mii;
34693f1e401SEdgar E. Iglesias
34793f1e401SEdgar E. Iglesias struct {
34893f1e401SEdgar E. Iglesias uint64_t rx_bytes;
34993f1e401SEdgar E. Iglesias uint64_t tx_bytes;
35093f1e401SEdgar E. Iglesias
35193f1e401SEdgar E. Iglesias uint64_t rx;
35293f1e401SEdgar E. Iglesias uint64_t rx_bcast;
35393f1e401SEdgar E. Iglesias uint64_t rx_mcast;
35493f1e401SEdgar E. Iglesias } stats;
35593f1e401SEdgar E. Iglesias
35693f1e401SEdgar E. Iglesias /* Receive configuration words. */
35793f1e401SEdgar E. Iglesias uint32_t rcw[2];
35893f1e401SEdgar E. Iglesias /* Transmit config. */
35993f1e401SEdgar E. Iglesias uint32_t tc;
36093f1e401SEdgar E. Iglesias uint32_t emmc;
36193f1e401SEdgar E. Iglesias uint32_t phyc;
36293f1e401SEdgar E. Iglesias
36393f1e401SEdgar E. Iglesias /* Unicast Address Word. */
36493f1e401SEdgar E. Iglesias uint32_t uaw[2];
36593f1e401SEdgar E. Iglesias /* Unicast address filter used with extended mcast. */
36693f1e401SEdgar E. Iglesias uint32_t ext_uaw[2];
36793f1e401SEdgar E. Iglesias uint32_t fmi;
36893f1e401SEdgar E. Iglesias
36993f1e401SEdgar E. Iglesias uint32_t regs[R_MAX];
37093f1e401SEdgar E. Iglesias
37193f1e401SEdgar E. Iglesias /* Multicast filter addrs. */
37293f1e401SEdgar E. Iglesias uint32_t maddr[4][2];
37393f1e401SEdgar E. Iglesias /* 32K x 1 lookup filter. */
37493f1e401SEdgar E. Iglesias uint32_t ext_mtable[1024];
37593f1e401SEdgar E. Iglesias
37642bb9c91SPeter Crosthwaite uint32_t hdr[CONTROL_PAYLOAD_WORDS];
37793f1e401SEdgar E. Iglesias
3782a4f2635SEdgar E. Iglesias uint8_t *txmem;
3792a4f2635SEdgar E. Iglesias uint32_t txpos;
3802a4f2635SEdgar E. Iglesias
38193f1e401SEdgar E. Iglesias 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;
39093f1e401SEdgar E. Iglesias };
39193f1e401SEdgar E. Iglesias
axienet_rx_reset(XilinxAXIEnet * s)392545129e5SPeter Crosthwaite static void axienet_rx_reset(XilinxAXIEnet *s)
39393f1e401SEdgar E. Iglesias {
39493f1e401SEdgar E. Iglesias s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN;
39593f1e401SEdgar E. Iglesias }
39693f1e401SEdgar E. Iglesias
axienet_tx_reset(XilinxAXIEnet * s)397545129e5SPeter Crosthwaite static void axienet_tx_reset(XilinxAXIEnet *s)
39893f1e401SEdgar E. Iglesias {
39993f1e401SEdgar E. Iglesias s->tc = TC_JUM | TC_TX | TC_VLAN;
4002a4f2635SEdgar E. Iglesias s->txpos = 0;
40193f1e401SEdgar E. Iglesias }
40293f1e401SEdgar E. Iglesias
axienet_rx_resetting(XilinxAXIEnet * s)403545129e5SPeter Crosthwaite static inline int axienet_rx_resetting(XilinxAXIEnet *s)
40493f1e401SEdgar E. Iglesias {
40593f1e401SEdgar E. Iglesias return s->rcw[1] & RCW1_RST;
40693f1e401SEdgar E. Iglesias }
40793f1e401SEdgar E. Iglesias
axienet_rx_enabled(XilinxAXIEnet * s)408545129e5SPeter Crosthwaite static inline int axienet_rx_enabled(XilinxAXIEnet *s)
40993f1e401SEdgar E. Iglesias {
41093f1e401SEdgar E. Iglesias return s->rcw[1] & RCW1_RX;
41193f1e401SEdgar E. Iglesias }
41293f1e401SEdgar E. Iglesias
axienet_extmcf_enabled(XilinxAXIEnet * s)413545129e5SPeter Crosthwaite static inline int axienet_extmcf_enabled(XilinxAXIEnet *s)
41493f1e401SEdgar E. Iglesias {
41593f1e401SEdgar E. Iglesias return !!(s->regs[R_RAF] & RAF_EMCF_EN);
41693f1e401SEdgar E. Iglesias }
41793f1e401SEdgar E. Iglesias
axienet_newfunc_enabled(XilinxAXIEnet * s)418545129e5SPeter Crosthwaite static inline int axienet_newfunc_enabled(XilinxAXIEnet *s)
41993f1e401SEdgar E. Iglesias {
42093f1e401SEdgar E. Iglesias return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN);
42193f1e401SEdgar E. Iglesias }
42293f1e401SEdgar E. Iglesias
xilinx_axienet_reset(DeviceState * d)4239ee0ceb7SPeter Crosthwaite static void xilinx_axienet_reset(DeviceState *d)
42493f1e401SEdgar E. Iglesias {
4259ee0ceb7SPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(d);
4269ee0ceb7SPeter Crosthwaite
42793f1e401SEdgar E. Iglesias axienet_rx_reset(s);
42893f1e401SEdgar E. Iglesias axienet_tx_reset(s);
42993f1e401SEdgar E. Iglesias
43093f1e401SEdgar E. Iglesias s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS;
43193f1e401SEdgar E. Iglesias s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE;
43293f1e401SEdgar E. Iglesias
43393f1e401SEdgar E. Iglesias s->emmc = EMMC_LINKSPEED_100MB;
43493f1e401SEdgar E. Iglesias }
43593f1e401SEdgar E. Iglesias
enet_update_irq(XilinxAXIEnet * s)436545129e5SPeter Crosthwaite static void enet_update_irq(XilinxAXIEnet *s)
43793f1e401SEdgar E. Iglesias {
43893f1e401SEdgar E. Iglesias s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE];
43993f1e401SEdgar E. Iglesias qemu_set_irq(s->irq, !!s->regs[R_IP]);
44093f1e401SEdgar E. Iglesias }
44193f1e401SEdgar E. Iglesias
enet_read(void * opaque,hwaddr addr,unsigned size)442a8170e5eSAvi Kivity static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size)
44393f1e401SEdgar E. Iglesias {
444545129e5SPeter Crosthwaite XilinxAXIEnet *s = opaque;
44593f1e401SEdgar E. Iglesias uint32_t r = 0;
44693f1e401SEdgar E. Iglesias addr >>= 2;
44793f1e401SEdgar E. Iglesias
44893f1e401SEdgar E. Iglesias switch (addr) {
44993f1e401SEdgar E. Iglesias case R_RCW0:
45093f1e401SEdgar E. Iglesias case R_RCW1:
45193f1e401SEdgar E. Iglesias r = s->rcw[addr & 1];
45293f1e401SEdgar E. Iglesias break;
45393f1e401SEdgar E. Iglesias
45493f1e401SEdgar E. Iglesias case R_TC:
45593f1e401SEdgar E. Iglesias r = s->tc;
45693f1e401SEdgar E. Iglesias break;
45793f1e401SEdgar E. Iglesias
45893f1e401SEdgar E. Iglesias case R_EMMC:
45993f1e401SEdgar E. Iglesias r = s->emmc;
46093f1e401SEdgar E. Iglesias break;
46193f1e401SEdgar E. Iglesias
46293f1e401SEdgar E. Iglesias case R_PHYC:
46393f1e401SEdgar E. Iglesias r = s->phyc;
46493f1e401SEdgar E. Iglesias break;
46593f1e401SEdgar E. Iglesias
46693f1e401SEdgar E. Iglesias case R_MCR:
46793f1e401SEdgar E. Iglesias r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready. */
46893f1e401SEdgar E. Iglesias break;
46993f1e401SEdgar E. Iglesias
47093f1e401SEdgar E. Iglesias case R_STATS_RX_BYTESL:
47193f1e401SEdgar E. Iglesias case R_STATS_RX_BYTESH:
47293f1e401SEdgar E. Iglesias r = s->stats.rx_bytes >> (32 * (addr & 1));
47393f1e401SEdgar E. Iglesias break;
47493f1e401SEdgar E. Iglesias
47593f1e401SEdgar E. Iglesias case R_STATS_TX_BYTESL:
47693f1e401SEdgar E. Iglesias case R_STATS_TX_BYTESH:
47793f1e401SEdgar E. Iglesias r = s->stats.tx_bytes >> (32 * (addr & 1));
47893f1e401SEdgar E. Iglesias break;
47993f1e401SEdgar E. Iglesias
48093f1e401SEdgar E. Iglesias case R_STATS_RXL:
48193f1e401SEdgar E. Iglesias case R_STATS_RXH:
48293f1e401SEdgar E. Iglesias r = s->stats.rx >> (32 * (addr & 1));
48393f1e401SEdgar E. Iglesias break;
48493f1e401SEdgar E. Iglesias case R_STATS_RX_BCASTL:
48593f1e401SEdgar E. Iglesias case R_STATS_RX_BCASTH:
48693f1e401SEdgar E. Iglesias r = s->stats.rx_bcast >> (32 * (addr & 1));
48793f1e401SEdgar E. Iglesias break;
48893f1e401SEdgar E. Iglesias case R_STATS_RX_MCASTL:
48993f1e401SEdgar E. Iglesias case R_STATS_RX_MCASTH:
49093f1e401SEdgar E. Iglesias r = s->stats.rx_mcast >> (32 * (addr & 1));
49193f1e401SEdgar E. Iglesias break;
49293f1e401SEdgar E. Iglesias
49393f1e401SEdgar E. Iglesias case R_MC:
49493f1e401SEdgar E. Iglesias case R_MWD:
49593f1e401SEdgar E. Iglesias case R_MRD:
49693f1e401SEdgar E. Iglesias r = s->mii.regs[addr & 3];
49793f1e401SEdgar E. Iglesias break;
49893f1e401SEdgar E. Iglesias
49993f1e401SEdgar E. Iglesias case R_UAW0:
50093f1e401SEdgar E. Iglesias case R_UAW1:
50193f1e401SEdgar E. Iglesias r = s->uaw[addr & 1];
50293f1e401SEdgar E. Iglesias break;
50393f1e401SEdgar E. Iglesias
50493f1e401SEdgar E. Iglesias case R_UAWU:
50593f1e401SEdgar E. Iglesias case R_UAWL:
50693f1e401SEdgar E. Iglesias r = s->ext_uaw[addr & 1];
50793f1e401SEdgar E. Iglesias break;
50893f1e401SEdgar E. Iglesias
50993f1e401SEdgar E. Iglesias case R_FMI:
51093f1e401SEdgar E. Iglesias r = s->fmi;
51193f1e401SEdgar E. Iglesias break;
51293f1e401SEdgar E. Iglesias
51393f1e401SEdgar E. Iglesias case R_AF0:
51493f1e401SEdgar E. Iglesias case R_AF1:
51593f1e401SEdgar E. Iglesias r = s->maddr[s->fmi & 3][addr & 1];
51693f1e401SEdgar E. Iglesias break;
51793f1e401SEdgar E. Iglesias
51893f1e401SEdgar E. Iglesias case 0x8000 ... 0x83ff:
51993f1e401SEdgar E. Iglesias r = s->ext_mtable[addr - 0x8000];
52093f1e401SEdgar E. Iglesias break;
52193f1e401SEdgar E. Iglesias
52293f1e401SEdgar E. Iglesias default:
52393f1e401SEdgar E. Iglesias if (addr < ARRAY_SIZE(s->regs)) {
52493f1e401SEdgar E. Iglesias r = s->regs[addr];
52593f1e401SEdgar E. Iglesias }
526883f2c59SPhilippe Mathieu-Daudé DENET(qemu_log("%s addr=" HWADDR_FMT_plx " v=%x\n",
52793f1e401SEdgar E. Iglesias __func__, addr * 4, r));
52893f1e401SEdgar E. Iglesias break;
52993f1e401SEdgar E. Iglesias }
53093f1e401SEdgar E. Iglesias return r;
53193f1e401SEdgar E. Iglesias }
53293f1e401SEdgar E. Iglesias
enet_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)533a8170e5eSAvi Kivity static void enet_write(void *opaque, hwaddr addr,
5340dc31f3bSAvi Kivity uint64_t value, unsigned size)
53593f1e401SEdgar E. Iglesias {
536545129e5SPeter Crosthwaite XilinxAXIEnet *s = opaque;
53793f1e401SEdgar E. Iglesias struct TEMAC *t = &s->TEMAC;
53893f1e401SEdgar E. Iglesias
53993f1e401SEdgar E. Iglesias addr >>= 2;
54093f1e401SEdgar E. Iglesias switch (addr) {
54193f1e401SEdgar E. Iglesias case R_RCW0:
54293f1e401SEdgar E. Iglesias case R_RCW1:
54393f1e401SEdgar E. Iglesias s->rcw[addr & 1] = value;
54493f1e401SEdgar E. Iglesias if ((addr & 1) && value & RCW1_RST) {
54593f1e401SEdgar E. Iglesias axienet_rx_reset(s);
5464dbb9ed3SPeter Crosthwaite } else {
5474dbb9ed3SPeter Crosthwaite qemu_flush_queued_packets(qemu_get_queue(s->nic));
54893f1e401SEdgar E. Iglesias }
54993f1e401SEdgar E. Iglesias break;
55093f1e401SEdgar E. Iglesias
55193f1e401SEdgar E. Iglesias case R_TC:
55293f1e401SEdgar E. Iglesias s->tc = value;
55393f1e401SEdgar E. Iglesias if (value & TC_RST) {
55493f1e401SEdgar E. Iglesias axienet_tx_reset(s);
55593f1e401SEdgar E. Iglesias }
55693f1e401SEdgar E. Iglesias break;
55793f1e401SEdgar E. Iglesias
55893f1e401SEdgar E. Iglesias case R_EMMC:
55993f1e401SEdgar E. Iglesias s->emmc = value;
56093f1e401SEdgar E. Iglesias break;
56193f1e401SEdgar E. Iglesias
56293f1e401SEdgar E. Iglesias case R_PHYC:
56393f1e401SEdgar E. Iglesias s->phyc = value;
56493f1e401SEdgar E. Iglesias break;
56593f1e401SEdgar E. Iglesias
56693f1e401SEdgar E. Iglesias case R_MC:
5674e298e46SStefan Weil value &= ((1 << 7) - 1);
56893f1e401SEdgar E. Iglesias
56993f1e401SEdgar E. Iglesias /* Enable the MII. */
57093f1e401SEdgar E. Iglesias if (value & MC_EN) {
57193f1e401SEdgar E. Iglesias unsigned int miiclkdiv = value & ((1 << 6) - 1);
57293f1e401SEdgar E. Iglesias if (!miiclkdiv) {
57393f1e401SEdgar E. Iglesias qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n");
57493f1e401SEdgar E. Iglesias }
57593f1e401SEdgar E. Iglesias }
57693f1e401SEdgar E. Iglesias s->mii.mc = value;
57793f1e401SEdgar E. Iglesias break;
57893f1e401SEdgar E. Iglesias
57993f1e401SEdgar E. Iglesias case R_MCR: {
58093f1e401SEdgar E. Iglesias unsigned int phyaddr = (value >> 24) & 0x1f;
58193f1e401SEdgar E. Iglesias unsigned int regaddr = (value >> 16) & 0x1f;
58293f1e401SEdgar E. Iglesias unsigned int op = (value >> 14) & 3;
58393f1e401SEdgar E. Iglesias unsigned int initiate = (value >> 11) & 1;
58493f1e401SEdgar E. Iglesias
58593f1e401SEdgar E. Iglesias if (initiate) {
58693f1e401SEdgar E. Iglesias if (op == 1) {
58793f1e401SEdgar E. Iglesias mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd);
58893f1e401SEdgar E. Iglesias } else if (op == 2) {
58993f1e401SEdgar E. Iglesias s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr);
59093f1e401SEdgar E. Iglesias } else {
59193f1e401SEdgar E. Iglesias qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op);
59293f1e401SEdgar E. Iglesias }
59393f1e401SEdgar E. Iglesias }
59493f1e401SEdgar E. Iglesias s->mii.mcr = value;
59593f1e401SEdgar E. Iglesias break;
59693f1e401SEdgar E. Iglesias }
59793f1e401SEdgar E. Iglesias
59893f1e401SEdgar E. Iglesias case R_MWD:
59993f1e401SEdgar E. Iglesias case R_MRD:
60093f1e401SEdgar E. Iglesias s->mii.regs[addr & 3] = value;
60193f1e401SEdgar E. Iglesias break;
60293f1e401SEdgar E. Iglesias
60393f1e401SEdgar E. Iglesias
60493f1e401SEdgar E. Iglesias case R_UAW0:
60593f1e401SEdgar E. Iglesias case R_UAW1:
60693f1e401SEdgar E. Iglesias s->uaw[addr & 1] = value;
60793f1e401SEdgar E. Iglesias break;
60893f1e401SEdgar E. Iglesias
60993f1e401SEdgar E. Iglesias case R_UAWL:
61093f1e401SEdgar E. Iglesias case R_UAWU:
61193f1e401SEdgar E. Iglesias s->ext_uaw[addr & 1] = value;
61293f1e401SEdgar E. Iglesias break;
61393f1e401SEdgar E. Iglesias
61493f1e401SEdgar E. Iglesias case R_FMI:
61593f1e401SEdgar E. Iglesias s->fmi = value;
61693f1e401SEdgar E. Iglesias break;
61793f1e401SEdgar E. Iglesias
61893f1e401SEdgar E. Iglesias case R_AF0:
61993f1e401SEdgar E. Iglesias case R_AF1:
62093f1e401SEdgar E. Iglesias s->maddr[s->fmi & 3][addr & 1] = value;
62193f1e401SEdgar E. Iglesias break;
62293f1e401SEdgar E. Iglesias
623d4d230daSPeter Crosthwaite case R_IS:
624d4d230daSPeter Crosthwaite s->regs[addr] &= ~value;
625d4d230daSPeter Crosthwaite break;
626d4d230daSPeter Crosthwaite
62793f1e401SEdgar E. Iglesias case 0x8000 ... 0x83ff:
62893f1e401SEdgar E. Iglesias s->ext_mtable[addr - 0x8000] = value;
62993f1e401SEdgar E. Iglesias break;
63093f1e401SEdgar E. Iglesias
63193f1e401SEdgar E. Iglesias default:
632883f2c59SPhilippe Mathieu-Daudé DENET(qemu_log("%s addr=" HWADDR_FMT_plx " v=%x\n",
6330dc31f3bSAvi Kivity __func__, addr * 4, (unsigned)value));
63493f1e401SEdgar E. Iglesias if (addr < ARRAY_SIZE(s->regs)) {
63593f1e401SEdgar E. Iglesias s->regs[addr] = value;
63693f1e401SEdgar E. Iglesias }
63793f1e401SEdgar E. Iglesias break;
63893f1e401SEdgar E. Iglesias }
63993f1e401SEdgar E. Iglesias enet_update_irq(s);
64093f1e401SEdgar E. Iglesias }
64193f1e401SEdgar E. Iglesias
6420dc31f3bSAvi Kivity static const MemoryRegionOps enet_ops = {
6430dc31f3bSAvi Kivity .read = enet_read,
6440dc31f3bSAvi Kivity .write = enet_write,
6450dc31f3bSAvi Kivity .endianness = DEVICE_LITTLE_ENDIAN,
64693f1e401SEdgar E. Iglesias };
64793f1e401SEdgar E. Iglesias
eth_can_rx(XilinxAXIEnet * s)648f9f7492eSFam Zheng static int eth_can_rx(XilinxAXIEnet *s)
64993f1e401SEdgar E. Iglesias {
65093f1e401SEdgar E. Iglesias /* RX enabled? */
6513630ae95SPeter Crosthwaite return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s);
65293f1e401SEdgar E. Iglesias }
65393f1e401SEdgar E. Iglesias
enet_match_addr(const uint8_t * buf,uint32_t f0,uint32_t f1)65493f1e401SEdgar E. Iglesias static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1)
65593f1e401SEdgar E. Iglesias {
65693f1e401SEdgar E. Iglesias int match = 1;
65793f1e401SEdgar E. Iglesias
65893f1e401SEdgar E. Iglesias if (memcmp(buf, &f0, 4)) {
65993f1e401SEdgar E. Iglesias match = 0;
66093f1e401SEdgar E. Iglesias }
66193f1e401SEdgar E. Iglesias
66293f1e401SEdgar E. Iglesias if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) {
66393f1e401SEdgar E. Iglesias match = 0;
66493f1e401SEdgar E. Iglesias }
66593f1e401SEdgar E. Iglesias
66693f1e401SEdgar E. Iglesias return match;
66793f1e401SEdgar E. Iglesias }
66893f1e401SEdgar E. Iglesias
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)6984e68f7a0SStefan Hajnoczi static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
69993f1e401SEdgar E. Iglesias {
700545129e5SPeter Crosthwaite XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
70193f1e401SEdgar E. Iglesias static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
70293f1e401SEdgar E. Iglesias 0xff, 0xff, 0xff};
70393f1e401SEdgar E. Iglesias static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52};
70442bb9c91SPeter Crosthwaite uint32_t app[CONTROL_PAYLOAD_WORDS] = {0};
70593f1e401SEdgar E. Iglesias int promisc = s->fmi & (1 << 31);
70693f1e401SEdgar E. Iglesias int unicast, broadcast, multicast, ip_multicast = 0;
70793f1e401SEdgar E. Iglesias uint32_t csum32;
70893f1e401SEdgar E. Iglesias uint16_t csum16;
70993f1e401SEdgar E. Iglesias int i;
71093f1e401SEdgar E. Iglesias
71193f1e401SEdgar E. Iglesias DENET(qemu_log("%s: %zd bytes\n", __func__, size));
71293f1e401SEdgar E. Iglesias
713f9f7492eSFam Zheng if (!eth_can_rx(s)) {
714f9f7492eSFam Zheng s->need_flush = true;
715f9f7492eSFam Zheng return 0;
716f9f7492eSFam Zheng }
717f9f7492eSFam Zheng
71893f1e401SEdgar E. Iglesias unicast = ~buf[0] & 0x1;
71993f1e401SEdgar E. Iglesias broadcast = memcmp(buf, sa_bcast, 6) == 0;
72093f1e401SEdgar E. Iglesias multicast = !unicast && !broadcast;
72193f1e401SEdgar E. Iglesias if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) {
72293f1e401SEdgar E. Iglesias ip_multicast = 1;
72393f1e401SEdgar E. Iglesias }
72493f1e401SEdgar E. Iglesias
72593f1e401SEdgar E. Iglesias /* Jumbo or vlan sizes ? */
72693f1e401SEdgar E. Iglesias if (!(s->rcw[1] & RCW1_JUM)) {
72793f1e401SEdgar E. Iglesias if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) {
72893f1e401SEdgar E. Iglesias return size;
72993f1e401SEdgar E. Iglesias }
73093f1e401SEdgar E. Iglesias }
73193f1e401SEdgar E. Iglesias
73293f1e401SEdgar E. Iglesias /* Basic Address filters. If you want to use the extended filters
73393f1e401SEdgar E. Iglesias you'll generally have to place the ethernet mac into promiscuous mode
73493f1e401SEdgar E. Iglesias to avoid the basic filtering from dropping most frames. */
73593f1e401SEdgar E. Iglesias if (!promisc) {
73693f1e401SEdgar E. Iglesias if (unicast) {
73793f1e401SEdgar E. Iglesias if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) {
73893f1e401SEdgar E. Iglesias return size;
73993f1e401SEdgar E. Iglesias }
74093f1e401SEdgar E. Iglesias } else {
74193f1e401SEdgar E. Iglesias if (broadcast) {
74293f1e401SEdgar E. Iglesias /* Broadcast. */
74393f1e401SEdgar E. Iglesias if (s->regs[R_RAF] & RAF_BCAST_REJ) {
74493f1e401SEdgar E. Iglesias return size;
74593f1e401SEdgar E. Iglesias }
74693f1e401SEdgar E. Iglesias } else {
74793f1e401SEdgar E. Iglesias int drop = 1;
74893f1e401SEdgar E. Iglesias
74993f1e401SEdgar E. Iglesias /* Multicast. */
75093f1e401SEdgar E. Iglesias if (s->regs[R_RAF] & RAF_MCAST_REJ) {
75193f1e401SEdgar E. Iglesias return size;
75293f1e401SEdgar E. Iglesias }
75393f1e401SEdgar E. Iglesias
75493f1e401SEdgar E. Iglesias for (i = 0; i < 4; i++) {
75593f1e401SEdgar E. Iglesias if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) {
75693f1e401SEdgar E. Iglesias drop = 0;
75793f1e401SEdgar E. Iglesias break;
75893f1e401SEdgar E. Iglesias }
75993f1e401SEdgar E. Iglesias }
76093f1e401SEdgar E. Iglesias
76193f1e401SEdgar E. Iglesias if (drop) {
76293f1e401SEdgar E. Iglesias return size;
76393f1e401SEdgar E. Iglesias }
76493f1e401SEdgar E. Iglesias }
76593f1e401SEdgar E. Iglesias }
76693f1e401SEdgar E. Iglesias }
76793f1e401SEdgar E. Iglesias
76893f1e401SEdgar E. Iglesias /* Extended mcast filtering enabled? */
76993f1e401SEdgar E. Iglesias if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) {
77093f1e401SEdgar E. Iglesias if (unicast) {
77193f1e401SEdgar E. Iglesias if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) {
77293f1e401SEdgar E. Iglesias return size;
77393f1e401SEdgar E. Iglesias }
77493f1e401SEdgar E. Iglesias } else {
77593f1e401SEdgar E. Iglesias if (broadcast) {
77693f1e401SEdgar E. Iglesias /* Broadcast. ??? */
77793f1e401SEdgar E. Iglesias if (s->regs[R_RAF] & RAF_BCAST_REJ) {
77893f1e401SEdgar E. Iglesias return size;
77993f1e401SEdgar E. Iglesias }
78093f1e401SEdgar E. Iglesias } else {
78193f1e401SEdgar E. Iglesias int idx, bit;
78293f1e401SEdgar E. Iglesias
78393f1e401SEdgar E. Iglesias /* Multicast. */
78493f1e401SEdgar E. Iglesias if (!memcmp(buf, sa_ipmcast, 3)) {
78593f1e401SEdgar E. Iglesias return size;
78693f1e401SEdgar E. Iglesias }
78793f1e401SEdgar E. Iglesias
78893f1e401SEdgar E. Iglesias idx = (buf[4] & 0x7f) << 8;
78993f1e401SEdgar E. Iglesias idx |= buf[5];
79093f1e401SEdgar E. Iglesias
79193f1e401SEdgar E. Iglesias bit = 1 << (idx & 0x1f);
79293f1e401SEdgar E. Iglesias idx >>= 5;
79393f1e401SEdgar E. Iglesias
79493f1e401SEdgar E. Iglesias if (!(s->ext_mtable[idx] & bit)) {
79593f1e401SEdgar E. Iglesias return size;
79693f1e401SEdgar E. Iglesias }
79793f1e401SEdgar E. Iglesias }
79893f1e401SEdgar E. Iglesias }
79993f1e401SEdgar E. Iglesias }
80093f1e401SEdgar E. Iglesias
80193f1e401SEdgar E. Iglesias if (size < 12) {
80293f1e401SEdgar E. Iglesias s->regs[R_IS] |= IS_RX_REJECT;
80393f1e401SEdgar E. Iglesias enet_update_irq(s);
80493f1e401SEdgar E. Iglesias return -1;
80593f1e401SEdgar E. Iglesias }
80693f1e401SEdgar E. Iglesias
80793f1e401SEdgar E. Iglesias if (size > (s->c_rxmem - 4)) {
80893f1e401SEdgar E. Iglesias size = s->c_rxmem - 4;
80993f1e401SEdgar E. Iglesias }
81093f1e401SEdgar E. Iglesias
81193f1e401SEdgar E. Iglesias memcpy(s->rxmem, buf, size);
81293f1e401SEdgar E. Iglesias memset(s->rxmem + size, 0, 4); /* Clear the FCS. */
81393f1e401SEdgar E. Iglesias
81493f1e401SEdgar E. Iglesias if (s->rcw[1] & RCW1_FCS) {
81593f1e401SEdgar E. Iglesias size += 4; /* fcs is inband. */
81693f1e401SEdgar E. Iglesias }
81793f1e401SEdgar E. Iglesias
81893f1e401SEdgar E. Iglesias app[0] = 5 << 28;
81993f1e401SEdgar E. Iglesias csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14);
82093f1e401SEdgar E. Iglesias /* Fold it once. */
82193f1e401SEdgar E. Iglesias csum32 = (csum32 & 0xffff) + (csum32 >> 16);
82293f1e401SEdgar E. Iglesias /* And twice to get rid of possible carries. */
82393f1e401SEdgar E. Iglesias csum16 = (csum32 & 0xffff) + (csum32 >> 16);
82493f1e401SEdgar E. Iglesias app[3] = csum16;
82593f1e401SEdgar E. Iglesias app[4] = size & 0xffff;
82693f1e401SEdgar E. Iglesias
82793f1e401SEdgar E. Iglesias s->stats.rx_bytes += size;
82893f1e401SEdgar E. Iglesias s->stats.rx++;
82993f1e401SEdgar E. Iglesias if (multicast) {
83093f1e401SEdgar E. Iglesias s->stats.rx_mcast++;
83193f1e401SEdgar E. Iglesias app[2] |= 1 | (ip_multicast << 1);
83293f1e401SEdgar E. Iglesias } else if (broadcast) {
83393f1e401SEdgar E. Iglesias s->stats.rx_bcast++;
83493f1e401SEdgar E. Iglesias app[2] |= 1 << 3;
83593f1e401SEdgar E. Iglesias }
83693f1e401SEdgar E. Iglesias
83793f1e401SEdgar E. Iglesias /* Good frame. */
83893f1e401SEdgar E. Iglesias app[2] |= 1 << 6;
83993f1e401SEdgar E. Iglesias
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);
84893f1e401SEdgar E. Iglesias
84993f1e401SEdgar E. Iglesias enet_update_irq(s);
8503a6d374bSFea.Wang return s->rxpos;
85193f1e401SEdgar E. Iglesias }
85293f1e401SEdgar E. Iglesias
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)
87893f1e401SEdgar E. Iglesias {
879357088b1SPhilippe Mathieu-Daudé XilinxAXIEnetStreamSink *ds = XILINX_AXI_ENET_DATA_STREAM(obj);
88055b3e0c2SPeter Crosthwaite XilinxAXIEnet *s = ds->enet;
88193f1e401SEdgar E. Iglesias
88293f1e401SEdgar E. Iglesias /* TX enable ? */
88393f1e401SEdgar E. Iglesias if (!(s->tc & TC_TX)) {
88435e60bfdSPeter Crosthwaite return size;
88593f1e401SEdgar E. Iglesias }
88693f1e401SEdgar E. Iglesias
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
90793f1e401SEdgar E. Iglesias /* Jumbo or vlan sizes ? */
90893f1e401SEdgar E. Iglesias 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;
91293f1e401SEdgar E. Iglesias }
91393f1e401SEdgar E. Iglesias }
91493f1e401SEdgar E. Iglesias
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;
91893f1e401SEdgar E. Iglesias uint32_t tmp_csum;
91993f1e401SEdgar E. Iglesias uint16_t csum;
92093f1e401SEdgar E. Iglesias
9212a4f2635SEdgar E. Iglesias tmp_csum = net_checksum_add(s->txpos - start_off,
922da59e178SEdgar E. Iglesias buf + start_off);
92393f1e401SEdgar E. Iglesias /* Accumulate the seed. */
92442bb9c91SPeter Crosthwaite tmp_csum += s->hdr[2] & 0xffff;
92593f1e401SEdgar E. Iglesias
92693f1e401SEdgar E. Iglesias /* Fold the 32bit partial checksum. */
92793f1e401SEdgar E. Iglesias csum = net_checksum_finish(tmp_csum);
92893f1e401SEdgar E. Iglesias
92993f1e401SEdgar E. Iglesias /* Writeback. */
93093f1e401SEdgar E. Iglesias buf[write_off] = csum >> 8;
93193f1e401SEdgar E. Iglesias buf[write_off + 1] = csum & 0xff;
93293f1e401SEdgar E. Iglesias }
93393f1e401SEdgar E. Iglesias
9342a4f2635SEdgar E. Iglesias qemu_send_packet(qemu_get_queue(s->nic), buf, s->txpos);
93593f1e401SEdgar E. Iglesias
9362a4f2635SEdgar E. Iglesias s->stats.tx_bytes += s->txpos;
93793f1e401SEdgar E. Iglesias s->regs[R_IS] |= IS_TX_COMPLETE;
93893f1e401SEdgar E. Iglesias enet_update_irq(s);
93935e60bfdSPeter Crosthwaite
9402a4f2635SEdgar E. Iglesias s->txpos = 0;
94135e60bfdSPeter Crosthwaite return size;
94293f1e401SEdgar E. Iglesias }
94393f1e401SEdgar E. Iglesias
94493f1e401SEdgar E. Iglesias static NetClientInfo net_xilinx_enet_info = {
945f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_NIC,
94693f1e401SEdgar E. Iglesias .size = sizeof(NICState),
94793f1e401SEdgar E. Iglesias .receive = eth_rx,
94893f1e401SEdgar E. Iglesias };
94993f1e401SEdgar E. Iglesias
xilinx_enet_realize(DeviceState * dev,Error ** errp)950b2d9dfe9SPeter Crosthwaite static void xilinx_enet_realize(DeviceState *dev, Error **errp)
95193f1e401SEdgar E. Iglesias {
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);
96793f1e401SEdgar E. Iglesias
96893f1e401SEdgar E. Iglesias qemu_macaddr_default_if_unset(&s->conf.macaddr);
96993f1e401SEdgar E. Iglesias 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);
972b356f76dSJason Wang qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
97393f1e401SEdgar E. Iglesias
97493f1e401SEdgar E. Iglesias tdk_init(&s->TEMAC.phy);
97593f1e401SEdgar E. Iglesias mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr);
97693f1e401SEdgar E. Iglesias
97793f1e401SEdgar E. Iglesias s->TEMAC.parent = s;
97893f1e401SEdgar E. Iglesias
9797267c094SAnthony Liguori s->rxmem = g_malloc(s->c_rxmem);
9802a4f2635SEdgar E. Iglesias s->txmem = g_malloc(s->c_txmem);
98193f1e401SEdgar E. Iglesias }
98293f1e401SEdgar E. Iglesias
xilinx_enet_init(Object * obj)983b2d9dfe9SPeter Crosthwaite static void xilinx_enet_init(Object *obj)
984669b4983SPeter A. G. Crosthwaite {
985f0e7a81cSPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(obj);
986b2d9dfe9SPeter Crosthwaite SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
987669b4983SPeter A. G. Crosthwaite
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);
997669b4983SPeter A. G. Crosthwaite }
998669b4983SPeter A. G. Crosthwaite
999e732f00fSRichard Henderson static const 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 *),
1008999e12bbSAnthony Liguori };
1009999e12bbSAnthony Liguori
xilinx_enet_class_init(ObjectClass * klass,const void * data)101012d1a768SPhilippe Mathieu-Daudé static void xilinx_enet_class_init(ObjectClass *klass, const void *data)
1011999e12bbSAnthony Liguori {
101239bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass);
1013999e12bbSAnthony Liguori
1014b2d9dfe9SPeter Crosthwaite dc->realize = xilinx_enet_realize;
10154f67d30bSMarc-André Lureau device_class_set_props(dc, xilinx_enet_properties);
1016e3d08143SPeter Maydell device_class_set_legacy_reset(dc, xilinx_axienet_reset);
101755b3e0c2SPeter Crosthwaite }
101855b3e0c2SPeter Crosthwaite
xilinx_enet_control_stream_class_init(ObjectClass * klass,const void * data)10190d9047c4SEdgar E. Iglesias static void xilinx_enet_control_stream_class_init(ObjectClass *klass,
102012d1a768SPhilippe Mathieu-Daudé const void *data)
102155b3e0c2SPeter Crosthwaite {
1022cfbef3f4SPhilippe Mathieu-Daudé StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
102355b3e0c2SPeter Crosthwaite
10240d9047c4SEdgar E. Iglesias ssc->push = xilinx_axienet_control_stream_push;
10250d9047c4SEdgar E. Iglesias }
10260d9047c4SEdgar E. Iglesias
xilinx_enet_data_stream_class_init(ObjectClass * klass,const void * data)102712d1a768SPhilippe Mathieu-Daudé static void xilinx_enet_data_stream_class_init(ObjectClass *klass,
102812d1a768SPhilippe Mathieu-Daudé const 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;
103393f1e401SEdgar E. Iglesias }
1034999e12bbSAnthony Liguori
10358c43a6f0SAndreas Färber static const TypeInfo xilinx_enet_info = {
1036f0e7a81cSPeter Crosthwaite .name = TYPE_XILINX_AXI_ENET,
103739bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE,
1038545129e5SPeter Crosthwaite .instance_size = sizeof(XilinxAXIEnet),
1039999e12bbSAnthony Liguori .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,
1048*2cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) {
1049cfbef3f4SPhilippe Mathieu-Daudé { TYPE_STREAM_SINK },
1050669b4983SPeter A. G. Crosthwaite { }
1051669b4983SPeter A. G. Crosthwaite }
105293f1e401SEdgar E. Iglesias };
105383f7d43aSAndreas Färber
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,
1059*2cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) {
1060cfbef3f4SPhilippe Mathieu-Daudé { TYPE_STREAM_SINK },
106142bb9c91SPeter Crosthwaite { }
106242bb9c91SPeter Crosthwaite }
106342bb9c91SPeter Crosthwaite };
106442bb9c91SPeter Crosthwaite
xilinx_enet_register_types(void)106583f7d43aSAndreas Färber static void xilinx_enet_register_types(void)
106693f1e401SEdgar E. Iglesias {
106739bffca2SAnthony Liguori 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);
107093f1e401SEdgar E. Iglesias }
107193f1e401SEdgar E. Iglesias
107283f7d43aSAndreas Färber type_init(xilinx_enet_register_types)
1073