193f1e401SEdgar E. Iglesias /* 293f1e401SEdgar E. Iglesias * QEMU model of Xilinx AXI-Ethernet. 393f1e401SEdgar E. Iglesias * 493f1e401SEdgar E. Iglesias * Copyright (c) 2011 Edgar E. Iglesias. 593f1e401SEdgar E. Iglesias * 693f1e401SEdgar E. Iglesias * Permission is hereby granted, free of charge, to any person obtaining a copy 793f1e401SEdgar E. Iglesias * of this software and associated documentation files (the "Software"), to deal 893f1e401SEdgar E. Iglesias * in the Software without restriction, including without limitation the rights 993f1e401SEdgar E. Iglesias * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1093f1e401SEdgar E. Iglesias * copies of the Software, and to permit persons to whom the Software is 1193f1e401SEdgar E. Iglesias * furnished to do so, subject to the following conditions: 1293f1e401SEdgar E. Iglesias * 1393f1e401SEdgar E. Iglesias * The above copyright notice and this permission notice shall be included in 1493f1e401SEdgar E. Iglesias * all copies or substantial portions of the Software. 1593f1e401SEdgar E. Iglesias * 1693f1e401SEdgar E. Iglesias * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1793f1e401SEdgar E. Iglesias * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1893f1e401SEdgar E. Iglesias * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1993f1e401SEdgar E. Iglesias * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2093f1e401SEdgar E. Iglesias * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2193f1e401SEdgar E. Iglesias * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2293f1e401SEdgar E. Iglesias * THE SOFTWARE. 2393f1e401SEdgar E. Iglesias */ 2493f1e401SEdgar E. Iglesias 25e8d40465SPeter Maydell #include "qemu/osdep.h" 26a27bd6c7SMarkus Armbruster #include "hw/hw.h" 2783c9f4caSPaolo Bonzini #include "hw/sysbus.h" 28da34e65cSMarkus Armbruster #include "qapi/error.h" 291de7afc9SPaolo Bonzini #include "qemu/log.h" 300b8fa32fSMarkus Armbruster #include "qemu/module.h" 311422e32dSPaolo Bonzini #include "net/net.h" 3293f1e401SEdgar E. Iglesias #include "net/checksum.h" 3393f1e401SEdgar E. Iglesias 34650d103dSMarkus Armbruster #include "hw/hw.h" 3564552b6bSMarkus Armbruster #include "hw/irq.h" 36a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 3783c9f4caSPaolo Bonzini #include "hw/stream.h" 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 45f0e7a81cSPeter Crosthwaite #define XILINX_AXI_ENET(obj) \ 46f0e7a81cSPeter Crosthwaite OBJECT_CHECK(XilinxAXIEnet, (obj), TYPE_XILINX_AXI_ENET) 47f0e7a81cSPeter Crosthwaite 4855b3e0c2SPeter Crosthwaite #define XILINX_AXI_ENET_DATA_STREAM(obj) \ 4955b3e0c2SPeter Crosthwaite OBJECT_CHECK(XilinxAXIEnetStreamSlave, (obj),\ 5055b3e0c2SPeter Crosthwaite TYPE_XILINX_AXI_ENET_DATA_STREAM) 5155b3e0c2SPeter Crosthwaite 5242bb9c91SPeter Crosthwaite #define XILINX_AXI_ENET_CONTROL_STREAM(obj) \ 5342bb9c91SPeter Crosthwaite OBJECT_CHECK(XilinxAXIEnetStreamSlave, (obj),\ 5442bb9c91SPeter Crosthwaite TYPE_XILINX_AXI_ENET_CONTROL_STREAM) 5542bb9c91SPeter Crosthwaite 5693f1e401SEdgar E. Iglesias /* Advertisement control register. */ 5793f1e401SEdgar E. Iglesias #define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ 5893f1e401SEdgar E. Iglesias #define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ 5993f1e401SEdgar E. Iglesias #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ 6093f1e401SEdgar E. Iglesias #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ 6193f1e401SEdgar E. Iglesias 6242bb9c91SPeter Crosthwaite #define CONTROL_PAYLOAD_WORDS 5 6342bb9c91SPeter Crosthwaite #define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t))) 6442bb9c91SPeter Crosthwaite 6593f1e401SEdgar E. Iglesias struct PHY { 6693f1e401SEdgar E. Iglesias uint32_t regs[32]; 6793f1e401SEdgar E. Iglesias 6893f1e401SEdgar E. Iglesias int link; 6993f1e401SEdgar E. Iglesias 7093f1e401SEdgar E. Iglesias unsigned int (*read)(struct PHY *phy, unsigned int req); 7193f1e401SEdgar E. Iglesias void (*write)(struct PHY *phy, unsigned int req, 7293f1e401SEdgar E. Iglesias unsigned int data); 7393f1e401SEdgar E. Iglesias }; 7493f1e401SEdgar E. Iglesias 7593f1e401SEdgar E. Iglesias static unsigned int tdk_read(struct PHY *phy, unsigned int req) 7693f1e401SEdgar E. Iglesias { 7793f1e401SEdgar E. Iglesias int regnum; 7893f1e401SEdgar E. Iglesias unsigned r = 0; 7993f1e401SEdgar E. Iglesias 8093f1e401SEdgar E. Iglesias regnum = req & 0x1f; 8193f1e401SEdgar E. Iglesias 8293f1e401SEdgar E. Iglesias switch (regnum) { 8393f1e401SEdgar E. Iglesias case 1: 8493f1e401SEdgar E. Iglesias if (!phy->link) { 8593f1e401SEdgar E. Iglesias break; 8693f1e401SEdgar E. Iglesias } 8793f1e401SEdgar E. Iglesias /* MR1. */ 8893f1e401SEdgar E. Iglesias /* Speeds and modes. */ 8993f1e401SEdgar E. Iglesias r |= (1 << 13) | (1 << 14); 9093f1e401SEdgar E. Iglesias r |= (1 << 11) | (1 << 12); 9193f1e401SEdgar E. Iglesias r |= (1 << 5); /* Autoneg complete. */ 9293f1e401SEdgar E. Iglesias r |= (1 << 3); /* Autoneg able. */ 9393f1e401SEdgar E. Iglesias r |= (1 << 2); /* link. */ 9493f1e401SEdgar E. Iglesias r |= (1 << 1); /* link. */ 9593f1e401SEdgar E. Iglesias break; 9693f1e401SEdgar E. Iglesias case 5: 9793f1e401SEdgar E. Iglesias /* Link partner ability. 9893f1e401SEdgar E. Iglesias We are kind; always agree with whatever best mode 9993f1e401SEdgar E. Iglesias the guest advertises. */ 10093f1e401SEdgar E. Iglesias r = 1 << 14; /* Success. */ 10193f1e401SEdgar E. Iglesias /* Copy advertised modes. */ 10293f1e401SEdgar E. Iglesias r |= phy->regs[4] & (15 << 5); 10393f1e401SEdgar E. Iglesias /* Autoneg support. */ 10493f1e401SEdgar E. Iglesias r |= 1; 10593f1e401SEdgar E. Iglesias break; 10693f1e401SEdgar E. Iglesias case 17: 10724c12b79SStefan Weil /* Marvell PHY on many xilinx boards. */ 10893f1e401SEdgar E. Iglesias r = 0x8000; /* 1000Mb */ 10993f1e401SEdgar E. Iglesias break; 11093f1e401SEdgar E. Iglesias case 18: 11193f1e401SEdgar E. Iglesias { 11293f1e401SEdgar E. Iglesias /* Diagnostics reg. */ 11393f1e401SEdgar E. Iglesias int duplex = 0; 11493f1e401SEdgar E. Iglesias int speed_100 = 0; 11593f1e401SEdgar E. Iglesias 11693f1e401SEdgar E. Iglesias if (!phy->link) { 11793f1e401SEdgar E. Iglesias break; 11893f1e401SEdgar E. Iglesias } 11993f1e401SEdgar E. Iglesias 12093f1e401SEdgar E. Iglesias /* Are we advertising 100 half or 100 duplex ? */ 12193f1e401SEdgar E. Iglesias speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); 12293f1e401SEdgar E. Iglesias speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); 12393f1e401SEdgar E. Iglesias 12493f1e401SEdgar E. Iglesias /* Are we advertising 10 duplex or 100 duplex ? */ 12593f1e401SEdgar E. Iglesias duplex = !!(phy->regs[4] & ADVERTISE_100FULL); 12693f1e401SEdgar E. Iglesias duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); 12793f1e401SEdgar E. Iglesias r = (speed_100 << 10) | (duplex << 11); 12893f1e401SEdgar E. Iglesias } 12993f1e401SEdgar E. Iglesias break; 13093f1e401SEdgar E. Iglesias 13193f1e401SEdgar E. Iglesias default: 13293f1e401SEdgar E. Iglesias r = phy->regs[regnum]; 13393f1e401SEdgar E. Iglesias break; 13493f1e401SEdgar E. Iglesias } 13593f1e401SEdgar E. Iglesias DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum)); 13693f1e401SEdgar E. Iglesias return r; 13793f1e401SEdgar E. Iglesias } 13893f1e401SEdgar E. Iglesias 13993f1e401SEdgar E. Iglesias static void 14093f1e401SEdgar E. Iglesias tdk_write(struct PHY *phy, unsigned int req, unsigned int data) 14193f1e401SEdgar E. Iglesias { 14293f1e401SEdgar E. Iglesias int regnum; 14393f1e401SEdgar E. Iglesias 14493f1e401SEdgar E. Iglesias regnum = req & 0x1f; 14593f1e401SEdgar E. Iglesias DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data)); 14693f1e401SEdgar E. Iglesias switch (regnum) { 14793f1e401SEdgar E. Iglesias default: 14893f1e401SEdgar E. Iglesias phy->regs[regnum] = data; 14993f1e401SEdgar E. Iglesias break; 15093f1e401SEdgar E. Iglesias } 151f663faacSNathan Rossi 1523e2a0cb9SEdgar E. Iglesias /* Unconditionally clear regs[BMCR][BMCR_RESET] and auto-neg */ 1533e2a0cb9SEdgar E. Iglesias phy->regs[0] &= ~0x8200; 15493f1e401SEdgar E. Iglesias } 15593f1e401SEdgar E. Iglesias 15693f1e401SEdgar E. Iglesias static void 15793f1e401SEdgar E. Iglesias tdk_init(struct PHY *phy) 15893f1e401SEdgar E. Iglesias { 15993f1e401SEdgar E. Iglesias phy->regs[0] = 0x3100; 16093f1e401SEdgar E. Iglesias /* PHY Id. */ 16193f1e401SEdgar E. Iglesias phy->regs[2] = 0x0300; 16293f1e401SEdgar E. Iglesias phy->regs[3] = 0xe400; 16393f1e401SEdgar E. Iglesias /* Autonegotiation advertisement reg. */ 16493f1e401SEdgar E. Iglesias phy->regs[4] = 0x01E1; 16593f1e401SEdgar E. Iglesias phy->link = 1; 16693f1e401SEdgar E. Iglesias 16793f1e401SEdgar E. Iglesias phy->read = tdk_read; 16893f1e401SEdgar E. Iglesias phy->write = tdk_write; 16993f1e401SEdgar E. Iglesias } 17093f1e401SEdgar E. Iglesias 17193f1e401SEdgar E. Iglesias struct MDIOBus { 17293f1e401SEdgar E. Iglesias /* bus. */ 17393f1e401SEdgar E. Iglesias int mdc; 17493f1e401SEdgar E. Iglesias int mdio; 17593f1e401SEdgar E. Iglesias 17693f1e401SEdgar E. Iglesias /* decoder. */ 17793f1e401SEdgar E. Iglesias enum { 17893f1e401SEdgar E. Iglesias PREAMBLE, 17993f1e401SEdgar E. Iglesias SOF, 18093f1e401SEdgar E. Iglesias OPC, 18193f1e401SEdgar E. Iglesias ADDR, 18293f1e401SEdgar E. Iglesias REQ, 18393f1e401SEdgar E. Iglesias TURNAROUND, 18493f1e401SEdgar E. Iglesias DATA 18593f1e401SEdgar E. Iglesias } state; 18693f1e401SEdgar E. Iglesias unsigned int drive; 18793f1e401SEdgar E. Iglesias 18893f1e401SEdgar E. Iglesias unsigned int cnt; 18993f1e401SEdgar E. Iglesias unsigned int addr; 19093f1e401SEdgar E. Iglesias unsigned int opc; 19193f1e401SEdgar E. Iglesias unsigned int req; 19293f1e401SEdgar E. Iglesias unsigned int data; 19393f1e401SEdgar E. Iglesias 19493f1e401SEdgar E. Iglesias struct PHY *devs[32]; 19593f1e401SEdgar E. Iglesias }; 19693f1e401SEdgar E. Iglesias 19793f1e401SEdgar E. Iglesias static void 19893f1e401SEdgar E. Iglesias mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr) 19993f1e401SEdgar E. Iglesias { 20093f1e401SEdgar E. Iglesias bus->devs[addr & 0x1f] = phy; 20193f1e401SEdgar E. Iglesias } 20293f1e401SEdgar E. Iglesias 20393f1e401SEdgar E. Iglesias #ifdef USE_THIS_DEAD_CODE 20493f1e401SEdgar E. Iglesias static void 20593f1e401SEdgar E. Iglesias mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr) 20693f1e401SEdgar E. Iglesias { 20793f1e401SEdgar E. Iglesias bus->devs[addr & 0x1f] = NULL; 20893f1e401SEdgar E. Iglesias } 20993f1e401SEdgar E. Iglesias #endif 21093f1e401SEdgar E. Iglesias 21193f1e401SEdgar E. Iglesias static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr, 21293f1e401SEdgar E. Iglesias unsigned int reg) 21393f1e401SEdgar E. Iglesias { 21493f1e401SEdgar E. Iglesias struct PHY *phy; 21593f1e401SEdgar E. Iglesias uint16_t data; 21693f1e401SEdgar E. Iglesias 21793f1e401SEdgar E. Iglesias phy = bus->devs[addr]; 21893f1e401SEdgar E. Iglesias if (phy && phy->read) { 21993f1e401SEdgar E. Iglesias data = phy->read(phy, reg); 22093f1e401SEdgar E. Iglesias } else { 22193f1e401SEdgar E. Iglesias data = 0xffff; 22293f1e401SEdgar E. Iglesias } 22393f1e401SEdgar E. Iglesias DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data)); 22493f1e401SEdgar E. Iglesias return data; 22593f1e401SEdgar E. Iglesias } 22693f1e401SEdgar E. Iglesias 22793f1e401SEdgar E. Iglesias static void mdio_write_req(struct MDIOBus *bus, unsigned int addr, 22893f1e401SEdgar E. Iglesias unsigned int reg, uint16_t data) 22993f1e401SEdgar E. Iglesias { 23093f1e401SEdgar E. Iglesias struct PHY *phy; 23193f1e401SEdgar E. Iglesias 23293f1e401SEdgar E. Iglesias DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data)); 23393f1e401SEdgar E. Iglesias phy = bus->devs[addr]; 23493f1e401SEdgar E. Iglesias if (phy && phy->write) { 23593f1e401SEdgar E. Iglesias phy->write(phy, reg, data); 23693f1e401SEdgar E. Iglesias } 23793f1e401SEdgar E. Iglesias } 23893f1e401SEdgar E. Iglesias 23993f1e401SEdgar E. Iglesias #define DENET(x) 24093f1e401SEdgar E. Iglesias 24193f1e401SEdgar E. Iglesias #define R_RAF (0x000 / 4) 24293f1e401SEdgar E. Iglesias enum { 24393f1e401SEdgar E. Iglesias RAF_MCAST_REJ = (1 << 1), 24493f1e401SEdgar E. Iglesias RAF_BCAST_REJ = (1 << 2), 24593f1e401SEdgar E. Iglesias RAF_EMCF_EN = (1 << 12), 24693f1e401SEdgar E. Iglesias RAF_NEWFUNC_EN = (1 << 11) 24793f1e401SEdgar E. Iglesias }; 24893f1e401SEdgar E. Iglesias 24993f1e401SEdgar E. Iglesias #define R_IS (0x00C / 4) 25093f1e401SEdgar E. Iglesias enum { 25193f1e401SEdgar E. Iglesias IS_HARD_ACCESS_COMPLETE = 1, 25293f1e401SEdgar E. Iglesias IS_AUTONEG = (1 << 1), 25393f1e401SEdgar E. Iglesias IS_RX_COMPLETE = (1 << 2), 25493f1e401SEdgar E. Iglesias IS_RX_REJECT = (1 << 3), 25593f1e401SEdgar E. Iglesias IS_TX_COMPLETE = (1 << 5), 25693f1e401SEdgar E. Iglesias IS_RX_DCM_LOCK = (1 << 6), 25793f1e401SEdgar E. Iglesias IS_MGM_RDY = (1 << 7), 25893f1e401SEdgar E. Iglesias IS_PHY_RST_DONE = (1 << 8), 25993f1e401SEdgar E. Iglesias }; 26093f1e401SEdgar E. Iglesias 26193f1e401SEdgar E. Iglesias #define R_IP (0x010 / 4) 26293f1e401SEdgar E. Iglesias #define R_IE (0x014 / 4) 26393f1e401SEdgar E. Iglesias #define R_UAWL (0x020 / 4) 26493f1e401SEdgar E. Iglesias #define R_UAWU (0x024 / 4) 26593f1e401SEdgar E. Iglesias #define R_PPST (0x030 / 4) 26693f1e401SEdgar E. Iglesias enum { 26793f1e401SEdgar E. Iglesias PPST_LINKSTATUS = (1 << 0), 26893f1e401SEdgar E. Iglesias PPST_PHY_LINKSTATUS = (1 << 7), 26993f1e401SEdgar E. Iglesias }; 27093f1e401SEdgar E. Iglesias 27193f1e401SEdgar E. Iglesias #define R_STATS_RX_BYTESL (0x200 / 4) 27293f1e401SEdgar E. Iglesias #define R_STATS_RX_BYTESH (0x204 / 4) 27393f1e401SEdgar E. Iglesias #define R_STATS_TX_BYTESL (0x208 / 4) 27493f1e401SEdgar E. Iglesias #define R_STATS_TX_BYTESH (0x20C / 4) 27593f1e401SEdgar E. Iglesias #define R_STATS_RXL (0x290 / 4) 27693f1e401SEdgar E. Iglesias #define R_STATS_RXH (0x294 / 4) 27793f1e401SEdgar E. Iglesias #define R_STATS_RX_BCASTL (0x2a0 / 4) 27893f1e401SEdgar E. Iglesias #define R_STATS_RX_BCASTH (0x2a4 / 4) 27993f1e401SEdgar E. Iglesias #define R_STATS_RX_MCASTL (0x2a8 / 4) 28093f1e401SEdgar E. Iglesias #define R_STATS_RX_MCASTH (0x2ac / 4) 28193f1e401SEdgar E. Iglesias 28293f1e401SEdgar E. Iglesias #define R_RCW0 (0x400 / 4) 28393f1e401SEdgar E. Iglesias #define R_RCW1 (0x404 / 4) 28493f1e401SEdgar E. Iglesias enum { 28593f1e401SEdgar E. Iglesias RCW1_VLAN = (1 << 27), 28693f1e401SEdgar E. Iglesias RCW1_RX = (1 << 28), 28793f1e401SEdgar E. Iglesias RCW1_FCS = (1 << 29), 28893f1e401SEdgar E. Iglesias RCW1_JUM = (1 << 30), 28993f1e401SEdgar E. Iglesias RCW1_RST = (1 << 31), 29093f1e401SEdgar E. Iglesias }; 29193f1e401SEdgar E. Iglesias 29293f1e401SEdgar E. Iglesias #define R_TC (0x408 / 4) 29393f1e401SEdgar E. Iglesias enum { 29493f1e401SEdgar E. Iglesias TC_VLAN = (1 << 27), 29593f1e401SEdgar E. Iglesias TC_TX = (1 << 28), 29693f1e401SEdgar E. Iglesias TC_FCS = (1 << 29), 29793f1e401SEdgar E. Iglesias TC_JUM = (1 << 30), 29893f1e401SEdgar E. Iglesias TC_RST = (1 << 31), 29993f1e401SEdgar E. Iglesias }; 30093f1e401SEdgar E. Iglesias 30193f1e401SEdgar E. Iglesias #define R_EMMC (0x410 / 4) 30293f1e401SEdgar E. Iglesias enum { 30393f1e401SEdgar E. Iglesias EMMC_LINKSPEED_10MB = (0 << 30), 30493f1e401SEdgar E. Iglesias EMMC_LINKSPEED_100MB = (1 << 30), 30593f1e401SEdgar E. Iglesias EMMC_LINKSPEED_1000MB = (2 << 30), 30693f1e401SEdgar E. Iglesias }; 30793f1e401SEdgar E. Iglesias 30893f1e401SEdgar E. Iglesias #define R_PHYC (0x414 / 4) 30993f1e401SEdgar E. Iglesias 31093f1e401SEdgar E. Iglesias #define R_MC (0x500 / 4) 31193f1e401SEdgar E. Iglesias #define MC_EN (1 << 6) 31293f1e401SEdgar E. Iglesias 31393f1e401SEdgar E. Iglesias #define R_MCR (0x504 / 4) 31493f1e401SEdgar E. Iglesias #define R_MWD (0x508 / 4) 31593f1e401SEdgar E. Iglesias #define R_MRD (0x50c / 4) 31693f1e401SEdgar E. Iglesias #define R_MIS (0x600 / 4) 31793f1e401SEdgar E. Iglesias #define R_MIP (0x620 / 4) 31893f1e401SEdgar E. Iglesias #define R_MIE (0x640 / 4) 31993f1e401SEdgar E. Iglesias #define R_MIC (0x640 / 4) 32093f1e401SEdgar E. Iglesias 32193f1e401SEdgar E. Iglesias #define R_UAW0 (0x700 / 4) 32293f1e401SEdgar E. Iglesias #define R_UAW1 (0x704 / 4) 32393f1e401SEdgar E. Iglesias #define R_FMI (0x708 / 4) 32493f1e401SEdgar E. Iglesias #define R_AF0 (0x710 / 4) 32593f1e401SEdgar E. Iglesias #define R_AF1 (0x714 / 4) 32693f1e401SEdgar E. Iglesias #define R_MAX (0x34 / 4) 32793f1e401SEdgar E. Iglesias 32893f1e401SEdgar E. Iglesias /* Indirect registers. */ 32993f1e401SEdgar E. Iglesias struct TEMAC { 33093f1e401SEdgar E. Iglesias struct MDIOBus mdio_bus; 33193f1e401SEdgar E. Iglesias struct PHY phy; 33293f1e401SEdgar E. Iglesias 33393f1e401SEdgar E. Iglesias void *parent; 33493f1e401SEdgar E. Iglesias }; 33593f1e401SEdgar E. Iglesias 33655b3e0c2SPeter Crosthwaite typedef struct XilinxAXIEnetStreamSlave XilinxAXIEnetStreamSlave; 337545129e5SPeter Crosthwaite typedef struct XilinxAXIEnet XilinxAXIEnet; 338545129e5SPeter Crosthwaite 33955b3e0c2SPeter Crosthwaite struct XilinxAXIEnetStreamSlave { 34055b3e0c2SPeter Crosthwaite Object parent; 34155b3e0c2SPeter Crosthwaite 34255b3e0c2SPeter Crosthwaite struct XilinxAXIEnet *enet; 34355b3e0c2SPeter Crosthwaite } ; 34455b3e0c2SPeter Crosthwaite 34593f1e401SEdgar E. Iglesias struct XilinxAXIEnet { 34693f1e401SEdgar E. Iglesias SysBusDevice busdev; 3470dc31f3bSAvi Kivity MemoryRegion iomem; 34893f1e401SEdgar E. Iglesias qemu_irq irq; 34942bb9c91SPeter Crosthwaite StreamSlave *tx_data_dev; 35042bb9c91SPeter Crosthwaite StreamSlave *tx_control_dev; 35155b3e0c2SPeter Crosthwaite XilinxAXIEnetStreamSlave rx_data_dev; 35242bb9c91SPeter Crosthwaite XilinxAXIEnetStreamSlave rx_control_dev; 35393f1e401SEdgar E. Iglesias NICState *nic; 35493f1e401SEdgar E. Iglesias NICConf conf; 35593f1e401SEdgar E. Iglesias 35693f1e401SEdgar E. Iglesias 35793f1e401SEdgar E. Iglesias uint32_t c_rxmem; 35893f1e401SEdgar E. Iglesias uint32_t c_txmem; 35993f1e401SEdgar E. Iglesias uint32_t c_phyaddr; 36093f1e401SEdgar E. Iglesias 36193f1e401SEdgar E. Iglesias struct TEMAC TEMAC; 36293f1e401SEdgar E. Iglesias 36393f1e401SEdgar E. Iglesias /* MII regs. */ 36493f1e401SEdgar E. Iglesias union { 36593f1e401SEdgar E. Iglesias uint32_t regs[4]; 36693f1e401SEdgar E. Iglesias struct { 36793f1e401SEdgar E. Iglesias uint32_t mc; 36893f1e401SEdgar E. Iglesias uint32_t mcr; 36993f1e401SEdgar E. Iglesias uint32_t mwd; 37093f1e401SEdgar E. Iglesias uint32_t mrd; 37193f1e401SEdgar E. Iglesias }; 37293f1e401SEdgar E. Iglesias } mii; 37393f1e401SEdgar E. Iglesias 37493f1e401SEdgar E. Iglesias struct { 37593f1e401SEdgar E. Iglesias uint64_t rx_bytes; 37693f1e401SEdgar E. Iglesias uint64_t tx_bytes; 37793f1e401SEdgar E. Iglesias 37893f1e401SEdgar E. Iglesias uint64_t rx; 37993f1e401SEdgar E. Iglesias uint64_t rx_bcast; 38093f1e401SEdgar E. Iglesias uint64_t rx_mcast; 38193f1e401SEdgar E. Iglesias } stats; 38293f1e401SEdgar E. Iglesias 38393f1e401SEdgar E. Iglesias /* Receive configuration words. */ 38493f1e401SEdgar E. Iglesias uint32_t rcw[2]; 38593f1e401SEdgar E. Iglesias /* Transmit config. */ 38693f1e401SEdgar E. Iglesias uint32_t tc; 38793f1e401SEdgar E. Iglesias uint32_t emmc; 38893f1e401SEdgar E. Iglesias uint32_t phyc; 38993f1e401SEdgar E. Iglesias 39093f1e401SEdgar E. Iglesias /* Unicast Address Word. */ 39193f1e401SEdgar E. Iglesias uint32_t uaw[2]; 39293f1e401SEdgar E. Iglesias /* Unicast address filter used with extended mcast. */ 39393f1e401SEdgar E. Iglesias uint32_t ext_uaw[2]; 39493f1e401SEdgar E. Iglesias uint32_t fmi; 39593f1e401SEdgar E. Iglesias 39693f1e401SEdgar E. Iglesias uint32_t regs[R_MAX]; 39793f1e401SEdgar E. Iglesias 39893f1e401SEdgar E. Iglesias /* Multicast filter addrs. */ 39993f1e401SEdgar E. Iglesias uint32_t maddr[4][2]; 40093f1e401SEdgar E. Iglesias /* 32K x 1 lookup filter. */ 40193f1e401SEdgar E. Iglesias uint32_t ext_mtable[1024]; 40293f1e401SEdgar E. Iglesias 40342bb9c91SPeter Crosthwaite uint32_t hdr[CONTROL_PAYLOAD_WORDS]; 40493f1e401SEdgar E. Iglesias 4052a4f2635SEdgar E. Iglesias uint8_t *txmem; 4062a4f2635SEdgar E. Iglesias uint32_t txpos; 4072a4f2635SEdgar E. Iglesias 40893f1e401SEdgar E. Iglesias uint8_t *rxmem; 4093630ae95SPeter Crosthwaite uint32_t rxsize; 4103630ae95SPeter Crosthwaite uint32_t rxpos; 41142bb9c91SPeter Crosthwaite 41242bb9c91SPeter Crosthwaite uint8_t rxapp[CONTROL_PAYLOAD_SIZE]; 41342bb9c91SPeter Crosthwaite uint32_t rxappsize; 414f9f7492eSFam Zheng 415f9f7492eSFam Zheng /* Whether axienet_eth_rx_notify should flush incoming queue. */ 416f9f7492eSFam Zheng bool need_flush; 41793f1e401SEdgar E. Iglesias }; 41893f1e401SEdgar E. Iglesias 419545129e5SPeter Crosthwaite static void axienet_rx_reset(XilinxAXIEnet *s) 42093f1e401SEdgar E. Iglesias { 42193f1e401SEdgar E. Iglesias s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN; 42293f1e401SEdgar E. Iglesias } 42393f1e401SEdgar E. Iglesias 424545129e5SPeter Crosthwaite static void axienet_tx_reset(XilinxAXIEnet *s) 42593f1e401SEdgar E. Iglesias { 42693f1e401SEdgar E. Iglesias s->tc = TC_JUM | TC_TX | TC_VLAN; 4272a4f2635SEdgar E. Iglesias s->txpos = 0; 42893f1e401SEdgar E. Iglesias } 42993f1e401SEdgar E. Iglesias 430545129e5SPeter Crosthwaite static inline int axienet_rx_resetting(XilinxAXIEnet *s) 43193f1e401SEdgar E. Iglesias { 43293f1e401SEdgar E. Iglesias return s->rcw[1] & RCW1_RST; 43393f1e401SEdgar E. Iglesias } 43493f1e401SEdgar E. Iglesias 435545129e5SPeter Crosthwaite static inline int axienet_rx_enabled(XilinxAXIEnet *s) 43693f1e401SEdgar E. Iglesias { 43793f1e401SEdgar E. Iglesias return s->rcw[1] & RCW1_RX; 43893f1e401SEdgar E. Iglesias } 43993f1e401SEdgar E. Iglesias 440545129e5SPeter Crosthwaite static inline int axienet_extmcf_enabled(XilinxAXIEnet *s) 44193f1e401SEdgar E. Iglesias { 44293f1e401SEdgar E. Iglesias return !!(s->regs[R_RAF] & RAF_EMCF_EN); 44393f1e401SEdgar E. Iglesias } 44493f1e401SEdgar E. Iglesias 445545129e5SPeter Crosthwaite static inline int axienet_newfunc_enabled(XilinxAXIEnet *s) 44693f1e401SEdgar E. Iglesias { 44793f1e401SEdgar E. Iglesias return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN); 44893f1e401SEdgar E. Iglesias } 44993f1e401SEdgar E. Iglesias 4509ee0ceb7SPeter Crosthwaite static void xilinx_axienet_reset(DeviceState *d) 45193f1e401SEdgar E. Iglesias { 4529ee0ceb7SPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(d); 4539ee0ceb7SPeter Crosthwaite 45493f1e401SEdgar E. Iglesias axienet_rx_reset(s); 45593f1e401SEdgar E. Iglesias axienet_tx_reset(s); 45693f1e401SEdgar E. Iglesias 45793f1e401SEdgar E. Iglesias s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS; 45893f1e401SEdgar E. Iglesias s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE; 45993f1e401SEdgar E. Iglesias 46093f1e401SEdgar E. Iglesias s->emmc = EMMC_LINKSPEED_100MB; 46193f1e401SEdgar E. Iglesias } 46293f1e401SEdgar E. Iglesias 463545129e5SPeter Crosthwaite static void enet_update_irq(XilinxAXIEnet *s) 46493f1e401SEdgar E. Iglesias { 46593f1e401SEdgar E. Iglesias s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE]; 46693f1e401SEdgar E. Iglesias qemu_set_irq(s->irq, !!s->regs[R_IP]); 46793f1e401SEdgar E. Iglesias } 46893f1e401SEdgar E. Iglesias 469a8170e5eSAvi Kivity static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size) 47093f1e401SEdgar E. Iglesias { 471545129e5SPeter Crosthwaite XilinxAXIEnet *s = opaque; 47293f1e401SEdgar E. Iglesias uint32_t r = 0; 47393f1e401SEdgar E. Iglesias addr >>= 2; 47493f1e401SEdgar E. Iglesias 47593f1e401SEdgar E. Iglesias switch (addr) { 47693f1e401SEdgar E. Iglesias case R_RCW0: 47793f1e401SEdgar E. Iglesias case R_RCW1: 47893f1e401SEdgar E. Iglesias r = s->rcw[addr & 1]; 47993f1e401SEdgar E. Iglesias break; 48093f1e401SEdgar E. Iglesias 48193f1e401SEdgar E. Iglesias case R_TC: 48293f1e401SEdgar E. Iglesias r = s->tc; 48393f1e401SEdgar E. Iglesias break; 48493f1e401SEdgar E. Iglesias 48593f1e401SEdgar E. Iglesias case R_EMMC: 48693f1e401SEdgar E. Iglesias r = s->emmc; 48793f1e401SEdgar E. Iglesias break; 48893f1e401SEdgar E. Iglesias 48993f1e401SEdgar E. Iglesias case R_PHYC: 49093f1e401SEdgar E. Iglesias r = s->phyc; 49193f1e401SEdgar E. Iglesias break; 49293f1e401SEdgar E. Iglesias 49393f1e401SEdgar E. Iglesias case R_MCR: 49493f1e401SEdgar E. Iglesias r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready. */ 49593f1e401SEdgar E. Iglesias break; 49693f1e401SEdgar E. Iglesias 49793f1e401SEdgar E. Iglesias case R_STATS_RX_BYTESL: 49893f1e401SEdgar E. Iglesias case R_STATS_RX_BYTESH: 49993f1e401SEdgar E. Iglesias r = s->stats.rx_bytes >> (32 * (addr & 1)); 50093f1e401SEdgar E. Iglesias break; 50193f1e401SEdgar E. Iglesias 50293f1e401SEdgar E. Iglesias case R_STATS_TX_BYTESL: 50393f1e401SEdgar E. Iglesias case R_STATS_TX_BYTESH: 50493f1e401SEdgar E. Iglesias r = s->stats.tx_bytes >> (32 * (addr & 1)); 50593f1e401SEdgar E. Iglesias break; 50693f1e401SEdgar E. Iglesias 50793f1e401SEdgar E. Iglesias case R_STATS_RXL: 50893f1e401SEdgar E. Iglesias case R_STATS_RXH: 50993f1e401SEdgar E. Iglesias r = s->stats.rx >> (32 * (addr & 1)); 51093f1e401SEdgar E. Iglesias break; 51193f1e401SEdgar E. Iglesias case R_STATS_RX_BCASTL: 51293f1e401SEdgar E. Iglesias case R_STATS_RX_BCASTH: 51393f1e401SEdgar E. Iglesias r = s->stats.rx_bcast >> (32 * (addr & 1)); 51493f1e401SEdgar E. Iglesias break; 51593f1e401SEdgar E. Iglesias case R_STATS_RX_MCASTL: 51693f1e401SEdgar E. Iglesias case R_STATS_RX_MCASTH: 51793f1e401SEdgar E. Iglesias r = s->stats.rx_mcast >> (32 * (addr & 1)); 51893f1e401SEdgar E. Iglesias break; 51993f1e401SEdgar E. Iglesias 52093f1e401SEdgar E. Iglesias case R_MC: 52193f1e401SEdgar E. Iglesias case R_MWD: 52293f1e401SEdgar E. Iglesias case R_MRD: 52393f1e401SEdgar E. Iglesias r = s->mii.regs[addr & 3]; 52493f1e401SEdgar E. Iglesias break; 52593f1e401SEdgar E. Iglesias 52693f1e401SEdgar E. Iglesias case R_UAW0: 52793f1e401SEdgar E. Iglesias case R_UAW1: 52893f1e401SEdgar E. Iglesias r = s->uaw[addr & 1]; 52993f1e401SEdgar E. Iglesias break; 53093f1e401SEdgar E. Iglesias 53193f1e401SEdgar E. Iglesias case R_UAWU: 53293f1e401SEdgar E. Iglesias case R_UAWL: 53393f1e401SEdgar E. Iglesias r = s->ext_uaw[addr & 1]; 53493f1e401SEdgar E. Iglesias break; 53593f1e401SEdgar E. Iglesias 53693f1e401SEdgar E. Iglesias case R_FMI: 53793f1e401SEdgar E. Iglesias r = s->fmi; 53893f1e401SEdgar E. Iglesias break; 53993f1e401SEdgar E. Iglesias 54093f1e401SEdgar E. Iglesias case R_AF0: 54193f1e401SEdgar E. Iglesias case R_AF1: 54293f1e401SEdgar E. Iglesias r = s->maddr[s->fmi & 3][addr & 1]; 54393f1e401SEdgar E. Iglesias break; 54493f1e401SEdgar E. Iglesias 54593f1e401SEdgar E. Iglesias case 0x8000 ... 0x83ff: 54693f1e401SEdgar E. Iglesias r = s->ext_mtable[addr - 0x8000]; 54793f1e401SEdgar E. Iglesias break; 54893f1e401SEdgar E. Iglesias 54993f1e401SEdgar E. Iglesias default: 55093f1e401SEdgar E. Iglesias if (addr < ARRAY_SIZE(s->regs)) { 55193f1e401SEdgar E. Iglesias r = s->regs[addr]; 55293f1e401SEdgar E. Iglesias } 55393f1e401SEdgar E. Iglesias DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n", 55493f1e401SEdgar E. Iglesias __func__, addr * 4, r)); 55593f1e401SEdgar E. Iglesias break; 55693f1e401SEdgar E. Iglesias } 55793f1e401SEdgar E. Iglesias return r; 55893f1e401SEdgar E. Iglesias } 55993f1e401SEdgar E. Iglesias 560a8170e5eSAvi Kivity static void enet_write(void *opaque, hwaddr addr, 5610dc31f3bSAvi Kivity uint64_t value, unsigned size) 56293f1e401SEdgar E. Iglesias { 563545129e5SPeter Crosthwaite XilinxAXIEnet *s = opaque; 56493f1e401SEdgar E. Iglesias struct TEMAC *t = &s->TEMAC; 56593f1e401SEdgar E. Iglesias 56693f1e401SEdgar E. Iglesias addr >>= 2; 56793f1e401SEdgar E. Iglesias switch (addr) { 56893f1e401SEdgar E. Iglesias case R_RCW0: 56993f1e401SEdgar E. Iglesias case R_RCW1: 57093f1e401SEdgar E. Iglesias s->rcw[addr & 1] = value; 57193f1e401SEdgar E. Iglesias if ((addr & 1) && value & RCW1_RST) { 57293f1e401SEdgar E. Iglesias axienet_rx_reset(s); 5734dbb9ed3SPeter Crosthwaite } else { 5744dbb9ed3SPeter Crosthwaite qemu_flush_queued_packets(qemu_get_queue(s->nic)); 57593f1e401SEdgar E. Iglesias } 57693f1e401SEdgar E. Iglesias break; 57793f1e401SEdgar E. Iglesias 57893f1e401SEdgar E. Iglesias case R_TC: 57993f1e401SEdgar E. Iglesias s->tc = value; 58093f1e401SEdgar E. Iglesias if (value & TC_RST) { 58193f1e401SEdgar E. Iglesias axienet_tx_reset(s); 58293f1e401SEdgar E. Iglesias } 58393f1e401SEdgar E. Iglesias break; 58493f1e401SEdgar E. Iglesias 58593f1e401SEdgar E. Iglesias case R_EMMC: 58693f1e401SEdgar E. Iglesias s->emmc = value; 58793f1e401SEdgar E. Iglesias break; 58893f1e401SEdgar E. Iglesias 58993f1e401SEdgar E. Iglesias case R_PHYC: 59093f1e401SEdgar E. Iglesias s->phyc = value; 59193f1e401SEdgar E. Iglesias break; 59293f1e401SEdgar E. Iglesias 59393f1e401SEdgar E. Iglesias case R_MC: 5944e298e46SStefan Weil value &= ((1 << 7) - 1); 59593f1e401SEdgar E. Iglesias 59693f1e401SEdgar E. Iglesias /* Enable the MII. */ 59793f1e401SEdgar E. Iglesias if (value & MC_EN) { 59893f1e401SEdgar E. Iglesias unsigned int miiclkdiv = value & ((1 << 6) - 1); 59993f1e401SEdgar E. Iglesias if (!miiclkdiv) { 60093f1e401SEdgar E. Iglesias qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n"); 60193f1e401SEdgar E. Iglesias } 60293f1e401SEdgar E. Iglesias } 60393f1e401SEdgar E. Iglesias s->mii.mc = value; 60493f1e401SEdgar E. Iglesias break; 60593f1e401SEdgar E. Iglesias 60693f1e401SEdgar E. Iglesias case R_MCR: { 60793f1e401SEdgar E. Iglesias unsigned int phyaddr = (value >> 24) & 0x1f; 60893f1e401SEdgar E. Iglesias unsigned int regaddr = (value >> 16) & 0x1f; 60993f1e401SEdgar E. Iglesias unsigned int op = (value >> 14) & 3; 61093f1e401SEdgar E. Iglesias unsigned int initiate = (value >> 11) & 1; 61193f1e401SEdgar E. Iglesias 61293f1e401SEdgar E. Iglesias if (initiate) { 61393f1e401SEdgar E. Iglesias if (op == 1) { 61493f1e401SEdgar E. Iglesias mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd); 61593f1e401SEdgar E. Iglesias } else if (op == 2) { 61693f1e401SEdgar E. Iglesias s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr); 61793f1e401SEdgar E. Iglesias } else { 61893f1e401SEdgar E. Iglesias qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op); 61993f1e401SEdgar E. Iglesias } 62093f1e401SEdgar E. Iglesias } 62193f1e401SEdgar E. Iglesias s->mii.mcr = value; 62293f1e401SEdgar E. Iglesias break; 62393f1e401SEdgar E. Iglesias } 62493f1e401SEdgar E. Iglesias 62593f1e401SEdgar E. Iglesias case R_MWD: 62693f1e401SEdgar E. Iglesias case R_MRD: 62793f1e401SEdgar E. Iglesias s->mii.regs[addr & 3] = value; 62893f1e401SEdgar E. Iglesias break; 62993f1e401SEdgar E. Iglesias 63093f1e401SEdgar E. Iglesias 63193f1e401SEdgar E. Iglesias case R_UAW0: 63293f1e401SEdgar E. Iglesias case R_UAW1: 63393f1e401SEdgar E. Iglesias s->uaw[addr & 1] = value; 63493f1e401SEdgar E. Iglesias break; 63593f1e401SEdgar E. Iglesias 63693f1e401SEdgar E. Iglesias case R_UAWL: 63793f1e401SEdgar E. Iglesias case R_UAWU: 63893f1e401SEdgar E. Iglesias s->ext_uaw[addr & 1] = value; 63993f1e401SEdgar E. Iglesias break; 64093f1e401SEdgar E. Iglesias 64193f1e401SEdgar E. Iglesias case R_FMI: 64293f1e401SEdgar E. Iglesias s->fmi = value; 64393f1e401SEdgar E. Iglesias break; 64493f1e401SEdgar E. Iglesias 64593f1e401SEdgar E. Iglesias case R_AF0: 64693f1e401SEdgar E. Iglesias case R_AF1: 64793f1e401SEdgar E. Iglesias s->maddr[s->fmi & 3][addr & 1] = value; 64893f1e401SEdgar E. Iglesias break; 64993f1e401SEdgar E. Iglesias 650d4d230daSPeter Crosthwaite case R_IS: 651d4d230daSPeter Crosthwaite s->regs[addr] &= ~value; 652d4d230daSPeter Crosthwaite break; 653d4d230daSPeter Crosthwaite 65493f1e401SEdgar E. Iglesias case 0x8000 ... 0x83ff: 65593f1e401SEdgar E. Iglesias s->ext_mtable[addr - 0x8000] = value; 65693f1e401SEdgar E. Iglesias break; 65793f1e401SEdgar E. Iglesias 65893f1e401SEdgar E. Iglesias default: 65993f1e401SEdgar E. Iglesias DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n", 6600dc31f3bSAvi Kivity __func__, addr * 4, (unsigned)value)); 66193f1e401SEdgar E. Iglesias if (addr < ARRAY_SIZE(s->regs)) { 66293f1e401SEdgar E. Iglesias s->regs[addr] = value; 66393f1e401SEdgar E. Iglesias } 66493f1e401SEdgar E. Iglesias break; 66593f1e401SEdgar E. Iglesias } 66693f1e401SEdgar E. Iglesias enet_update_irq(s); 66793f1e401SEdgar E. Iglesias } 66893f1e401SEdgar E. Iglesias 6690dc31f3bSAvi Kivity static const MemoryRegionOps enet_ops = { 6700dc31f3bSAvi Kivity .read = enet_read, 6710dc31f3bSAvi Kivity .write = enet_write, 6720dc31f3bSAvi Kivity .endianness = DEVICE_LITTLE_ENDIAN, 67393f1e401SEdgar E. Iglesias }; 67493f1e401SEdgar E. Iglesias 675f9f7492eSFam Zheng static int eth_can_rx(XilinxAXIEnet *s) 67693f1e401SEdgar E. Iglesias { 67793f1e401SEdgar E. Iglesias /* RX enabled? */ 6783630ae95SPeter Crosthwaite return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s); 67993f1e401SEdgar E. Iglesias } 68093f1e401SEdgar E. Iglesias 68193f1e401SEdgar E. Iglesias static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1) 68293f1e401SEdgar E. Iglesias { 68393f1e401SEdgar E. Iglesias int match = 1; 68493f1e401SEdgar E. Iglesias 68593f1e401SEdgar E. Iglesias if (memcmp(buf, &f0, 4)) { 68693f1e401SEdgar E. Iglesias match = 0; 68793f1e401SEdgar E. Iglesias } 68893f1e401SEdgar E. Iglesias 68993f1e401SEdgar E. Iglesias if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) { 69093f1e401SEdgar E. Iglesias match = 0; 69193f1e401SEdgar E. Iglesias } 69293f1e401SEdgar E. Iglesias 69393f1e401SEdgar E. Iglesias return match; 69493f1e401SEdgar E. Iglesias } 69593f1e401SEdgar E. Iglesias 6963630ae95SPeter Crosthwaite static void axienet_eth_rx_notify(void *opaque) 6973630ae95SPeter Crosthwaite { 6983630ae95SPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(opaque); 6993630ae95SPeter Crosthwaite 70042bb9c91SPeter Crosthwaite while (s->rxappsize && stream_can_push(s->tx_control_dev, 70142bb9c91SPeter Crosthwaite axienet_eth_rx_notify, s)) { 70242bb9c91SPeter Crosthwaite size_t ret = stream_push(s->tx_control_dev, 70342bb9c91SPeter Crosthwaite (void *)s->rxapp + CONTROL_PAYLOAD_SIZE 70451b19950SEdgar E. Iglesias - s->rxappsize, s->rxappsize, true); 70542bb9c91SPeter Crosthwaite s->rxappsize -= ret; 70642bb9c91SPeter Crosthwaite } 70742bb9c91SPeter Crosthwaite 70842bb9c91SPeter Crosthwaite while (s->rxsize && stream_can_push(s->tx_data_dev, 70942bb9c91SPeter Crosthwaite axienet_eth_rx_notify, s)) { 71042bb9c91SPeter Crosthwaite size_t ret = stream_push(s->tx_data_dev, (void *)s->rxmem + s->rxpos, 71151b19950SEdgar E. Iglesias s->rxsize, true); 7123630ae95SPeter Crosthwaite s->rxsize -= ret; 7133630ae95SPeter Crosthwaite s->rxpos += ret; 7143630ae95SPeter Crosthwaite if (!s->rxsize) { 7153630ae95SPeter Crosthwaite s->regs[R_IS] |= IS_RX_COMPLETE; 716f9f7492eSFam Zheng if (s->need_flush) { 717f9f7492eSFam Zheng s->need_flush = false; 718f9f7492eSFam Zheng qemu_flush_queued_packets(qemu_get_queue(s->nic)); 719f9f7492eSFam Zheng } 7203630ae95SPeter Crosthwaite } 7213630ae95SPeter Crosthwaite } 7223630ae95SPeter Crosthwaite enet_update_irq(s); 7233630ae95SPeter Crosthwaite } 7243630ae95SPeter Crosthwaite 7254e68f7a0SStefan Hajnoczi static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) 72693f1e401SEdgar E. Iglesias { 727545129e5SPeter Crosthwaite XilinxAXIEnet *s = qemu_get_nic_opaque(nc); 72893f1e401SEdgar E. Iglesias static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 72993f1e401SEdgar E. Iglesias 0xff, 0xff, 0xff}; 73093f1e401SEdgar E. Iglesias static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52}; 73142bb9c91SPeter Crosthwaite uint32_t app[CONTROL_PAYLOAD_WORDS] = {0}; 73293f1e401SEdgar E. Iglesias int promisc = s->fmi & (1 << 31); 73393f1e401SEdgar E. Iglesias int unicast, broadcast, multicast, ip_multicast = 0; 73493f1e401SEdgar E. Iglesias uint32_t csum32; 73593f1e401SEdgar E. Iglesias uint16_t csum16; 73693f1e401SEdgar E. Iglesias int i; 73793f1e401SEdgar E. Iglesias 73893f1e401SEdgar E. Iglesias DENET(qemu_log("%s: %zd bytes\n", __func__, size)); 73993f1e401SEdgar E. Iglesias 740f9f7492eSFam Zheng if (!eth_can_rx(s)) { 741f9f7492eSFam Zheng s->need_flush = true; 742f9f7492eSFam Zheng return 0; 743f9f7492eSFam Zheng } 744f9f7492eSFam Zheng 74593f1e401SEdgar E. Iglesias unicast = ~buf[0] & 0x1; 74693f1e401SEdgar E. Iglesias broadcast = memcmp(buf, sa_bcast, 6) == 0; 74793f1e401SEdgar E. Iglesias multicast = !unicast && !broadcast; 74893f1e401SEdgar E. Iglesias if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) { 74993f1e401SEdgar E. Iglesias ip_multicast = 1; 75093f1e401SEdgar E. Iglesias } 75193f1e401SEdgar E. Iglesias 75293f1e401SEdgar E. Iglesias /* Jumbo or vlan sizes ? */ 75393f1e401SEdgar E. Iglesias if (!(s->rcw[1] & RCW1_JUM)) { 75493f1e401SEdgar E. Iglesias if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) { 75593f1e401SEdgar E. Iglesias return size; 75693f1e401SEdgar E. Iglesias } 75793f1e401SEdgar E. Iglesias } 75893f1e401SEdgar E. Iglesias 75993f1e401SEdgar E. Iglesias /* Basic Address filters. If you want to use the extended filters 76093f1e401SEdgar E. Iglesias you'll generally have to place the ethernet mac into promiscuous mode 76193f1e401SEdgar E. Iglesias to avoid the basic filtering from dropping most frames. */ 76293f1e401SEdgar E. Iglesias if (!promisc) { 76393f1e401SEdgar E. Iglesias if (unicast) { 76493f1e401SEdgar E. Iglesias if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) { 76593f1e401SEdgar E. Iglesias return size; 76693f1e401SEdgar E. Iglesias } 76793f1e401SEdgar E. Iglesias } else { 76893f1e401SEdgar E. Iglesias if (broadcast) { 76993f1e401SEdgar E. Iglesias /* Broadcast. */ 77093f1e401SEdgar E. Iglesias if (s->regs[R_RAF] & RAF_BCAST_REJ) { 77193f1e401SEdgar E. Iglesias return size; 77293f1e401SEdgar E. Iglesias } 77393f1e401SEdgar E. Iglesias } else { 77493f1e401SEdgar E. Iglesias int drop = 1; 77593f1e401SEdgar E. Iglesias 77693f1e401SEdgar E. Iglesias /* Multicast. */ 77793f1e401SEdgar E. Iglesias if (s->regs[R_RAF] & RAF_MCAST_REJ) { 77893f1e401SEdgar E. Iglesias return size; 77993f1e401SEdgar E. Iglesias } 78093f1e401SEdgar E. Iglesias 78193f1e401SEdgar E. Iglesias for (i = 0; i < 4; i++) { 78293f1e401SEdgar E. Iglesias if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) { 78393f1e401SEdgar E. Iglesias drop = 0; 78493f1e401SEdgar E. Iglesias break; 78593f1e401SEdgar E. Iglesias } 78693f1e401SEdgar E. Iglesias } 78793f1e401SEdgar E. Iglesias 78893f1e401SEdgar E. Iglesias if (drop) { 78993f1e401SEdgar E. Iglesias return size; 79093f1e401SEdgar E. Iglesias } 79193f1e401SEdgar E. Iglesias } 79293f1e401SEdgar E. Iglesias } 79393f1e401SEdgar E. Iglesias } 79493f1e401SEdgar E. Iglesias 79593f1e401SEdgar E. Iglesias /* Extended mcast filtering enabled? */ 79693f1e401SEdgar E. Iglesias if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) { 79793f1e401SEdgar E. Iglesias if (unicast) { 79893f1e401SEdgar E. Iglesias if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) { 79993f1e401SEdgar E. Iglesias return size; 80093f1e401SEdgar E. Iglesias } 80193f1e401SEdgar E. Iglesias } else { 80293f1e401SEdgar E. Iglesias if (broadcast) { 80393f1e401SEdgar E. Iglesias /* Broadcast. ??? */ 80493f1e401SEdgar E. Iglesias if (s->regs[R_RAF] & RAF_BCAST_REJ) { 80593f1e401SEdgar E. Iglesias return size; 80693f1e401SEdgar E. Iglesias } 80793f1e401SEdgar E. Iglesias } else { 80893f1e401SEdgar E. Iglesias int idx, bit; 80993f1e401SEdgar E. Iglesias 81093f1e401SEdgar E. Iglesias /* Multicast. */ 81193f1e401SEdgar E. Iglesias if (!memcmp(buf, sa_ipmcast, 3)) { 81293f1e401SEdgar E. Iglesias return size; 81393f1e401SEdgar E. Iglesias } 81493f1e401SEdgar E. Iglesias 81593f1e401SEdgar E. Iglesias idx = (buf[4] & 0x7f) << 8; 81693f1e401SEdgar E. Iglesias idx |= buf[5]; 81793f1e401SEdgar E. Iglesias 81893f1e401SEdgar E. Iglesias bit = 1 << (idx & 0x1f); 81993f1e401SEdgar E. Iglesias idx >>= 5; 82093f1e401SEdgar E. Iglesias 82193f1e401SEdgar E. Iglesias if (!(s->ext_mtable[idx] & bit)) { 82293f1e401SEdgar E. Iglesias return size; 82393f1e401SEdgar E. Iglesias } 82493f1e401SEdgar E. Iglesias } 82593f1e401SEdgar E. Iglesias } 82693f1e401SEdgar E. Iglesias } 82793f1e401SEdgar E. Iglesias 82893f1e401SEdgar E. Iglesias if (size < 12) { 82993f1e401SEdgar E. Iglesias s->regs[R_IS] |= IS_RX_REJECT; 83093f1e401SEdgar E. Iglesias enet_update_irq(s); 83193f1e401SEdgar E. Iglesias return -1; 83293f1e401SEdgar E. Iglesias } 83393f1e401SEdgar E. Iglesias 83493f1e401SEdgar E. Iglesias if (size > (s->c_rxmem - 4)) { 83593f1e401SEdgar E. Iglesias size = s->c_rxmem - 4; 83693f1e401SEdgar E. Iglesias } 83793f1e401SEdgar E. Iglesias 83893f1e401SEdgar E. Iglesias memcpy(s->rxmem, buf, size); 83993f1e401SEdgar E. Iglesias memset(s->rxmem + size, 0, 4); /* Clear the FCS. */ 84093f1e401SEdgar E. Iglesias 84193f1e401SEdgar E. Iglesias if (s->rcw[1] & RCW1_FCS) { 84293f1e401SEdgar E. Iglesias size += 4; /* fcs is inband. */ 84393f1e401SEdgar E. Iglesias } 84493f1e401SEdgar E. Iglesias 84593f1e401SEdgar E. Iglesias app[0] = 5 << 28; 84693f1e401SEdgar E. Iglesias csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14); 84793f1e401SEdgar E. Iglesias /* Fold it once. */ 84893f1e401SEdgar E. Iglesias csum32 = (csum32 & 0xffff) + (csum32 >> 16); 84993f1e401SEdgar E. Iglesias /* And twice to get rid of possible carries. */ 85093f1e401SEdgar E. Iglesias csum16 = (csum32 & 0xffff) + (csum32 >> 16); 85193f1e401SEdgar E. Iglesias app[3] = csum16; 85293f1e401SEdgar E. Iglesias app[4] = size & 0xffff; 85393f1e401SEdgar E. Iglesias 85493f1e401SEdgar E. Iglesias s->stats.rx_bytes += size; 85593f1e401SEdgar E. Iglesias s->stats.rx++; 85693f1e401SEdgar E. Iglesias if (multicast) { 85793f1e401SEdgar E. Iglesias s->stats.rx_mcast++; 85893f1e401SEdgar E. Iglesias app[2] |= 1 | (ip_multicast << 1); 85993f1e401SEdgar E. Iglesias } else if (broadcast) { 86093f1e401SEdgar E. Iglesias s->stats.rx_bcast++; 86193f1e401SEdgar E. Iglesias app[2] |= 1 << 3; 86293f1e401SEdgar E. Iglesias } 86393f1e401SEdgar E. Iglesias 86493f1e401SEdgar E. Iglesias /* Good frame. */ 86593f1e401SEdgar E. Iglesias app[2] |= 1 << 6; 86693f1e401SEdgar E. Iglesias 8673630ae95SPeter Crosthwaite s->rxsize = size; 8683630ae95SPeter Crosthwaite s->rxpos = 0; 86942bb9c91SPeter Crosthwaite for (i = 0; i < ARRAY_SIZE(app); ++i) { 87042bb9c91SPeter Crosthwaite app[i] = cpu_to_le32(app[i]); 87142bb9c91SPeter Crosthwaite } 87242bb9c91SPeter Crosthwaite s->rxappsize = CONTROL_PAYLOAD_SIZE; 87342bb9c91SPeter Crosthwaite memcpy(s->rxapp, app, s->rxappsize); 8743630ae95SPeter Crosthwaite axienet_eth_rx_notify(s); 87593f1e401SEdgar E. Iglesias 87693f1e401SEdgar E. Iglesias enet_update_irq(s); 87793f1e401SEdgar E. Iglesias return size; 87893f1e401SEdgar E. Iglesias } 87993f1e401SEdgar E. Iglesias 88035e60bfdSPeter Crosthwaite static size_t 88151b19950SEdgar E. Iglesias xilinx_axienet_control_stream_push(StreamSlave *obj, uint8_t *buf, size_t len, 88251b19950SEdgar E. Iglesias bool eop) 88342bb9c91SPeter Crosthwaite { 88442bb9c91SPeter Crosthwaite int i; 88542bb9c91SPeter Crosthwaite XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM(obj); 88642bb9c91SPeter Crosthwaite XilinxAXIEnet *s = cs->enet; 88742bb9c91SPeter Crosthwaite 88851b19950SEdgar E. Iglesias assert(eop); 88942bb9c91SPeter Crosthwaite if (len != CONTROL_PAYLOAD_SIZE) { 89042bb9c91SPeter Crosthwaite hw_error("AXI Enet requires %d byte control stream payload\n", 89142bb9c91SPeter Crosthwaite (int)CONTROL_PAYLOAD_SIZE); 89242bb9c91SPeter Crosthwaite } 89342bb9c91SPeter Crosthwaite 89442bb9c91SPeter Crosthwaite memcpy(s->hdr, buf, len); 89542bb9c91SPeter Crosthwaite 89642bb9c91SPeter Crosthwaite for (i = 0; i < ARRAY_SIZE(s->hdr); ++i) { 89742bb9c91SPeter Crosthwaite s->hdr[i] = le32_to_cpu(s->hdr[i]); 89842bb9c91SPeter Crosthwaite } 89942bb9c91SPeter Crosthwaite return len; 90042bb9c91SPeter Crosthwaite } 90142bb9c91SPeter Crosthwaite 90242bb9c91SPeter Crosthwaite static size_t 90351b19950SEdgar E. Iglesias xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, 90451b19950SEdgar E. Iglesias bool eop) 90593f1e401SEdgar E. Iglesias { 90655b3e0c2SPeter Crosthwaite XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(obj); 90755b3e0c2SPeter Crosthwaite XilinxAXIEnet *s = ds->enet; 90893f1e401SEdgar E. Iglesias 90993f1e401SEdgar E. Iglesias /* TX enable ? */ 91093f1e401SEdgar E. Iglesias if (!(s->tc & TC_TX)) { 91135e60bfdSPeter Crosthwaite return size; 91293f1e401SEdgar E. Iglesias } 91393f1e401SEdgar E. Iglesias 9142a4f2635SEdgar E. Iglesias if (s->txpos + size > s->c_txmem) { 9152a4f2635SEdgar E. Iglesias qemu_log_mask(LOG_GUEST_ERROR, "%s: Packet larger than txmem\n", 9162a4f2635SEdgar E. Iglesias TYPE_XILINX_AXI_ENET); 9172a4f2635SEdgar E. Iglesias s->txpos = 0; 9182a4f2635SEdgar E. Iglesias return size; 9192a4f2635SEdgar E. Iglesias } 9202a4f2635SEdgar E. Iglesias 9212a4f2635SEdgar E. Iglesias if (s->txpos == 0 && eop) { 9222a4f2635SEdgar E. Iglesias /* Fast path single fragment. */ 9232a4f2635SEdgar E. Iglesias s->txpos = size; 9242a4f2635SEdgar E. Iglesias } else { 9252a4f2635SEdgar E. Iglesias memcpy(s->txmem + s->txpos, buf, size); 9262a4f2635SEdgar E. Iglesias buf = s->txmem; 9272a4f2635SEdgar E. Iglesias s->txpos += size; 9282a4f2635SEdgar E. Iglesias 9292a4f2635SEdgar E. Iglesias if (!eop) { 9302a4f2635SEdgar E. Iglesias return size; 9312a4f2635SEdgar E. Iglesias } 9322a4f2635SEdgar E. Iglesias } 9332a4f2635SEdgar E. Iglesias 93493f1e401SEdgar E. Iglesias /* Jumbo or vlan sizes ? */ 93593f1e401SEdgar E. Iglesias if (!(s->tc & TC_JUM)) { 9362a4f2635SEdgar E. Iglesias if (s->txpos > 1518 && s->txpos <= 1522 && !(s->tc & TC_VLAN)) { 9372a4f2635SEdgar E. Iglesias s->txpos = 0; 93835e60bfdSPeter Crosthwaite return size; 93993f1e401SEdgar E. Iglesias } 94093f1e401SEdgar E. Iglesias } 94193f1e401SEdgar E. Iglesias 94242bb9c91SPeter Crosthwaite if (s->hdr[0] & 1) { 94342bb9c91SPeter Crosthwaite unsigned int start_off = s->hdr[1] >> 16; 94442bb9c91SPeter Crosthwaite unsigned int write_off = s->hdr[1] & 0xffff; 94593f1e401SEdgar E. Iglesias uint32_t tmp_csum; 94693f1e401SEdgar E. Iglesias uint16_t csum; 94793f1e401SEdgar E. Iglesias 9482a4f2635SEdgar E. Iglesias tmp_csum = net_checksum_add(s->txpos - start_off, 949da59e178SEdgar E. Iglesias buf + start_off); 95093f1e401SEdgar E. Iglesias /* Accumulate the seed. */ 95142bb9c91SPeter Crosthwaite tmp_csum += s->hdr[2] & 0xffff; 95293f1e401SEdgar E. Iglesias 95393f1e401SEdgar E. Iglesias /* Fold the 32bit partial checksum. */ 95493f1e401SEdgar E. Iglesias csum = net_checksum_finish(tmp_csum); 95593f1e401SEdgar E. Iglesias 95693f1e401SEdgar E. Iglesias /* Writeback. */ 95793f1e401SEdgar E. Iglesias buf[write_off] = csum >> 8; 95893f1e401SEdgar E. Iglesias buf[write_off + 1] = csum & 0xff; 95993f1e401SEdgar E. Iglesias } 96093f1e401SEdgar E. Iglesias 9612a4f2635SEdgar E. Iglesias qemu_send_packet(qemu_get_queue(s->nic), buf, s->txpos); 96293f1e401SEdgar E. Iglesias 9632a4f2635SEdgar E. Iglesias s->stats.tx_bytes += s->txpos; 96493f1e401SEdgar E. Iglesias s->regs[R_IS] |= IS_TX_COMPLETE; 96593f1e401SEdgar E. Iglesias enet_update_irq(s); 96635e60bfdSPeter Crosthwaite 9672a4f2635SEdgar E. Iglesias s->txpos = 0; 96835e60bfdSPeter Crosthwaite return size; 96993f1e401SEdgar E. Iglesias } 97093f1e401SEdgar E. Iglesias 97193f1e401SEdgar E. Iglesias static NetClientInfo net_xilinx_enet_info = { 972f394b2e2SEric Blake .type = NET_CLIENT_DRIVER_NIC, 97393f1e401SEdgar E. Iglesias .size = sizeof(NICState), 97493f1e401SEdgar E. Iglesias .receive = eth_rx, 97593f1e401SEdgar E. Iglesias }; 97693f1e401SEdgar E. Iglesias 977b2d9dfe9SPeter Crosthwaite static void xilinx_enet_realize(DeviceState *dev, Error **errp) 97893f1e401SEdgar E. Iglesias { 979f0e7a81cSPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(dev); 98055b3e0c2SPeter Crosthwaite XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(&s->rx_data_dev); 98142bb9c91SPeter Crosthwaite XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM( 98242bb9c91SPeter Crosthwaite &s->rx_control_dev); 9832f719f19SMarkus Armbruster Error *local_err = NULL; 98455b3e0c2SPeter Crosthwaite 98555b3e0c2SPeter Crosthwaite object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet", 9869561fda8SStefan Hajnoczi (Object **) &ds->enet, 98739f72ef9SStefan Hajnoczi object_property_allow_set_link, 988d2623129SMarkus Armbruster OBJ_PROP_LINK_STRONG); 98942bb9c91SPeter Crosthwaite object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet", 9909561fda8SStefan Hajnoczi (Object **) &cs->enet, 99139f72ef9SStefan Hajnoczi object_property_allow_set_link, 992d2623129SMarkus Armbruster OBJ_PROP_LINK_STRONG); 9932f719f19SMarkus Armbruster object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_err); 9942f719f19SMarkus Armbruster object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_err); 9952f719f19SMarkus Armbruster if (local_err) { 99655b3e0c2SPeter Crosthwaite goto xilinx_enet_realize_fail; 99755b3e0c2SPeter Crosthwaite } 99893f1e401SEdgar E. Iglesias 99993f1e401SEdgar E. Iglesias qemu_macaddr_default_if_unset(&s->conf.macaddr); 100093f1e401SEdgar E. Iglesias s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf, 1001b2d9dfe9SPeter Crosthwaite object_get_typename(OBJECT(dev)), dev->id, s); 1002b356f76dSJason Wang qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); 100393f1e401SEdgar E. Iglesias 100493f1e401SEdgar E. Iglesias tdk_init(&s->TEMAC.phy); 100593f1e401SEdgar E. Iglesias mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr); 100693f1e401SEdgar E. Iglesias 100793f1e401SEdgar E. Iglesias s->TEMAC.parent = s; 100893f1e401SEdgar E. Iglesias 10097267c094SAnthony Liguori s->rxmem = g_malloc(s->c_rxmem); 10102a4f2635SEdgar E. Iglesias s->txmem = g_malloc(s->c_txmem); 101155b3e0c2SPeter Crosthwaite return; 101255b3e0c2SPeter Crosthwaite 101355b3e0c2SPeter Crosthwaite xilinx_enet_realize_fail: 1014a9859c90SEduardo Habkost error_propagate(errp, local_err); 101593f1e401SEdgar E. Iglesias } 101693f1e401SEdgar E. Iglesias 1017b2d9dfe9SPeter Crosthwaite static void xilinx_enet_init(Object *obj) 1018669b4983SPeter A. G. Crosthwaite { 1019f0e7a81cSPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(obj); 1020b2d9dfe9SPeter Crosthwaite SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 1021669b4983SPeter A. G. Crosthwaite 102265da9142SPhilippe Mathieu-Daudé object_initialize_child(OBJECT(s), "axistream-connected-target", 1023*9fc7fc4dSMarkus Armbruster &s->rx_data_dev, TYPE_XILINX_AXI_ENET_DATA_STREAM); 102465da9142SPhilippe Mathieu-Daudé object_initialize_child(OBJECT(s), "axistream-control-connected-target", 1025*9fc7fc4dSMarkus Armbruster &s->rx_control_dev, 1026*9fc7fc4dSMarkus Armbruster TYPE_XILINX_AXI_ENET_CONTROL_STREAM); 1027b2d9dfe9SPeter Crosthwaite sysbus_init_irq(sbd, &s->irq); 1028b2d9dfe9SPeter Crosthwaite 1029eedfac6fSPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &enet_ops, s, "enet", 0x40000); 1030b2d9dfe9SPeter Crosthwaite sysbus_init_mmio(sbd, &s->iomem); 1031669b4983SPeter A. G. Crosthwaite } 1032669b4983SPeter A. G. Crosthwaite 1033999e12bbSAnthony Liguori static Property xilinx_enet_properties[] = { 1034545129e5SPeter Crosthwaite DEFINE_PROP_UINT32("phyaddr", XilinxAXIEnet, c_phyaddr, 7), 1035545129e5SPeter Crosthwaite DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000), 1036545129e5SPeter Crosthwaite DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000), 1037545129e5SPeter Crosthwaite DEFINE_NIC_PROPERTIES(XilinxAXIEnet, conf), 103826cfb11fSFam Zheng DEFINE_PROP_LINK("axistream-connected", XilinxAXIEnet, 103926cfb11fSFam Zheng tx_data_dev, TYPE_STREAM_SLAVE, StreamSlave *), 104026cfb11fSFam Zheng DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIEnet, 104126cfb11fSFam Zheng tx_control_dev, TYPE_STREAM_SLAVE, StreamSlave *), 104293f1e401SEdgar E. Iglesias DEFINE_PROP_END_OF_LIST(), 1043999e12bbSAnthony Liguori }; 1044999e12bbSAnthony Liguori 1045999e12bbSAnthony Liguori static void xilinx_enet_class_init(ObjectClass *klass, void *data) 1046999e12bbSAnthony Liguori { 104739bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 1048999e12bbSAnthony Liguori 1049b2d9dfe9SPeter Crosthwaite dc->realize = xilinx_enet_realize; 10504f67d30bSMarc-André Lureau device_class_set_props(dc, xilinx_enet_properties); 10519ee0ceb7SPeter Crosthwaite dc->reset = xilinx_axienet_reset; 105255b3e0c2SPeter Crosthwaite } 105355b3e0c2SPeter Crosthwaite 10540d9047c4SEdgar E. Iglesias static void xilinx_enet_control_stream_class_init(ObjectClass *klass, 10550d9047c4SEdgar E. Iglesias void *data) 105655b3e0c2SPeter Crosthwaite { 105755b3e0c2SPeter Crosthwaite StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass); 105855b3e0c2SPeter Crosthwaite 10590d9047c4SEdgar E. Iglesias ssc->push = xilinx_axienet_control_stream_push; 10600d9047c4SEdgar E. Iglesias } 10610d9047c4SEdgar E. Iglesias 10620d9047c4SEdgar E. Iglesias static void xilinx_enet_data_stream_class_init(ObjectClass *klass, void *data) 10630d9047c4SEdgar E. Iglesias { 10640d9047c4SEdgar E. Iglesias StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass); 10650d9047c4SEdgar E. Iglesias 10660d9047c4SEdgar E. Iglesias ssc->push = xilinx_axienet_data_stream_push; 106793f1e401SEdgar E. Iglesias } 1068999e12bbSAnthony Liguori 10698c43a6f0SAndreas Färber static const TypeInfo xilinx_enet_info = { 1070f0e7a81cSPeter Crosthwaite .name = TYPE_XILINX_AXI_ENET, 107139bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 1072545129e5SPeter Crosthwaite .instance_size = sizeof(XilinxAXIEnet), 1073999e12bbSAnthony Liguori .class_init = xilinx_enet_class_init, 1074b2d9dfe9SPeter Crosthwaite .instance_init = xilinx_enet_init, 107555b3e0c2SPeter Crosthwaite }; 107655b3e0c2SPeter Crosthwaite 107755b3e0c2SPeter Crosthwaite static const TypeInfo xilinx_enet_data_stream_info = { 107855b3e0c2SPeter Crosthwaite .name = TYPE_XILINX_AXI_ENET_DATA_STREAM, 107955b3e0c2SPeter Crosthwaite .parent = TYPE_OBJECT, 108055b3e0c2SPeter Crosthwaite .instance_size = sizeof(struct XilinxAXIEnetStreamSlave), 10810d9047c4SEdgar E. Iglesias .class_init = xilinx_enet_data_stream_class_init, 1082669b4983SPeter A. G. Crosthwaite .interfaces = (InterfaceInfo[]) { 1083669b4983SPeter A. G. Crosthwaite { TYPE_STREAM_SLAVE }, 1084669b4983SPeter A. G. Crosthwaite { } 1085669b4983SPeter A. G. Crosthwaite } 108693f1e401SEdgar E. Iglesias }; 108783f7d43aSAndreas Färber 108842bb9c91SPeter Crosthwaite static const TypeInfo xilinx_enet_control_stream_info = { 108942bb9c91SPeter Crosthwaite .name = TYPE_XILINX_AXI_ENET_CONTROL_STREAM, 109042bb9c91SPeter Crosthwaite .parent = TYPE_OBJECT, 109142bb9c91SPeter Crosthwaite .instance_size = sizeof(struct XilinxAXIEnetStreamSlave), 10920d9047c4SEdgar E. Iglesias .class_init = xilinx_enet_control_stream_class_init, 109342bb9c91SPeter Crosthwaite .interfaces = (InterfaceInfo[]) { 109442bb9c91SPeter Crosthwaite { TYPE_STREAM_SLAVE }, 109542bb9c91SPeter Crosthwaite { } 109642bb9c91SPeter Crosthwaite } 109742bb9c91SPeter Crosthwaite }; 109842bb9c91SPeter Crosthwaite 109983f7d43aSAndreas Färber static void xilinx_enet_register_types(void) 110093f1e401SEdgar E. Iglesias { 110139bffca2SAnthony Liguori type_register_static(&xilinx_enet_info); 110255b3e0c2SPeter Crosthwaite type_register_static(&xilinx_enet_data_stream_info); 110342bb9c91SPeter Crosthwaite type_register_static(&xilinx_enet_control_stream_info); 110493f1e401SEdgar E. Iglesias } 110593f1e401SEdgar E. Iglesias 110683f7d43aSAndreas Färber type_init(xilinx_enet_register_types) 1107