1fcbd8018SJean-Christophe Dubois /* 2fcbd8018SJean-Christophe Dubois * i.MX Fast Ethernet Controller emulation. 3fcbd8018SJean-Christophe Dubois * 4fcbd8018SJean-Christophe Dubois * Copyright (c) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net> 5fcbd8018SJean-Christophe Dubois * 6fcbd8018SJean-Christophe Dubois * Based on Coldfire Fast Ethernet Controller emulation. 7fcbd8018SJean-Christophe Dubois * 8fcbd8018SJean-Christophe Dubois * Copyright (c) 2007 CodeSourcery. 9fcbd8018SJean-Christophe Dubois * 10fcbd8018SJean-Christophe Dubois * This program is free software; you can redistribute it and/or modify it 11fcbd8018SJean-Christophe Dubois * under the terms of the GNU General Public License as published by the 12fcbd8018SJean-Christophe Dubois * Free Software Foundation; either version 2 of the License, or 13fcbd8018SJean-Christophe Dubois * (at your option) any later version. 14fcbd8018SJean-Christophe Dubois * 15fcbd8018SJean-Christophe Dubois * This program is distributed in the hope that it will be useful, but WITHOUT 16fcbd8018SJean-Christophe Dubois * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17fcbd8018SJean-Christophe Dubois * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18fcbd8018SJean-Christophe Dubois * for more details. 19fcbd8018SJean-Christophe Dubois * 20fcbd8018SJean-Christophe Dubois * You should have received a copy of the GNU General Public License along 21fcbd8018SJean-Christophe Dubois * with this program; if not, see <http://www.gnu.org/licenses/>. 22fcbd8018SJean-Christophe Dubois */ 23fcbd8018SJean-Christophe Dubois 24*8ef94f0bSPeter Maydell #include "qemu/osdep.h" 25fcbd8018SJean-Christophe Dubois #include "hw/net/imx_fec.h" 26fcbd8018SJean-Christophe Dubois #include "sysemu/dma.h" 27fcbd8018SJean-Christophe Dubois 28fcbd8018SJean-Christophe Dubois /* For crc32 */ 29fcbd8018SJean-Christophe Dubois #include <zlib.h> 30fcbd8018SJean-Christophe Dubois 31b72d8d25SJean-Christophe Dubois #ifndef DEBUG_IMX_FEC 32b72d8d25SJean-Christophe Dubois #define DEBUG_IMX_FEC 0 33fcbd8018SJean-Christophe Dubois #endif 34fcbd8018SJean-Christophe Dubois 35b72d8d25SJean-Christophe Dubois #define FEC_PRINTF(fmt, args...) \ 36b72d8d25SJean-Christophe Dubois do { \ 37b72d8d25SJean-Christophe Dubois if (DEBUG_IMX_FEC) { \ 38b72d8d25SJean-Christophe Dubois fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_FEC, \ 39b72d8d25SJean-Christophe Dubois __func__, ##args); \ 40b72d8d25SJean-Christophe Dubois } \ 41fcbd8018SJean-Christophe Dubois } while (0) 42b72d8d25SJean-Christophe Dubois 43b72d8d25SJean-Christophe Dubois #ifndef DEBUG_IMX_PHY 44b72d8d25SJean-Christophe Dubois #define DEBUG_IMX_PHY 0 45fcbd8018SJean-Christophe Dubois #endif 46fcbd8018SJean-Christophe Dubois 47b72d8d25SJean-Christophe Dubois #define PHY_PRINTF(fmt, args...) \ 48b72d8d25SJean-Christophe Dubois do { \ 49b72d8d25SJean-Christophe Dubois if (DEBUG_IMX_PHY) { \ 50b72d8d25SJean-Christophe Dubois fprintf(stderr, "[%s.phy]%s: " fmt , TYPE_IMX_FEC, \ 51b72d8d25SJean-Christophe Dubois __func__, ##args); \ 52b72d8d25SJean-Christophe Dubois } \ 53fcbd8018SJean-Christophe Dubois } while (0) 54fcbd8018SJean-Christophe Dubois 55fcbd8018SJean-Christophe Dubois static const VMStateDescription vmstate_imx_fec = { 56fcbd8018SJean-Christophe Dubois .name = TYPE_IMX_FEC, 57fcbd8018SJean-Christophe Dubois .version_id = 1, 58fcbd8018SJean-Christophe Dubois .minimum_version_id = 1, 59fcbd8018SJean-Christophe Dubois .fields = (VMStateField[]) { 60fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(irq_state, IMXFECState), 61fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(eir, IMXFECState), 62fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(eimr, IMXFECState), 63fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(rx_enabled, IMXFECState), 64fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(rx_descriptor, IMXFECState), 65fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(tx_descriptor, IMXFECState), 66fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(ecr, IMXFECState), 67fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(mmfr, IMXFECState), 68fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(mscr, IMXFECState), 69fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(mibc, IMXFECState), 70fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(rcr, IMXFECState), 71fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(tcr, IMXFECState), 72fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(tfwr, IMXFECState), 73fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(frsr, IMXFECState), 74fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(erdsr, IMXFECState), 75fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(etdsr, IMXFECState), 76fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(emrbr, IMXFECState), 77fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(miigsk_cfgr, IMXFECState), 78fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(miigsk_enr, IMXFECState), 79fcbd8018SJean-Christophe Dubois 80fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(phy_status, IMXFECState), 81fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(phy_control, IMXFECState), 82fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(phy_advertise, IMXFECState), 83fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(phy_int, IMXFECState), 84fcbd8018SJean-Christophe Dubois VMSTATE_UINT32(phy_int_mask, IMXFECState), 85fcbd8018SJean-Christophe Dubois VMSTATE_END_OF_LIST() 86fcbd8018SJean-Christophe Dubois } 87fcbd8018SJean-Christophe Dubois }; 88fcbd8018SJean-Christophe Dubois 89fcbd8018SJean-Christophe Dubois #define PHY_INT_ENERGYON (1 << 7) 90fcbd8018SJean-Christophe Dubois #define PHY_INT_AUTONEG_COMPLETE (1 << 6) 91fcbd8018SJean-Christophe Dubois #define PHY_INT_FAULT (1 << 5) 92fcbd8018SJean-Christophe Dubois #define PHY_INT_DOWN (1 << 4) 93fcbd8018SJean-Christophe Dubois #define PHY_INT_AUTONEG_LP (1 << 3) 94fcbd8018SJean-Christophe Dubois #define PHY_INT_PARFAULT (1 << 2) 95fcbd8018SJean-Christophe Dubois #define PHY_INT_AUTONEG_PAGE (1 << 1) 96fcbd8018SJean-Christophe Dubois 97fcbd8018SJean-Christophe Dubois static void imx_fec_update(IMXFECState *s); 98fcbd8018SJean-Christophe Dubois 99fcbd8018SJean-Christophe Dubois /* 100fcbd8018SJean-Christophe Dubois * The MII phy could raise a GPIO to the processor which in turn 101fcbd8018SJean-Christophe Dubois * could be handled as an interrpt by the OS. 102fcbd8018SJean-Christophe Dubois * For now we don't handle any GPIO/interrupt line, so the OS will 103fcbd8018SJean-Christophe Dubois * have to poll for the PHY status. 104fcbd8018SJean-Christophe Dubois */ 105fcbd8018SJean-Christophe Dubois static void phy_update_irq(IMXFECState *s) 106fcbd8018SJean-Christophe Dubois { 107fcbd8018SJean-Christophe Dubois imx_fec_update(s); 108fcbd8018SJean-Christophe Dubois } 109fcbd8018SJean-Christophe Dubois 110fcbd8018SJean-Christophe Dubois static void phy_update_link(IMXFECState *s) 111fcbd8018SJean-Christophe Dubois { 112fcbd8018SJean-Christophe Dubois /* Autonegotiation status mirrors link status. */ 113fcbd8018SJean-Christophe Dubois if (qemu_get_queue(s->nic)->link_down) { 114fcbd8018SJean-Christophe Dubois PHY_PRINTF("link is down\n"); 115fcbd8018SJean-Christophe Dubois s->phy_status &= ~0x0024; 116fcbd8018SJean-Christophe Dubois s->phy_int |= PHY_INT_DOWN; 117fcbd8018SJean-Christophe Dubois } else { 118fcbd8018SJean-Christophe Dubois PHY_PRINTF("link is up\n"); 119fcbd8018SJean-Christophe Dubois s->phy_status |= 0x0024; 120fcbd8018SJean-Christophe Dubois s->phy_int |= PHY_INT_ENERGYON; 121fcbd8018SJean-Christophe Dubois s->phy_int |= PHY_INT_AUTONEG_COMPLETE; 122fcbd8018SJean-Christophe Dubois } 123fcbd8018SJean-Christophe Dubois phy_update_irq(s); 124fcbd8018SJean-Christophe Dubois } 125fcbd8018SJean-Christophe Dubois 126fcbd8018SJean-Christophe Dubois static void imx_fec_set_link(NetClientState *nc) 127fcbd8018SJean-Christophe Dubois { 128fcbd8018SJean-Christophe Dubois phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc))); 129fcbd8018SJean-Christophe Dubois } 130fcbd8018SJean-Christophe Dubois 131fcbd8018SJean-Christophe Dubois static void phy_reset(IMXFECState *s) 132fcbd8018SJean-Christophe Dubois { 133fcbd8018SJean-Christophe Dubois s->phy_status = 0x7809; 134fcbd8018SJean-Christophe Dubois s->phy_control = 0x3000; 135fcbd8018SJean-Christophe Dubois s->phy_advertise = 0x01e1; 136fcbd8018SJean-Christophe Dubois s->phy_int_mask = 0; 137fcbd8018SJean-Christophe Dubois s->phy_int = 0; 138fcbd8018SJean-Christophe Dubois phy_update_link(s); 139fcbd8018SJean-Christophe Dubois } 140fcbd8018SJean-Christophe Dubois 141fcbd8018SJean-Christophe Dubois static uint32_t do_phy_read(IMXFECState *s, int reg) 142fcbd8018SJean-Christophe Dubois { 143fcbd8018SJean-Christophe Dubois uint32_t val; 144fcbd8018SJean-Christophe Dubois 145fcbd8018SJean-Christophe Dubois if (reg > 31) { 146fcbd8018SJean-Christophe Dubois /* we only advertise one phy */ 147fcbd8018SJean-Christophe Dubois return 0; 148fcbd8018SJean-Christophe Dubois } 149fcbd8018SJean-Christophe Dubois 150fcbd8018SJean-Christophe Dubois switch (reg) { 151fcbd8018SJean-Christophe Dubois case 0: /* Basic Control */ 152fcbd8018SJean-Christophe Dubois val = s->phy_control; 153fcbd8018SJean-Christophe Dubois break; 154fcbd8018SJean-Christophe Dubois case 1: /* Basic Status */ 155fcbd8018SJean-Christophe Dubois val = s->phy_status; 156fcbd8018SJean-Christophe Dubois break; 157fcbd8018SJean-Christophe Dubois case 2: /* ID1 */ 158fcbd8018SJean-Christophe Dubois val = 0x0007; 159fcbd8018SJean-Christophe Dubois break; 160fcbd8018SJean-Christophe Dubois case 3: /* ID2 */ 161fcbd8018SJean-Christophe Dubois val = 0xc0d1; 162fcbd8018SJean-Christophe Dubois break; 163fcbd8018SJean-Christophe Dubois case 4: /* Auto-neg advertisement */ 164fcbd8018SJean-Christophe Dubois val = s->phy_advertise; 165fcbd8018SJean-Christophe Dubois break; 166fcbd8018SJean-Christophe Dubois case 5: /* Auto-neg Link Partner Ability */ 167fcbd8018SJean-Christophe Dubois val = 0x0f71; 168fcbd8018SJean-Christophe Dubois break; 169fcbd8018SJean-Christophe Dubois case 6: /* Auto-neg Expansion */ 170fcbd8018SJean-Christophe Dubois val = 1; 171fcbd8018SJean-Christophe Dubois break; 172fcbd8018SJean-Christophe Dubois case 29: /* Interrupt source. */ 173fcbd8018SJean-Christophe Dubois val = s->phy_int; 174fcbd8018SJean-Christophe Dubois s->phy_int = 0; 175fcbd8018SJean-Christophe Dubois phy_update_irq(s); 176fcbd8018SJean-Christophe Dubois break; 177fcbd8018SJean-Christophe Dubois case 30: /* Interrupt mask */ 178fcbd8018SJean-Christophe Dubois val = s->phy_int_mask; 179fcbd8018SJean-Christophe Dubois break; 180fcbd8018SJean-Christophe Dubois case 17: 181fcbd8018SJean-Christophe Dubois case 18: 182fcbd8018SJean-Christophe Dubois case 27: 183fcbd8018SJean-Christophe Dubois case 31: 184b72d8d25SJean-Christophe Dubois qemu_log_mask(LOG_UNIMP, "[%s.phy]%s: reg %d not implemented\n", 185fcbd8018SJean-Christophe Dubois TYPE_IMX_FEC, __func__, reg); 186fcbd8018SJean-Christophe Dubois val = 0; 187fcbd8018SJean-Christophe Dubois break; 188fcbd8018SJean-Christophe Dubois default: 189b72d8d25SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n", 190fcbd8018SJean-Christophe Dubois TYPE_IMX_FEC, __func__, reg); 191fcbd8018SJean-Christophe Dubois val = 0; 192fcbd8018SJean-Christophe Dubois break; 193fcbd8018SJean-Christophe Dubois } 194fcbd8018SJean-Christophe Dubois 195fcbd8018SJean-Christophe Dubois PHY_PRINTF("read 0x%04x @ %d\n", val, reg); 196fcbd8018SJean-Christophe Dubois 197fcbd8018SJean-Christophe Dubois return val; 198fcbd8018SJean-Christophe Dubois } 199fcbd8018SJean-Christophe Dubois 200fcbd8018SJean-Christophe Dubois static void do_phy_write(IMXFECState *s, int reg, uint32_t val) 201fcbd8018SJean-Christophe Dubois { 202fcbd8018SJean-Christophe Dubois PHY_PRINTF("write 0x%04x @ %d\n", val, reg); 203fcbd8018SJean-Christophe Dubois 204fcbd8018SJean-Christophe Dubois if (reg > 31) { 205fcbd8018SJean-Christophe Dubois /* we only advertise one phy */ 206fcbd8018SJean-Christophe Dubois return; 207fcbd8018SJean-Christophe Dubois } 208fcbd8018SJean-Christophe Dubois 209fcbd8018SJean-Christophe Dubois switch (reg) { 210fcbd8018SJean-Christophe Dubois case 0: /* Basic Control */ 211fcbd8018SJean-Christophe Dubois if (val & 0x8000) { 212fcbd8018SJean-Christophe Dubois phy_reset(s); 213fcbd8018SJean-Christophe Dubois } else { 214fcbd8018SJean-Christophe Dubois s->phy_control = val & 0x7980; 215fcbd8018SJean-Christophe Dubois /* Complete autonegotiation immediately. */ 216fcbd8018SJean-Christophe Dubois if (val & 0x1000) { 217fcbd8018SJean-Christophe Dubois s->phy_status |= 0x0020; 218fcbd8018SJean-Christophe Dubois } 219fcbd8018SJean-Christophe Dubois } 220fcbd8018SJean-Christophe Dubois break; 221fcbd8018SJean-Christophe Dubois case 4: /* Auto-neg advertisement */ 222fcbd8018SJean-Christophe Dubois s->phy_advertise = (val & 0x2d7f) | 0x80; 223fcbd8018SJean-Christophe Dubois break; 224fcbd8018SJean-Christophe Dubois case 30: /* Interrupt mask */ 225fcbd8018SJean-Christophe Dubois s->phy_int_mask = val & 0xff; 226fcbd8018SJean-Christophe Dubois phy_update_irq(s); 227fcbd8018SJean-Christophe Dubois break; 228fcbd8018SJean-Christophe Dubois case 17: 229fcbd8018SJean-Christophe Dubois case 18: 230fcbd8018SJean-Christophe Dubois case 27: 231fcbd8018SJean-Christophe Dubois case 31: 232b72d8d25SJean-Christophe Dubois qemu_log_mask(LOG_UNIMP, "[%s.phy)%s: reg %d not implemented\n", 233fcbd8018SJean-Christophe Dubois TYPE_IMX_FEC, __func__, reg); 234fcbd8018SJean-Christophe Dubois break; 235fcbd8018SJean-Christophe Dubois default: 236b72d8d25SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n", 237fcbd8018SJean-Christophe Dubois TYPE_IMX_FEC, __func__, reg); 238fcbd8018SJean-Christophe Dubois break; 239fcbd8018SJean-Christophe Dubois } 240fcbd8018SJean-Christophe Dubois } 241fcbd8018SJean-Christophe Dubois 242fcbd8018SJean-Christophe Dubois static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr) 243fcbd8018SJean-Christophe Dubois { 244fcbd8018SJean-Christophe Dubois dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd)); 245fcbd8018SJean-Christophe Dubois } 246fcbd8018SJean-Christophe Dubois 247fcbd8018SJean-Christophe Dubois static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr) 248fcbd8018SJean-Christophe Dubois { 249fcbd8018SJean-Christophe Dubois dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd)); 250fcbd8018SJean-Christophe Dubois } 251fcbd8018SJean-Christophe Dubois 252fcbd8018SJean-Christophe Dubois static void imx_fec_update(IMXFECState *s) 253fcbd8018SJean-Christophe Dubois { 254fcbd8018SJean-Christophe Dubois uint32_t active; 255fcbd8018SJean-Christophe Dubois uint32_t changed; 256fcbd8018SJean-Christophe Dubois 257fcbd8018SJean-Christophe Dubois active = s->eir & s->eimr; 258fcbd8018SJean-Christophe Dubois changed = active ^ s->irq_state; 259fcbd8018SJean-Christophe Dubois if (changed) { 260fcbd8018SJean-Christophe Dubois qemu_set_irq(s->irq, active); 261fcbd8018SJean-Christophe Dubois } 262fcbd8018SJean-Christophe Dubois s->irq_state = active; 263fcbd8018SJean-Christophe Dubois } 264fcbd8018SJean-Christophe Dubois 265fcbd8018SJean-Christophe Dubois static void imx_fec_do_tx(IMXFECState *s) 266fcbd8018SJean-Christophe Dubois { 267fcbd8018SJean-Christophe Dubois int frame_size = 0; 268fcbd8018SJean-Christophe Dubois uint8_t frame[FEC_MAX_FRAME_SIZE]; 269fcbd8018SJean-Christophe Dubois uint8_t *ptr = frame; 270fcbd8018SJean-Christophe Dubois uint32_t addr = s->tx_descriptor; 271fcbd8018SJean-Christophe Dubois 272fcbd8018SJean-Christophe Dubois while (1) { 273fcbd8018SJean-Christophe Dubois IMXFECBufDesc bd; 274fcbd8018SJean-Christophe Dubois int len; 275fcbd8018SJean-Christophe Dubois 276fcbd8018SJean-Christophe Dubois imx_fec_read_bd(&bd, addr); 277fcbd8018SJean-Christophe Dubois FEC_PRINTF("tx_bd %x flags %04x len %d data %08x\n", 278fcbd8018SJean-Christophe Dubois addr, bd.flags, bd.length, bd.data); 279fcbd8018SJean-Christophe Dubois if ((bd.flags & FEC_BD_R) == 0) { 280fcbd8018SJean-Christophe Dubois /* Run out of descriptors to transmit. */ 281fcbd8018SJean-Christophe Dubois break; 282fcbd8018SJean-Christophe Dubois } 283fcbd8018SJean-Christophe Dubois len = bd.length; 284fcbd8018SJean-Christophe Dubois if (frame_size + len > FEC_MAX_FRAME_SIZE) { 285fcbd8018SJean-Christophe Dubois len = FEC_MAX_FRAME_SIZE - frame_size; 286fcbd8018SJean-Christophe Dubois s->eir |= FEC_INT_BABT; 287fcbd8018SJean-Christophe Dubois } 288fcbd8018SJean-Christophe Dubois dma_memory_read(&address_space_memory, bd.data, ptr, len); 289fcbd8018SJean-Christophe Dubois ptr += len; 290fcbd8018SJean-Christophe Dubois frame_size += len; 291fcbd8018SJean-Christophe Dubois if (bd.flags & FEC_BD_L) { 292fcbd8018SJean-Christophe Dubois /* Last buffer in frame. */ 293fcbd8018SJean-Christophe Dubois qemu_send_packet(qemu_get_queue(s->nic), frame, len); 294fcbd8018SJean-Christophe Dubois ptr = frame; 295fcbd8018SJean-Christophe Dubois frame_size = 0; 296fcbd8018SJean-Christophe Dubois s->eir |= FEC_INT_TXF; 297fcbd8018SJean-Christophe Dubois } 298fcbd8018SJean-Christophe Dubois s->eir |= FEC_INT_TXB; 299fcbd8018SJean-Christophe Dubois bd.flags &= ~FEC_BD_R; 300fcbd8018SJean-Christophe Dubois /* Write back the modified descriptor. */ 301fcbd8018SJean-Christophe Dubois imx_fec_write_bd(&bd, addr); 302fcbd8018SJean-Christophe Dubois /* Advance to the next descriptor. */ 303fcbd8018SJean-Christophe Dubois if ((bd.flags & FEC_BD_W) != 0) { 304fcbd8018SJean-Christophe Dubois addr = s->etdsr; 305fcbd8018SJean-Christophe Dubois } else { 306fcbd8018SJean-Christophe Dubois addr += 8; 307fcbd8018SJean-Christophe Dubois } 308fcbd8018SJean-Christophe Dubois } 309fcbd8018SJean-Christophe Dubois 310fcbd8018SJean-Christophe Dubois s->tx_descriptor = addr; 311fcbd8018SJean-Christophe Dubois 312fcbd8018SJean-Christophe Dubois imx_fec_update(s); 313fcbd8018SJean-Christophe Dubois } 314fcbd8018SJean-Christophe Dubois 315fcbd8018SJean-Christophe Dubois static void imx_fec_enable_rx(IMXFECState *s) 316fcbd8018SJean-Christophe Dubois { 317fcbd8018SJean-Christophe Dubois IMXFECBufDesc bd; 318fcbd8018SJean-Christophe Dubois uint32_t tmp; 319fcbd8018SJean-Christophe Dubois 320fcbd8018SJean-Christophe Dubois imx_fec_read_bd(&bd, s->rx_descriptor); 321fcbd8018SJean-Christophe Dubois 322fcbd8018SJean-Christophe Dubois tmp = ((bd.flags & FEC_BD_E) != 0); 323fcbd8018SJean-Christophe Dubois 324fcbd8018SJean-Christophe Dubois if (!tmp) { 325fcbd8018SJean-Christophe Dubois FEC_PRINTF("RX buffer full\n"); 326fcbd8018SJean-Christophe Dubois } else if (!s->rx_enabled) { 327fcbd8018SJean-Christophe Dubois qemu_flush_queued_packets(qemu_get_queue(s->nic)); 328fcbd8018SJean-Christophe Dubois } 329fcbd8018SJean-Christophe Dubois 330fcbd8018SJean-Christophe Dubois s->rx_enabled = tmp; 331fcbd8018SJean-Christophe Dubois } 332fcbd8018SJean-Christophe Dubois 333fcbd8018SJean-Christophe Dubois static void imx_fec_reset(DeviceState *d) 334fcbd8018SJean-Christophe Dubois { 335fcbd8018SJean-Christophe Dubois IMXFECState *s = IMX_FEC(d); 336fcbd8018SJean-Christophe Dubois 337fcbd8018SJean-Christophe Dubois /* Reset the FEC */ 338fcbd8018SJean-Christophe Dubois s->eir = 0; 339fcbd8018SJean-Christophe Dubois s->eimr = 0; 340fcbd8018SJean-Christophe Dubois s->rx_enabled = 0; 341fcbd8018SJean-Christophe Dubois s->ecr = 0; 342fcbd8018SJean-Christophe Dubois s->mscr = 0; 343fcbd8018SJean-Christophe Dubois s->mibc = 0xc0000000; 344fcbd8018SJean-Christophe Dubois s->rcr = 0x05ee0001; 345fcbd8018SJean-Christophe Dubois s->tcr = 0; 346fcbd8018SJean-Christophe Dubois s->tfwr = 0; 347fcbd8018SJean-Christophe Dubois s->frsr = 0x500; 348fcbd8018SJean-Christophe Dubois s->miigsk_cfgr = 0; 349fcbd8018SJean-Christophe Dubois s->miigsk_enr = 0x6; 350fcbd8018SJean-Christophe Dubois 351fcbd8018SJean-Christophe Dubois /* We also reset the PHY */ 352fcbd8018SJean-Christophe Dubois phy_reset(s); 353fcbd8018SJean-Christophe Dubois } 354fcbd8018SJean-Christophe Dubois 355fcbd8018SJean-Christophe Dubois static uint64_t imx_fec_read(void *opaque, hwaddr addr, unsigned size) 356fcbd8018SJean-Christophe Dubois { 357fcbd8018SJean-Christophe Dubois IMXFECState *s = IMX_FEC(opaque); 358fcbd8018SJean-Christophe Dubois 359b72d8d25SJean-Christophe Dubois FEC_PRINTF("reading from @ 0x%" HWADDR_PRIx "\n", addr); 360fcbd8018SJean-Christophe Dubois 361fcbd8018SJean-Christophe Dubois switch (addr & 0x3ff) { 362fcbd8018SJean-Christophe Dubois case 0x004: 363fcbd8018SJean-Christophe Dubois return s->eir; 364fcbd8018SJean-Christophe Dubois case 0x008: 365fcbd8018SJean-Christophe Dubois return s->eimr; 366fcbd8018SJean-Christophe Dubois case 0x010: 367fcbd8018SJean-Christophe Dubois return s->rx_enabled ? (1 << 24) : 0; /* RDAR */ 368fcbd8018SJean-Christophe Dubois case 0x014: 369fcbd8018SJean-Christophe Dubois return 0; /* TDAR */ 370fcbd8018SJean-Christophe Dubois case 0x024: 371fcbd8018SJean-Christophe Dubois return s->ecr; 372fcbd8018SJean-Christophe Dubois case 0x040: 373fcbd8018SJean-Christophe Dubois return s->mmfr; 374fcbd8018SJean-Christophe Dubois case 0x044: 375fcbd8018SJean-Christophe Dubois return s->mscr; 376fcbd8018SJean-Christophe Dubois case 0x064: 377fcbd8018SJean-Christophe Dubois return s->mibc; /* MIBC */ 378fcbd8018SJean-Christophe Dubois case 0x084: 379fcbd8018SJean-Christophe Dubois return s->rcr; 380fcbd8018SJean-Christophe Dubois case 0x0c4: 381fcbd8018SJean-Christophe Dubois return s->tcr; 382fcbd8018SJean-Christophe Dubois case 0x0e4: /* PALR */ 383fcbd8018SJean-Christophe Dubois return (s->conf.macaddr.a[0] << 24) 384fcbd8018SJean-Christophe Dubois | (s->conf.macaddr.a[1] << 16) 385fcbd8018SJean-Christophe Dubois | (s->conf.macaddr.a[2] << 8) 386fcbd8018SJean-Christophe Dubois | s->conf.macaddr.a[3]; 387fcbd8018SJean-Christophe Dubois break; 388fcbd8018SJean-Christophe Dubois case 0x0e8: /* PAUR */ 389fcbd8018SJean-Christophe Dubois return (s->conf.macaddr.a[4] << 24) 390fcbd8018SJean-Christophe Dubois | (s->conf.macaddr.a[5] << 16) 391fcbd8018SJean-Christophe Dubois | 0x8808; 392fcbd8018SJean-Christophe Dubois case 0x0ec: 393fcbd8018SJean-Christophe Dubois return 0x10000; /* OPD */ 394fcbd8018SJean-Christophe Dubois case 0x118: 395fcbd8018SJean-Christophe Dubois return 0; 396fcbd8018SJean-Christophe Dubois case 0x11c: 397fcbd8018SJean-Christophe Dubois return 0; 398fcbd8018SJean-Christophe Dubois case 0x120: 399fcbd8018SJean-Christophe Dubois return 0; 400fcbd8018SJean-Christophe Dubois case 0x124: 401fcbd8018SJean-Christophe Dubois return 0; 402fcbd8018SJean-Christophe Dubois case 0x144: 403fcbd8018SJean-Christophe Dubois return s->tfwr; 404fcbd8018SJean-Christophe Dubois case 0x14c: 405fcbd8018SJean-Christophe Dubois return 0x600; 406fcbd8018SJean-Christophe Dubois case 0x150: 407fcbd8018SJean-Christophe Dubois return s->frsr; 408fcbd8018SJean-Christophe Dubois case 0x180: 409fcbd8018SJean-Christophe Dubois return s->erdsr; 410fcbd8018SJean-Christophe Dubois case 0x184: 411fcbd8018SJean-Christophe Dubois return s->etdsr; 412fcbd8018SJean-Christophe Dubois case 0x188: 413fcbd8018SJean-Christophe Dubois return s->emrbr; 414fcbd8018SJean-Christophe Dubois case 0x300: 415fcbd8018SJean-Christophe Dubois return s->miigsk_cfgr; 416fcbd8018SJean-Christophe Dubois case 0x308: 417fcbd8018SJean-Christophe Dubois return s->miigsk_enr; 418fcbd8018SJean-Christophe Dubois default: 419b72d8d25SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" 420b72d8d25SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_FEC, __func__, addr); 421fcbd8018SJean-Christophe Dubois return 0; 422fcbd8018SJean-Christophe Dubois } 423fcbd8018SJean-Christophe Dubois } 424fcbd8018SJean-Christophe Dubois 425fcbd8018SJean-Christophe Dubois static void imx_fec_write(void *opaque, hwaddr addr, 426fcbd8018SJean-Christophe Dubois uint64_t value, unsigned size) 427fcbd8018SJean-Christophe Dubois { 428fcbd8018SJean-Christophe Dubois IMXFECState *s = IMX_FEC(opaque); 429fcbd8018SJean-Christophe Dubois 430b72d8d25SJean-Christophe Dubois FEC_PRINTF("writing 0x%08x @ 0x%" HWADDR_PRIx "\n", (int)value, addr); 431fcbd8018SJean-Christophe Dubois 432fcbd8018SJean-Christophe Dubois switch (addr & 0x3ff) { 433fcbd8018SJean-Christophe Dubois case 0x004: /* EIR */ 434fcbd8018SJean-Christophe Dubois s->eir &= ~value; 435fcbd8018SJean-Christophe Dubois break; 436fcbd8018SJean-Christophe Dubois case 0x008: /* EIMR */ 437fcbd8018SJean-Christophe Dubois s->eimr = value; 438fcbd8018SJean-Christophe Dubois break; 439fcbd8018SJean-Christophe Dubois case 0x010: /* RDAR */ 440fcbd8018SJean-Christophe Dubois if ((s->ecr & FEC_EN) && !s->rx_enabled) { 441fcbd8018SJean-Christophe Dubois imx_fec_enable_rx(s); 442fcbd8018SJean-Christophe Dubois } 443fcbd8018SJean-Christophe Dubois break; 444fcbd8018SJean-Christophe Dubois case 0x014: /* TDAR */ 445fcbd8018SJean-Christophe Dubois if (s->ecr & FEC_EN) { 446fcbd8018SJean-Christophe Dubois imx_fec_do_tx(s); 447fcbd8018SJean-Christophe Dubois } 448fcbd8018SJean-Christophe Dubois break; 449fcbd8018SJean-Christophe Dubois case 0x024: /* ECR */ 450fcbd8018SJean-Christophe Dubois s->ecr = value; 451fcbd8018SJean-Christophe Dubois if (value & FEC_RESET) { 452fcbd8018SJean-Christophe Dubois imx_fec_reset(DEVICE(s)); 453fcbd8018SJean-Christophe Dubois } 454fcbd8018SJean-Christophe Dubois if ((s->ecr & FEC_EN) == 0) { 455fcbd8018SJean-Christophe Dubois s->rx_enabled = 0; 456fcbd8018SJean-Christophe Dubois } 457fcbd8018SJean-Christophe Dubois break; 458fcbd8018SJean-Christophe Dubois case 0x040: /* MMFR */ 459fcbd8018SJean-Christophe Dubois /* store the value */ 460fcbd8018SJean-Christophe Dubois s->mmfr = value; 461fcbd8018SJean-Christophe Dubois if (extract32(value, 28, 1)) { 462fcbd8018SJean-Christophe Dubois do_phy_write(s, extract32(value, 18, 9), extract32(value, 0, 16)); 463fcbd8018SJean-Christophe Dubois } else { 464fcbd8018SJean-Christophe Dubois s->mmfr = do_phy_read(s, extract32(value, 18, 9)); 465fcbd8018SJean-Christophe Dubois } 466fcbd8018SJean-Christophe Dubois /* raise the interrupt as the PHY operation is done */ 467fcbd8018SJean-Christophe Dubois s->eir |= FEC_INT_MII; 468fcbd8018SJean-Christophe Dubois break; 469fcbd8018SJean-Christophe Dubois case 0x044: /* MSCR */ 470fcbd8018SJean-Christophe Dubois s->mscr = value & 0xfe; 471fcbd8018SJean-Christophe Dubois break; 472fcbd8018SJean-Christophe Dubois case 0x064: /* MIBC */ 473fcbd8018SJean-Christophe Dubois /* TODO: Implement MIB. */ 474fcbd8018SJean-Christophe Dubois s->mibc = (value & 0x80000000) ? 0xc0000000 : 0; 475fcbd8018SJean-Christophe Dubois break; 476fcbd8018SJean-Christophe Dubois case 0x084: /* RCR */ 477fcbd8018SJean-Christophe Dubois s->rcr = value & 0x07ff003f; 478fcbd8018SJean-Christophe Dubois /* TODO: Implement LOOP mode. */ 479fcbd8018SJean-Christophe Dubois break; 480fcbd8018SJean-Christophe Dubois case 0x0c4: /* TCR */ 481fcbd8018SJean-Christophe Dubois /* We transmit immediately, so raise GRA immediately. */ 482fcbd8018SJean-Christophe Dubois s->tcr = value; 483fcbd8018SJean-Christophe Dubois if (value & 1) { 484fcbd8018SJean-Christophe Dubois s->eir |= FEC_INT_GRA; 485fcbd8018SJean-Christophe Dubois } 486fcbd8018SJean-Christophe Dubois break; 487fcbd8018SJean-Christophe Dubois case 0x0e4: /* PALR */ 488fcbd8018SJean-Christophe Dubois s->conf.macaddr.a[0] = value >> 24; 489fcbd8018SJean-Christophe Dubois s->conf.macaddr.a[1] = value >> 16; 490fcbd8018SJean-Christophe Dubois s->conf.macaddr.a[2] = value >> 8; 491fcbd8018SJean-Christophe Dubois s->conf.macaddr.a[3] = value; 492fcbd8018SJean-Christophe Dubois break; 493fcbd8018SJean-Christophe Dubois case 0x0e8: /* PAUR */ 494fcbd8018SJean-Christophe Dubois s->conf.macaddr.a[4] = value >> 24; 495fcbd8018SJean-Christophe Dubois s->conf.macaddr.a[5] = value >> 16; 496fcbd8018SJean-Christophe Dubois break; 497fcbd8018SJean-Christophe Dubois case 0x0ec: /* OPDR */ 498fcbd8018SJean-Christophe Dubois break; 499fcbd8018SJean-Christophe Dubois case 0x118: /* IAUR */ 500fcbd8018SJean-Christophe Dubois case 0x11c: /* IALR */ 501fcbd8018SJean-Christophe Dubois case 0x120: /* GAUR */ 502fcbd8018SJean-Christophe Dubois case 0x124: /* GALR */ 503fcbd8018SJean-Christophe Dubois /* TODO: implement MAC hash filtering. */ 504fcbd8018SJean-Christophe Dubois break; 505fcbd8018SJean-Christophe Dubois case 0x144: /* TFWR */ 506fcbd8018SJean-Christophe Dubois s->tfwr = value & 3; 507fcbd8018SJean-Christophe Dubois break; 508fcbd8018SJean-Christophe Dubois case 0x14c: /* FRBR */ 509fcbd8018SJean-Christophe Dubois /* FRBR writes ignored. */ 510fcbd8018SJean-Christophe Dubois break; 511fcbd8018SJean-Christophe Dubois case 0x150: /* FRSR */ 512fcbd8018SJean-Christophe Dubois s->frsr = (value & 0x3fc) | 0x400; 513fcbd8018SJean-Christophe Dubois break; 514fcbd8018SJean-Christophe Dubois case 0x180: /* ERDSR */ 515fcbd8018SJean-Christophe Dubois s->erdsr = value & ~3; 516fcbd8018SJean-Christophe Dubois s->rx_descriptor = s->erdsr; 517fcbd8018SJean-Christophe Dubois break; 518fcbd8018SJean-Christophe Dubois case 0x184: /* ETDSR */ 519fcbd8018SJean-Christophe Dubois s->etdsr = value & ~3; 520fcbd8018SJean-Christophe Dubois s->tx_descriptor = s->etdsr; 521fcbd8018SJean-Christophe Dubois break; 522fcbd8018SJean-Christophe Dubois case 0x188: /* EMRBR */ 523fcbd8018SJean-Christophe Dubois s->emrbr = value & 0x7f0; 524fcbd8018SJean-Christophe Dubois break; 525fcbd8018SJean-Christophe Dubois case 0x300: /* MIIGSK_CFGR */ 526fcbd8018SJean-Christophe Dubois s->miigsk_cfgr = value & 0x53; 527fcbd8018SJean-Christophe Dubois break; 528fcbd8018SJean-Christophe Dubois case 0x308: /* MIIGSK_ENR */ 529fcbd8018SJean-Christophe Dubois s->miigsk_enr = (value & 0x2) ? 0x6 : 0; 530fcbd8018SJean-Christophe Dubois break; 531fcbd8018SJean-Christophe Dubois default: 532b72d8d25SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" 533b72d8d25SJean-Christophe Dubois HWADDR_PRIx "\n", TYPE_IMX_FEC, __func__, addr); 534fcbd8018SJean-Christophe Dubois break; 535fcbd8018SJean-Christophe Dubois } 536fcbd8018SJean-Christophe Dubois 537fcbd8018SJean-Christophe Dubois imx_fec_update(s); 538fcbd8018SJean-Christophe Dubois } 539fcbd8018SJean-Christophe Dubois 540fcbd8018SJean-Christophe Dubois static int imx_fec_can_receive(NetClientState *nc) 541fcbd8018SJean-Christophe Dubois { 542fcbd8018SJean-Christophe Dubois IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); 543fcbd8018SJean-Christophe Dubois 544fcbd8018SJean-Christophe Dubois return s->rx_enabled; 545fcbd8018SJean-Christophe Dubois } 546fcbd8018SJean-Christophe Dubois 547fcbd8018SJean-Christophe Dubois static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, 548fcbd8018SJean-Christophe Dubois size_t len) 549fcbd8018SJean-Christophe Dubois { 550fcbd8018SJean-Christophe Dubois IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); 551fcbd8018SJean-Christophe Dubois IMXFECBufDesc bd; 552fcbd8018SJean-Christophe Dubois uint32_t flags = 0; 553fcbd8018SJean-Christophe Dubois uint32_t addr; 554fcbd8018SJean-Christophe Dubois uint32_t crc; 555fcbd8018SJean-Christophe Dubois uint32_t buf_addr; 556fcbd8018SJean-Christophe Dubois uint8_t *crc_ptr; 557fcbd8018SJean-Christophe Dubois unsigned int buf_len; 558fcbd8018SJean-Christophe Dubois size_t size = len; 559fcbd8018SJean-Christophe Dubois 560fcbd8018SJean-Christophe Dubois FEC_PRINTF("len %d\n", (int)size); 561fcbd8018SJean-Christophe Dubois 562fcbd8018SJean-Christophe Dubois if (!s->rx_enabled) { 563b72d8d25SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Unexpected packet\n", 564fcbd8018SJean-Christophe Dubois TYPE_IMX_FEC, __func__); 565fcbd8018SJean-Christophe Dubois return 0; 566fcbd8018SJean-Christophe Dubois } 567fcbd8018SJean-Christophe Dubois 568fcbd8018SJean-Christophe Dubois /* 4 bytes for the CRC. */ 569fcbd8018SJean-Christophe Dubois size += 4; 570fcbd8018SJean-Christophe Dubois crc = cpu_to_be32(crc32(~0, buf, size)); 571fcbd8018SJean-Christophe Dubois crc_ptr = (uint8_t *) &crc; 572fcbd8018SJean-Christophe Dubois 573fcbd8018SJean-Christophe Dubois /* Huge frames are truncted. */ 574fcbd8018SJean-Christophe Dubois if (size > FEC_MAX_FRAME_SIZE) { 575fcbd8018SJean-Christophe Dubois size = FEC_MAX_FRAME_SIZE; 576fcbd8018SJean-Christophe Dubois flags |= FEC_BD_TR | FEC_BD_LG; 577fcbd8018SJean-Christophe Dubois } 578fcbd8018SJean-Christophe Dubois 579fcbd8018SJean-Christophe Dubois /* Frames larger than the user limit just set error flags. */ 580fcbd8018SJean-Christophe Dubois if (size > (s->rcr >> 16)) { 581fcbd8018SJean-Christophe Dubois flags |= FEC_BD_LG; 582fcbd8018SJean-Christophe Dubois } 583fcbd8018SJean-Christophe Dubois 584fcbd8018SJean-Christophe Dubois addr = s->rx_descriptor; 585fcbd8018SJean-Christophe Dubois while (size > 0) { 586fcbd8018SJean-Christophe Dubois imx_fec_read_bd(&bd, addr); 587fcbd8018SJean-Christophe Dubois if ((bd.flags & FEC_BD_E) == 0) { 588fcbd8018SJean-Christophe Dubois /* No descriptors available. Bail out. */ 589fcbd8018SJean-Christophe Dubois /* 590fcbd8018SJean-Christophe Dubois * FIXME: This is wrong. We should probably either 591fcbd8018SJean-Christophe Dubois * save the remainder for when more RX buffers are 592fcbd8018SJean-Christophe Dubois * available, or flag an error. 593fcbd8018SJean-Christophe Dubois */ 594b72d8d25SJean-Christophe Dubois qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Lost end of frame\n", 595fcbd8018SJean-Christophe Dubois TYPE_IMX_FEC, __func__); 596fcbd8018SJean-Christophe Dubois break; 597fcbd8018SJean-Christophe Dubois } 598fcbd8018SJean-Christophe Dubois buf_len = (size <= s->emrbr) ? size : s->emrbr; 599fcbd8018SJean-Christophe Dubois bd.length = buf_len; 600fcbd8018SJean-Christophe Dubois size -= buf_len; 601b72d8d25SJean-Christophe Dubois 602b72d8d25SJean-Christophe Dubois FEC_PRINTF("rx_bd 0x%x length %d\n", addr, bd.length); 603b72d8d25SJean-Christophe Dubois 604fcbd8018SJean-Christophe Dubois /* The last 4 bytes are the CRC. */ 605fcbd8018SJean-Christophe Dubois if (size < 4) { 606fcbd8018SJean-Christophe Dubois buf_len += size - 4; 607fcbd8018SJean-Christophe Dubois } 608fcbd8018SJean-Christophe Dubois buf_addr = bd.data; 609fcbd8018SJean-Christophe Dubois dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); 610fcbd8018SJean-Christophe Dubois buf += buf_len; 611fcbd8018SJean-Christophe Dubois if (size < 4) { 612fcbd8018SJean-Christophe Dubois dma_memory_write(&address_space_memory, buf_addr + buf_len, 613fcbd8018SJean-Christophe Dubois crc_ptr, 4 - size); 614fcbd8018SJean-Christophe Dubois crc_ptr += 4 - size; 615fcbd8018SJean-Christophe Dubois } 616fcbd8018SJean-Christophe Dubois bd.flags &= ~FEC_BD_E; 617fcbd8018SJean-Christophe Dubois if (size == 0) { 618fcbd8018SJean-Christophe Dubois /* Last buffer in frame. */ 619fcbd8018SJean-Christophe Dubois bd.flags |= flags | FEC_BD_L; 620fcbd8018SJean-Christophe Dubois FEC_PRINTF("rx frame flags %04x\n", bd.flags); 621fcbd8018SJean-Christophe Dubois s->eir |= FEC_INT_RXF; 622fcbd8018SJean-Christophe Dubois } else { 623fcbd8018SJean-Christophe Dubois s->eir |= FEC_INT_RXB; 624fcbd8018SJean-Christophe Dubois } 625fcbd8018SJean-Christophe Dubois imx_fec_write_bd(&bd, addr); 626fcbd8018SJean-Christophe Dubois /* Advance to the next descriptor. */ 627fcbd8018SJean-Christophe Dubois if ((bd.flags & FEC_BD_W) != 0) { 628fcbd8018SJean-Christophe Dubois addr = s->erdsr; 629fcbd8018SJean-Christophe Dubois } else { 630fcbd8018SJean-Christophe Dubois addr += 8; 631fcbd8018SJean-Christophe Dubois } 632fcbd8018SJean-Christophe Dubois } 633fcbd8018SJean-Christophe Dubois s->rx_descriptor = addr; 634fcbd8018SJean-Christophe Dubois imx_fec_enable_rx(s); 635fcbd8018SJean-Christophe Dubois imx_fec_update(s); 636fcbd8018SJean-Christophe Dubois return len; 637fcbd8018SJean-Christophe Dubois } 638fcbd8018SJean-Christophe Dubois 639fcbd8018SJean-Christophe Dubois static const MemoryRegionOps imx_fec_ops = { 640fcbd8018SJean-Christophe Dubois .read = imx_fec_read, 641fcbd8018SJean-Christophe Dubois .write = imx_fec_write, 642fcbd8018SJean-Christophe Dubois .valid.min_access_size = 4, 643fcbd8018SJean-Christophe Dubois .valid.max_access_size = 4, 644fcbd8018SJean-Christophe Dubois .endianness = DEVICE_NATIVE_ENDIAN, 645fcbd8018SJean-Christophe Dubois }; 646fcbd8018SJean-Christophe Dubois 647fcbd8018SJean-Christophe Dubois static void imx_fec_cleanup(NetClientState *nc) 648fcbd8018SJean-Christophe Dubois { 649fcbd8018SJean-Christophe Dubois IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); 650fcbd8018SJean-Christophe Dubois 651fcbd8018SJean-Christophe Dubois s->nic = NULL; 652fcbd8018SJean-Christophe Dubois } 653fcbd8018SJean-Christophe Dubois 654fcbd8018SJean-Christophe Dubois static NetClientInfo net_imx_fec_info = { 655fcbd8018SJean-Christophe Dubois .type = NET_CLIENT_OPTIONS_KIND_NIC, 656fcbd8018SJean-Christophe Dubois .size = sizeof(NICState), 657fcbd8018SJean-Christophe Dubois .can_receive = imx_fec_can_receive, 658fcbd8018SJean-Christophe Dubois .receive = imx_fec_receive, 659fcbd8018SJean-Christophe Dubois .cleanup = imx_fec_cleanup, 660fcbd8018SJean-Christophe Dubois .link_status_changed = imx_fec_set_link, 661fcbd8018SJean-Christophe Dubois }; 662fcbd8018SJean-Christophe Dubois 663fcbd8018SJean-Christophe Dubois 664fcbd8018SJean-Christophe Dubois static void imx_fec_realize(DeviceState *dev, Error **errp) 665fcbd8018SJean-Christophe Dubois { 666fcbd8018SJean-Christophe Dubois IMXFECState *s = IMX_FEC(dev); 667fcbd8018SJean-Christophe Dubois SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 668fcbd8018SJean-Christophe Dubois 669fcbd8018SJean-Christophe Dubois memory_region_init_io(&s->iomem, OBJECT(dev), &imx_fec_ops, s, 670fcbd8018SJean-Christophe Dubois TYPE_IMX_FEC, 0x400); 671fcbd8018SJean-Christophe Dubois sysbus_init_mmio(sbd, &s->iomem); 672fcbd8018SJean-Christophe Dubois sysbus_init_irq(sbd, &s->irq); 673fcbd8018SJean-Christophe Dubois qemu_macaddr_default_if_unset(&s->conf.macaddr); 674fcbd8018SJean-Christophe Dubois 675fcbd8018SJean-Christophe Dubois s->conf.peers.ncs[0] = nd_table[0].netdev; 676fcbd8018SJean-Christophe Dubois 677fcbd8018SJean-Christophe Dubois s->nic = qemu_new_nic(&net_imx_fec_info, &s->conf, 678fcbd8018SJean-Christophe Dubois object_get_typename(OBJECT(dev)), DEVICE(dev)->id, 679fcbd8018SJean-Christophe Dubois s); 680fcbd8018SJean-Christophe Dubois qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); 681fcbd8018SJean-Christophe Dubois } 682fcbd8018SJean-Christophe Dubois 683fcbd8018SJean-Christophe Dubois static Property imx_fec_properties[] = { 684fcbd8018SJean-Christophe Dubois DEFINE_NIC_PROPERTIES(IMXFECState, conf), 685fcbd8018SJean-Christophe Dubois DEFINE_PROP_END_OF_LIST(), 686fcbd8018SJean-Christophe Dubois }; 687fcbd8018SJean-Christophe Dubois 688fcbd8018SJean-Christophe Dubois static void imx_fec_class_init(ObjectClass *klass, void *data) 689fcbd8018SJean-Christophe Dubois { 690fcbd8018SJean-Christophe Dubois DeviceClass *dc = DEVICE_CLASS(klass); 691fcbd8018SJean-Christophe Dubois 692fcbd8018SJean-Christophe Dubois dc->vmsd = &vmstate_imx_fec; 693fcbd8018SJean-Christophe Dubois dc->reset = imx_fec_reset; 694fcbd8018SJean-Christophe Dubois dc->props = imx_fec_properties; 695fcbd8018SJean-Christophe Dubois dc->realize = imx_fec_realize; 696fcbd8018SJean-Christophe Dubois } 697fcbd8018SJean-Christophe Dubois 698fcbd8018SJean-Christophe Dubois static const TypeInfo imx_fec_info = { 699fcbd8018SJean-Christophe Dubois .name = TYPE_IMX_FEC, 700fcbd8018SJean-Christophe Dubois .parent = TYPE_SYS_BUS_DEVICE, 701fcbd8018SJean-Christophe Dubois .instance_size = sizeof(IMXFECState), 702fcbd8018SJean-Christophe Dubois .class_init = imx_fec_class_init, 703fcbd8018SJean-Christophe Dubois }; 704fcbd8018SJean-Christophe Dubois 705fcbd8018SJean-Christophe Dubois static void imx_fec_register_types(void) 706fcbd8018SJean-Christophe Dubois { 707fcbd8018SJean-Christophe Dubois type_register_static(&imx_fec_info); 708fcbd8018SJean-Christophe Dubois } 709fcbd8018SJean-Christophe Dubois 710fcbd8018SJean-Christophe Dubois type_init(imx_fec_register_types) 711