149ab747fSPaolo Bonzini /* 249ab747fSPaolo Bonzini * QEMU model of Xilinx AXI-Ethernet. 349ab747fSPaolo Bonzini * 449ab747fSPaolo Bonzini * Copyright (c) 2011 Edgar E. Iglesias. 549ab747fSPaolo Bonzini * 649ab747fSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 749ab747fSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 849ab747fSPaolo Bonzini * in the Software without restriction, including without limitation the rights 949ab747fSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1049ab747fSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 1149ab747fSPaolo Bonzini * furnished to do so, subject to the following conditions: 1249ab747fSPaolo Bonzini * 1349ab747fSPaolo Bonzini * The above copyright notice and this permission notice shall be included in 1449ab747fSPaolo Bonzini * all copies or substantial portions of the Software. 1549ab747fSPaolo Bonzini * 1649ab747fSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1749ab747fSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1849ab747fSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1949ab747fSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2049ab747fSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2149ab747fSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2249ab747fSPaolo Bonzini * THE SOFTWARE. 2349ab747fSPaolo Bonzini */ 2449ab747fSPaolo Bonzini 2549ab747fSPaolo Bonzini #include "hw/sysbus.h" 2649ab747fSPaolo Bonzini #include "qemu/log.h" 2749ab747fSPaolo Bonzini #include "net/net.h" 2849ab747fSPaolo Bonzini #include "net/checksum.h" 2949ab747fSPaolo Bonzini #include "qapi/qmp/qerror.h" 3049ab747fSPaolo Bonzini 3149ab747fSPaolo Bonzini #include "hw/stream.h" 3249ab747fSPaolo Bonzini 3349ab747fSPaolo Bonzini #define DPHY(x) 3449ab747fSPaolo Bonzini 35f0e7a81cSPeter Crosthwaite #define TYPE_XILINX_AXI_ENET "xlnx.axi-ethernet" 3655b3e0c2SPeter Crosthwaite #define TYPE_XILINX_AXI_ENET_DATA_STREAM "xilinx-axienet-data-stream" 37f0e7a81cSPeter Crosthwaite 38f0e7a81cSPeter Crosthwaite #define XILINX_AXI_ENET(obj) \ 39f0e7a81cSPeter Crosthwaite OBJECT_CHECK(XilinxAXIEnet, (obj), TYPE_XILINX_AXI_ENET) 40f0e7a81cSPeter Crosthwaite 4155b3e0c2SPeter Crosthwaite #define XILINX_AXI_ENET_DATA_STREAM(obj) \ 4255b3e0c2SPeter Crosthwaite OBJECT_CHECK(XilinxAXIEnetStreamSlave, (obj),\ 4355b3e0c2SPeter Crosthwaite TYPE_XILINX_AXI_ENET_DATA_STREAM) 4455b3e0c2SPeter Crosthwaite 4549ab747fSPaolo Bonzini /* Advertisement control register. */ 4649ab747fSPaolo Bonzini #define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ 4749ab747fSPaolo Bonzini #define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ 4849ab747fSPaolo Bonzini #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ 4949ab747fSPaolo Bonzini #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ 5049ab747fSPaolo Bonzini 5149ab747fSPaolo Bonzini struct PHY { 5249ab747fSPaolo Bonzini uint32_t regs[32]; 5349ab747fSPaolo Bonzini 5449ab747fSPaolo Bonzini int link; 5549ab747fSPaolo Bonzini 5649ab747fSPaolo Bonzini unsigned int (*read)(struct PHY *phy, unsigned int req); 5749ab747fSPaolo Bonzini void (*write)(struct PHY *phy, unsigned int req, 5849ab747fSPaolo Bonzini unsigned int data); 5949ab747fSPaolo Bonzini }; 6049ab747fSPaolo Bonzini 6149ab747fSPaolo Bonzini static unsigned int tdk_read(struct PHY *phy, unsigned int req) 6249ab747fSPaolo Bonzini { 6349ab747fSPaolo Bonzini int regnum; 6449ab747fSPaolo Bonzini unsigned r = 0; 6549ab747fSPaolo Bonzini 6649ab747fSPaolo Bonzini regnum = req & 0x1f; 6749ab747fSPaolo Bonzini 6849ab747fSPaolo Bonzini switch (regnum) { 6949ab747fSPaolo Bonzini case 1: 7049ab747fSPaolo Bonzini if (!phy->link) { 7149ab747fSPaolo Bonzini break; 7249ab747fSPaolo Bonzini } 7349ab747fSPaolo Bonzini /* MR1. */ 7449ab747fSPaolo Bonzini /* Speeds and modes. */ 7549ab747fSPaolo Bonzini r |= (1 << 13) | (1 << 14); 7649ab747fSPaolo Bonzini r |= (1 << 11) | (1 << 12); 7749ab747fSPaolo Bonzini r |= (1 << 5); /* Autoneg complete. */ 7849ab747fSPaolo Bonzini r |= (1 << 3); /* Autoneg able. */ 7949ab747fSPaolo Bonzini r |= (1 << 2); /* link. */ 8049ab747fSPaolo Bonzini r |= (1 << 1); /* link. */ 8149ab747fSPaolo Bonzini break; 8249ab747fSPaolo Bonzini case 5: 8349ab747fSPaolo Bonzini /* Link partner ability. 8449ab747fSPaolo Bonzini We are kind; always agree with whatever best mode 8549ab747fSPaolo Bonzini the guest advertises. */ 8649ab747fSPaolo Bonzini r = 1 << 14; /* Success. */ 8749ab747fSPaolo Bonzini /* Copy advertised modes. */ 8849ab747fSPaolo Bonzini r |= phy->regs[4] & (15 << 5); 8949ab747fSPaolo Bonzini /* Autoneg support. */ 9049ab747fSPaolo Bonzini r |= 1; 9149ab747fSPaolo Bonzini break; 9249ab747fSPaolo Bonzini case 17: 9349ab747fSPaolo Bonzini /* Marvel PHY on many xilinx boards. */ 9449ab747fSPaolo Bonzini r = 0x8000; /* 1000Mb */ 9549ab747fSPaolo Bonzini break; 9649ab747fSPaolo Bonzini case 18: 9749ab747fSPaolo Bonzini { 9849ab747fSPaolo Bonzini /* Diagnostics reg. */ 9949ab747fSPaolo Bonzini int duplex = 0; 10049ab747fSPaolo Bonzini int speed_100 = 0; 10149ab747fSPaolo Bonzini 10249ab747fSPaolo Bonzini if (!phy->link) { 10349ab747fSPaolo Bonzini break; 10449ab747fSPaolo Bonzini } 10549ab747fSPaolo Bonzini 10649ab747fSPaolo Bonzini /* Are we advertising 100 half or 100 duplex ? */ 10749ab747fSPaolo Bonzini speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); 10849ab747fSPaolo Bonzini speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); 10949ab747fSPaolo Bonzini 11049ab747fSPaolo Bonzini /* Are we advertising 10 duplex or 100 duplex ? */ 11149ab747fSPaolo Bonzini duplex = !!(phy->regs[4] & ADVERTISE_100FULL); 11249ab747fSPaolo Bonzini duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); 11349ab747fSPaolo Bonzini r = (speed_100 << 10) | (duplex << 11); 11449ab747fSPaolo Bonzini } 11549ab747fSPaolo Bonzini break; 11649ab747fSPaolo Bonzini 11749ab747fSPaolo Bonzini default: 11849ab747fSPaolo Bonzini r = phy->regs[regnum]; 11949ab747fSPaolo Bonzini break; 12049ab747fSPaolo Bonzini } 12149ab747fSPaolo Bonzini DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum)); 12249ab747fSPaolo Bonzini return r; 12349ab747fSPaolo Bonzini } 12449ab747fSPaolo Bonzini 12549ab747fSPaolo Bonzini static void 12649ab747fSPaolo Bonzini tdk_write(struct PHY *phy, unsigned int req, unsigned int data) 12749ab747fSPaolo Bonzini { 12849ab747fSPaolo Bonzini int regnum; 12949ab747fSPaolo Bonzini 13049ab747fSPaolo Bonzini regnum = req & 0x1f; 13149ab747fSPaolo Bonzini DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data)); 13249ab747fSPaolo Bonzini switch (regnum) { 13349ab747fSPaolo Bonzini default: 13449ab747fSPaolo Bonzini phy->regs[regnum] = data; 13549ab747fSPaolo Bonzini break; 13649ab747fSPaolo Bonzini } 13749ab747fSPaolo Bonzini } 13849ab747fSPaolo Bonzini 13949ab747fSPaolo Bonzini static void 14049ab747fSPaolo Bonzini tdk_init(struct PHY *phy) 14149ab747fSPaolo Bonzini { 14249ab747fSPaolo Bonzini phy->regs[0] = 0x3100; 14349ab747fSPaolo Bonzini /* PHY Id. */ 14449ab747fSPaolo Bonzini phy->regs[2] = 0x0300; 14549ab747fSPaolo Bonzini phy->regs[3] = 0xe400; 14649ab747fSPaolo Bonzini /* Autonegotiation advertisement reg. */ 14749ab747fSPaolo Bonzini phy->regs[4] = 0x01E1; 14849ab747fSPaolo Bonzini phy->link = 1; 14949ab747fSPaolo Bonzini 15049ab747fSPaolo Bonzini phy->read = tdk_read; 15149ab747fSPaolo Bonzini phy->write = tdk_write; 15249ab747fSPaolo Bonzini } 15349ab747fSPaolo Bonzini 15449ab747fSPaolo Bonzini struct MDIOBus { 15549ab747fSPaolo Bonzini /* bus. */ 15649ab747fSPaolo Bonzini int mdc; 15749ab747fSPaolo Bonzini int mdio; 15849ab747fSPaolo Bonzini 15949ab747fSPaolo Bonzini /* decoder. */ 16049ab747fSPaolo Bonzini enum { 16149ab747fSPaolo Bonzini PREAMBLE, 16249ab747fSPaolo Bonzini SOF, 16349ab747fSPaolo Bonzini OPC, 16449ab747fSPaolo Bonzini ADDR, 16549ab747fSPaolo Bonzini REQ, 16649ab747fSPaolo Bonzini TURNAROUND, 16749ab747fSPaolo Bonzini DATA 16849ab747fSPaolo Bonzini } state; 16949ab747fSPaolo Bonzini unsigned int drive; 17049ab747fSPaolo Bonzini 17149ab747fSPaolo Bonzini unsigned int cnt; 17249ab747fSPaolo Bonzini unsigned int addr; 17349ab747fSPaolo Bonzini unsigned int opc; 17449ab747fSPaolo Bonzini unsigned int req; 17549ab747fSPaolo Bonzini unsigned int data; 17649ab747fSPaolo Bonzini 17749ab747fSPaolo Bonzini struct PHY *devs[32]; 17849ab747fSPaolo Bonzini }; 17949ab747fSPaolo Bonzini 18049ab747fSPaolo Bonzini static void 18149ab747fSPaolo Bonzini mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr) 18249ab747fSPaolo Bonzini { 18349ab747fSPaolo Bonzini bus->devs[addr & 0x1f] = phy; 18449ab747fSPaolo Bonzini } 18549ab747fSPaolo Bonzini 18649ab747fSPaolo Bonzini #ifdef USE_THIS_DEAD_CODE 18749ab747fSPaolo Bonzini static void 18849ab747fSPaolo Bonzini mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr) 18949ab747fSPaolo Bonzini { 19049ab747fSPaolo Bonzini bus->devs[addr & 0x1f] = NULL; 19149ab747fSPaolo Bonzini } 19249ab747fSPaolo Bonzini #endif 19349ab747fSPaolo Bonzini 19449ab747fSPaolo Bonzini static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr, 19549ab747fSPaolo Bonzini unsigned int reg) 19649ab747fSPaolo Bonzini { 19749ab747fSPaolo Bonzini struct PHY *phy; 19849ab747fSPaolo Bonzini uint16_t data; 19949ab747fSPaolo Bonzini 20049ab747fSPaolo Bonzini phy = bus->devs[addr]; 20149ab747fSPaolo Bonzini if (phy && phy->read) { 20249ab747fSPaolo Bonzini data = phy->read(phy, reg); 20349ab747fSPaolo Bonzini } else { 20449ab747fSPaolo Bonzini data = 0xffff; 20549ab747fSPaolo Bonzini } 20649ab747fSPaolo Bonzini DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data)); 20749ab747fSPaolo Bonzini return data; 20849ab747fSPaolo Bonzini } 20949ab747fSPaolo Bonzini 21049ab747fSPaolo Bonzini static void mdio_write_req(struct MDIOBus *bus, unsigned int addr, 21149ab747fSPaolo Bonzini unsigned int reg, uint16_t data) 21249ab747fSPaolo Bonzini { 21349ab747fSPaolo Bonzini struct PHY *phy; 21449ab747fSPaolo Bonzini 21549ab747fSPaolo Bonzini DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data)); 21649ab747fSPaolo Bonzini phy = bus->devs[addr]; 21749ab747fSPaolo Bonzini if (phy && phy->write) { 21849ab747fSPaolo Bonzini phy->write(phy, reg, data); 21949ab747fSPaolo Bonzini } 22049ab747fSPaolo Bonzini } 22149ab747fSPaolo Bonzini 22249ab747fSPaolo Bonzini #define DENET(x) 22349ab747fSPaolo Bonzini 22449ab747fSPaolo Bonzini #define R_RAF (0x000 / 4) 22549ab747fSPaolo Bonzini enum { 22649ab747fSPaolo Bonzini RAF_MCAST_REJ = (1 << 1), 22749ab747fSPaolo Bonzini RAF_BCAST_REJ = (1 << 2), 22849ab747fSPaolo Bonzini RAF_EMCF_EN = (1 << 12), 22949ab747fSPaolo Bonzini RAF_NEWFUNC_EN = (1 << 11) 23049ab747fSPaolo Bonzini }; 23149ab747fSPaolo Bonzini 23249ab747fSPaolo Bonzini #define R_IS (0x00C / 4) 23349ab747fSPaolo Bonzini enum { 23449ab747fSPaolo Bonzini IS_HARD_ACCESS_COMPLETE = 1, 23549ab747fSPaolo Bonzini IS_AUTONEG = (1 << 1), 23649ab747fSPaolo Bonzini IS_RX_COMPLETE = (1 << 2), 23749ab747fSPaolo Bonzini IS_RX_REJECT = (1 << 3), 23849ab747fSPaolo Bonzini IS_TX_COMPLETE = (1 << 5), 23949ab747fSPaolo Bonzini IS_RX_DCM_LOCK = (1 << 6), 24049ab747fSPaolo Bonzini IS_MGM_RDY = (1 << 7), 24149ab747fSPaolo Bonzini IS_PHY_RST_DONE = (1 << 8), 24249ab747fSPaolo Bonzini }; 24349ab747fSPaolo Bonzini 24449ab747fSPaolo Bonzini #define R_IP (0x010 / 4) 24549ab747fSPaolo Bonzini #define R_IE (0x014 / 4) 24649ab747fSPaolo Bonzini #define R_UAWL (0x020 / 4) 24749ab747fSPaolo Bonzini #define R_UAWU (0x024 / 4) 24849ab747fSPaolo Bonzini #define R_PPST (0x030 / 4) 24949ab747fSPaolo Bonzini enum { 25049ab747fSPaolo Bonzini PPST_LINKSTATUS = (1 << 0), 25149ab747fSPaolo Bonzini PPST_PHY_LINKSTATUS = (1 << 7), 25249ab747fSPaolo Bonzini }; 25349ab747fSPaolo Bonzini 25449ab747fSPaolo Bonzini #define R_STATS_RX_BYTESL (0x200 / 4) 25549ab747fSPaolo Bonzini #define R_STATS_RX_BYTESH (0x204 / 4) 25649ab747fSPaolo Bonzini #define R_STATS_TX_BYTESL (0x208 / 4) 25749ab747fSPaolo Bonzini #define R_STATS_TX_BYTESH (0x20C / 4) 25849ab747fSPaolo Bonzini #define R_STATS_RXL (0x290 / 4) 25949ab747fSPaolo Bonzini #define R_STATS_RXH (0x294 / 4) 26049ab747fSPaolo Bonzini #define R_STATS_RX_BCASTL (0x2a0 / 4) 26149ab747fSPaolo Bonzini #define R_STATS_RX_BCASTH (0x2a4 / 4) 26249ab747fSPaolo Bonzini #define R_STATS_RX_MCASTL (0x2a8 / 4) 26349ab747fSPaolo Bonzini #define R_STATS_RX_MCASTH (0x2ac / 4) 26449ab747fSPaolo Bonzini 26549ab747fSPaolo Bonzini #define R_RCW0 (0x400 / 4) 26649ab747fSPaolo Bonzini #define R_RCW1 (0x404 / 4) 26749ab747fSPaolo Bonzini enum { 26849ab747fSPaolo Bonzini RCW1_VLAN = (1 << 27), 26949ab747fSPaolo Bonzini RCW1_RX = (1 << 28), 27049ab747fSPaolo Bonzini RCW1_FCS = (1 << 29), 27149ab747fSPaolo Bonzini RCW1_JUM = (1 << 30), 27249ab747fSPaolo Bonzini RCW1_RST = (1 << 31), 27349ab747fSPaolo Bonzini }; 27449ab747fSPaolo Bonzini 27549ab747fSPaolo Bonzini #define R_TC (0x408 / 4) 27649ab747fSPaolo Bonzini enum { 27749ab747fSPaolo Bonzini TC_VLAN = (1 << 27), 27849ab747fSPaolo Bonzini TC_TX = (1 << 28), 27949ab747fSPaolo Bonzini TC_FCS = (1 << 29), 28049ab747fSPaolo Bonzini TC_JUM = (1 << 30), 28149ab747fSPaolo Bonzini TC_RST = (1 << 31), 28249ab747fSPaolo Bonzini }; 28349ab747fSPaolo Bonzini 28449ab747fSPaolo Bonzini #define R_EMMC (0x410 / 4) 28549ab747fSPaolo Bonzini enum { 28649ab747fSPaolo Bonzini EMMC_LINKSPEED_10MB = (0 << 30), 28749ab747fSPaolo Bonzini EMMC_LINKSPEED_100MB = (1 << 30), 28849ab747fSPaolo Bonzini EMMC_LINKSPEED_1000MB = (2 << 30), 28949ab747fSPaolo Bonzini }; 29049ab747fSPaolo Bonzini 29149ab747fSPaolo Bonzini #define R_PHYC (0x414 / 4) 29249ab747fSPaolo Bonzini 29349ab747fSPaolo Bonzini #define R_MC (0x500 / 4) 29449ab747fSPaolo Bonzini #define MC_EN (1 << 6) 29549ab747fSPaolo Bonzini 29649ab747fSPaolo Bonzini #define R_MCR (0x504 / 4) 29749ab747fSPaolo Bonzini #define R_MWD (0x508 / 4) 29849ab747fSPaolo Bonzini #define R_MRD (0x50c / 4) 29949ab747fSPaolo Bonzini #define R_MIS (0x600 / 4) 30049ab747fSPaolo Bonzini #define R_MIP (0x620 / 4) 30149ab747fSPaolo Bonzini #define R_MIE (0x640 / 4) 30249ab747fSPaolo Bonzini #define R_MIC (0x640 / 4) 30349ab747fSPaolo Bonzini 30449ab747fSPaolo Bonzini #define R_UAW0 (0x700 / 4) 30549ab747fSPaolo Bonzini #define R_UAW1 (0x704 / 4) 30649ab747fSPaolo Bonzini #define R_FMI (0x708 / 4) 30749ab747fSPaolo Bonzini #define R_AF0 (0x710 / 4) 30849ab747fSPaolo Bonzini #define R_AF1 (0x714 / 4) 30949ab747fSPaolo Bonzini #define R_MAX (0x34 / 4) 31049ab747fSPaolo Bonzini 31149ab747fSPaolo Bonzini /* Indirect registers. */ 31249ab747fSPaolo Bonzini struct TEMAC { 31349ab747fSPaolo Bonzini struct MDIOBus mdio_bus; 31449ab747fSPaolo Bonzini struct PHY phy; 31549ab747fSPaolo Bonzini 31649ab747fSPaolo Bonzini void *parent; 31749ab747fSPaolo Bonzini }; 31849ab747fSPaolo Bonzini 31955b3e0c2SPeter Crosthwaite typedef struct XilinxAXIEnetStreamSlave XilinxAXIEnetStreamSlave; 320545129e5SPeter Crosthwaite typedef struct XilinxAXIEnet XilinxAXIEnet; 321545129e5SPeter Crosthwaite 32255b3e0c2SPeter Crosthwaite struct XilinxAXIEnetStreamSlave { 32355b3e0c2SPeter Crosthwaite Object parent; 32455b3e0c2SPeter Crosthwaite 32555b3e0c2SPeter Crosthwaite struct XilinxAXIEnet *enet; 32655b3e0c2SPeter Crosthwaite } ; 32755b3e0c2SPeter Crosthwaite 32849ab747fSPaolo Bonzini struct XilinxAXIEnet { 32949ab747fSPaolo Bonzini SysBusDevice busdev; 33049ab747fSPaolo Bonzini MemoryRegion iomem; 33149ab747fSPaolo Bonzini qemu_irq irq; 33249ab747fSPaolo Bonzini StreamSlave *tx_dev; 33355b3e0c2SPeter Crosthwaite XilinxAXIEnetStreamSlave rx_data_dev; 33449ab747fSPaolo Bonzini NICState *nic; 33549ab747fSPaolo Bonzini NICConf conf; 33649ab747fSPaolo Bonzini 33749ab747fSPaolo Bonzini 33849ab747fSPaolo Bonzini uint32_t c_rxmem; 33949ab747fSPaolo Bonzini uint32_t c_txmem; 34049ab747fSPaolo Bonzini uint32_t c_phyaddr; 34149ab747fSPaolo Bonzini 34249ab747fSPaolo Bonzini struct TEMAC TEMAC; 34349ab747fSPaolo Bonzini 34449ab747fSPaolo Bonzini /* MII regs. */ 34549ab747fSPaolo Bonzini union { 34649ab747fSPaolo Bonzini uint32_t regs[4]; 34749ab747fSPaolo Bonzini struct { 34849ab747fSPaolo Bonzini uint32_t mc; 34949ab747fSPaolo Bonzini uint32_t mcr; 35049ab747fSPaolo Bonzini uint32_t mwd; 35149ab747fSPaolo Bonzini uint32_t mrd; 35249ab747fSPaolo Bonzini }; 35349ab747fSPaolo Bonzini } mii; 35449ab747fSPaolo Bonzini 35549ab747fSPaolo Bonzini struct { 35649ab747fSPaolo Bonzini uint64_t rx_bytes; 35749ab747fSPaolo Bonzini uint64_t tx_bytes; 35849ab747fSPaolo Bonzini 35949ab747fSPaolo Bonzini uint64_t rx; 36049ab747fSPaolo Bonzini uint64_t rx_bcast; 36149ab747fSPaolo Bonzini uint64_t rx_mcast; 36249ab747fSPaolo Bonzini } stats; 36349ab747fSPaolo Bonzini 36449ab747fSPaolo Bonzini /* Receive configuration words. */ 36549ab747fSPaolo Bonzini uint32_t rcw[2]; 36649ab747fSPaolo Bonzini /* Transmit config. */ 36749ab747fSPaolo Bonzini uint32_t tc; 36849ab747fSPaolo Bonzini uint32_t emmc; 36949ab747fSPaolo Bonzini uint32_t phyc; 37049ab747fSPaolo Bonzini 37149ab747fSPaolo Bonzini /* Unicast Address Word. */ 37249ab747fSPaolo Bonzini uint32_t uaw[2]; 37349ab747fSPaolo Bonzini /* Unicast address filter used with extended mcast. */ 37449ab747fSPaolo Bonzini uint32_t ext_uaw[2]; 37549ab747fSPaolo Bonzini uint32_t fmi; 37649ab747fSPaolo Bonzini 37749ab747fSPaolo Bonzini uint32_t regs[R_MAX]; 37849ab747fSPaolo Bonzini 37949ab747fSPaolo Bonzini /* Multicast filter addrs. */ 38049ab747fSPaolo Bonzini uint32_t maddr[4][2]; 38149ab747fSPaolo Bonzini /* 32K x 1 lookup filter. */ 38249ab747fSPaolo Bonzini uint32_t ext_mtable[1024]; 38349ab747fSPaolo Bonzini 38449ab747fSPaolo Bonzini 38549ab747fSPaolo Bonzini uint8_t *rxmem; 38649ab747fSPaolo Bonzini }; 38749ab747fSPaolo Bonzini 388545129e5SPeter Crosthwaite static void axienet_rx_reset(XilinxAXIEnet *s) 38949ab747fSPaolo Bonzini { 39049ab747fSPaolo Bonzini s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN; 39149ab747fSPaolo Bonzini } 39249ab747fSPaolo Bonzini 393545129e5SPeter Crosthwaite static void axienet_tx_reset(XilinxAXIEnet *s) 39449ab747fSPaolo Bonzini { 39549ab747fSPaolo Bonzini s->tc = TC_JUM | TC_TX | TC_VLAN; 39649ab747fSPaolo Bonzini } 39749ab747fSPaolo Bonzini 398545129e5SPeter Crosthwaite static inline int axienet_rx_resetting(XilinxAXIEnet *s) 39949ab747fSPaolo Bonzini { 40049ab747fSPaolo Bonzini return s->rcw[1] & RCW1_RST; 40149ab747fSPaolo Bonzini } 40249ab747fSPaolo Bonzini 403545129e5SPeter Crosthwaite static inline int axienet_rx_enabled(XilinxAXIEnet *s) 40449ab747fSPaolo Bonzini { 40549ab747fSPaolo Bonzini return s->rcw[1] & RCW1_RX; 40649ab747fSPaolo Bonzini } 40749ab747fSPaolo Bonzini 408545129e5SPeter Crosthwaite static inline int axienet_extmcf_enabled(XilinxAXIEnet *s) 40949ab747fSPaolo Bonzini { 41049ab747fSPaolo Bonzini return !!(s->regs[R_RAF] & RAF_EMCF_EN); 41149ab747fSPaolo Bonzini } 41249ab747fSPaolo Bonzini 413545129e5SPeter Crosthwaite static inline int axienet_newfunc_enabled(XilinxAXIEnet *s) 41449ab747fSPaolo Bonzini { 41549ab747fSPaolo Bonzini return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN); 41649ab747fSPaolo Bonzini } 41749ab747fSPaolo Bonzini 4189ee0ceb7SPeter Crosthwaite static void xilinx_axienet_reset(DeviceState *d) 41949ab747fSPaolo Bonzini { 4209ee0ceb7SPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(d); 4219ee0ceb7SPeter Crosthwaite 42249ab747fSPaolo Bonzini axienet_rx_reset(s); 42349ab747fSPaolo Bonzini axienet_tx_reset(s); 42449ab747fSPaolo Bonzini 42549ab747fSPaolo Bonzini s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS; 42649ab747fSPaolo Bonzini s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE; 42749ab747fSPaolo Bonzini 42849ab747fSPaolo Bonzini s->emmc = EMMC_LINKSPEED_100MB; 42949ab747fSPaolo Bonzini } 43049ab747fSPaolo Bonzini 431545129e5SPeter Crosthwaite static void enet_update_irq(XilinxAXIEnet *s) 43249ab747fSPaolo Bonzini { 43349ab747fSPaolo Bonzini s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE]; 43449ab747fSPaolo Bonzini qemu_set_irq(s->irq, !!s->regs[R_IP]); 43549ab747fSPaolo Bonzini } 43649ab747fSPaolo Bonzini 43749ab747fSPaolo Bonzini static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size) 43849ab747fSPaolo Bonzini { 439545129e5SPeter Crosthwaite XilinxAXIEnet *s = opaque; 44049ab747fSPaolo Bonzini uint32_t r = 0; 44149ab747fSPaolo Bonzini addr >>= 2; 44249ab747fSPaolo Bonzini 44349ab747fSPaolo Bonzini switch (addr) { 44449ab747fSPaolo Bonzini case R_RCW0: 44549ab747fSPaolo Bonzini case R_RCW1: 44649ab747fSPaolo Bonzini r = s->rcw[addr & 1]; 44749ab747fSPaolo Bonzini break; 44849ab747fSPaolo Bonzini 44949ab747fSPaolo Bonzini case R_TC: 45049ab747fSPaolo Bonzini r = s->tc; 45149ab747fSPaolo Bonzini break; 45249ab747fSPaolo Bonzini 45349ab747fSPaolo Bonzini case R_EMMC: 45449ab747fSPaolo Bonzini r = s->emmc; 45549ab747fSPaolo Bonzini break; 45649ab747fSPaolo Bonzini 45749ab747fSPaolo Bonzini case R_PHYC: 45849ab747fSPaolo Bonzini r = s->phyc; 45949ab747fSPaolo Bonzini break; 46049ab747fSPaolo Bonzini 46149ab747fSPaolo Bonzini case R_MCR: 46249ab747fSPaolo Bonzini r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready. */ 46349ab747fSPaolo Bonzini break; 46449ab747fSPaolo Bonzini 46549ab747fSPaolo Bonzini case R_STATS_RX_BYTESL: 46649ab747fSPaolo Bonzini case R_STATS_RX_BYTESH: 46749ab747fSPaolo Bonzini r = s->stats.rx_bytes >> (32 * (addr & 1)); 46849ab747fSPaolo Bonzini break; 46949ab747fSPaolo Bonzini 47049ab747fSPaolo Bonzini case R_STATS_TX_BYTESL: 47149ab747fSPaolo Bonzini case R_STATS_TX_BYTESH: 47249ab747fSPaolo Bonzini r = s->stats.tx_bytes >> (32 * (addr & 1)); 47349ab747fSPaolo Bonzini break; 47449ab747fSPaolo Bonzini 47549ab747fSPaolo Bonzini case R_STATS_RXL: 47649ab747fSPaolo Bonzini case R_STATS_RXH: 47749ab747fSPaolo Bonzini r = s->stats.rx >> (32 * (addr & 1)); 47849ab747fSPaolo Bonzini break; 47949ab747fSPaolo Bonzini case R_STATS_RX_BCASTL: 48049ab747fSPaolo Bonzini case R_STATS_RX_BCASTH: 48149ab747fSPaolo Bonzini r = s->stats.rx_bcast >> (32 * (addr & 1)); 48249ab747fSPaolo Bonzini break; 48349ab747fSPaolo Bonzini case R_STATS_RX_MCASTL: 48449ab747fSPaolo Bonzini case R_STATS_RX_MCASTH: 48549ab747fSPaolo Bonzini r = s->stats.rx_mcast >> (32 * (addr & 1)); 48649ab747fSPaolo Bonzini break; 48749ab747fSPaolo Bonzini 48849ab747fSPaolo Bonzini case R_MC: 48949ab747fSPaolo Bonzini case R_MWD: 49049ab747fSPaolo Bonzini case R_MRD: 49149ab747fSPaolo Bonzini r = s->mii.regs[addr & 3]; 49249ab747fSPaolo Bonzini break; 49349ab747fSPaolo Bonzini 49449ab747fSPaolo Bonzini case R_UAW0: 49549ab747fSPaolo Bonzini case R_UAW1: 49649ab747fSPaolo Bonzini r = s->uaw[addr & 1]; 49749ab747fSPaolo Bonzini break; 49849ab747fSPaolo Bonzini 49949ab747fSPaolo Bonzini case R_UAWU: 50049ab747fSPaolo Bonzini case R_UAWL: 50149ab747fSPaolo Bonzini r = s->ext_uaw[addr & 1]; 50249ab747fSPaolo Bonzini break; 50349ab747fSPaolo Bonzini 50449ab747fSPaolo Bonzini case R_FMI: 50549ab747fSPaolo Bonzini r = s->fmi; 50649ab747fSPaolo Bonzini break; 50749ab747fSPaolo Bonzini 50849ab747fSPaolo Bonzini case R_AF0: 50949ab747fSPaolo Bonzini case R_AF1: 51049ab747fSPaolo Bonzini r = s->maddr[s->fmi & 3][addr & 1]; 51149ab747fSPaolo Bonzini break; 51249ab747fSPaolo Bonzini 51349ab747fSPaolo Bonzini case 0x8000 ... 0x83ff: 51449ab747fSPaolo Bonzini r = s->ext_mtable[addr - 0x8000]; 51549ab747fSPaolo Bonzini break; 51649ab747fSPaolo Bonzini 51749ab747fSPaolo Bonzini default: 51849ab747fSPaolo Bonzini if (addr < ARRAY_SIZE(s->regs)) { 51949ab747fSPaolo Bonzini r = s->regs[addr]; 52049ab747fSPaolo Bonzini } 52149ab747fSPaolo Bonzini DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n", 52249ab747fSPaolo Bonzini __func__, addr * 4, r)); 52349ab747fSPaolo Bonzini break; 52449ab747fSPaolo Bonzini } 52549ab747fSPaolo Bonzini return r; 52649ab747fSPaolo Bonzini } 52749ab747fSPaolo Bonzini 52849ab747fSPaolo Bonzini static void enet_write(void *opaque, hwaddr addr, 52949ab747fSPaolo Bonzini uint64_t value, unsigned size) 53049ab747fSPaolo Bonzini { 531545129e5SPeter Crosthwaite XilinxAXIEnet *s = opaque; 53249ab747fSPaolo Bonzini struct TEMAC *t = &s->TEMAC; 53349ab747fSPaolo Bonzini 53449ab747fSPaolo Bonzini addr >>= 2; 53549ab747fSPaolo Bonzini switch (addr) { 53649ab747fSPaolo Bonzini case R_RCW0: 53749ab747fSPaolo Bonzini case R_RCW1: 53849ab747fSPaolo Bonzini s->rcw[addr & 1] = value; 53949ab747fSPaolo Bonzini if ((addr & 1) && value & RCW1_RST) { 54049ab747fSPaolo Bonzini axienet_rx_reset(s); 54149ab747fSPaolo Bonzini } else { 54249ab747fSPaolo Bonzini qemu_flush_queued_packets(qemu_get_queue(s->nic)); 54349ab747fSPaolo Bonzini } 54449ab747fSPaolo Bonzini break; 54549ab747fSPaolo Bonzini 54649ab747fSPaolo Bonzini case R_TC: 54749ab747fSPaolo Bonzini s->tc = value; 54849ab747fSPaolo Bonzini if (value & TC_RST) { 54949ab747fSPaolo Bonzini axienet_tx_reset(s); 55049ab747fSPaolo Bonzini } 55149ab747fSPaolo Bonzini break; 55249ab747fSPaolo Bonzini 55349ab747fSPaolo Bonzini case R_EMMC: 55449ab747fSPaolo Bonzini s->emmc = value; 55549ab747fSPaolo Bonzini break; 55649ab747fSPaolo Bonzini 55749ab747fSPaolo Bonzini case R_PHYC: 55849ab747fSPaolo Bonzini s->phyc = value; 55949ab747fSPaolo Bonzini break; 56049ab747fSPaolo Bonzini 56149ab747fSPaolo Bonzini case R_MC: 56249ab747fSPaolo Bonzini value &= ((1 < 7) - 1); 56349ab747fSPaolo Bonzini 56449ab747fSPaolo Bonzini /* Enable the MII. */ 56549ab747fSPaolo Bonzini if (value & MC_EN) { 56649ab747fSPaolo Bonzini unsigned int miiclkdiv = value & ((1 << 6) - 1); 56749ab747fSPaolo Bonzini if (!miiclkdiv) { 56849ab747fSPaolo Bonzini qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n"); 56949ab747fSPaolo Bonzini } 57049ab747fSPaolo Bonzini } 57149ab747fSPaolo Bonzini s->mii.mc = value; 57249ab747fSPaolo Bonzini break; 57349ab747fSPaolo Bonzini 57449ab747fSPaolo Bonzini case R_MCR: { 57549ab747fSPaolo Bonzini unsigned int phyaddr = (value >> 24) & 0x1f; 57649ab747fSPaolo Bonzini unsigned int regaddr = (value >> 16) & 0x1f; 57749ab747fSPaolo Bonzini unsigned int op = (value >> 14) & 3; 57849ab747fSPaolo Bonzini unsigned int initiate = (value >> 11) & 1; 57949ab747fSPaolo Bonzini 58049ab747fSPaolo Bonzini if (initiate) { 58149ab747fSPaolo Bonzini if (op == 1) { 58249ab747fSPaolo Bonzini mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd); 58349ab747fSPaolo Bonzini } else if (op == 2) { 58449ab747fSPaolo Bonzini s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr); 58549ab747fSPaolo Bonzini } else { 58649ab747fSPaolo Bonzini qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op); 58749ab747fSPaolo Bonzini } 58849ab747fSPaolo Bonzini } 58949ab747fSPaolo Bonzini s->mii.mcr = value; 59049ab747fSPaolo Bonzini break; 59149ab747fSPaolo Bonzini } 59249ab747fSPaolo Bonzini 59349ab747fSPaolo Bonzini case R_MWD: 59449ab747fSPaolo Bonzini case R_MRD: 59549ab747fSPaolo Bonzini s->mii.regs[addr & 3] = value; 59649ab747fSPaolo Bonzini break; 59749ab747fSPaolo Bonzini 59849ab747fSPaolo Bonzini 59949ab747fSPaolo Bonzini case R_UAW0: 60049ab747fSPaolo Bonzini case R_UAW1: 60149ab747fSPaolo Bonzini s->uaw[addr & 1] = value; 60249ab747fSPaolo Bonzini break; 60349ab747fSPaolo Bonzini 60449ab747fSPaolo Bonzini case R_UAWL: 60549ab747fSPaolo Bonzini case R_UAWU: 60649ab747fSPaolo Bonzini s->ext_uaw[addr & 1] = value; 60749ab747fSPaolo Bonzini break; 60849ab747fSPaolo Bonzini 60949ab747fSPaolo Bonzini case R_FMI: 61049ab747fSPaolo Bonzini s->fmi = value; 61149ab747fSPaolo Bonzini break; 61249ab747fSPaolo Bonzini 61349ab747fSPaolo Bonzini case R_AF0: 61449ab747fSPaolo Bonzini case R_AF1: 61549ab747fSPaolo Bonzini s->maddr[s->fmi & 3][addr & 1] = value; 61649ab747fSPaolo Bonzini break; 61749ab747fSPaolo Bonzini 61849ab747fSPaolo Bonzini case R_IS: 61949ab747fSPaolo Bonzini s->regs[addr] &= ~value; 62049ab747fSPaolo Bonzini break; 62149ab747fSPaolo Bonzini 62249ab747fSPaolo Bonzini case 0x8000 ... 0x83ff: 62349ab747fSPaolo Bonzini s->ext_mtable[addr - 0x8000] = value; 62449ab747fSPaolo Bonzini break; 62549ab747fSPaolo Bonzini 62649ab747fSPaolo Bonzini default: 62749ab747fSPaolo Bonzini DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n", 62849ab747fSPaolo Bonzini __func__, addr * 4, (unsigned)value)); 62949ab747fSPaolo Bonzini if (addr < ARRAY_SIZE(s->regs)) { 63049ab747fSPaolo Bonzini s->regs[addr] = value; 63149ab747fSPaolo Bonzini } 63249ab747fSPaolo Bonzini break; 63349ab747fSPaolo Bonzini } 63449ab747fSPaolo Bonzini enet_update_irq(s); 63549ab747fSPaolo Bonzini } 63649ab747fSPaolo Bonzini 63749ab747fSPaolo Bonzini static const MemoryRegionOps enet_ops = { 63849ab747fSPaolo Bonzini .read = enet_read, 63949ab747fSPaolo Bonzini .write = enet_write, 64049ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 64149ab747fSPaolo Bonzini }; 64249ab747fSPaolo Bonzini 64349ab747fSPaolo Bonzini static int eth_can_rx(NetClientState *nc) 64449ab747fSPaolo Bonzini { 645545129e5SPeter Crosthwaite XilinxAXIEnet *s = qemu_get_nic_opaque(nc); 64649ab747fSPaolo Bonzini 64749ab747fSPaolo Bonzini /* RX enabled? */ 64849ab747fSPaolo Bonzini return !axienet_rx_resetting(s) && axienet_rx_enabled(s); 64949ab747fSPaolo Bonzini } 65049ab747fSPaolo Bonzini 65149ab747fSPaolo Bonzini static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1) 65249ab747fSPaolo Bonzini { 65349ab747fSPaolo Bonzini int match = 1; 65449ab747fSPaolo Bonzini 65549ab747fSPaolo Bonzini if (memcmp(buf, &f0, 4)) { 65649ab747fSPaolo Bonzini match = 0; 65749ab747fSPaolo Bonzini } 65849ab747fSPaolo Bonzini 65949ab747fSPaolo Bonzini if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) { 66049ab747fSPaolo Bonzini match = 0; 66149ab747fSPaolo Bonzini } 66249ab747fSPaolo Bonzini 66349ab747fSPaolo Bonzini return match; 66449ab747fSPaolo Bonzini } 66549ab747fSPaolo Bonzini 66649ab747fSPaolo Bonzini static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) 66749ab747fSPaolo Bonzini { 668545129e5SPeter Crosthwaite XilinxAXIEnet *s = qemu_get_nic_opaque(nc); 66949ab747fSPaolo Bonzini static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 67049ab747fSPaolo Bonzini 0xff, 0xff, 0xff}; 67149ab747fSPaolo Bonzini static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52}; 67249ab747fSPaolo Bonzini uint32_t app[6] = {0}; 67349ab747fSPaolo Bonzini int promisc = s->fmi & (1 << 31); 67449ab747fSPaolo Bonzini int unicast, broadcast, multicast, ip_multicast = 0; 67549ab747fSPaolo Bonzini uint32_t csum32; 67649ab747fSPaolo Bonzini uint16_t csum16; 67749ab747fSPaolo Bonzini int i; 67849ab747fSPaolo Bonzini 67949ab747fSPaolo Bonzini DENET(qemu_log("%s: %zd bytes\n", __func__, size)); 68049ab747fSPaolo Bonzini 68149ab747fSPaolo Bonzini unicast = ~buf[0] & 0x1; 68249ab747fSPaolo Bonzini broadcast = memcmp(buf, sa_bcast, 6) == 0; 68349ab747fSPaolo Bonzini multicast = !unicast && !broadcast; 68449ab747fSPaolo Bonzini if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) { 68549ab747fSPaolo Bonzini ip_multicast = 1; 68649ab747fSPaolo Bonzini } 68749ab747fSPaolo Bonzini 68849ab747fSPaolo Bonzini /* Jumbo or vlan sizes ? */ 68949ab747fSPaolo Bonzini if (!(s->rcw[1] & RCW1_JUM)) { 69049ab747fSPaolo Bonzini if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) { 69149ab747fSPaolo Bonzini return size; 69249ab747fSPaolo Bonzini } 69349ab747fSPaolo Bonzini } 69449ab747fSPaolo Bonzini 69549ab747fSPaolo Bonzini /* Basic Address filters. If you want to use the extended filters 69649ab747fSPaolo Bonzini you'll generally have to place the ethernet mac into promiscuous mode 69749ab747fSPaolo Bonzini to avoid the basic filtering from dropping most frames. */ 69849ab747fSPaolo Bonzini if (!promisc) { 69949ab747fSPaolo Bonzini if (unicast) { 70049ab747fSPaolo Bonzini if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) { 70149ab747fSPaolo Bonzini return size; 70249ab747fSPaolo Bonzini } 70349ab747fSPaolo Bonzini } else { 70449ab747fSPaolo Bonzini if (broadcast) { 70549ab747fSPaolo Bonzini /* Broadcast. */ 70649ab747fSPaolo Bonzini if (s->regs[R_RAF] & RAF_BCAST_REJ) { 70749ab747fSPaolo Bonzini return size; 70849ab747fSPaolo Bonzini } 70949ab747fSPaolo Bonzini } else { 71049ab747fSPaolo Bonzini int drop = 1; 71149ab747fSPaolo Bonzini 71249ab747fSPaolo Bonzini /* Multicast. */ 71349ab747fSPaolo Bonzini if (s->regs[R_RAF] & RAF_MCAST_REJ) { 71449ab747fSPaolo Bonzini return size; 71549ab747fSPaolo Bonzini } 71649ab747fSPaolo Bonzini 71749ab747fSPaolo Bonzini for (i = 0; i < 4; i++) { 71849ab747fSPaolo Bonzini if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) { 71949ab747fSPaolo Bonzini drop = 0; 72049ab747fSPaolo Bonzini break; 72149ab747fSPaolo Bonzini } 72249ab747fSPaolo Bonzini } 72349ab747fSPaolo Bonzini 72449ab747fSPaolo Bonzini if (drop) { 72549ab747fSPaolo Bonzini return size; 72649ab747fSPaolo Bonzini } 72749ab747fSPaolo Bonzini } 72849ab747fSPaolo Bonzini } 72949ab747fSPaolo Bonzini } 73049ab747fSPaolo Bonzini 73149ab747fSPaolo Bonzini /* Extended mcast filtering enabled? */ 73249ab747fSPaolo Bonzini if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) { 73349ab747fSPaolo Bonzini if (unicast) { 73449ab747fSPaolo Bonzini if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) { 73549ab747fSPaolo Bonzini return size; 73649ab747fSPaolo Bonzini } 73749ab747fSPaolo Bonzini } else { 73849ab747fSPaolo Bonzini if (broadcast) { 73949ab747fSPaolo Bonzini /* Broadcast. ??? */ 74049ab747fSPaolo Bonzini if (s->regs[R_RAF] & RAF_BCAST_REJ) { 74149ab747fSPaolo Bonzini return size; 74249ab747fSPaolo Bonzini } 74349ab747fSPaolo Bonzini } else { 74449ab747fSPaolo Bonzini int idx, bit; 74549ab747fSPaolo Bonzini 74649ab747fSPaolo Bonzini /* Multicast. */ 74749ab747fSPaolo Bonzini if (!memcmp(buf, sa_ipmcast, 3)) { 74849ab747fSPaolo Bonzini return size; 74949ab747fSPaolo Bonzini } 75049ab747fSPaolo Bonzini 75149ab747fSPaolo Bonzini idx = (buf[4] & 0x7f) << 8; 75249ab747fSPaolo Bonzini idx |= buf[5]; 75349ab747fSPaolo Bonzini 75449ab747fSPaolo Bonzini bit = 1 << (idx & 0x1f); 75549ab747fSPaolo Bonzini idx >>= 5; 75649ab747fSPaolo Bonzini 75749ab747fSPaolo Bonzini if (!(s->ext_mtable[idx] & bit)) { 75849ab747fSPaolo Bonzini return size; 75949ab747fSPaolo Bonzini } 76049ab747fSPaolo Bonzini } 76149ab747fSPaolo Bonzini } 76249ab747fSPaolo Bonzini } 76349ab747fSPaolo Bonzini 76449ab747fSPaolo Bonzini if (size < 12) { 76549ab747fSPaolo Bonzini s->regs[R_IS] |= IS_RX_REJECT; 76649ab747fSPaolo Bonzini enet_update_irq(s); 76749ab747fSPaolo Bonzini return -1; 76849ab747fSPaolo Bonzini } 76949ab747fSPaolo Bonzini 77049ab747fSPaolo Bonzini if (size > (s->c_rxmem - 4)) { 77149ab747fSPaolo Bonzini size = s->c_rxmem - 4; 77249ab747fSPaolo Bonzini } 77349ab747fSPaolo Bonzini 77449ab747fSPaolo Bonzini memcpy(s->rxmem, buf, size); 77549ab747fSPaolo Bonzini memset(s->rxmem + size, 0, 4); /* Clear the FCS. */ 77649ab747fSPaolo Bonzini 77749ab747fSPaolo Bonzini if (s->rcw[1] & RCW1_FCS) { 77849ab747fSPaolo Bonzini size += 4; /* fcs is inband. */ 77949ab747fSPaolo Bonzini } 78049ab747fSPaolo Bonzini 78149ab747fSPaolo Bonzini app[0] = 5 << 28; 78249ab747fSPaolo Bonzini csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14); 78349ab747fSPaolo Bonzini /* Fold it once. */ 78449ab747fSPaolo Bonzini csum32 = (csum32 & 0xffff) + (csum32 >> 16); 78549ab747fSPaolo Bonzini /* And twice to get rid of possible carries. */ 78649ab747fSPaolo Bonzini csum16 = (csum32 & 0xffff) + (csum32 >> 16); 78749ab747fSPaolo Bonzini app[3] = csum16; 78849ab747fSPaolo Bonzini app[4] = size & 0xffff; 78949ab747fSPaolo Bonzini 79049ab747fSPaolo Bonzini s->stats.rx_bytes += size; 79149ab747fSPaolo Bonzini s->stats.rx++; 79249ab747fSPaolo Bonzini if (multicast) { 79349ab747fSPaolo Bonzini s->stats.rx_mcast++; 79449ab747fSPaolo Bonzini app[2] |= 1 | (ip_multicast << 1); 79549ab747fSPaolo Bonzini } else if (broadcast) { 79649ab747fSPaolo Bonzini s->stats.rx_bcast++; 79749ab747fSPaolo Bonzini app[2] |= 1 << 3; 79849ab747fSPaolo Bonzini } 79949ab747fSPaolo Bonzini 80049ab747fSPaolo Bonzini /* Good frame. */ 80149ab747fSPaolo Bonzini app[2] |= 1 << 6; 80249ab747fSPaolo Bonzini 80349ab747fSPaolo Bonzini stream_push(s->tx_dev, (void *)s->rxmem, size, app); 80449ab747fSPaolo Bonzini 80549ab747fSPaolo Bonzini s->regs[R_IS] |= IS_RX_COMPLETE; 80649ab747fSPaolo Bonzini enet_update_irq(s); 80749ab747fSPaolo Bonzini return size; 80849ab747fSPaolo Bonzini } 80949ab747fSPaolo Bonzini 81049ab747fSPaolo Bonzini static void eth_cleanup(NetClientState *nc) 81149ab747fSPaolo Bonzini { 81249ab747fSPaolo Bonzini /* FIXME. */ 813545129e5SPeter Crosthwaite XilinxAXIEnet *s = qemu_get_nic_opaque(nc); 81449ab747fSPaolo Bonzini g_free(s->rxmem); 81549ab747fSPaolo Bonzini g_free(s); 81649ab747fSPaolo Bonzini } 81749ab747fSPaolo Bonzini 818*35e60bfdSPeter Crosthwaite static size_t 81955b3e0c2SPeter Crosthwaite xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, 82055b3e0c2SPeter Crosthwaite uint32_t *hdr) 82149ab747fSPaolo Bonzini { 82255b3e0c2SPeter Crosthwaite XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(obj); 82355b3e0c2SPeter Crosthwaite XilinxAXIEnet *s = ds->enet; 82449ab747fSPaolo Bonzini 82549ab747fSPaolo Bonzini /* TX enable ? */ 82649ab747fSPaolo Bonzini if (!(s->tc & TC_TX)) { 827*35e60bfdSPeter Crosthwaite return size; 82849ab747fSPaolo Bonzini } 82949ab747fSPaolo Bonzini 83049ab747fSPaolo Bonzini /* Jumbo or vlan sizes ? */ 83149ab747fSPaolo Bonzini if (!(s->tc & TC_JUM)) { 83249ab747fSPaolo Bonzini if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) { 833*35e60bfdSPeter Crosthwaite return size; 83449ab747fSPaolo Bonzini } 83549ab747fSPaolo Bonzini } 83649ab747fSPaolo Bonzini 83749ab747fSPaolo Bonzini if (hdr[0] & 1) { 83849ab747fSPaolo Bonzini unsigned int start_off = hdr[1] >> 16; 83949ab747fSPaolo Bonzini unsigned int write_off = hdr[1] & 0xffff; 84049ab747fSPaolo Bonzini uint32_t tmp_csum; 84149ab747fSPaolo Bonzini uint16_t csum; 84249ab747fSPaolo Bonzini 84349ab747fSPaolo Bonzini tmp_csum = net_checksum_add(size - start_off, 84449ab747fSPaolo Bonzini (uint8_t *)buf + start_off); 84549ab747fSPaolo Bonzini /* Accumulate the seed. */ 84649ab747fSPaolo Bonzini tmp_csum += hdr[2] & 0xffff; 84749ab747fSPaolo Bonzini 84849ab747fSPaolo Bonzini /* Fold the 32bit partial checksum. */ 84949ab747fSPaolo Bonzini csum = net_checksum_finish(tmp_csum); 85049ab747fSPaolo Bonzini 85149ab747fSPaolo Bonzini /* Writeback. */ 85249ab747fSPaolo Bonzini buf[write_off] = csum >> 8; 85349ab747fSPaolo Bonzini buf[write_off + 1] = csum & 0xff; 85449ab747fSPaolo Bonzini } 85549ab747fSPaolo Bonzini 85649ab747fSPaolo Bonzini qemu_send_packet(qemu_get_queue(s->nic), buf, size); 85749ab747fSPaolo Bonzini 85849ab747fSPaolo Bonzini s->stats.tx_bytes += size; 85949ab747fSPaolo Bonzini s->regs[R_IS] |= IS_TX_COMPLETE; 86049ab747fSPaolo Bonzini enet_update_irq(s); 861*35e60bfdSPeter Crosthwaite 862*35e60bfdSPeter Crosthwaite return size; 86349ab747fSPaolo Bonzini } 86449ab747fSPaolo Bonzini 86549ab747fSPaolo Bonzini static NetClientInfo net_xilinx_enet_info = { 86649ab747fSPaolo Bonzini .type = NET_CLIENT_OPTIONS_KIND_NIC, 86749ab747fSPaolo Bonzini .size = sizeof(NICState), 86849ab747fSPaolo Bonzini .can_receive = eth_can_rx, 86949ab747fSPaolo Bonzini .receive = eth_rx, 87049ab747fSPaolo Bonzini .cleanup = eth_cleanup, 87149ab747fSPaolo Bonzini }; 87249ab747fSPaolo Bonzini 873b2d9dfe9SPeter Crosthwaite static void xilinx_enet_realize(DeviceState *dev, Error **errp) 87449ab747fSPaolo Bonzini { 875f0e7a81cSPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(dev); 87655b3e0c2SPeter Crosthwaite XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(&s->rx_data_dev); 87755b3e0c2SPeter Crosthwaite Error *local_errp = NULL; 87855b3e0c2SPeter Crosthwaite 87955b3e0c2SPeter Crosthwaite object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet", 88055b3e0c2SPeter Crosthwaite (Object **) &ds->enet, &local_errp); 88155b3e0c2SPeter Crosthwaite if (local_errp) { 88255b3e0c2SPeter Crosthwaite goto xilinx_enet_realize_fail; 88355b3e0c2SPeter Crosthwaite } 88455b3e0c2SPeter Crosthwaite object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_errp); 88555b3e0c2SPeter Crosthwaite if (local_errp) { 88655b3e0c2SPeter Crosthwaite goto xilinx_enet_realize_fail; 88755b3e0c2SPeter Crosthwaite } 88849ab747fSPaolo Bonzini 88949ab747fSPaolo Bonzini qemu_macaddr_default_if_unset(&s->conf.macaddr); 89049ab747fSPaolo Bonzini s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf, 891b2d9dfe9SPeter Crosthwaite object_get_typename(OBJECT(dev)), dev->id, s); 89249ab747fSPaolo Bonzini qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); 89349ab747fSPaolo Bonzini 89449ab747fSPaolo Bonzini tdk_init(&s->TEMAC.phy); 89549ab747fSPaolo Bonzini mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr); 89649ab747fSPaolo Bonzini 89749ab747fSPaolo Bonzini s->TEMAC.parent = s; 89849ab747fSPaolo Bonzini 89949ab747fSPaolo Bonzini s->rxmem = g_malloc(s->c_rxmem); 90055b3e0c2SPeter Crosthwaite return; 90155b3e0c2SPeter Crosthwaite 90255b3e0c2SPeter Crosthwaite xilinx_enet_realize_fail: 90355b3e0c2SPeter Crosthwaite if (!*errp) { 90455b3e0c2SPeter Crosthwaite *errp = local_errp; 90555b3e0c2SPeter Crosthwaite } 90649ab747fSPaolo Bonzini } 90749ab747fSPaolo Bonzini 908b2d9dfe9SPeter Crosthwaite static void xilinx_enet_init(Object *obj) 90949ab747fSPaolo Bonzini { 910f0e7a81cSPeter Crosthwaite XilinxAXIEnet *s = XILINX_AXI_ENET(obj); 911b2d9dfe9SPeter Crosthwaite SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 91249ab747fSPaolo Bonzini Error *errp = NULL; 91349ab747fSPaolo Bonzini 91449ab747fSPaolo Bonzini object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE, 91549ab747fSPaolo Bonzini (Object **) &s->tx_dev, &errp); 91649ab747fSPaolo Bonzini assert_no_error(errp); 917b2d9dfe9SPeter Crosthwaite 91855b3e0c2SPeter Crosthwaite object_initialize(&s->rx_data_dev, TYPE_XILINX_AXI_ENET_DATA_STREAM); 91955b3e0c2SPeter Crosthwaite object_property_add_child(OBJECT(s), "axistream-connected-target", 92055b3e0c2SPeter Crosthwaite (Object *)&s->rx_data_dev, &errp); 92155b3e0c2SPeter Crosthwaite assert_no_error(errp); 92255b3e0c2SPeter Crosthwaite 923b2d9dfe9SPeter Crosthwaite sysbus_init_irq(sbd, &s->irq); 924b2d9dfe9SPeter Crosthwaite 925b2d9dfe9SPeter Crosthwaite memory_region_init_io(&s->iomem, &enet_ops, s, "enet", 0x40000); 926b2d9dfe9SPeter Crosthwaite sysbus_init_mmio(sbd, &s->iomem); 92749ab747fSPaolo Bonzini } 92849ab747fSPaolo Bonzini 92949ab747fSPaolo Bonzini static Property xilinx_enet_properties[] = { 930545129e5SPeter Crosthwaite DEFINE_PROP_UINT32("phyaddr", XilinxAXIEnet, c_phyaddr, 7), 931545129e5SPeter Crosthwaite DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000), 932545129e5SPeter Crosthwaite DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000), 933545129e5SPeter Crosthwaite DEFINE_NIC_PROPERTIES(XilinxAXIEnet, conf), 93449ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 93549ab747fSPaolo Bonzini }; 93649ab747fSPaolo Bonzini 93749ab747fSPaolo Bonzini static void xilinx_enet_class_init(ObjectClass *klass, void *data) 93849ab747fSPaolo Bonzini { 93949ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 94049ab747fSPaolo Bonzini 941b2d9dfe9SPeter Crosthwaite dc->realize = xilinx_enet_realize; 94249ab747fSPaolo Bonzini dc->props = xilinx_enet_properties; 9439ee0ceb7SPeter Crosthwaite dc->reset = xilinx_axienet_reset; 94455b3e0c2SPeter Crosthwaite } 94555b3e0c2SPeter Crosthwaite 94655b3e0c2SPeter Crosthwaite static void xilinx_enet_stream_class_init(ObjectClass *klass, void *data) 94755b3e0c2SPeter Crosthwaite { 94855b3e0c2SPeter Crosthwaite StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass); 94955b3e0c2SPeter Crosthwaite 95055b3e0c2SPeter Crosthwaite ssc->push = data; 95149ab747fSPaolo Bonzini } 95249ab747fSPaolo Bonzini 95349ab747fSPaolo Bonzini static const TypeInfo xilinx_enet_info = { 954f0e7a81cSPeter Crosthwaite .name = TYPE_XILINX_AXI_ENET, 95549ab747fSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE, 956545129e5SPeter Crosthwaite .instance_size = sizeof(XilinxAXIEnet), 95749ab747fSPaolo Bonzini .class_init = xilinx_enet_class_init, 958b2d9dfe9SPeter Crosthwaite .instance_init = xilinx_enet_init, 95955b3e0c2SPeter Crosthwaite }; 96055b3e0c2SPeter Crosthwaite 96155b3e0c2SPeter Crosthwaite static const TypeInfo xilinx_enet_data_stream_info = { 96255b3e0c2SPeter Crosthwaite .name = TYPE_XILINX_AXI_ENET_DATA_STREAM, 96355b3e0c2SPeter Crosthwaite .parent = TYPE_OBJECT, 96455b3e0c2SPeter Crosthwaite .instance_size = sizeof(struct XilinxAXIEnetStreamSlave), 96555b3e0c2SPeter Crosthwaite .class_init = xilinx_enet_stream_class_init, 96655b3e0c2SPeter Crosthwaite .class_data = xilinx_axienet_data_stream_push, 96749ab747fSPaolo Bonzini .interfaces = (InterfaceInfo[]) { 96849ab747fSPaolo Bonzini { TYPE_STREAM_SLAVE }, 96949ab747fSPaolo Bonzini { } 97049ab747fSPaolo Bonzini } 97149ab747fSPaolo Bonzini }; 97249ab747fSPaolo Bonzini 97349ab747fSPaolo Bonzini static void xilinx_enet_register_types(void) 97449ab747fSPaolo Bonzini { 97549ab747fSPaolo Bonzini type_register_static(&xilinx_enet_info); 97655b3e0c2SPeter Crosthwaite type_register_static(&xilinx_enet_data_stream_info); 97749ab747fSPaolo Bonzini } 97849ab747fSPaolo Bonzini 97949ab747fSPaolo Bonzini type_init(xilinx_enet_register_types) 980