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