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 2583c9f4caSPaolo Bonzini #include "hw/sysbus.h" 261de7afc9SPaolo Bonzini #include "qemu/log.h" 271422e32dSPaolo Bonzini #include "net/net.h" 2893f1e401SEdgar E. Iglesias #include "net/checksum.h" 29b4a42f81SPaolo Bonzini #include "qapi/qmp/qerror.h" 3093f1e401SEdgar E. Iglesias 3183c9f4caSPaolo Bonzini #include "hw/stream.h" 3293f1e401SEdgar E. Iglesias 3393f1e401SEdgar E. Iglesias #define DPHY(x) 3493f1e401SEdgar E. Iglesias 35f0e7a81cSPeter Crosthwaite #define TYPE_XILINX_AXI_ENET "xlnx.axi-ethernet" 3655b3e0c2SPeter Crosthwaite #define TYPE_XILINX_AXI_ENET_DATA_STREAM "xilinx-axienet-data-stream" 3742bb9c91SPeter Crosthwaite #define TYPE_XILINX_AXI_ENET_CONTROL_STREAM "xilinx-axienet-control-stream" 38f0e7a81cSPeter Crosthwaite 39f0e7a81cSPeter Crosthwaite #define XILINX_AXI_ENET(obj) \ 40f0e7a81cSPeter Crosthwaite OBJECT_CHECK(XilinxAXIEnet, (obj), TYPE_XILINX_AXI_ENET) 41f0e7a81cSPeter Crosthwaite 4255b3e0c2SPeter Crosthwaite #define XILINX_AXI_ENET_DATA_STREAM(obj) \ 4355b3e0c2SPeter Crosthwaite OBJECT_CHECK(XilinxAXIEnetStreamSlave, (obj),\ 4455b3e0c2SPeter Crosthwaite TYPE_XILINX_AXI_ENET_DATA_STREAM) 4555b3e0c2SPeter Crosthwaite 4642bb9c91SPeter Crosthwaite #define XILINX_AXI_ENET_CONTROL_STREAM(obj) \ 4742bb9c91SPeter Crosthwaite OBJECT_CHECK(XilinxAXIEnetStreamSlave, (obj),\ 4842bb9c91SPeter Crosthwaite TYPE_XILINX_AXI_ENET_CONTROL_STREAM) 4942bb9c91SPeter Crosthwaite 5093f1e401SEdgar E. Iglesias /* Advertisement control register. */ 5193f1e401SEdgar E. Iglesias #define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ 5293f1e401SEdgar E. Iglesias #define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ 5393f1e401SEdgar E. Iglesias #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ 5493f1e401SEdgar E. Iglesias #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ 5593f1e401SEdgar E. Iglesias 5642bb9c91SPeter Crosthwaite #define CONTROL_PAYLOAD_WORDS 5 5742bb9c91SPeter Crosthwaite #define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t))) 5842bb9c91SPeter Crosthwaite 5993f1e401SEdgar E. Iglesias struct PHY { 6093f1e401SEdgar E. Iglesias uint32_t regs[32]; 6193f1e401SEdgar E. Iglesias 6293f1e401SEdgar E. Iglesias int link; 6393f1e401SEdgar E. Iglesias 6493f1e401SEdgar E. Iglesias unsigned int (*read)(struct PHY *phy, unsigned int req); 6593f1e401SEdgar E. Iglesias void (*write)(struct PHY *phy, unsigned int req, 6693f1e401SEdgar E. Iglesias unsigned int data); 6793f1e401SEdgar E. Iglesias }; 6893f1e401SEdgar E. Iglesias 6993f1e401SEdgar E. Iglesias static unsigned int tdk_read(struct PHY *phy, unsigned int req) 7093f1e401SEdgar E. Iglesias { 7193f1e401SEdgar E. Iglesias int regnum; 7293f1e401SEdgar E. Iglesias unsigned r = 0; 7393f1e401SEdgar E. Iglesias 7493f1e401SEdgar E. Iglesias regnum = req & 0x1f; 7593f1e401SEdgar E. Iglesias 7693f1e401SEdgar E. Iglesias switch (regnum) { 7793f1e401SEdgar E. Iglesias case 1: 7893f1e401SEdgar E. Iglesias if (!phy->link) { 7993f1e401SEdgar E. Iglesias break; 8093f1e401SEdgar E. Iglesias } 8193f1e401SEdgar E. Iglesias /* MR1. */ 8293f1e401SEdgar E. Iglesias /* Speeds and modes. */ 8393f1e401SEdgar E. Iglesias r |= (1 << 13) | (1 << 14); 8493f1e401SEdgar E. Iglesias r |= (1 << 11) | (1 << 12); 8593f1e401SEdgar E. Iglesias r |= (1 << 5); /* Autoneg complete. */ 8693f1e401SEdgar E. Iglesias r |= (1 << 3); /* Autoneg able. */ 8793f1e401SEdgar E. Iglesias r |= (1 << 2); /* link. */ 8893f1e401SEdgar E. Iglesias r |= (1 << 1); /* link. */ 8993f1e401SEdgar E. Iglesias break; 9093f1e401SEdgar E. Iglesias case 5: 9193f1e401SEdgar E. Iglesias /* Link partner ability. 9293f1e401SEdgar E. Iglesias We are kind; always agree with whatever best mode 9393f1e401SEdgar E. Iglesias the guest advertises. */ 9493f1e401SEdgar E. Iglesias r = 1 << 14; /* Success. */ 9593f1e401SEdgar E. Iglesias /* Copy advertised modes. */ 9693f1e401SEdgar E. Iglesias r |= phy->regs[4] & (15 << 5); 9793f1e401SEdgar E. Iglesias /* Autoneg support. */ 9893f1e401SEdgar E. Iglesias r |= 1; 9993f1e401SEdgar E. Iglesias break; 10093f1e401SEdgar E. Iglesias case 17: 10193f1e401SEdgar E. Iglesias /* Marvel PHY on many xilinx boards. */ 10293f1e401SEdgar E. Iglesias r = 0x8000; /* 1000Mb */ 10393f1e401SEdgar E. Iglesias break; 10493f1e401SEdgar E. Iglesias case 18: 10593f1e401SEdgar E. Iglesias { 10693f1e401SEdgar E. Iglesias /* Diagnostics reg. */ 10793f1e401SEdgar E. Iglesias int duplex = 0; 10893f1e401SEdgar E. Iglesias int speed_100 = 0; 10993f1e401SEdgar E. Iglesias 11093f1e401SEdgar E. Iglesias if (!phy->link) { 11193f1e401SEdgar E. Iglesias break; 11293f1e401SEdgar E. Iglesias } 11393f1e401SEdgar E. Iglesias 11493f1e401SEdgar E. Iglesias /* Are we advertising 100 half or 100 duplex ? */ 11593f1e401SEdgar E. Iglesias speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); 11693f1e401SEdgar E. Iglesias speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); 11793f1e401SEdgar E. Iglesias 11893f1e401SEdgar E. Iglesias /* Are we advertising 10 duplex or 100 duplex ? */ 11993f1e401SEdgar E. Iglesias duplex = !!(phy->regs[4] & ADVERTISE_100FULL); 12093f1e401SEdgar E. Iglesias duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); 12193f1e401SEdgar E. Iglesias r = (speed_100 << 10) | (duplex << 11); 12293f1e401SEdgar E. Iglesias } 12393f1e401SEdgar E. Iglesias break; 12493f1e401SEdgar E. Iglesias 12593f1e401SEdgar E. Iglesias default: 12693f1e401SEdgar E. Iglesias r = phy->regs[regnum]; 12793f1e401SEdgar E. Iglesias break; 12893f1e401SEdgar E. Iglesias } 12993f1e401SEdgar E. Iglesias DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum)); 13093f1e401SEdgar E. Iglesias return r; 13193f1e401SEdgar E. Iglesias } 13293f1e401SEdgar E. Iglesias 13393f1e401SEdgar E. Iglesias static void 13493f1e401SEdgar E. Iglesias tdk_write(struct PHY *phy, unsigned int req, unsigned int data) 13593f1e401SEdgar E. Iglesias { 13693f1e401SEdgar E. Iglesias int regnum; 13793f1e401SEdgar E. Iglesias 13893f1e401SEdgar E. Iglesias regnum = req & 0x1f; 13993f1e401SEdgar E. Iglesias DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data)); 14093f1e401SEdgar E. Iglesias switch (regnum) { 14193f1e401SEdgar E. Iglesias default: 14293f1e401SEdgar E. Iglesias phy->regs[regnum] = data; 14393f1e401SEdgar E. Iglesias break; 14493f1e401SEdgar E. Iglesias } 145*f663faacSNathan Rossi 146*f663faacSNathan Rossi /* Unconditionally clear regs[BMCR][BMCR_RESET] */ 147*f663faacSNathan Rossi phy->regs[0] &= ~0x8000; 14893f1e401SEdgar E. Iglesias } 14993f1e401SEdgar E. Iglesias 15093f1e401SEdgar E. Iglesias static void 15193f1e401SEdgar E. Iglesias tdk_init(struct PHY *phy) 15293f1e401SEdgar E. Iglesias { 15393f1e401SEdgar E. Iglesias phy->regs[0] = 0x3100; 15493f1e401SEdgar E. Iglesias /* PHY Id. */ 15593f1e401SEdgar E. Iglesias phy->regs[2] = 0x0300; 15693f1e401SEdgar E. Iglesias phy->regs[3] = 0xe400; 15793f1e401SEdgar E. Iglesias /* Autonegotiation advertisement reg. */ 15893f1e401SEdgar E. Iglesias phy->regs[4] = 0x01E1; 15993f1e401SEdgar E. Iglesias phy->link = 1; 16093f1e401SEdgar E. Iglesias 16193f1e401SEdgar E. Iglesias phy->read = tdk_read; 16293f1e401SEdgar E. Iglesias phy->write = tdk_write; 16393f1e401SEdgar E. Iglesias } 16493f1e401SEdgar E. Iglesias 16593f1e401SEdgar E. Iglesias struct MDIOBus { 16693f1e401SEdgar E. Iglesias /* bus. */ 16793f1e401SEdgar E. Iglesias int mdc; 16893f1e401SEdgar E. Iglesias int mdio; 16993f1e401SEdgar E. Iglesias 17093f1e401SEdgar E. Iglesias /* decoder. */ 17193f1e401SEdgar E. Iglesias enum { 17293f1e401SEdgar E. Iglesias PREAMBLE, 17393f1e401SEdgar E. Iglesias SOF, 17493f1e401SEdgar E. Iglesias OPC, 17593f1e401SEdgar E. Iglesias ADDR, 17693f1e401SEdgar E. Iglesias REQ, 17793f1e401SEdgar E. Iglesias TURNAROUND, 17893f1e401SEdgar E. Iglesias DATA 17993f1e401SEdgar E. Iglesias } state; 18093f1e401SEdgar E. Iglesias unsigned int drive; 18193f1e401SEdgar E. Iglesias 18293f1e401SEdgar E. Iglesias unsigned int cnt; 18393f1e401SEdgar E. Iglesias unsigned int addr; 18493f1e401SEdgar E. Iglesias unsigned int opc; 18593f1e401SEdgar E. Iglesias unsigned int req; 18693f1e401SEdgar E. Iglesias unsigned int data; 18793f1e401SEdgar E. Iglesias 18893f1e401SEdgar E. Iglesias struct PHY *devs[32]; 18993f1e401SEdgar E. Iglesias }; 19093f1e401SEdgar E. Iglesias 19193f1e401SEdgar E. Iglesias static void 19293f1e401SEdgar E. Iglesias mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr) 19393f1e401SEdgar E. Iglesias { 19493f1e401SEdgar E. Iglesias bus->devs[addr & 0x1f] = phy; 19593f1e401SEdgar E. Iglesias } 19693f1e401SEdgar E. Iglesias 19793f1e401SEdgar E. Iglesias #ifdef USE_THIS_DEAD_CODE 19893f1e401SEdgar E. Iglesias static void 19993f1e401SEdgar E. Iglesias mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr) 20093f1e401SEdgar E. Iglesias { 20193f1e401SEdgar E. Iglesias bus->devs[addr & 0x1f] = NULL; 20293f1e401SEdgar E. Iglesias } 20393f1e401SEdgar E. Iglesias #endif 20493f1e401SEdgar E. Iglesias 20593f1e401SEdgar E. Iglesias static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr, 20693f1e401SEdgar E. Iglesias unsigned int reg) 20793f1e401SEdgar E. Iglesias { 20893f1e401SEdgar E. Iglesias struct PHY *phy; 20993f1e401SEdgar E. Iglesias uint16_t data; 21093f1e401SEdgar E. Iglesias 21193f1e401SEdgar E. Iglesias phy = bus->devs[addr]; 21293f1e401SEdgar E. Iglesias if (phy && phy->read) { 21393f1e401SEdgar E. Iglesias data = phy->read(phy, reg); 21493f1e401SEdgar E. Iglesias } else { 21593f1e401SEdgar E. Iglesias data = 0xffff; 21693f1e401SEdgar E. Iglesias } 21793f1e401SEdgar E. Iglesias DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data)); 21893f1e401SEdgar E. Iglesias return data; 21993f1e401SEdgar E. Iglesias } 22093f1e401SEdgar E. Iglesias 22193f1e401SEdgar E. Iglesias static void mdio_write_req(struct MDIOBus *bus, unsigned int addr, 22293f1e401SEdgar E. Iglesias unsigned int reg, uint16_t data) 22393f1e401SEdgar E. Iglesias { 22493f1e401SEdgar E. Iglesias struct PHY *phy; 22593f1e401SEdgar E. Iglesias 22693f1e401SEdgar E. Iglesias DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data)); 22793f1e401SEdgar E. Iglesias phy = bus->devs[addr]; 22893f1e401SEdgar E. Iglesias if (phy && phy->write) { 22993f1e401SEdgar E. Iglesias phy->write(phy, reg, data); 23093f1e401SEdgar E. Iglesias } 23193f1e401SEdgar E. Iglesias } 23293f1e401SEdgar E. Iglesias 23393f1e401SEdgar E. Iglesias #define DENET(x) 23493f1e401SEdgar E. Iglesias 23593f1e401SEdgar E. Iglesias #define R_RAF (0x000 / 4) 23693f1e401SEdgar E. Iglesias enum { 23793f1e401SEdgar E. Iglesias RAF_MCAST_REJ = (1 << 1), 23893f1e401SEdgar E. Iglesias RAF_BCAST_REJ = (1 << 2), 23993f1e401SEdgar E. Iglesias RAF_EMCF_EN = (1 << 12), 24093f1e401SEdgar E. Iglesias RAF_NEWFUNC_EN = (1 << 11) 24193f1e401SEdgar E. Iglesias }; 24293f1e401SEdgar E. Iglesias 24393f1e401SEdgar E. Iglesias #define R_IS (0x00C / 4) 24493f1e401SEdgar E. Iglesias enum { 24593f1e401SEdgar E. Iglesias IS_HARD_ACCESS_COMPLETE = 1, 24693f1e401SEdgar E. Iglesias IS_AUTONEG = (1 << 1), 24793f1e401SEdgar E. Iglesias IS_RX_COMPLETE = (1 << 2), 24893f1e401SEdgar E. Iglesias IS_RX_REJECT = (1 << 3), 24993f1e401SEdgar E. Iglesias IS_TX_COMPLETE = (1 << 5), 25093f1e401SEdgar E. Iglesias IS_RX_DCM_LOCK = (1 << 6), 25193f1e401SEdgar E. Iglesias IS_MGM_RDY = (1 << 7), 25293f1e401SEdgar E. Iglesias IS_PHY_RST_DONE = (1 << 8), 25393f1e401SEdgar E. Iglesias }; 25493f1e401SEdgar E. Iglesias 25593f1e401SEdgar E. Iglesias #define R_IP (0x010 / 4) 25693f1e401SEdgar E. Iglesias #define R_IE (0x014 / 4) 25793f1e401SEdgar E. Iglesias #define R_UAWL (0x020 / 4) 25893f1e401SEdgar E. Iglesias #define R_UAWU (0x024 / 4) 25993f1e401SEdgar E. Iglesias #define R_PPST (0x030 / 4) 26093f1e401SEdgar E. Iglesias enum { 26193f1e401SEdgar E. Iglesias PPST_LINKSTATUS = (1 << 0), 26293f1e401SEdgar E. Iglesias PPST_PHY_LINKSTATUS = (1 << 7), 26393f1e401SEdgar E. Iglesias }; 26493f1e401SEdgar E. Iglesias 26593f1e401SEdgar E. Iglesias #define R_STATS_RX_BYTESL (0x200 / 4) 26693f1e401SEdgar E. Iglesias #define R_STATS_RX_BYTESH (0x204 / 4) 26793f1e401SEdgar E. Iglesias #define R_STATS_TX_BYTESL (0x208 / 4) 26893f1e401SEdgar E. Iglesias #define R_STATS_TX_BYTESH (0x20C / 4) 26993f1e401SEdgar E. Iglesias #define R_STATS_RXL (0x290 / 4) 27093f1e401SEdgar E. Iglesias #define R_STATS_RXH (0x294 / 4) 27193f1e401SEdgar E. Iglesias #define R_STATS_RX_BCASTL (0x2a0 / 4) 27293f1e401SEdgar E. Iglesias #define R_STATS_RX_BCASTH (0x2a4 / 4) 27393f1e401SEdgar E. Iglesias #define R_STATS_RX_MCASTL (0x2a8 / 4) 27493f1e401SEdgar E. Iglesias #define R_STATS_RX_MCASTH (0x2ac / 4) 27593f1e401SEdgar E. Iglesias 27693f1e401SEdgar E. Iglesias #define R_RCW0 (0x400 / 4) 27793f1e401SEdgar E. Iglesias #define R_RCW1 (0x404 / 4) 27893f1e401SEdgar E. Iglesias enum { 27993f1e401SEdgar E. Iglesias RCW1_VLAN = (1 << 27), 28093f1e401SEdgar E. Iglesias RCW1_RX = (1 << 28), 28193f1e401SEdgar E. Iglesias RCW1_FCS = (1 << 29), 28293f1e401SEdgar E. Iglesias RCW1_JUM = (1 << 30), 28393f1e401SEdgar E. Iglesias RCW1_RST = (1 << 31), 28493f1e401SEdgar E. Iglesias }; 28593f1e401SEdgar E. Iglesias 28693f1e401SEdgar E. Iglesias #define R_TC (0x408 / 4) 28793f1e401SEdgar E. Iglesias enum { 28893f1e401SEdgar E. Iglesias TC_VLAN = (1 << 27), 28993f1e401SEdgar E. Iglesias TC_TX = (1 << 28), 29093f1e401SEdgar E. Iglesias TC_FCS = (1 << 29), 29193f1e401SEdgar E. Iglesias TC_JUM = (1 << 30), 29293f1e401SEdgar E. Iglesias TC_RST = (1 << 31), 29393f1e401SEdgar E. Iglesias }; 29493f1e401SEdgar E. Iglesias 29593f1e401SEdgar E. Iglesias #define R_EMMC (0x410 / 4) 29693f1e401SEdgar E. Iglesias enum { 29793f1e401SEdgar E. Iglesias EMMC_LINKSPEED_10MB = (0 << 30), 29893f1e401SEdgar E. Iglesias EMMC_LINKSPEED_100MB = (1 << 30), 29993f1e401SEdgar E. Iglesias EMMC_LINKSPEED_1000MB = (2 << 30), 30093f1e401SEdgar E. Iglesias }; 30193f1e401SEdgar E. Iglesias 30293f1e401SEdgar E. Iglesias #define R_PHYC (0x414 / 4) 30393f1e401SEdgar E. Iglesias 30493f1e401SEdgar E. Iglesias #define R_MC (0x500 / 4) 30593f1e401SEdgar E. Iglesias #define MC_EN (1 << 6) 30693f1e401SEdgar E. Iglesias 30793f1e401SEdgar E. Iglesias #define R_MCR (0x504 / 4) 30893f1e401SEdgar E. Iglesias #define R_MWD (0x508 / 4) 30993f1e401SEdgar E. Iglesias #define R_MRD (0x50c / 4) 31093f1e401SEdgar E. Iglesias #define R_MIS (0x600 / 4) 31193f1e401SEdgar E. Iglesias #define R_MIP (0x620 / 4) 31293f1e401SEdgar E. Iglesias #define R_MIE (0x640 / 4) 31393f1e401SEdgar E. Iglesias #define R_MIC (0x640 / 4) 31493f1e401SEdgar E. Iglesias 31593f1e401SEdgar E. Iglesias #define R_UAW0 (0x700 / 4) 31693f1e401SEdgar E. Iglesias #define R_UAW1 (0x704 / 4) 31793f1e401SEdgar E. Iglesias #define R_FMI (0x708 / 4) 31893f1e401SEdgar E. Iglesias #define R_AF0 (0x710 / 4) 31993f1e401SEdgar E. Iglesias #define R_AF1 (0x714 / 4) 32093f1e401SEdgar E. Iglesias #define R_MAX (0x34 / 4) 32193f1e401SEdgar E. Iglesias 32293f1e401SEdgar E. Iglesias /* Indirect registers. */ 32393f1e401SEdgar E. Iglesias struct TEMAC { 32493f1e401SEdgar E. Iglesias struct MDIOBus mdio_bus; 32593f1e401SEdgar E. Iglesias struct PHY phy; 32693f1e401SEdgar E. Iglesias 32793f1e401SEdgar E. Iglesias void *parent; 32893f1e401SEdgar E. Iglesias }; 32993f1e401SEdgar E. Iglesias 33055b3e0c2SPeter Crosthwaite typedef struct XilinxAXIEnetStreamSlave XilinxAXIEnetStreamSlave; 331545129e5SPeter Crosthwaite typedef struct XilinxAXIEnet XilinxAXIEnet; 332545129e5SPeter Crosthwaite 33355b3e0c2SPeter Crosthwaite struct XilinxAXIEnetStreamSlave { 33455b3e0c2SPeter Crosthwaite Object parent; 33555b3e0c2SPeter Crosthwaite 33655b3e0c2SPeter Crosthwaite struct XilinxAXIEnet *enet; 33755b3e0c2SPeter Crosthwaite } ; 33855b3e0c2SPeter Crosthwaite 33993f1e401SEdgar E. Iglesias struct XilinxAXIEnet { 34093f1e401SEdgar E. Iglesias SysBusDevice busdev; 3410dc31f3bSAvi Kivity MemoryRegion iomem; 34293f1e401SEdgar E. Iglesias qemu_irq irq; 34342bb9c91SPeter Crosthwaite StreamSlave *tx_data_dev; 34442bb9c91SPeter Crosthwaite StreamSlave *tx_control_dev; 34555b3e0c2SPeter Crosthwaite XilinxAXIEnetStreamSlave rx_data_dev; 34642bb9c91SPeter Crosthwaite XilinxAXIEnetStreamSlave rx_control_dev; 34793f1e401SEdgar E. Iglesias NICState *nic; 34893f1e401SEdgar E. Iglesias NICConf conf; 34993f1e401SEdgar E. Iglesias 35093f1e401SEdgar E. Iglesias 35193f1e401SEdgar E. Iglesias uint32_t c_rxmem; 35293f1e401SEdgar E. Iglesias uint32_t c_txmem; 35393f1e401SEdgar E. Iglesias uint32_t c_phyaddr; 35493f1e401SEdgar E. Iglesias 35593f1e401SEdgar E. Iglesias struct TEMAC TEMAC; 35693f1e401SEdgar E. Iglesias 35793f1e401SEdgar E. Iglesias /* MII regs. */ 35893f1e401SEdgar E. Iglesias union { 35993f1e401SEdgar E. Iglesias uint32_t regs[4]; 36093f1e401SEdgar E. Iglesias struct { 36193f1e401SEdgar E. Iglesias uint32_t mc; 36293f1e401SEdgar E. Iglesias uint32_t mcr; 36393f1e401SEdgar E. Iglesias uint32_t mwd; 36493f1e401SEdgar E. Iglesias uint32_t mrd; 36593f1e401SEdgar E. Iglesias }; 36693f1e401SEdgar E. Iglesias } mii; 36793f1e401SEdgar E. Iglesias 36893f1e401SEdgar E. Iglesias struct { 36993f1e401SEdgar E. Iglesias uint64_t rx_bytes; 37093f1e401SEdgar E. Iglesias uint64_t tx_bytes; 37193f1e401SEdgar E. Iglesias 37293f1e401SEdgar E. Iglesias uint64_t rx; 37393f1e401SEdgar E. Iglesias uint64_t rx_bcast; 37493f1e401SEdgar E. Iglesias uint64_t rx_mcast; 37593f1e401SEdgar E. Iglesias } stats; 37693f1e401SEdgar E. Iglesias 37793f1e401SEdgar E. Iglesias /* Receive configuration words. */ 37893f1e401SEdgar E. Iglesias uint32_t rcw[2]; 37993f1e401SEdgar E. Iglesias /* Transmit config. */ 38093f1e401SEdgar E. Iglesias uint32_t tc; 38193f1e401SEdgar E. Iglesias uint32_t emmc; 38293f1e401SEdgar E. Iglesias uint32_t phyc; 38393f1e401SEdgar E. Iglesias 38493f1e401SEdgar E. Iglesias /* Unicast Address Word. */ 38593f1e401SEdgar E. Iglesias uint32_t uaw[2]; 38693f1e401SEdgar E. Iglesias /* Unicast address filter used with extended mcast. */ 38793f1e401SEdgar E. Iglesias uint32_t ext_uaw[2]; 38893f1e401SEdgar E. Iglesias uint32_t fmi; 38993f1e401SEdgar E. Iglesias 39093f1e401SEdgar E. Iglesias uint32_t regs[R_MAX]; 39193f1e401SEdgar E. Iglesias 39293f1e401SEdgar E. Iglesias /* Multicast filter addrs. */ 39393f1e401SEdgar E. Iglesias uint32_t maddr[4][2]; 39493f1e401SEdgar E. Iglesias /* 32K x 1 lookup filter. */ 39593f1e401SEdgar E. Iglesias uint32_t ext_mtable[1024]; 39693f1e401SEdgar E. Iglesias 39742bb9c91SPeter Crosthwaite uint32_t hdr[CONTROL_PAYLOAD_WORDS]; 39893f1e401SEdgar E. Iglesias 39993f1e401SEdgar E. Iglesias uint8_t *rxmem; 4003630ae95SPeter Crosthwaite uint32_t rxsize; 4013630ae95SPeter Crosthwaite uint32_t rxpos; 40242bb9c91SPeter Crosthwaite 40342bb9c91SPeter Crosthwaite uint8_t rxapp[CONTROL_PAYLOAD_SIZE]; 40442bb9c91SPeter Crosthwaite uint32_t rxappsize; 40593f1e401SEdgar E. Iglesias }; 40693f1e401SEdgar E. Iglesias 407545129e5SPeter Crosthwaite static void axienet_rx_reset(XilinxAXIEnet *s) 40893f1e401SEdgar E. Iglesias { 40993f1e401SEdgar E. Iglesias s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN; 41093f1e401SEdgar E. Iglesias } 41193f1e401SEdgar E. Iglesias 412545129e5SPeter Crosthwaite static void axienet_tx_reset(XilinxAXIEnet *s) 41393f1e401SEdgar E. Iglesias { 41493f1e401SEdgar E. Iglesias s->tc = TC_JUM | TC_TX | TC_VLAN; 41593f1e401SEdgar E. Iglesias } 41693f1e401SEdgar E. Iglesias 417545129e5SPeter Crosthwaite static inline int axienet_rx_resetting(XilinxAXIEnet *s) 41893f1e401SEdgar E. Iglesias { 41993f1e401SEdgar E. Iglesias return s->rcw[1] & RCW1_RST; 42093f1e401SEdgar E. Iglesias } 42193f1e401SEdgar E. Iglesias 422545129e5SPeter Crosthwaite static inline int axienet_rx_enabled(XilinxAXIEnet *s) 42393f1e401SEdgar E. Iglesias { 42493f1e401SEdgar E. Iglesias return s->rcw[1] & RCW1_RX; 42593f1e401SEdgar E. Iglesias } 42693f1e401SEdgar E. Iglesias 427545129e5SPeter Crosthwaite static inline int axienet_extmcf_enabled(XilinxAXIEnet *s) 42893f1e401SEdgar E. Iglesias { 42993f1e401SEdgar E. Iglesias return !!(s->regs[R_RAF] & RAF_EMCF_EN); 43093f1e401SEdgar E. Iglesias } 43193f1e401SEdgar E. Iglesias 432545129e5SPeter Crosthwaite static inline int axienet_newfunc_enabled(XilinxAXIEnet *s) 43393f1e401SEdgar E. Iglesias { 43493f1e401SEdgar E. Iglesias return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN); 43593f1e401SEdgar E. Iglesias } 43693f1e401SEdgar E. Iglesias 4379ee0ceb7SPeter Crosthwaite static void xilinx_axienet_reset(DeviceState *d) 43893f1e401SEdgar E. Iglesias { 4399ee0ceb7SPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(d); 4409ee0ceb7SPeter Crosthwaite 44193f1e401SEdgar E. Iglesias axienet_rx_reset(s); 44293f1e401SEdgar E. Iglesias axienet_tx_reset(s); 44393f1e401SEdgar E. Iglesias 44493f1e401SEdgar E. Iglesias s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS; 44593f1e401SEdgar E. Iglesias s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE; 44693f1e401SEdgar E. Iglesias 44793f1e401SEdgar E. Iglesias s->emmc = EMMC_LINKSPEED_100MB; 44893f1e401SEdgar E. Iglesias } 44993f1e401SEdgar E. Iglesias 450545129e5SPeter Crosthwaite static void enet_update_irq(XilinxAXIEnet *s) 45193f1e401SEdgar E. Iglesias { 45293f1e401SEdgar E. Iglesias s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE]; 45393f1e401SEdgar E. Iglesias qemu_set_irq(s->irq, !!s->regs[R_IP]); 45493f1e401SEdgar E. Iglesias } 45593f1e401SEdgar E. Iglesias 456a8170e5eSAvi Kivity static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size) 45793f1e401SEdgar E. Iglesias { 458545129e5SPeter Crosthwaite XilinxAXIEnet *s = opaque; 45993f1e401SEdgar E. Iglesias uint32_t r = 0; 46093f1e401SEdgar E. Iglesias addr >>= 2; 46193f1e401SEdgar E. Iglesias 46293f1e401SEdgar E. Iglesias switch (addr) { 46393f1e401SEdgar E. Iglesias case R_RCW0: 46493f1e401SEdgar E. Iglesias case R_RCW1: 46593f1e401SEdgar E. Iglesias r = s->rcw[addr & 1]; 46693f1e401SEdgar E. Iglesias break; 46793f1e401SEdgar E. Iglesias 46893f1e401SEdgar E. Iglesias case R_TC: 46993f1e401SEdgar E. Iglesias r = s->tc; 47093f1e401SEdgar E. Iglesias break; 47193f1e401SEdgar E. Iglesias 47293f1e401SEdgar E. Iglesias case R_EMMC: 47393f1e401SEdgar E. Iglesias r = s->emmc; 47493f1e401SEdgar E. Iglesias break; 47593f1e401SEdgar E. Iglesias 47693f1e401SEdgar E. Iglesias case R_PHYC: 47793f1e401SEdgar E. Iglesias r = s->phyc; 47893f1e401SEdgar E. Iglesias break; 47993f1e401SEdgar E. Iglesias 48093f1e401SEdgar E. Iglesias case R_MCR: 48193f1e401SEdgar E. Iglesias r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready. */ 48293f1e401SEdgar E. Iglesias break; 48393f1e401SEdgar E. Iglesias 48493f1e401SEdgar E. Iglesias case R_STATS_RX_BYTESL: 48593f1e401SEdgar E. Iglesias case R_STATS_RX_BYTESH: 48693f1e401SEdgar E. Iglesias r = s->stats.rx_bytes >> (32 * (addr & 1)); 48793f1e401SEdgar E. Iglesias break; 48893f1e401SEdgar E. Iglesias 48993f1e401SEdgar E. Iglesias case R_STATS_TX_BYTESL: 49093f1e401SEdgar E. Iglesias case R_STATS_TX_BYTESH: 49193f1e401SEdgar E. Iglesias r = s->stats.tx_bytes >> (32 * (addr & 1)); 49293f1e401SEdgar E. Iglesias break; 49393f1e401SEdgar E. Iglesias 49493f1e401SEdgar E. Iglesias case R_STATS_RXL: 49593f1e401SEdgar E. Iglesias case R_STATS_RXH: 49693f1e401SEdgar E. Iglesias r = s->stats.rx >> (32 * (addr & 1)); 49793f1e401SEdgar E. Iglesias break; 49893f1e401SEdgar E. Iglesias case R_STATS_RX_BCASTL: 49993f1e401SEdgar E. Iglesias case R_STATS_RX_BCASTH: 50093f1e401SEdgar E. Iglesias r = s->stats.rx_bcast >> (32 * (addr & 1)); 50193f1e401SEdgar E. Iglesias break; 50293f1e401SEdgar E. Iglesias case R_STATS_RX_MCASTL: 50393f1e401SEdgar E. Iglesias case R_STATS_RX_MCASTH: 50493f1e401SEdgar E. Iglesias r = s->stats.rx_mcast >> (32 * (addr & 1)); 50593f1e401SEdgar E. Iglesias break; 50693f1e401SEdgar E. Iglesias 50793f1e401SEdgar E. Iglesias case R_MC: 50893f1e401SEdgar E. Iglesias case R_MWD: 50993f1e401SEdgar E. Iglesias case R_MRD: 51093f1e401SEdgar E. Iglesias r = s->mii.regs[addr & 3]; 51193f1e401SEdgar E. Iglesias break; 51293f1e401SEdgar E. Iglesias 51393f1e401SEdgar E. Iglesias case R_UAW0: 51493f1e401SEdgar E. Iglesias case R_UAW1: 51593f1e401SEdgar E. Iglesias r = s->uaw[addr & 1]; 51693f1e401SEdgar E. Iglesias break; 51793f1e401SEdgar E. Iglesias 51893f1e401SEdgar E. Iglesias case R_UAWU: 51993f1e401SEdgar E. Iglesias case R_UAWL: 52093f1e401SEdgar E. Iglesias r = s->ext_uaw[addr & 1]; 52193f1e401SEdgar E. Iglesias break; 52293f1e401SEdgar E. Iglesias 52393f1e401SEdgar E. Iglesias case R_FMI: 52493f1e401SEdgar E. Iglesias r = s->fmi; 52593f1e401SEdgar E. Iglesias break; 52693f1e401SEdgar E. Iglesias 52793f1e401SEdgar E. Iglesias case R_AF0: 52893f1e401SEdgar E. Iglesias case R_AF1: 52993f1e401SEdgar E. Iglesias r = s->maddr[s->fmi & 3][addr & 1]; 53093f1e401SEdgar E. Iglesias break; 53193f1e401SEdgar E. Iglesias 53293f1e401SEdgar E. Iglesias case 0x8000 ... 0x83ff: 53393f1e401SEdgar E. Iglesias r = s->ext_mtable[addr - 0x8000]; 53493f1e401SEdgar E. Iglesias break; 53593f1e401SEdgar E. Iglesias 53693f1e401SEdgar E. Iglesias default: 53793f1e401SEdgar E. Iglesias if (addr < ARRAY_SIZE(s->regs)) { 53893f1e401SEdgar E. Iglesias r = s->regs[addr]; 53993f1e401SEdgar E. Iglesias } 54093f1e401SEdgar E. Iglesias DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n", 54193f1e401SEdgar E. Iglesias __func__, addr * 4, r)); 54293f1e401SEdgar E. Iglesias break; 54393f1e401SEdgar E. Iglesias } 54493f1e401SEdgar E. Iglesias return r; 54593f1e401SEdgar E. Iglesias } 54693f1e401SEdgar E. Iglesias 547a8170e5eSAvi Kivity static void enet_write(void *opaque, hwaddr addr, 5480dc31f3bSAvi Kivity uint64_t value, unsigned size) 54993f1e401SEdgar E. Iglesias { 550545129e5SPeter Crosthwaite XilinxAXIEnet *s = opaque; 55193f1e401SEdgar E. Iglesias struct TEMAC *t = &s->TEMAC; 55293f1e401SEdgar E. Iglesias 55393f1e401SEdgar E. Iglesias addr >>= 2; 55493f1e401SEdgar E. Iglesias switch (addr) { 55593f1e401SEdgar E. Iglesias case R_RCW0: 55693f1e401SEdgar E. Iglesias case R_RCW1: 55793f1e401SEdgar E. Iglesias s->rcw[addr & 1] = value; 55893f1e401SEdgar E. Iglesias if ((addr & 1) && value & RCW1_RST) { 55993f1e401SEdgar E. Iglesias axienet_rx_reset(s); 5604dbb9ed3SPeter Crosthwaite } else { 5614dbb9ed3SPeter Crosthwaite qemu_flush_queued_packets(qemu_get_queue(s->nic)); 56293f1e401SEdgar E. Iglesias } 56393f1e401SEdgar E. Iglesias break; 56493f1e401SEdgar E. Iglesias 56593f1e401SEdgar E. Iglesias case R_TC: 56693f1e401SEdgar E. Iglesias s->tc = value; 56793f1e401SEdgar E. Iglesias if (value & TC_RST) { 56893f1e401SEdgar E. Iglesias axienet_tx_reset(s); 56993f1e401SEdgar E. Iglesias } 57093f1e401SEdgar E. Iglesias break; 57193f1e401SEdgar E. Iglesias 57293f1e401SEdgar E. Iglesias case R_EMMC: 57393f1e401SEdgar E. Iglesias s->emmc = value; 57493f1e401SEdgar E. Iglesias break; 57593f1e401SEdgar E. Iglesias 57693f1e401SEdgar E. Iglesias case R_PHYC: 57793f1e401SEdgar E. Iglesias s->phyc = value; 57893f1e401SEdgar E. Iglesias break; 57993f1e401SEdgar E. Iglesias 58093f1e401SEdgar E. Iglesias case R_MC: 5814e298e46SStefan Weil value &= ((1 << 7) - 1); 58293f1e401SEdgar E. Iglesias 58393f1e401SEdgar E. Iglesias /* Enable the MII. */ 58493f1e401SEdgar E. Iglesias if (value & MC_EN) { 58593f1e401SEdgar E. Iglesias unsigned int miiclkdiv = value & ((1 << 6) - 1); 58693f1e401SEdgar E. Iglesias if (!miiclkdiv) { 58793f1e401SEdgar E. Iglesias qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n"); 58893f1e401SEdgar E. Iglesias } 58993f1e401SEdgar E. Iglesias } 59093f1e401SEdgar E. Iglesias s->mii.mc = value; 59193f1e401SEdgar E. Iglesias break; 59293f1e401SEdgar E. Iglesias 59393f1e401SEdgar E. Iglesias case R_MCR: { 59493f1e401SEdgar E. Iglesias unsigned int phyaddr = (value >> 24) & 0x1f; 59593f1e401SEdgar E. Iglesias unsigned int regaddr = (value >> 16) & 0x1f; 59693f1e401SEdgar E. Iglesias unsigned int op = (value >> 14) & 3; 59793f1e401SEdgar E. Iglesias unsigned int initiate = (value >> 11) & 1; 59893f1e401SEdgar E. Iglesias 59993f1e401SEdgar E. Iglesias if (initiate) { 60093f1e401SEdgar E. Iglesias if (op == 1) { 60193f1e401SEdgar E. Iglesias mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd); 60293f1e401SEdgar E. Iglesias } else if (op == 2) { 60393f1e401SEdgar E. Iglesias s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr); 60493f1e401SEdgar E. Iglesias } else { 60593f1e401SEdgar E. Iglesias qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op); 60693f1e401SEdgar E. Iglesias } 60793f1e401SEdgar E. Iglesias } 60893f1e401SEdgar E. Iglesias s->mii.mcr = value; 60993f1e401SEdgar E. Iglesias break; 61093f1e401SEdgar E. Iglesias } 61193f1e401SEdgar E. Iglesias 61293f1e401SEdgar E. Iglesias case R_MWD: 61393f1e401SEdgar E. Iglesias case R_MRD: 61493f1e401SEdgar E. Iglesias s->mii.regs[addr & 3] = value; 61593f1e401SEdgar E. Iglesias break; 61693f1e401SEdgar E. Iglesias 61793f1e401SEdgar E. Iglesias 61893f1e401SEdgar E. Iglesias case R_UAW0: 61993f1e401SEdgar E. Iglesias case R_UAW1: 62093f1e401SEdgar E. Iglesias s->uaw[addr & 1] = value; 62193f1e401SEdgar E. Iglesias break; 62293f1e401SEdgar E. Iglesias 62393f1e401SEdgar E. Iglesias case R_UAWL: 62493f1e401SEdgar E. Iglesias case R_UAWU: 62593f1e401SEdgar E. Iglesias s->ext_uaw[addr & 1] = value; 62693f1e401SEdgar E. Iglesias break; 62793f1e401SEdgar E. Iglesias 62893f1e401SEdgar E. Iglesias case R_FMI: 62993f1e401SEdgar E. Iglesias s->fmi = value; 63093f1e401SEdgar E. Iglesias break; 63193f1e401SEdgar E. Iglesias 63293f1e401SEdgar E. Iglesias case R_AF0: 63393f1e401SEdgar E. Iglesias case R_AF1: 63493f1e401SEdgar E. Iglesias s->maddr[s->fmi & 3][addr & 1] = value; 63593f1e401SEdgar E. Iglesias break; 63693f1e401SEdgar E. Iglesias 637d4d230daSPeter Crosthwaite case R_IS: 638d4d230daSPeter Crosthwaite s->regs[addr] &= ~value; 639d4d230daSPeter Crosthwaite break; 640d4d230daSPeter Crosthwaite 64193f1e401SEdgar E. Iglesias case 0x8000 ... 0x83ff: 64293f1e401SEdgar E. Iglesias s->ext_mtable[addr - 0x8000] = value; 64393f1e401SEdgar E. Iglesias break; 64493f1e401SEdgar E. Iglesias 64593f1e401SEdgar E. Iglesias default: 64693f1e401SEdgar E. Iglesias DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n", 6470dc31f3bSAvi Kivity __func__, addr * 4, (unsigned)value)); 64893f1e401SEdgar E. Iglesias if (addr < ARRAY_SIZE(s->regs)) { 64993f1e401SEdgar E. Iglesias s->regs[addr] = value; 65093f1e401SEdgar E. Iglesias } 65193f1e401SEdgar E. Iglesias break; 65293f1e401SEdgar E. Iglesias } 65393f1e401SEdgar E. Iglesias enet_update_irq(s); 65493f1e401SEdgar E. Iglesias } 65593f1e401SEdgar E. Iglesias 6560dc31f3bSAvi Kivity static const MemoryRegionOps enet_ops = { 6570dc31f3bSAvi Kivity .read = enet_read, 6580dc31f3bSAvi Kivity .write = enet_write, 6590dc31f3bSAvi Kivity .endianness = DEVICE_LITTLE_ENDIAN, 66093f1e401SEdgar E. Iglesias }; 66193f1e401SEdgar E. Iglesias 6624e68f7a0SStefan Hajnoczi static int eth_can_rx(NetClientState *nc) 66393f1e401SEdgar E. Iglesias { 664545129e5SPeter Crosthwaite XilinxAXIEnet *s = qemu_get_nic_opaque(nc); 66593f1e401SEdgar E. Iglesias 66693f1e401SEdgar E. Iglesias /* RX enabled? */ 6673630ae95SPeter Crosthwaite return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s); 66893f1e401SEdgar E. Iglesias } 66993f1e401SEdgar E. Iglesias 67093f1e401SEdgar E. Iglesias static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1) 67193f1e401SEdgar E. Iglesias { 67293f1e401SEdgar E. Iglesias int match = 1; 67393f1e401SEdgar E. Iglesias 67493f1e401SEdgar E. Iglesias if (memcmp(buf, &f0, 4)) { 67593f1e401SEdgar E. Iglesias match = 0; 67693f1e401SEdgar E. Iglesias } 67793f1e401SEdgar E. Iglesias 67893f1e401SEdgar E. Iglesias if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) { 67993f1e401SEdgar E. Iglesias match = 0; 68093f1e401SEdgar E. Iglesias } 68193f1e401SEdgar E. Iglesias 68293f1e401SEdgar E. Iglesias return match; 68393f1e401SEdgar E. Iglesias } 68493f1e401SEdgar E. Iglesias 6853630ae95SPeter Crosthwaite static void axienet_eth_rx_notify(void *opaque) 6863630ae95SPeter Crosthwaite { 6873630ae95SPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(opaque); 6883630ae95SPeter Crosthwaite 68942bb9c91SPeter Crosthwaite while (s->rxappsize && stream_can_push(s->tx_control_dev, 69042bb9c91SPeter Crosthwaite axienet_eth_rx_notify, s)) { 69142bb9c91SPeter Crosthwaite size_t ret = stream_push(s->tx_control_dev, 69242bb9c91SPeter Crosthwaite (void *)s->rxapp + CONTROL_PAYLOAD_SIZE 69342bb9c91SPeter Crosthwaite - s->rxappsize, s->rxappsize); 69442bb9c91SPeter Crosthwaite s->rxappsize -= ret; 69542bb9c91SPeter Crosthwaite } 69642bb9c91SPeter Crosthwaite 69742bb9c91SPeter Crosthwaite while (s->rxsize && stream_can_push(s->tx_data_dev, 69842bb9c91SPeter Crosthwaite axienet_eth_rx_notify, s)) { 69942bb9c91SPeter Crosthwaite size_t ret = stream_push(s->tx_data_dev, (void *)s->rxmem + s->rxpos, 70042bb9c91SPeter Crosthwaite s->rxsize); 7013630ae95SPeter Crosthwaite s->rxsize -= ret; 7023630ae95SPeter Crosthwaite s->rxpos += ret; 7033630ae95SPeter Crosthwaite if (!s->rxsize) { 7043630ae95SPeter Crosthwaite s->regs[R_IS] |= IS_RX_COMPLETE; 7053630ae95SPeter Crosthwaite } 7063630ae95SPeter Crosthwaite } 7073630ae95SPeter Crosthwaite enet_update_irq(s); 7083630ae95SPeter Crosthwaite } 7093630ae95SPeter Crosthwaite 7104e68f7a0SStefan Hajnoczi static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) 71193f1e401SEdgar E. Iglesias { 712545129e5SPeter Crosthwaite XilinxAXIEnet *s = qemu_get_nic_opaque(nc); 71393f1e401SEdgar E. Iglesias static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 71493f1e401SEdgar E. Iglesias 0xff, 0xff, 0xff}; 71593f1e401SEdgar E. Iglesias static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52}; 71642bb9c91SPeter Crosthwaite uint32_t app[CONTROL_PAYLOAD_WORDS] = {0}; 71793f1e401SEdgar E. Iglesias int promisc = s->fmi & (1 << 31); 71893f1e401SEdgar E. Iglesias int unicast, broadcast, multicast, ip_multicast = 0; 71993f1e401SEdgar E. Iglesias uint32_t csum32; 72093f1e401SEdgar E. Iglesias uint16_t csum16; 72193f1e401SEdgar E. Iglesias int i; 72293f1e401SEdgar E. Iglesias 72393f1e401SEdgar E. Iglesias DENET(qemu_log("%s: %zd bytes\n", __func__, size)); 72493f1e401SEdgar E. Iglesias 72593f1e401SEdgar E. Iglesias unicast = ~buf[0] & 0x1; 72693f1e401SEdgar E. Iglesias broadcast = memcmp(buf, sa_bcast, 6) == 0; 72793f1e401SEdgar E. Iglesias multicast = !unicast && !broadcast; 72893f1e401SEdgar E. Iglesias if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) { 72993f1e401SEdgar E. Iglesias ip_multicast = 1; 73093f1e401SEdgar E. Iglesias } 73193f1e401SEdgar E. Iglesias 73293f1e401SEdgar E. Iglesias /* Jumbo or vlan sizes ? */ 73393f1e401SEdgar E. Iglesias if (!(s->rcw[1] & RCW1_JUM)) { 73493f1e401SEdgar E. Iglesias if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) { 73593f1e401SEdgar E. Iglesias return size; 73693f1e401SEdgar E. Iglesias } 73793f1e401SEdgar E. Iglesias } 73893f1e401SEdgar E. Iglesias 73993f1e401SEdgar E. Iglesias /* Basic Address filters. If you want to use the extended filters 74093f1e401SEdgar E. Iglesias you'll generally have to place the ethernet mac into promiscuous mode 74193f1e401SEdgar E. Iglesias to avoid the basic filtering from dropping most frames. */ 74293f1e401SEdgar E. Iglesias if (!promisc) { 74393f1e401SEdgar E. Iglesias if (unicast) { 74493f1e401SEdgar E. Iglesias if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) { 74593f1e401SEdgar E. Iglesias return size; 74693f1e401SEdgar E. Iglesias } 74793f1e401SEdgar E. Iglesias } else { 74893f1e401SEdgar E. Iglesias if (broadcast) { 74993f1e401SEdgar E. Iglesias /* Broadcast. */ 75093f1e401SEdgar E. Iglesias if (s->regs[R_RAF] & RAF_BCAST_REJ) { 75193f1e401SEdgar E. Iglesias return size; 75293f1e401SEdgar E. Iglesias } 75393f1e401SEdgar E. Iglesias } else { 75493f1e401SEdgar E. Iglesias int drop = 1; 75593f1e401SEdgar E. Iglesias 75693f1e401SEdgar E. Iglesias /* Multicast. */ 75793f1e401SEdgar E. Iglesias if (s->regs[R_RAF] & RAF_MCAST_REJ) { 75893f1e401SEdgar E. Iglesias return size; 75993f1e401SEdgar E. Iglesias } 76093f1e401SEdgar E. Iglesias 76193f1e401SEdgar E. Iglesias for (i = 0; i < 4; i++) { 76293f1e401SEdgar E. Iglesias if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) { 76393f1e401SEdgar E. Iglesias drop = 0; 76493f1e401SEdgar E. Iglesias break; 76593f1e401SEdgar E. Iglesias } 76693f1e401SEdgar E. Iglesias } 76793f1e401SEdgar E. Iglesias 76893f1e401SEdgar E. Iglesias if (drop) { 76993f1e401SEdgar E. Iglesias return size; 77093f1e401SEdgar E. Iglesias } 77193f1e401SEdgar E. Iglesias } 77293f1e401SEdgar E. Iglesias } 77393f1e401SEdgar E. Iglesias } 77493f1e401SEdgar E. Iglesias 77593f1e401SEdgar E. Iglesias /* Extended mcast filtering enabled? */ 77693f1e401SEdgar E. Iglesias if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) { 77793f1e401SEdgar E. Iglesias if (unicast) { 77893f1e401SEdgar E. Iglesias if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) { 77993f1e401SEdgar E. Iglesias return size; 78093f1e401SEdgar E. Iglesias } 78193f1e401SEdgar E. Iglesias } else { 78293f1e401SEdgar E. Iglesias if (broadcast) { 78393f1e401SEdgar E. Iglesias /* Broadcast. ??? */ 78493f1e401SEdgar E. Iglesias if (s->regs[R_RAF] & RAF_BCAST_REJ) { 78593f1e401SEdgar E. Iglesias return size; 78693f1e401SEdgar E. Iglesias } 78793f1e401SEdgar E. Iglesias } else { 78893f1e401SEdgar E. Iglesias int idx, bit; 78993f1e401SEdgar E. Iglesias 79093f1e401SEdgar E. Iglesias /* Multicast. */ 79193f1e401SEdgar E. Iglesias if (!memcmp(buf, sa_ipmcast, 3)) { 79293f1e401SEdgar E. Iglesias return size; 79393f1e401SEdgar E. Iglesias } 79493f1e401SEdgar E. Iglesias 79593f1e401SEdgar E. Iglesias idx = (buf[4] & 0x7f) << 8; 79693f1e401SEdgar E. Iglesias idx |= buf[5]; 79793f1e401SEdgar E. Iglesias 79893f1e401SEdgar E. Iglesias bit = 1 << (idx & 0x1f); 79993f1e401SEdgar E. Iglesias idx >>= 5; 80093f1e401SEdgar E. Iglesias 80193f1e401SEdgar E. Iglesias if (!(s->ext_mtable[idx] & bit)) { 80293f1e401SEdgar E. Iglesias return size; 80393f1e401SEdgar E. Iglesias } 80493f1e401SEdgar E. Iglesias } 80593f1e401SEdgar E. Iglesias } 80693f1e401SEdgar E. Iglesias } 80793f1e401SEdgar E. Iglesias 80893f1e401SEdgar E. Iglesias if (size < 12) { 80993f1e401SEdgar E. Iglesias s->regs[R_IS] |= IS_RX_REJECT; 81093f1e401SEdgar E. Iglesias enet_update_irq(s); 81193f1e401SEdgar E. Iglesias return -1; 81293f1e401SEdgar E. Iglesias } 81393f1e401SEdgar E. Iglesias 81493f1e401SEdgar E. Iglesias if (size > (s->c_rxmem - 4)) { 81593f1e401SEdgar E. Iglesias size = s->c_rxmem - 4; 81693f1e401SEdgar E. Iglesias } 81793f1e401SEdgar E. Iglesias 81893f1e401SEdgar E. Iglesias memcpy(s->rxmem, buf, size); 81993f1e401SEdgar E. Iglesias memset(s->rxmem + size, 0, 4); /* Clear the FCS. */ 82093f1e401SEdgar E. Iglesias 82193f1e401SEdgar E. Iglesias if (s->rcw[1] & RCW1_FCS) { 82293f1e401SEdgar E. Iglesias size += 4; /* fcs is inband. */ 82393f1e401SEdgar E. Iglesias } 82493f1e401SEdgar E. Iglesias 82593f1e401SEdgar E. Iglesias app[0] = 5 << 28; 82693f1e401SEdgar E. Iglesias csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14); 82793f1e401SEdgar E. Iglesias /* Fold it once. */ 82893f1e401SEdgar E. Iglesias csum32 = (csum32 & 0xffff) + (csum32 >> 16); 82993f1e401SEdgar E. Iglesias /* And twice to get rid of possible carries. */ 83093f1e401SEdgar E. Iglesias csum16 = (csum32 & 0xffff) + (csum32 >> 16); 83193f1e401SEdgar E. Iglesias app[3] = csum16; 83293f1e401SEdgar E. Iglesias app[4] = size & 0xffff; 83393f1e401SEdgar E. Iglesias 83493f1e401SEdgar E. Iglesias s->stats.rx_bytes += size; 83593f1e401SEdgar E. Iglesias s->stats.rx++; 83693f1e401SEdgar E. Iglesias if (multicast) { 83793f1e401SEdgar E. Iglesias s->stats.rx_mcast++; 83893f1e401SEdgar E. Iglesias app[2] |= 1 | (ip_multicast << 1); 83993f1e401SEdgar E. Iglesias } else if (broadcast) { 84093f1e401SEdgar E. Iglesias s->stats.rx_bcast++; 84193f1e401SEdgar E. Iglesias app[2] |= 1 << 3; 84293f1e401SEdgar E. Iglesias } 84393f1e401SEdgar E. Iglesias 84493f1e401SEdgar E. Iglesias /* Good frame. */ 84593f1e401SEdgar E. Iglesias app[2] |= 1 << 6; 84693f1e401SEdgar E. Iglesias 8473630ae95SPeter Crosthwaite s->rxsize = size; 8483630ae95SPeter Crosthwaite s->rxpos = 0; 84942bb9c91SPeter Crosthwaite for (i = 0; i < ARRAY_SIZE(app); ++i) { 85042bb9c91SPeter Crosthwaite app[i] = cpu_to_le32(app[i]); 85142bb9c91SPeter Crosthwaite } 85242bb9c91SPeter Crosthwaite s->rxappsize = CONTROL_PAYLOAD_SIZE; 85342bb9c91SPeter Crosthwaite memcpy(s->rxapp, app, s->rxappsize); 8543630ae95SPeter Crosthwaite axienet_eth_rx_notify(s); 85593f1e401SEdgar E. Iglesias 85693f1e401SEdgar E. Iglesias enet_update_irq(s); 85793f1e401SEdgar E. Iglesias return size; 85893f1e401SEdgar E. Iglesias } 85993f1e401SEdgar E. Iglesias 8604e68f7a0SStefan Hajnoczi static void eth_cleanup(NetClientState *nc) 86193f1e401SEdgar E. Iglesias { 86293f1e401SEdgar E. Iglesias /* FIXME. */ 863545129e5SPeter Crosthwaite XilinxAXIEnet *s = qemu_get_nic_opaque(nc); 8647267c094SAnthony Liguori g_free(s->rxmem); 8657267c094SAnthony Liguori g_free(s); 86693f1e401SEdgar E. Iglesias } 86793f1e401SEdgar E. Iglesias 86835e60bfdSPeter Crosthwaite static size_t 86942bb9c91SPeter Crosthwaite xilinx_axienet_control_stream_push(StreamSlave *obj, uint8_t *buf, size_t len) 87042bb9c91SPeter Crosthwaite { 87142bb9c91SPeter Crosthwaite int i; 87242bb9c91SPeter Crosthwaite XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM(obj); 87342bb9c91SPeter Crosthwaite XilinxAXIEnet *s = cs->enet; 87442bb9c91SPeter Crosthwaite 87542bb9c91SPeter Crosthwaite if (len != CONTROL_PAYLOAD_SIZE) { 87642bb9c91SPeter Crosthwaite hw_error("AXI Enet requires %d byte control stream payload\n", 87742bb9c91SPeter Crosthwaite (int)CONTROL_PAYLOAD_SIZE); 87842bb9c91SPeter Crosthwaite } 87942bb9c91SPeter Crosthwaite 88042bb9c91SPeter Crosthwaite memcpy(s->hdr, buf, len); 88142bb9c91SPeter Crosthwaite 88242bb9c91SPeter Crosthwaite for (i = 0; i < ARRAY_SIZE(s->hdr); ++i) { 88342bb9c91SPeter Crosthwaite s->hdr[i] = le32_to_cpu(s->hdr[i]); 88442bb9c91SPeter Crosthwaite } 88542bb9c91SPeter Crosthwaite return len; 88642bb9c91SPeter Crosthwaite } 88742bb9c91SPeter Crosthwaite 88842bb9c91SPeter Crosthwaite static size_t 88942bb9c91SPeter Crosthwaite xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size) 89093f1e401SEdgar E. Iglesias { 89155b3e0c2SPeter Crosthwaite XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(obj); 89255b3e0c2SPeter Crosthwaite XilinxAXIEnet *s = ds->enet; 89393f1e401SEdgar E. Iglesias 89493f1e401SEdgar E. Iglesias /* TX enable ? */ 89593f1e401SEdgar E. Iglesias if (!(s->tc & TC_TX)) { 89635e60bfdSPeter Crosthwaite return size; 89793f1e401SEdgar E. Iglesias } 89893f1e401SEdgar E. Iglesias 89993f1e401SEdgar E. Iglesias /* Jumbo or vlan sizes ? */ 90093f1e401SEdgar E. Iglesias if (!(s->tc & TC_JUM)) { 90193f1e401SEdgar E. Iglesias if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) { 90235e60bfdSPeter Crosthwaite return size; 90393f1e401SEdgar E. Iglesias } 90493f1e401SEdgar E. Iglesias } 90593f1e401SEdgar E. Iglesias 90642bb9c91SPeter Crosthwaite if (s->hdr[0] & 1) { 90742bb9c91SPeter Crosthwaite unsigned int start_off = s->hdr[1] >> 16; 90842bb9c91SPeter Crosthwaite unsigned int write_off = s->hdr[1] & 0xffff; 90993f1e401SEdgar E. Iglesias uint32_t tmp_csum; 91093f1e401SEdgar E. Iglesias uint16_t csum; 91193f1e401SEdgar E. Iglesias 91293f1e401SEdgar E. Iglesias tmp_csum = net_checksum_add(size - start_off, 91393f1e401SEdgar E. Iglesias (uint8_t *)buf + start_off); 91493f1e401SEdgar E. Iglesias /* Accumulate the seed. */ 91542bb9c91SPeter Crosthwaite tmp_csum += s->hdr[2] & 0xffff; 91693f1e401SEdgar E. Iglesias 91793f1e401SEdgar E. Iglesias /* Fold the 32bit partial checksum. */ 91893f1e401SEdgar E. Iglesias csum = net_checksum_finish(tmp_csum); 91993f1e401SEdgar E. Iglesias 92093f1e401SEdgar E. Iglesias /* Writeback. */ 92193f1e401SEdgar E. Iglesias buf[write_off] = csum >> 8; 92293f1e401SEdgar E. Iglesias buf[write_off + 1] = csum & 0xff; 92393f1e401SEdgar E. Iglesias } 92493f1e401SEdgar E. Iglesias 925b356f76dSJason Wang qemu_send_packet(qemu_get_queue(s->nic), buf, size); 92693f1e401SEdgar E. Iglesias 92793f1e401SEdgar E. Iglesias s->stats.tx_bytes += size; 92893f1e401SEdgar E. Iglesias s->regs[R_IS] |= IS_TX_COMPLETE; 92993f1e401SEdgar E. Iglesias enet_update_irq(s); 93035e60bfdSPeter Crosthwaite 93135e60bfdSPeter Crosthwaite return size; 93293f1e401SEdgar E. Iglesias } 93393f1e401SEdgar E. Iglesias 93493f1e401SEdgar E. Iglesias static NetClientInfo net_xilinx_enet_info = { 9352be64a68SLaszlo Ersek .type = NET_CLIENT_OPTIONS_KIND_NIC, 93693f1e401SEdgar E. Iglesias .size = sizeof(NICState), 93793f1e401SEdgar E. Iglesias .can_receive = eth_can_rx, 93893f1e401SEdgar E. Iglesias .receive = eth_rx, 93993f1e401SEdgar E. Iglesias .cleanup = eth_cleanup, 94093f1e401SEdgar E. Iglesias }; 94193f1e401SEdgar E. Iglesias 942b2d9dfe9SPeter Crosthwaite static void xilinx_enet_realize(DeviceState *dev, Error **errp) 94393f1e401SEdgar E. Iglesias { 944f0e7a81cSPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(dev); 94555b3e0c2SPeter Crosthwaite XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(&s->rx_data_dev); 94642bb9c91SPeter Crosthwaite XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM( 94742bb9c91SPeter Crosthwaite &s->rx_control_dev); 94855b3e0c2SPeter Crosthwaite Error *local_errp = NULL; 94955b3e0c2SPeter Crosthwaite 95055b3e0c2SPeter Crosthwaite object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet", 9519561fda8SStefan Hajnoczi (Object **) &ds->enet, 95239f72ef9SStefan Hajnoczi object_property_allow_set_link, 9539561fda8SStefan Hajnoczi OBJ_PROP_LINK_UNREF_ON_RELEASE, 9549561fda8SStefan Hajnoczi &local_errp); 95542bb9c91SPeter Crosthwaite object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet", 9569561fda8SStefan Hajnoczi (Object **) &cs->enet, 95739f72ef9SStefan Hajnoczi object_property_allow_set_link, 9589561fda8SStefan Hajnoczi OBJ_PROP_LINK_UNREF_ON_RELEASE, 9599561fda8SStefan Hajnoczi &local_errp); 96055b3e0c2SPeter Crosthwaite if (local_errp) { 96155b3e0c2SPeter Crosthwaite goto xilinx_enet_realize_fail; 96255b3e0c2SPeter Crosthwaite } 96355b3e0c2SPeter Crosthwaite object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_errp); 96442bb9c91SPeter Crosthwaite object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_errp); 96555b3e0c2SPeter Crosthwaite if (local_errp) { 96655b3e0c2SPeter Crosthwaite goto xilinx_enet_realize_fail; 96755b3e0c2SPeter Crosthwaite } 96893f1e401SEdgar E. Iglesias 96993f1e401SEdgar E. Iglesias qemu_macaddr_default_if_unset(&s->conf.macaddr); 97093f1e401SEdgar E. Iglesias s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf, 971b2d9dfe9SPeter Crosthwaite object_get_typename(OBJECT(dev)), dev->id, 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); 98055b3e0c2SPeter Crosthwaite return; 98155b3e0c2SPeter Crosthwaite 98255b3e0c2SPeter Crosthwaite xilinx_enet_realize_fail: 98355b3e0c2SPeter Crosthwaite if (!*errp) { 98455b3e0c2SPeter Crosthwaite *errp = local_errp; 98555b3e0c2SPeter Crosthwaite } 98693f1e401SEdgar E. Iglesias } 98793f1e401SEdgar E. Iglesias 988b2d9dfe9SPeter Crosthwaite static void xilinx_enet_init(Object *obj) 989669b4983SPeter A. G. Crosthwaite { 990f0e7a81cSPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(obj); 991b2d9dfe9SPeter Crosthwaite SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 992669b4983SPeter A. G. Crosthwaite 993669b4983SPeter A. G. Crosthwaite object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE, 9949561fda8SStefan Hajnoczi (Object **) &s->tx_data_dev, 99539f72ef9SStefan Hajnoczi qdev_prop_allow_set_link_before_realize, 9969561fda8SStefan Hajnoczi OBJ_PROP_LINK_UNREF_ON_RELEASE, 9979561fda8SStefan Hajnoczi &error_abort); 99842bb9c91SPeter Crosthwaite object_property_add_link(obj, "axistream-control-connected", 99942bb9c91SPeter Crosthwaite TYPE_STREAM_SLAVE, 10009561fda8SStefan Hajnoczi (Object **) &s->tx_control_dev, 100139f72ef9SStefan Hajnoczi qdev_prop_allow_set_link_before_realize, 10029561fda8SStefan Hajnoczi OBJ_PROP_LINK_UNREF_ON_RELEASE, 10039561fda8SStefan Hajnoczi &error_abort); 1004b2d9dfe9SPeter Crosthwaite 1005213f0c4fSAndreas Färber object_initialize(&s->rx_data_dev, sizeof(s->rx_data_dev), 1006213f0c4fSAndreas Färber TYPE_XILINX_AXI_ENET_DATA_STREAM); 1007213f0c4fSAndreas Färber object_initialize(&s->rx_control_dev, sizeof(s->rx_control_dev), 1008213f0c4fSAndreas Färber TYPE_XILINX_AXI_ENET_CONTROL_STREAM); 100955b3e0c2SPeter Crosthwaite object_property_add_child(OBJECT(s), "axistream-connected-target", 10105433a0a8SPeter Crosthwaite (Object *)&s->rx_data_dev, &error_abort); 101142bb9c91SPeter Crosthwaite object_property_add_child(OBJECT(s), "axistream-control-connected-target", 10125433a0a8SPeter Crosthwaite (Object *)&s->rx_control_dev, &error_abort); 101355b3e0c2SPeter Crosthwaite 1014b2d9dfe9SPeter Crosthwaite sysbus_init_irq(sbd, &s->irq); 1015b2d9dfe9SPeter Crosthwaite 1016eedfac6fSPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &enet_ops, s, "enet", 0x40000); 1017b2d9dfe9SPeter Crosthwaite sysbus_init_mmio(sbd, &s->iomem); 1018669b4983SPeter A. G. Crosthwaite } 1019669b4983SPeter A. G. Crosthwaite 1020999e12bbSAnthony Liguori static Property xilinx_enet_properties[] = { 1021545129e5SPeter Crosthwaite DEFINE_PROP_UINT32("phyaddr", XilinxAXIEnet, c_phyaddr, 7), 1022545129e5SPeter Crosthwaite DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000), 1023545129e5SPeter Crosthwaite DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000), 1024545129e5SPeter Crosthwaite DEFINE_NIC_PROPERTIES(XilinxAXIEnet, conf), 102593f1e401SEdgar E. Iglesias DEFINE_PROP_END_OF_LIST(), 1026999e12bbSAnthony Liguori }; 1027999e12bbSAnthony Liguori 1028999e12bbSAnthony Liguori static void xilinx_enet_class_init(ObjectClass *klass, void *data) 1029999e12bbSAnthony Liguori { 103039bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 1031999e12bbSAnthony Liguori 1032b2d9dfe9SPeter Crosthwaite dc->realize = xilinx_enet_realize; 103339bffca2SAnthony Liguori dc->props = xilinx_enet_properties; 10349ee0ceb7SPeter Crosthwaite dc->reset = xilinx_axienet_reset; 103555b3e0c2SPeter Crosthwaite } 103655b3e0c2SPeter Crosthwaite 103755b3e0c2SPeter Crosthwaite static void xilinx_enet_stream_class_init(ObjectClass *klass, void *data) 103855b3e0c2SPeter Crosthwaite { 103955b3e0c2SPeter Crosthwaite StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass); 104055b3e0c2SPeter Crosthwaite 104155b3e0c2SPeter Crosthwaite ssc->push = data; 104293f1e401SEdgar E. Iglesias } 1043999e12bbSAnthony Liguori 10448c43a6f0SAndreas Färber static const TypeInfo xilinx_enet_info = { 1045f0e7a81cSPeter Crosthwaite .name = TYPE_XILINX_AXI_ENET, 104639bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 1047545129e5SPeter Crosthwaite .instance_size = sizeof(XilinxAXIEnet), 1048999e12bbSAnthony Liguori .class_init = xilinx_enet_class_init, 1049b2d9dfe9SPeter Crosthwaite .instance_init = xilinx_enet_init, 105055b3e0c2SPeter Crosthwaite }; 105155b3e0c2SPeter Crosthwaite 105255b3e0c2SPeter Crosthwaite static const TypeInfo xilinx_enet_data_stream_info = { 105355b3e0c2SPeter Crosthwaite .name = TYPE_XILINX_AXI_ENET_DATA_STREAM, 105455b3e0c2SPeter Crosthwaite .parent = TYPE_OBJECT, 105555b3e0c2SPeter Crosthwaite .instance_size = sizeof(struct XilinxAXIEnetStreamSlave), 105655b3e0c2SPeter Crosthwaite .class_init = xilinx_enet_stream_class_init, 105755b3e0c2SPeter Crosthwaite .class_data = xilinx_axienet_data_stream_push, 1058669b4983SPeter A. G. Crosthwaite .interfaces = (InterfaceInfo[]) { 1059669b4983SPeter A. G. Crosthwaite { TYPE_STREAM_SLAVE }, 1060669b4983SPeter A. G. Crosthwaite { } 1061669b4983SPeter A. G. Crosthwaite } 106293f1e401SEdgar E. Iglesias }; 106383f7d43aSAndreas Färber 106442bb9c91SPeter Crosthwaite static const TypeInfo xilinx_enet_control_stream_info = { 106542bb9c91SPeter Crosthwaite .name = TYPE_XILINX_AXI_ENET_CONTROL_STREAM, 106642bb9c91SPeter Crosthwaite .parent = TYPE_OBJECT, 106742bb9c91SPeter Crosthwaite .instance_size = sizeof(struct XilinxAXIEnetStreamSlave), 106842bb9c91SPeter Crosthwaite .class_init = xilinx_enet_stream_class_init, 106942bb9c91SPeter Crosthwaite .class_data = xilinx_axienet_control_stream_push, 107042bb9c91SPeter Crosthwaite .interfaces = (InterfaceInfo[]) { 107142bb9c91SPeter Crosthwaite { TYPE_STREAM_SLAVE }, 107242bb9c91SPeter Crosthwaite { } 107342bb9c91SPeter Crosthwaite } 107442bb9c91SPeter Crosthwaite }; 107542bb9c91SPeter Crosthwaite 107683f7d43aSAndreas Färber static void xilinx_enet_register_types(void) 107793f1e401SEdgar E. Iglesias { 107839bffca2SAnthony Liguori type_register_static(&xilinx_enet_info); 107955b3e0c2SPeter Crosthwaite type_register_static(&xilinx_enet_data_stream_info); 108042bb9c91SPeter Crosthwaite type_register_static(&xilinx_enet_control_stream_info); 108193f1e401SEdgar E. Iglesias } 108293f1e401SEdgar E. Iglesias 108383f7d43aSAndreas Färber type_init(xilinx_enet_register_types) 1084