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 35*f0e7a81cSPeter Crosthwaite #define TYPE_XILINX_AXI_ENET "xlnx.axi-ethernet" 36*f0e7a81cSPeter Crosthwaite 37*f0e7a81cSPeter Crosthwaite #define XILINX_AXI_ENET(obj) \ 38*f0e7a81cSPeter Crosthwaite OBJECT_CHECK(XilinxAXIEnet, (obj), TYPE_XILINX_AXI_ENET) 39*f0e7a81cSPeter Crosthwaite 4093f1e401SEdgar E. Iglesias /* Advertisement control register. */ 4193f1e401SEdgar E. Iglesias #define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ 4293f1e401SEdgar E. Iglesias #define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ 4393f1e401SEdgar E. Iglesias #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ 4493f1e401SEdgar E. Iglesias #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ 4593f1e401SEdgar E. Iglesias 4693f1e401SEdgar E. Iglesias struct PHY { 4793f1e401SEdgar E. Iglesias uint32_t regs[32]; 4893f1e401SEdgar E. Iglesias 4993f1e401SEdgar E. Iglesias int link; 5093f1e401SEdgar E. Iglesias 5193f1e401SEdgar E. Iglesias unsigned int (*read)(struct PHY *phy, unsigned int req); 5293f1e401SEdgar E. Iglesias void (*write)(struct PHY *phy, unsigned int req, 5393f1e401SEdgar E. Iglesias unsigned int data); 5493f1e401SEdgar E. Iglesias }; 5593f1e401SEdgar E. Iglesias 5693f1e401SEdgar E. Iglesias static unsigned int tdk_read(struct PHY *phy, unsigned int req) 5793f1e401SEdgar E. Iglesias { 5893f1e401SEdgar E. Iglesias int regnum; 5993f1e401SEdgar E. Iglesias unsigned r = 0; 6093f1e401SEdgar E. Iglesias 6193f1e401SEdgar E. Iglesias regnum = req & 0x1f; 6293f1e401SEdgar E. Iglesias 6393f1e401SEdgar E. Iglesias switch (regnum) { 6493f1e401SEdgar E. Iglesias case 1: 6593f1e401SEdgar E. Iglesias if (!phy->link) { 6693f1e401SEdgar E. Iglesias break; 6793f1e401SEdgar E. Iglesias } 6893f1e401SEdgar E. Iglesias /* MR1. */ 6993f1e401SEdgar E. Iglesias /* Speeds and modes. */ 7093f1e401SEdgar E. Iglesias r |= (1 << 13) | (1 << 14); 7193f1e401SEdgar E. Iglesias r |= (1 << 11) | (1 << 12); 7293f1e401SEdgar E. Iglesias r |= (1 << 5); /* Autoneg complete. */ 7393f1e401SEdgar E. Iglesias r |= (1 << 3); /* Autoneg able. */ 7493f1e401SEdgar E. Iglesias r |= (1 << 2); /* link. */ 7593f1e401SEdgar E. Iglesias r |= (1 << 1); /* link. */ 7693f1e401SEdgar E. Iglesias break; 7793f1e401SEdgar E. Iglesias case 5: 7893f1e401SEdgar E. Iglesias /* Link partner ability. 7993f1e401SEdgar E. Iglesias We are kind; always agree with whatever best mode 8093f1e401SEdgar E. Iglesias the guest advertises. */ 8193f1e401SEdgar E. Iglesias r = 1 << 14; /* Success. */ 8293f1e401SEdgar E. Iglesias /* Copy advertised modes. */ 8393f1e401SEdgar E. Iglesias r |= phy->regs[4] & (15 << 5); 8493f1e401SEdgar E. Iglesias /* Autoneg support. */ 8593f1e401SEdgar E. Iglesias r |= 1; 8693f1e401SEdgar E. Iglesias break; 8793f1e401SEdgar E. Iglesias case 17: 8893f1e401SEdgar E. Iglesias /* Marvel PHY on many xilinx boards. */ 8993f1e401SEdgar E. Iglesias r = 0x8000; /* 1000Mb */ 9093f1e401SEdgar E. Iglesias break; 9193f1e401SEdgar E. Iglesias case 18: 9293f1e401SEdgar E. Iglesias { 9393f1e401SEdgar E. Iglesias /* Diagnostics reg. */ 9493f1e401SEdgar E. Iglesias int duplex = 0; 9593f1e401SEdgar E. Iglesias int speed_100 = 0; 9693f1e401SEdgar E. Iglesias 9793f1e401SEdgar E. Iglesias if (!phy->link) { 9893f1e401SEdgar E. Iglesias break; 9993f1e401SEdgar E. Iglesias } 10093f1e401SEdgar E. Iglesias 10193f1e401SEdgar E. Iglesias /* Are we advertising 100 half or 100 duplex ? */ 10293f1e401SEdgar E. Iglesias speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); 10393f1e401SEdgar E. Iglesias speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); 10493f1e401SEdgar E. Iglesias 10593f1e401SEdgar E. Iglesias /* Are we advertising 10 duplex or 100 duplex ? */ 10693f1e401SEdgar E. Iglesias duplex = !!(phy->regs[4] & ADVERTISE_100FULL); 10793f1e401SEdgar E. Iglesias duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); 10893f1e401SEdgar E. Iglesias r = (speed_100 << 10) | (duplex << 11); 10993f1e401SEdgar E. Iglesias } 11093f1e401SEdgar E. Iglesias break; 11193f1e401SEdgar E. Iglesias 11293f1e401SEdgar E. Iglesias default: 11393f1e401SEdgar E. Iglesias r = phy->regs[regnum]; 11493f1e401SEdgar E. Iglesias break; 11593f1e401SEdgar E. Iglesias } 11693f1e401SEdgar E. Iglesias DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum)); 11793f1e401SEdgar E. Iglesias return r; 11893f1e401SEdgar E. Iglesias } 11993f1e401SEdgar E. Iglesias 12093f1e401SEdgar E. Iglesias static void 12193f1e401SEdgar E. Iglesias tdk_write(struct PHY *phy, unsigned int req, unsigned int data) 12293f1e401SEdgar E. Iglesias { 12393f1e401SEdgar E. Iglesias int regnum; 12493f1e401SEdgar E. Iglesias 12593f1e401SEdgar E. Iglesias regnum = req & 0x1f; 12693f1e401SEdgar E. Iglesias DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data)); 12793f1e401SEdgar E. Iglesias switch (regnum) { 12893f1e401SEdgar E. Iglesias default: 12993f1e401SEdgar E. Iglesias phy->regs[regnum] = data; 13093f1e401SEdgar E. Iglesias break; 13193f1e401SEdgar E. Iglesias } 13293f1e401SEdgar E. Iglesias } 13393f1e401SEdgar E. Iglesias 13493f1e401SEdgar E. Iglesias static void 13593f1e401SEdgar E. Iglesias tdk_init(struct PHY *phy) 13693f1e401SEdgar E. Iglesias { 13793f1e401SEdgar E. Iglesias phy->regs[0] = 0x3100; 13893f1e401SEdgar E. Iglesias /* PHY Id. */ 13993f1e401SEdgar E. Iglesias phy->regs[2] = 0x0300; 14093f1e401SEdgar E. Iglesias phy->regs[3] = 0xe400; 14193f1e401SEdgar E. Iglesias /* Autonegotiation advertisement reg. */ 14293f1e401SEdgar E. Iglesias phy->regs[4] = 0x01E1; 14393f1e401SEdgar E. Iglesias phy->link = 1; 14493f1e401SEdgar E. Iglesias 14593f1e401SEdgar E. Iglesias phy->read = tdk_read; 14693f1e401SEdgar E. Iglesias phy->write = tdk_write; 14793f1e401SEdgar E. Iglesias } 14893f1e401SEdgar E. Iglesias 14993f1e401SEdgar E. Iglesias struct MDIOBus { 15093f1e401SEdgar E. Iglesias /* bus. */ 15193f1e401SEdgar E. Iglesias int mdc; 15293f1e401SEdgar E. Iglesias int mdio; 15393f1e401SEdgar E. Iglesias 15493f1e401SEdgar E. Iglesias /* decoder. */ 15593f1e401SEdgar E. Iglesias enum { 15693f1e401SEdgar E. Iglesias PREAMBLE, 15793f1e401SEdgar E. Iglesias SOF, 15893f1e401SEdgar E. Iglesias OPC, 15993f1e401SEdgar E. Iglesias ADDR, 16093f1e401SEdgar E. Iglesias REQ, 16193f1e401SEdgar E. Iglesias TURNAROUND, 16293f1e401SEdgar E. Iglesias DATA 16393f1e401SEdgar E. Iglesias } state; 16493f1e401SEdgar E. Iglesias unsigned int drive; 16593f1e401SEdgar E. Iglesias 16693f1e401SEdgar E. Iglesias unsigned int cnt; 16793f1e401SEdgar E. Iglesias unsigned int addr; 16893f1e401SEdgar E. Iglesias unsigned int opc; 16993f1e401SEdgar E. Iglesias unsigned int req; 17093f1e401SEdgar E. Iglesias unsigned int data; 17193f1e401SEdgar E. Iglesias 17293f1e401SEdgar E. Iglesias struct PHY *devs[32]; 17393f1e401SEdgar E. Iglesias }; 17493f1e401SEdgar E. Iglesias 17593f1e401SEdgar E. Iglesias static void 17693f1e401SEdgar E. Iglesias mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr) 17793f1e401SEdgar E. Iglesias { 17893f1e401SEdgar E. Iglesias bus->devs[addr & 0x1f] = phy; 17993f1e401SEdgar E. Iglesias } 18093f1e401SEdgar E. Iglesias 18193f1e401SEdgar E. Iglesias #ifdef USE_THIS_DEAD_CODE 18293f1e401SEdgar E. Iglesias static void 18393f1e401SEdgar E. Iglesias mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr) 18493f1e401SEdgar E. Iglesias { 18593f1e401SEdgar E. Iglesias bus->devs[addr & 0x1f] = NULL; 18693f1e401SEdgar E. Iglesias } 18793f1e401SEdgar E. Iglesias #endif 18893f1e401SEdgar E. Iglesias 18993f1e401SEdgar E. Iglesias static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr, 19093f1e401SEdgar E. Iglesias unsigned int reg) 19193f1e401SEdgar E. Iglesias { 19293f1e401SEdgar E. Iglesias struct PHY *phy; 19393f1e401SEdgar E. Iglesias uint16_t data; 19493f1e401SEdgar E. Iglesias 19593f1e401SEdgar E. Iglesias phy = bus->devs[addr]; 19693f1e401SEdgar E. Iglesias if (phy && phy->read) { 19793f1e401SEdgar E. Iglesias data = phy->read(phy, reg); 19893f1e401SEdgar E. Iglesias } else { 19993f1e401SEdgar E. Iglesias data = 0xffff; 20093f1e401SEdgar E. Iglesias } 20193f1e401SEdgar E. Iglesias DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data)); 20293f1e401SEdgar E. Iglesias return data; 20393f1e401SEdgar E. Iglesias } 20493f1e401SEdgar E. Iglesias 20593f1e401SEdgar E. Iglesias static void mdio_write_req(struct MDIOBus *bus, unsigned int addr, 20693f1e401SEdgar E. Iglesias unsigned int reg, uint16_t data) 20793f1e401SEdgar E. Iglesias { 20893f1e401SEdgar E. Iglesias struct PHY *phy; 20993f1e401SEdgar E. Iglesias 21093f1e401SEdgar E. Iglesias DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data)); 21193f1e401SEdgar E. Iglesias phy = bus->devs[addr]; 21293f1e401SEdgar E. Iglesias if (phy && phy->write) { 21393f1e401SEdgar E. Iglesias phy->write(phy, reg, data); 21493f1e401SEdgar E. Iglesias } 21593f1e401SEdgar E. Iglesias } 21693f1e401SEdgar E. Iglesias 21793f1e401SEdgar E. Iglesias #define DENET(x) 21893f1e401SEdgar E. Iglesias 21993f1e401SEdgar E. Iglesias #define R_RAF (0x000 / 4) 22093f1e401SEdgar E. Iglesias enum { 22193f1e401SEdgar E. Iglesias RAF_MCAST_REJ = (1 << 1), 22293f1e401SEdgar E. Iglesias RAF_BCAST_REJ = (1 << 2), 22393f1e401SEdgar E. Iglesias RAF_EMCF_EN = (1 << 12), 22493f1e401SEdgar E. Iglesias RAF_NEWFUNC_EN = (1 << 11) 22593f1e401SEdgar E. Iglesias }; 22693f1e401SEdgar E. Iglesias 22793f1e401SEdgar E. Iglesias #define R_IS (0x00C / 4) 22893f1e401SEdgar E. Iglesias enum { 22993f1e401SEdgar E. Iglesias IS_HARD_ACCESS_COMPLETE = 1, 23093f1e401SEdgar E. Iglesias IS_AUTONEG = (1 << 1), 23193f1e401SEdgar E. Iglesias IS_RX_COMPLETE = (1 << 2), 23293f1e401SEdgar E. Iglesias IS_RX_REJECT = (1 << 3), 23393f1e401SEdgar E. Iglesias IS_TX_COMPLETE = (1 << 5), 23493f1e401SEdgar E. Iglesias IS_RX_DCM_LOCK = (1 << 6), 23593f1e401SEdgar E. Iglesias IS_MGM_RDY = (1 << 7), 23693f1e401SEdgar E. Iglesias IS_PHY_RST_DONE = (1 << 8), 23793f1e401SEdgar E. Iglesias }; 23893f1e401SEdgar E. Iglesias 23993f1e401SEdgar E. Iglesias #define R_IP (0x010 / 4) 24093f1e401SEdgar E. Iglesias #define R_IE (0x014 / 4) 24193f1e401SEdgar E. Iglesias #define R_UAWL (0x020 / 4) 24293f1e401SEdgar E. Iglesias #define R_UAWU (0x024 / 4) 24393f1e401SEdgar E. Iglesias #define R_PPST (0x030 / 4) 24493f1e401SEdgar E. Iglesias enum { 24593f1e401SEdgar E. Iglesias PPST_LINKSTATUS = (1 << 0), 24693f1e401SEdgar E. Iglesias PPST_PHY_LINKSTATUS = (1 << 7), 24793f1e401SEdgar E. Iglesias }; 24893f1e401SEdgar E. Iglesias 24993f1e401SEdgar E. Iglesias #define R_STATS_RX_BYTESL (0x200 / 4) 25093f1e401SEdgar E. Iglesias #define R_STATS_RX_BYTESH (0x204 / 4) 25193f1e401SEdgar E. Iglesias #define R_STATS_TX_BYTESL (0x208 / 4) 25293f1e401SEdgar E. Iglesias #define R_STATS_TX_BYTESH (0x20C / 4) 25393f1e401SEdgar E. Iglesias #define R_STATS_RXL (0x290 / 4) 25493f1e401SEdgar E. Iglesias #define R_STATS_RXH (0x294 / 4) 25593f1e401SEdgar E. Iglesias #define R_STATS_RX_BCASTL (0x2a0 / 4) 25693f1e401SEdgar E. Iglesias #define R_STATS_RX_BCASTH (0x2a4 / 4) 25793f1e401SEdgar E. Iglesias #define R_STATS_RX_MCASTL (0x2a8 / 4) 25893f1e401SEdgar E. Iglesias #define R_STATS_RX_MCASTH (0x2ac / 4) 25993f1e401SEdgar E. Iglesias 26093f1e401SEdgar E. Iglesias #define R_RCW0 (0x400 / 4) 26193f1e401SEdgar E. Iglesias #define R_RCW1 (0x404 / 4) 26293f1e401SEdgar E. Iglesias enum { 26393f1e401SEdgar E. Iglesias RCW1_VLAN = (1 << 27), 26493f1e401SEdgar E. Iglesias RCW1_RX = (1 << 28), 26593f1e401SEdgar E. Iglesias RCW1_FCS = (1 << 29), 26693f1e401SEdgar E. Iglesias RCW1_JUM = (1 << 30), 26793f1e401SEdgar E. Iglesias RCW1_RST = (1 << 31), 26893f1e401SEdgar E. Iglesias }; 26993f1e401SEdgar E. Iglesias 27093f1e401SEdgar E. Iglesias #define R_TC (0x408 / 4) 27193f1e401SEdgar E. Iglesias enum { 27293f1e401SEdgar E. Iglesias TC_VLAN = (1 << 27), 27393f1e401SEdgar E. Iglesias TC_TX = (1 << 28), 27493f1e401SEdgar E. Iglesias TC_FCS = (1 << 29), 27593f1e401SEdgar E. Iglesias TC_JUM = (1 << 30), 27693f1e401SEdgar E. Iglesias TC_RST = (1 << 31), 27793f1e401SEdgar E. Iglesias }; 27893f1e401SEdgar E. Iglesias 27993f1e401SEdgar E. Iglesias #define R_EMMC (0x410 / 4) 28093f1e401SEdgar E. Iglesias enum { 28193f1e401SEdgar E. Iglesias EMMC_LINKSPEED_10MB = (0 << 30), 28293f1e401SEdgar E. Iglesias EMMC_LINKSPEED_100MB = (1 << 30), 28393f1e401SEdgar E. Iglesias EMMC_LINKSPEED_1000MB = (2 << 30), 28493f1e401SEdgar E. Iglesias }; 28593f1e401SEdgar E. Iglesias 28693f1e401SEdgar E. Iglesias #define R_PHYC (0x414 / 4) 28793f1e401SEdgar E. Iglesias 28893f1e401SEdgar E. Iglesias #define R_MC (0x500 / 4) 28993f1e401SEdgar E. Iglesias #define MC_EN (1 << 6) 29093f1e401SEdgar E. Iglesias 29193f1e401SEdgar E. Iglesias #define R_MCR (0x504 / 4) 29293f1e401SEdgar E. Iglesias #define R_MWD (0x508 / 4) 29393f1e401SEdgar E. Iglesias #define R_MRD (0x50c / 4) 29493f1e401SEdgar E. Iglesias #define R_MIS (0x600 / 4) 29593f1e401SEdgar E. Iglesias #define R_MIP (0x620 / 4) 29693f1e401SEdgar E. Iglesias #define R_MIE (0x640 / 4) 29793f1e401SEdgar E. Iglesias #define R_MIC (0x640 / 4) 29893f1e401SEdgar E. Iglesias 29993f1e401SEdgar E. Iglesias #define R_UAW0 (0x700 / 4) 30093f1e401SEdgar E. Iglesias #define R_UAW1 (0x704 / 4) 30193f1e401SEdgar E. Iglesias #define R_FMI (0x708 / 4) 30293f1e401SEdgar E. Iglesias #define R_AF0 (0x710 / 4) 30393f1e401SEdgar E. Iglesias #define R_AF1 (0x714 / 4) 30493f1e401SEdgar E. Iglesias #define R_MAX (0x34 / 4) 30593f1e401SEdgar E. Iglesias 30693f1e401SEdgar E. Iglesias /* Indirect registers. */ 30793f1e401SEdgar E. Iglesias struct TEMAC { 30893f1e401SEdgar E. Iglesias struct MDIOBus mdio_bus; 30993f1e401SEdgar E. Iglesias struct PHY phy; 31093f1e401SEdgar E. Iglesias 31193f1e401SEdgar E. Iglesias void *parent; 31293f1e401SEdgar E. Iglesias }; 31393f1e401SEdgar E. Iglesias 314545129e5SPeter Crosthwaite typedef struct XilinxAXIEnet XilinxAXIEnet; 315545129e5SPeter Crosthwaite 31693f1e401SEdgar E. Iglesias struct XilinxAXIEnet { 31793f1e401SEdgar E. Iglesias SysBusDevice busdev; 3180dc31f3bSAvi Kivity MemoryRegion iomem; 31993f1e401SEdgar E. Iglesias qemu_irq irq; 320669b4983SPeter A. G. Crosthwaite StreamSlave *tx_dev; 32193f1e401SEdgar E. Iglesias NICState *nic; 32293f1e401SEdgar E. Iglesias NICConf conf; 32393f1e401SEdgar E. Iglesias 32493f1e401SEdgar E. Iglesias 32593f1e401SEdgar E. Iglesias uint32_t c_rxmem; 32693f1e401SEdgar E. Iglesias uint32_t c_txmem; 32793f1e401SEdgar E. Iglesias uint32_t c_phyaddr; 32893f1e401SEdgar E. Iglesias 32993f1e401SEdgar E. Iglesias struct TEMAC TEMAC; 33093f1e401SEdgar E. Iglesias 33193f1e401SEdgar E. Iglesias /* MII regs. */ 33293f1e401SEdgar E. Iglesias union { 33393f1e401SEdgar E. Iglesias uint32_t regs[4]; 33493f1e401SEdgar E. Iglesias struct { 33593f1e401SEdgar E. Iglesias uint32_t mc; 33693f1e401SEdgar E. Iglesias uint32_t mcr; 33793f1e401SEdgar E. Iglesias uint32_t mwd; 33893f1e401SEdgar E. Iglesias uint32_t mrd; 33993f1e401SEdgar E. Iglesias }; 34093f1e401SEdgar E. Iglesias } mii; 34193f1e401SEdgar E. Iglesias 34293f1e401SEdgar E. Iglesias struct { 34393f1e401SEdgar E. Iglesias uint64_t rx_bytes; 34493f1e401SEdgar E. Iglesias uint64_t tx_bytes; 34593f1e401SEdgar E. Iglesias 34693f1e401SEdgar E. Iglesias uint64_t rx; 34793f1e401SEdgar E. Iglesias uint64_t rx_bcast; 34893f1e401SEdgar E. Iglesias uint64_t rx_mcast; 34993f1e401SEdgar E. Iglesias } stats; 35093f1e401SEdgar E. Iglesias 35193f1e401SEdgar E. Iglesias /* Receive configuration words. */ 35293f1e401SEdgar E. Iglesias uint32_t rcw[2]; 35393f1e401SEdgar E. Iglesias /* Transmit config. */ 35493f1e401SEdgar E. Iglesias uint32_t tc; 35593f1e401SEdgar E. Iglesias uint32_t emmc; 35693f1e401SEdgar E. Iglesias uint32_t phyc; 35793f1e401SEdgar E. Iglesias 35893f1e401SEdgar E. Iglesias /* Unicast Address Word. */ 35993f1e401SEdgar E. Iglesias uint32_t uaw[2]; 36093f1e401SEdgar E. Iglesias /* Unicast address filter used with extended mcast. */ 36193f1e401SEdgar E. Iglesias uint32_t ext_uaw[2]; 36293f1e401SEdgar E. Iglesias uint32_t fmi; 36393f1e401SEdgar E. Iglesias 36493f1e401SEdgar E. Iglesias uint32_t regs[R_MAX]; 36593f1e401SEdgar E. Iglesias 36693f1e401SEdgar E. Iglesias /* Multicast filter addrs. */ 36793f1e401SEdgar E. Iglesias uint32_t maddr[4][2]; 36893f1e401SEdgar E. Iglesias /* 32K x 1 lookup filter. */ 36993f1e401SEdgar E. Iglesias uint32_t ext_mtable[1024]; 37093f1e401SEdgar E. Iglesias 37193f1e401SEdgar E. Iglesias 37293f1e401SEdgar E. Iglesias uint8_t *rxmem; 37393f1e401SEdgar E. Iglesias }; 37493f1e401SEdgar E. Iglesias 375545129e5SPeter Crosthwaite static void axienet_rx_reset(XilinxAXIEnet *s) 37693f1e401SEdgar E. Iglesias { 37793f1e401SEdgar E. Iglesias s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN; 37893f1e401SEdgar E. Iglesias } 37993f1e401SEdgar E. Iglesias 380545129e5SPeter Crosthwaite static void axienet_tx_reset(XilinxAXIEnet *s) 38193f1e401SEdgar E. Iglesias { 38293f1e401SEdgar E. Iglesias s->tc = TC_JUM | TC_TX | TC_VLAN; 38393f1e401SEdgar E. Iglesias } 38493f1e401SEdgar E. Iglesias 385545129e5SPeter Crosthwaite static inline int axienet_rx_resetting(XilinxAXIEnet *s) 38693f1e401SEdgar E. Iglesias { 38793f1e401SEdgar E. Iglesias return s->rcw[1] & RCW1_RST; 38893f1e401SEdgar E. Iglesias } 38993f1e401SEdgar E. Iglesias 390545129e5SPeter Crosthwaite static inline int axienet_rx_enabled(XilinxAXIEnet *s) 39193f1e401SEdgar E. Iglesias { 39293f1e401SEdgar E. Iglesias return s->rcw[1] & RCW1_RX; 39393f1e401SEdgar E. Iglesias } 39493f1e401SEdgar E. Iglesias 395545129e5SPeter Crosthwaite static inline int axienet_extmcf_enabled(XilinxAXIEnet *s) 39693f1e401SEdgar E. Iglesias { 39793f1e401SEdgar E. Iglesias return !!(s->regs[R_RAF] & RAF_EMCF_EN); 39893f1e401SEdgar E. Iglesias } 39993f1e401SEdgar E. Iglesias 400545129e5SPeter Crosthwaite static inline int axienet_newfunc_enabled(XilinxAXIEnet *s) 40193f1e401SEdgar E. Iglesias { 40293f1e401SEdgar E. Iglesias return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN); 40393f1e401SEdgar E. Iglesias } 40493f1e401SEdgar E. Iglesias 405545129e5SPeter Crosthwaite static void axienet_reset(XilinxAXIEnet *s) 40693f1e401SEdgar E. Iglesias { 40793f1e401SEdgar E. Iglesias axienet_rx_reset(s); 40893f1e401SEdgar E. Iglesias axienet_tx_reset(s); 40993f1e401SEdgar E. Iglesias 41093f1e401SEdgar E. Iglesias s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS; 41193f1e401SEdgar E. Iglesias s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE; 41293f1e401SEdgar E. Iglesias 41393f1e401SEdgar E. Iglesias s->emmc = EMMC_LINKSPEED_100MB; 41493f1e401SEdgar E. Iglesias } 41593f1e401SEdgar E. Iglesias 416545129e5SPeter Crosthwaite static void enet_update_irq(XilinxAXIEnet *s) 41793f1e401SEdgar E. Iglesias { 41893f1e401SEdgar E. Iglesias s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE]; 41993f1e401SEdgar E. Iglesias qemu_set_irq(s->irq, !!s->regs[R_IP]); 42093f1e401SEdgar E. Iglesias } 42193f1e401SEdgar E. Iglesias 422a8170e5eSAvi Kivity static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size) 42393f1e401SEdgar E. Iglesias { 424545129e5SPeter Crosthwaite XilinxAXIEnet *s = opaque; 42593f1e401SEdgar E. Iglesias uint32_t r = 0; 42693f1e401SEdgar E. Iglesias addr >>= 2; 42793f1e401SEdgar E. Iglesias 42893f1e401SEdgar E. Iglesias switch (addr) { 42993f1e401SEdgar E. Iglesias case R_RCW0: 43093f1e401SEdgar E. Iglesias case R_RCW1: 43193f1e401SEdgar E. Iglesias r = s->rcw[addr & 1]; 43293f1e401SEdgar E. Iglesias break; 43393f1e401SEdgar E. Iglesias 43493f1e401SEdgar E. Iglesias case R_TC: 43593f1e401SEdgar E. Iglesias r = s->tc; 43693f1e401SEdgar E. Iglesias break; 43793f1e401SEdgar E. Iglesias 43893f1e401SEdgar E. Iglesias case R_EMMC: 43993f1e401SEdgar E. Iglesias r = s->emmc; 44093f1e401SEdgar E. Iglesias break; 44193f1e401SEdgar E. Iglesias 44293f1e401SEdgar E. Iglesias case R_PHYC: 44393f1e401SEdgar E. Iglesias r = s->phyc; 44493f1e401SEdgar E. Iglesias break; 44593f1e401SEdgar E. Iglesias 44693f1e401SEdgar E. Iglesias case R_MCR: 44793f1e401SEdgar E. Iglesias r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready. */ 44893f1e401SEdgar E. Iglesias break; 44993f1e401SEdgar E. Iglesias 45093f1e401SEdgar E. Iglesias case R_STATS_RX_BYTESL: 45193f1e401SEdgar E. Iglesias case R_STATS_RX_BYTESH: 45293f1e401SEdgar E. Iglesias r = s->stats.rx_bytes >> (32 * (addr & 1)); 45393f1e401SEdgar E. Iglesias break; 45493f1e401SEdgar E. Iglesias 45593f1e401SEdgar E. Iglesias case R_STATS_TX_BYTESL: 45693f1e401SEdgar E. Iglesias case R_STATS_TX_BYTESH: 45793f1e401SEdgar E. Iglesias r = s->stats.tx_bytes >> (32 * (addr & 1)); 45893f1e401SEdgar E. Iglesias break; 45993f1e401SEdgar E. Iglesias 46093f1e401SEdgar E. Iglesias case R_STATS_RXL: 46193f1e401SEdgar E. Iglesias case R_STATS_RXH: 46293f1e401SEdgar E. Iglesias r = s->stats.rx >> (32 * (addr & 1)); 46393f1e401SEdgar E. Iglesias break; 46493f1e401SEdgar E. Iglesias case R_STATS_RX_BCASTL: 46593f1e401SEdgar E. Iglesias case R_STATS_RX_BCASTH: 46693f1e401SEdgar E. Iglesias r = s->stats.rx_bcast >> (32 * (addr & 1)); 46793f1e401SEdgar E. Iglesias break; 46893f1e401SEdgar E. Iglesias case R_STATS_RX_MCASTL: 46993f1e401SEdgar E. Iglesias case R_STATS_RX_MCASTH: 47093f1e401SEdgar E. Iglesias r = s->stats.rx_mcast >> (32 * (addr & 1)); 47193f1e401SEdgar E. Iglesias break; 47293f1e401SEdgar E. Iglesias 47393f1e401SEdgar E. Iglesias case R_MC: 47493f1e401SEdgar E. Iglesias case R_MWD: 47593f1e401SEdgar E. Iglesias case R_MRD: 47693f1e401SEdgar E. Iglesias r = s->mii.regs[addr & 3]; 47793f1e401SEdgar E. Iglesias break; 47893f1e401SEdgar E. Iglesias 47993f1e401SEdgar E. Iglesias case R_UAW0: 48093f1e401SEdgar E. Iglesias case R_UAW1: 48193f1e401SEdgar E. Iglesias r = s->uaw[addr & 1]; 48293f1e401SEdgar E. Iglesias break; 48393f1e401SEdgar E. Iglesias 48493f1e401SEdgar E. Iglesias case R_UAWU: 48593f1e401SEdgar E. Iglesias case R_UAWL: 48693f1e401SEdgar E. Iglesias r = s->ext_uaw[addr & 1]; 48793f1e401SEdgar E. Iglesias break; 48893f1e401SEdgar E. Iglesias 48993f1e401SEdgar E. Iglesias case R_FMI: 49093f1e401SEdgar E. Iglesias r = s->fmi; 49193f1e401SEdgar E. Iglesias break; 49293f1e401SEdgar E. Iglesias 49393f1e401SEdgar E. Iglesias case R_AF0: 49493f1e401SEdgar E. Iglesias case R_AF1: 49593f1e401SEdgar E. Iglesias r = s->maddr[s->fmi & 3][addr & 1]; 49693f1e401SEdgar E. Iglesias break; 49793f1e401SEdgar E. Iglesias 49893f1e401SEdgar E. Iglesias case 0x8000 ... 0x83ff: 49993f1e401SEdgar E. Iglesias r = s->ext_mtable[addr - 0x8000]; 50093f1e401SEdgar E. Iglesias break; 50193f1e401SEdgar E. Iglesias 50293f1e401SEdgar E. Iglesias default: 50393f1e401SEdgar E. Iglesias if (addr < ARRAY_SIZE(s->regs)) { 50493f1e401SEdgar E. Iglesias r = s->regs[addr]; 50593f1e401SEdgar E. Iglesias } 50693f1e401SEdgar E. Iglesias DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n", 50793f1e401SEdgar E. Iglesias __func__, addr * 4, r)); 50893f1e401SEdgar E. Iglesias break; 50993f1e401SEdgar E. Iglesias } 51093f1e401SEdgar E. Iglesias return r; 51193f1e401SEdgar E. Iglesias } 51293f1e401SEdgar E. Iglesias 513a8170e5eSAvi Kivity static void enet_write(void *opaque, hwaddr addr, 5140dc31f3bSAvi Kivity uint64_t value, unsigned size) 51593f1e401SEdgar E. Iglesias { 516545129e5SPeter Crosthwaite XilinxAXIEnet *s = opaque; 51793f1e401SEdgar E. Iglesias struct TEMAC *t = &s->TEMAC; 51893f1e401SEdgar E. Iglesias 51993f1e401SEdgar E. Iglesias addr >>= 2; 52093f1e401SEdgar E. Iglesias switch (addr) { 52193f1e401SEdgar E. Iglesias case R_RCW0: 52293f1e401SEdgar E. Iglesias case R_RCW1: 52393f1e401SEdgar E. Iglesias s->rcw[addr & 1] = value; 52493f1e401SEdgar E. Iglesias if ((addr & 1) && value & RCW1_RST) { 52593f1e401SEdgar E. Iglesias axienet_rx_reset(s); 5264dbb9ed3SPeter Crosthwaite } else { 5274dbb9ed3SPeter Crosthwaite qemu_flush_queued_packets(qemu_get_queue(s->nic)); 52893f1e401SEdgar E. Iglesias } 52993f1e401SEdgar E. Iglesias break; 53093f1e401SEdgar E. Iglesias 53193f1e401SEdgar E. Iglesias case R_TC: 53293f1e401SEdgar E. Iglesias s->tc = value; 53393f1e401SEdgar E. Iglesias if (value & TC_RST) { 53493f1e401SEdgar E. Iglesias axienet_tx_reset(s); 53593f1e401SEdgar E. Iglesias } 53693f1e401SEdgar E. Iglesias break; 53793f1e401SEdgar E. Iglesias 53893f1e401SEdgar E. Iglesias case R_EMMC: 53993f1e401SEdgar E. Iglesias s->emmc = value; 54093f1e401SEdgar E. Iglesias break; 54193f1e401SEdgar E. Iglesias 54293f1e401SEdgar E. Iglesias case R_PHYC: 54393f1e401SEdgar E. Iglesias s->phyc = value; 54493f1e401SEdgar E. Iglesias break; 54593f1e401SEdgar E. Iglesias 54693f1e401SEdgar E. Iglesias case R_MC: 54793f1e401SEdgar E. Iglesias value &= ((1 < 7) - 1); 54893f1e401SEdgar E. Iglesias 54993f1e401SEdgar E. Iglesias /* Enable the MII. */ 55093f1e401SEdgar E. Iglesias if (value & MC_EN) { 55193f1e401SEdgar E. Iglesias unsigned int miiclkdiv = value & ((1 << 6) - 1); 55293f1e401SEdgar E. Iglesias if (!miiclkdiv) { 55393f1e401SEdgar E. Iglesias qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n"); 55493f1e401SEdgar E. Iglesias } 55593f1e401SEdgar E. Iglesias } 55693f1e401SEdgar E. Iglesias s->mii.mc = value; 55793f1e401SEdgar E. Iglesias break; 55893f1e401SEdgar E. Iglesias 55993f1e401SEdgar E. Iglesias case R_MCR: { 56093f1e401SEdgar E. Iglesias unsigned int phyaddr = (value >> 24) & 0x1f; 56193f1e401SEdgar E. Iglesias unsigned int regaddr = (value >> 16) & 0x1f; 56293f1e401SEdgar E. Iglesias unsigned int op = (value >> 14) & 3; 56393f1e401SEdgar E. Iglesias unsigned int initiate = (value >> 11) & 1; 56493f1e401SEdgar E. Iglesias 56593f1e401SEdgar E. Iglesias if (initiate) { 56693f1e401SEdgar E. Iglesias if (op == 1) { 56793f1e401SEdgar E. Iglesias mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd); 56893f1e401SEdgar E. Iglesias } else if (op == 2) { 56993f1e401SEdgar E. Iglesias s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr); 57093f1e401SEdgar E. Iglesias } else { 57193f1e401SEdgar E. Iglesias qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op); 57293f1e401SEdgar E. Iglesias } 57393f1e401SEdgar E. Iglesias } 57493f1e401SEdgar E. Iglesias s->mii.mcr = value; 57593f1e401SEdgar E. Iglesias break; 57693f1e401SEdgar E. Iglesias } 57793f1e401SEdgar E. Iglesias 57893f1e401SEdgar E. Iglesias case R_MWD: 57993f1e401SEdgar E. Iglesias case R_MRD: 58093f1e401SEdgar E. Iglesias s->mii.regs[addr & 3] = value; 58193f1e401SEdgar E. Iglesias break; 58293f1e401SEdgar E. Iglesias 58393f1e401SEdgar E. Iglesias 58493f1e401SEdgar E. Iglesias case R_UAW0: 58593f1e401SEdgar E. Iglesias case R_UAW1: 58693f1e401SEdgar E. Iglesias s->uaw[addr & 1] = value; 58793f1e401SEdgar E. Iglesias break; 58893f1e401SEdgar E. Iglesias 58993f1e401SEdgar E. Iglesias case R_UAWL: 59093f1e401SEdgar E. Iglesias case R_UAWU: 59193f1e401SEdgar E. Iglesias s->ext_uaw[addr & 1] = value; 59293f1e401SEdgar E. Iglesias break; 59393f1e401SEdgar E. Iglesias 59493f1e401SEdgar E. Iglesias case R_FMI: 59593f1e401SEdgar E. Iglesias s->fmi = value; 59693f1e401SEdgar E. Iglesias break; 59793f1e401SEdgar E. Iglesias 59893f1e401SEdgar E. Iglesias case R_AF0: 59993f1e401SEdgar E. Iglesias case R_AF1: 60093f1e401SEdgar E. Iglesias s->maddr[s->fmi & 3][addr & 1] = value; 60193f1e401SEdgar E. Iglesias break; 60293f1e401SEdgar E. Iglesias 603d4d230daSPeter Crosthwaite case R_IS: 604d4d230daSPeter Crosthwaite s->regs[addr] &= ~value; 605d4d230daSPeter Crosthwaite break; 606d4d230daSPeter Crosthwaite 60793f1e401SEdgar E. Iglesias case 0x8000 ... 0x83ff: 60893f1e401SEdgar E. Iglesias s->ext_mtable[addr - 0x8000] = value; 60993f1e401SEdgar E. Iglesias break; 61093f1e401SEdgar E. Iglesias 61193f1e401SEdgar E. Iglesias default: 61293f1e401SEdgar E. Iglesias DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n", 6130dc31f3bSAvi Kivity __func__, addr * 4, (unsigned)value)); 61493f1e401SEdgar E. Iglesias if (addr < ARRAY_SIZE(s->regs)) { 61593f1e401SEdgar E. Iglesias s->regs[addr] = value; 61693f1e401SEdgar E. Iglesias } 61793f1e401SEdgar E. Iglesias break; 61893f1e401SEdgar E. Iglesias } 61993f1e401SEdgar E. Iglesias enet_update_irq(s); 62093f1e401SEdgar E. Iglesias } 62193f1e401SEdgar E. Iglesias 6220dc31f3bSAvi Kivity static const MemoryRegionOps enet_ops = { 6230dc31f3bSAvi Kivity .read = enet_read, 6240dc31f3bSAvi Kivity .write = enet_write, 6250dc31f3bSAvi Kivity .endianness = DEVICE_LITTLE_ENDIAN, 62693f1e401SEdgar E. Iglesias }; 62793f1e401SEdgar E. Iglesias 6284e68f7a0SStefan Hajnoczi static int eth_can_rx(NetClientState *nc) 62993f1e401SEdgar E. Iglesias { 630545129e5SPeter Crosthwaite XilinxAXIEnet *s = qemu_get_nic_opaque(nc); 63193f1e401SEdgar E. Iglesias 63293f1e401SEdgar E. Iglesias /* RX enabled? */ 63393f1e401SEdgar E. Iglesias return !axienet_rx_resetting(s) && axienet_rx_enabled(s); 63493f1e401SEdgar E. Iglesias } 63593f1e401SEdgar E. Iglesias 63693f1e401SEdgar E. Iglesias static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1) 63793f1e401SEdgar E. Iglesias { 63893f1e401SEdgar E. Iglesias int match = 1; 63993f1e401SEdgar E. Iglesias 64093f1e401SEdgar E. Iglesias if (memcmp(buf, &f0, 4)) { 64193f1e401SEdgar E. Iglesias match = 0; 64293f1e401SEdgar E. Iglesias } 64393f1e401SEdgar E. Iglesias 64493f1e401SEdgar E. Iglesias if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) { 64593f1e401SEdgar E. Iglesias match = 0; 64693f1e401SEdgar E. Iglesias } 64793f1e401SEdgar E. Iglesias 64893f1e401SEdgar E. Iglesias return match; 64993f1e401SEdgar E. Iglesias } 65093f1e401SEdgar E. Iglesias 6514e68f7a0SStefan Hajnoczi static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) 65293f1e401SEdgar E. Iglesias { 653545129e5SPeter Crosthwaite XilinxAXIEnet *s = qemu_get_nic_opaque(nc); 65493f1e401SEdgar E. Iglesias static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 65593f1e401SEdgar E. Iglesias 0xff, 0xff, 0xff}; 65693f1e401SEdgar E. Iglesias static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52}; 65793f1e401SEdgar E. Iglesias uint32_t app[6] = {0}; 65893f1e401SEdgar E. Iglesias int promisc = s->fmi & (1 << 31); 65993f1e401SEdgar E. Iglesias int unicast, broadcast, multicast, ip_multicast = 0; 66093f1e401SEdgar E. Iglesias uint32_t csum32; 66193f1e401SEdgar E. Iglesias uint16_t csum16; 66293f1e401SEdgar E. Iglesias int i; 66393f1e401SEdgar E. Iglesias 66493f1e401SEdgar E. Iglesias DENET(qemu_log("%s: %zd bytes\n", __func__, size)); 66593f1e401SEdgar E. Iglesias 66693f1e401SEdgar E. Iglesias unicast = ~buf[0] & 0x1; 66793f1e401SEdgar E. Iglesias broadcast = memcmp(buf, sa_bcast, 6) == 0; 66893f1e401SEdgar E. Iglesias multicast = !unicast && !broadcast; 66993f1e401SEdgar E. Iglesias if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) { 67093f1e401SEdgar E. Iglesias ip_multicast = 1; 67193f1e401SEdgar E. Iglesias } 67293f1e401SEdgar E. Iglesias 67393f1e401SEdgar E. Iglesias /* Jumbo or vlan sizes ? */ 67493f1e401SEdgar E. Iglesias if (!(s->rcw[1] & RCW1_JUM)) { 67593f1e401SEdgar E. Iglesias if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) { 67693f1e401SEdgar E. Iglesias return size; 67793f1e401SEdgar E. Iglesias } 67893f1e401SEdgar E. Iglesias } 67993f1e401SEdgar E. Iglesias 68093f1e401SEdgar E. Iglesias /* Basic Address filters. If you want to use the extended filters 68193f1e401SEdgar E. Iglesias you'll generally have to place the ethernet mac into promiscuous mode 68293f1e401SEdgar E. Iglesias to avoid the basic filtering from dropping most frames. */ 68393f1e401SEdgar E. Iglesias if (!promisc) { 68493f1e401SEdgar E. Iglesias if (unicast) { 68593f1e401SEdgar E. Iglesias if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) { 68693f1e401SEdgar E. Iglesias return size; 68793f1e401SEdgar E. Iglesias } 68893f1e401SEdgar E. Iglesias } else { 68993f1e401SEdgar E. Iglesias if (broadcast) { 69093f1e401SEdgar E. Iglesias /* Broadcast. */ 69193f1e401SEdgar E. Iglesias if (s->regs[R_RAF] & RAF_BCAST_REJ) { 69293f1e401SEdgar E. Iglesias return size; 69393f1e401SEdgar E. Iglesias } 69493f1e401SEdgar E. Iglesias } else { 69593f1e401SEdgar E. Iglesias int drop = 1; 69693f1e401SEdgar E. Iglesias 69793f1e401SEdgar E. Iglesias /* Multicast. */ 69893f1e401SEdgar E. Iglesias if (s->regs[R_RAF] & RAF_MCAST_REJ) { 69993f1e401SEdgar E. Iglesias return size; 70093f1e401SEdgar E. Iglesias } 70193f1e401SEdgar E. Iglesias 70293f1e401SEdgar E. Iglesias for (i = 0; i < 4; i++) { 70393f1e401SEdgar E. Iglesias if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) { 70493f1e401SEdgar E. Iglesias drop = 0; 70593f1e401SEdgar E. Iglesias break; 70693f1e401SEdgar E. Iglesias } 70793f1e401SEdgar E. Iglesias } 70893f1e401SEdgar E. Iglesias 70993f1e401SEdgar E. Iglesias if (drop) { 71093f1e401SEdgar E. Iglesias return size; 71193f1e401SEdgar E. Iglesias } 71293f1e401SEdgar E. Iglesias } 71393f1e401SEdgar E. Iglesias } 71493f1e401SEdgar E. Iglesias } 71593f1e401SEdgar E. Iglesias 71693f1e401SEdgar E. Iglesias /* Extended mcast filtering enabled? */ 71793f1e401SEdgar E. Iglesias if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) { 71893f1e401SEdgar E. Iglesias if (unicast) { 71993f1e401SEdgar E. Iglesias if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) { 72093f1e401SEdgar E. Iglesias return size; 72193f1e401SEdgar E. Iglesias } 72293f1e401SEdgar E. Iglesias } else { 72393f1e401SEdgar E. Iglesias if (broadcast) { 72493f1e401SEdgar E. Iglesias /* Broadcast. ??? */ 72593f1e401SEdgar E. Iglesias if (s->regs[R_RAF] & RAF_BCAST_REJ) { 72693f1e401SEdgar E. Iglesias return size; 72793f1e401SEdgar E. Iglesias } 72893f1e401SEdgar E. Iglesias } else { 72993f1e401SEdgar E. Iglesias int idx, bit; 73093f1e401SEdgar E. Iglesias 73193f1e401SEdgar E. Iglesias /* Multicast. */ 73293f1e401SEdgar E. Iglesias if (!memcmp(buf, sa_ipmcast, 3)) { 73393f1e401SEdgar E. Iglesias return size; 73493f1e401SEdgar E. Iglesias } 73593f1e401SEdgar E. Iglesias 73693f1e401SEdgar E. Iglesias idx = (buf[4] & 0x7f) << 8; 73793f1e401SEdgar E. Iglesias idx |= buf[5]; 73893f1e401SEdgar E. Iglesias 73993f1e401SEdgar E. Iglesias bit = 1 << (idx & 0x1f); 74093f1e401SEdgar E. Iglesias idx >>= 5; 74193f1e401SEdgar E. Iglesias 74293f1e401SEdgar E. Iglesias if (!(s->ext_mtable[idx] & bit)) { 74393f1e401SEdgar E. Iglesias return size; 74493f1e401SEdgar E. Iglesias } 74593f1e401SEdgar E. Iglesias } 74693f1e401SEdgar E. Iglesias } 74793f1e401SEdgar E. Iglesias } 74893f1e401SEdgar E. Iglesias 74993f1e401SEdgar E. Iglesias if (size < 12) { 75093f1e401SEdgar E. Iglesias s->regs[R_IS] |= IS_RX_REJECT; 75193f1e401SEdgar E. Iglesias enet_update_irq(s); 75293f1e401SEdgar E. Iglesias return -1; 75393f1e401SEdgar E. Iglesias } 75493f1e401SEdgar E. Iglesias 75593f1e401SEdgar E. Iglesias if (size > (s->c_rxmem - 4)) { 75693f1e401SEdgar E. Iglesias size = s->c_rxmem - 4; 75793f1e401SEdgar E. Iglesias } 75893f1e401SEdgar E. Iglesias 75993f1e401SEdgar E. Iglesias memcpy(s->rxmem, buf, size); 76093f1e401SEdgar E. Iglesias memset(s->rxmem + size, 0, 4); /* Clear the FCS. */ 76193f1e401SEdgar E. Iglesias 76293f1e401SEdgar E. Iglesias if (s->rcw[1] & RCW1_FCS) { 76393f1e401SEdgar E. Iglesias size += 4; /* fcs is inband. */ 76493f1e401SEdgar E. Iglesias } 76593f1e401SEdgar E. Iglesias 76693f1e401SEdgar E. Iglesias app[0] = 5 << 28; 76793f1e401SEdgar E. Iglesias csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14); 76893f1e401SEdgar E. Iglesias /* Fold it once. */ 76993f1e401SEdgar E. Iglesias csum32 = (csum32 & 0xffff) + (csum32 >> 16); 77093f1e401SEdgar E. Iglesias /* And twice to get rid of possible carries. */ 77193f1e401SEdgar E. Iglesias csum16 = (csum32 & 0xffff) + (csum32 >> 16); 77293f1e401SEdgar E. Iglesias app[3] = csum16; 77393f1e401SEdgar E. Iglesias app[4] = size & 0xffff; 77493f1e401SEdgar E. Iglesias 77593f1e401SEdgar E. Iglesias s->stats.rx_bytes += size; 77693f1e401SEdgar E. Iglesias s->stats.rx++; 77793f1e401SEdgar E. Iglesias if (multicast) { 77893f1e401SEdgar E. Iglesias s->stats.rx_mcast++; 77993f1e401SEdgar E. Iglesias app[2] |= 1 | (ip_multicast << 1); 78093f1e401SEdgar E. Iglesias } else if (broadcast) { 78193f1e401SEdgar E. Iglesias s->stats.rx_bcast++; 78293f1e401SEdgar E. Iglesias app[2] |= 1 << 3; 78393f1e401SEdgar E. Iglesias } 78493f1e401SEdgar E. Iglesias 78593f1e401SEdgar E. Iglesias /* Good frame. */ 78693f1e401SEdgar E. Iglesias app[2] |= 1 << 6; 78793f1e401SEdgar E. Iglesias 788669b4983SPeter A. G. Crosthwaite stream_push(s->tx_dev, (void *)s->rxmem, size, app); 78993f1e401SEdgar E. Iglesias 79093f1e401SEdgar E. Iglesias s->regs[R_IS] |= IS_RX_COMPLETE; 79193f1e401SEdgar E. Iglesias enet_update_irq(s); 79293f1e401SEdgar E. Iglesias return size; 79393f1e401SEdgar E. Iglesias } 79493f1e401SEdgar E. Iglesias 7954e68f7a0SStefan Hajnoczi static void eth_cleanup(NetClientState *nc) 79693f1e401SEdgar E. Iglesias { 79793f1e401SEdgar E. Iglesias /* FIXME. */ 798545129e5SPeter Crosthwaite XilinxAXIEnet *s = qemu_get_nic_opaque(nc); 7997267c094SAnthony Liguori g_free(s->rxmem); 8007267c094SAnthony Liguori g_free(s); 80193f1e401SEdgar E. Iglesias } 80293f1e401SEdgar E. Iglesias 80393f1e401SEdgar E. Iglesias static void 804669b4983SPeter A. G. Crosthwaite axienet_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t *hdr) 80593f1e401SEdgar E. Iglesias { 806545129e5SPeter Crosthwaite XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj)); 80793f1e401SEdgar E. Iglesias 80893f1e401SEdgar E. Iglesias /* TX enable ? */ 80993f1e401SEdgar E. Iglesias if (!(s->tc & TC_TX)) { 81093f1e401SEdgar E. Iglesias return; 81193f1e401SEdgar E. Iglesias } 81293f1e401SEdgar E. Iglesias 81393f1e401SEdgar E. Iglesias /* Jumbo or vlan sizes ? */ 81493f1e401SEdgar E. Iglesias if (!(s->tc & TC_JUM)) { 81593f1e401SEdgar E. Iglesias if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) { 81693f1e401SEdgar E. Iglesias return; 81793f1e401SEdgar E. Iglesias } 81893f1e401SEdgar E. Iglesias } 81993f1e401SEdgar E. Iglesias 82093f1e401SEdgar E. Iglesias if (hdr[0] & 1) { 82193f1e401SEdgar E. Iglesias unsigned int start_off = hdr[1] >> 16; 82293f1e401SEdgar E. Iglesias unsigned int write_off = hdr[1] & 0xffff; 82393f1e401SEdgar E. Iglesias uint32_t tmp_csum; 82493f1e401SEdgar E. Iglesias uint16_t csum; 82593f1e401SEdgar E. Iglesias 82693f1e401SEdgar E. Iglesias tmp_csum = net_checksum_add(size - start_off, 82793f1e401SEdgar E. Iglesias (uint8_t *)buf + start_off); 82893f1e401SEdgar E. Iglesias /* Accumulate the seed. */ 82993f1e401SEdgar E. Iglesias tmp_csum += hdr[2] & 0xffff; 83093f1e401SEdgar E. Iglesias 83193f1e401SEdgar E. Iglesias /* Fold the 32bit partial checksum. */ 83293f1e401SEdgar E. Iglesias csum = net_checksum_finish(tmp_csum); 83393f1e401SEdgar E. Iglesias 83493f1e401SEdgar E. Iglesias /* Writeback. */ 83593f1e401SEdgar E. Iglesias buf[write_off] = csum >> 8; 83693f1e401SEdgar E. Iglesias buf[write_off + 1] = csum & 0xff; 83793f1e401SEdgar E. Iglesias } 83893f1e401SEdgar E. Iglesias 839b356f76dSJason Wang qemu_send_packet(qemu_get_queue(s->nic), buf, size); 84093f1e401SEdgar E. Iglesias 84193f1e401SEdgar E. Iglesias s->stats.tx_bytes += size; 84293f1e401SEdgar E. Iglesias s->regs[R_IS] |= IS_TX_COMPLETE; 84393f1e401SEdgar E. Iglesias enet_update_irq(s); 84493f1e401SEdgar E. Iglesias } 84593f1e401SEdgar E. Iglesias 84693f1e401SEdgar E. Iglesias static NetClientInfo net_xilinx_enet_info = { 8472be64a68SLaszlo Ersek .type = NET_CLIENT_OPTIONS_KIND_NIC, 84893f1e401SEdgar E. Iglesias .size = sizeof(NICState), 84993f1e401SEdgar E. Iglesias .can_receive = eth_can_rx, 85093f1e401SEdgar E. Iglesias .receive = eth_rx, 85193f1e401SEdgar E. Iglesias .cleanup = eth_cleanup, 85293f1e401SEdgar E. Iglesias }; 85393f1e401SEdgar E. Iglesias 85493f1e401SEdgar E. Iglesias static int xilinx_enet_init(SysBusDevice *dev) 85593f1e401SEdgar E. Iglesias { 856*f0e7a81cSPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(dev); 85793f1e401SEdgar E. Iglesias 85893f1e401SEdgar E. Iglesias sysbus_init_irq(dev, &s->irq); 85993f1e401SEdgar E. Iglesias 8600dc31f3bSAvi Kivity memory_region_init_io(&s->iomem, &enet_ops, s, "enet", 0x40000); 861750ecd44SAvi Kivity sysbus_init_mmio(dev, &s->iomem); 86293f1e401SEdgar E. Iglesias 86393f1e401SEdgar E. Iglesias qemu_macaddr_default_if_unset(&s->conf.macaddr); 86493f1e401SEdgar E. Iglesias s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf, 865f79f2bfcSAnthony Liguori object_get_typename(OBJECT(dev)), dev->qdev.id, s); 866b356f76dSJason Wang qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); 86793f1e401SEdgar E. Iglesias 86893f1e401SEdgar E. Iglesias tdk_init(&s->TEMAC.phy); 86993f1e401SEdgar E. Iglesias mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr); 87093f1e401SEdgar E. Iglesias 87193f1e401SEdgar E. Iglesias s->TEMAC.parent = s; 87293f1e401SEdgar E. Iglesias 8737267c094SAnthony Liguori s->rxmem = g_malloc(s->c_rxmem); 87493f1e401SEdgar E. Iglesias axienet_reset(s); 87593f1e401SEdgar E. Iglesias 87693f1e401SEdgar E. Iglesias return 0; 87793f1e401SEdgar E. Iglesias } 87893f1e401SEdgar E. Iglesias 879669b4983SPeter A. G. Crosthwaite static void xilinx_enet_initfn(Object *obj) 880669b4983SPeter A. G. Crosthwaite { 881*f0e7a81cSPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(obj); 882b15aaca4SPeter Crosthwaite Error *errp = NULL; 883669b4983SPeter A. G. Crosthwaite 884669b4983SPeter A. G. Crosthwaite object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE, 885b15aaca4SPeter Crosthwaite (Object **) &s->tx_dev, &errp); 886b15aaca4SPeter Crosthwaite assert_no_error(errp); 887669b4983SPeter A. G. Crosthwaite } 888669b4983SPeter A. G. Crosthwaite 889999e12bbSAnthony Liguori static Property xilinx_enet_properties[] = { 890545129e5SPeter Crosthwaite DEFINE_PROP_UINT32("phyaddr", XilinxAXIEnet, c_phyaddr, 7), 891545129e5SPeter Crosthwaite DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000), 892545129e5SPeter Crosthwaite DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000), 893545129e5SPeter Crosthwaite DEFINE_NIC_PROPERTIES(XilinxAXIEnet, conf), 89493f1e401SEdgar E. Iglesias DEFINE_PROP_END_OF_LIST(), 895999e12bbSAnthony Liguori }; 896999e12bbSAnthony Liguori 897999e12bbSAnthony Liguori static void xilinx_enet_class_init(ObjectClass *klass, void *data) 898999e12bbSAnthony Liguori { 89939bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 900999e12bbSAnthony Liguori SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 901669b4983SPeter A. G. Crosthwaite StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass); 902999e12bbSAnthony Liguori 903999e12bbSAnthony Liguori k->init = xilinx_enet_init; 90439bffca2SAnthony Liguori dc->props = xilinx_enet_properties; 905669b4983SPeter A. G. Crosthwaite ssc->push = axienet_stream_push; 90693f1e401SEdgar E. Iglesias } 907999e12bbSAnthony Liguori 9088c43a6f0SAndreas Färber static const TypeInfo xilinx_enet_info = { 909*f0e7a81cSPeter Crosthwaite .name = TYPE_XILINX_AXI_ENET, 91039bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 911545129e5SPeter Crosthwaite .instance_size = sizeof(XilinxAXIEnet), 912999e12bbSAnthony Liguori .class_init = xilinx_enet_class_init, 913669b4983SPeter A. G. Crosthwaite .instance_init = xilinx_enet_initfn, 914669b4983SPeter A. G. Crosthwaite .interfaces = (InterfaceInfo[]) { 915669b4983SPeter A. G. Crosthwaite { TYPE_STREAM_SLAVE }, 916669b4983SPeter A. G. Crosthwaite { } 917669b4983SPeter A. G. Crosthwaite } 91893f1e401SEdgar E. Iglesias }; 91983f7d43aSAndreas Färber 92083f7d43aSAndreas Färber static void xilinx_enet_register_types(void) 92193f1e401SEdgar E. Iglesias { 92239bffca2SAnthony Liguori type_register_static(&xilinx_enet_info); 92393f1e401SEdgar E. Iglesias } 92493f1e401SEdgar E. Iglesias 92583f7d43aSAndreas Färber type_init(xilinx_enet_register_types) 926