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 "hw/net/imx_fec.h" 25 #include "sysemu/dma.h" 26 27 /* For crc32 */ 28 #include <zlib.h> 29 30 #ifndef IMX_FEC_DEBUG 31 #define IMX_FEC_DEBUG 0 32 #endif 33 34 #ifndef IMX_PHY_DEBUG 35 #define IMX_PHY_DEBUG 0 36 #endif 37 38 #if IMX_FEC_DEBUG 39 #define FEC_PRINTF(fmt, ...) \ 40 do { fprintf(stderr, "%s[%s]: " fmt , TYPE_IMX_FEC, __func__, \ 41 ## __VA_ARGS__); \ 42 } while (0) 43 #else 44 #define FEC_PRINTF(fmt, ...) do {} while (0) 45 #endif 46 47 #if IMX_PHY_DEBUG 48 #define PHY_PRINTF(fmt, ...) \ 49 do { fprintf(stderr, "%s.phy[%s]: " fmt , TYPE_IMX_FEC, __func__, \ 50 ## __VA_ARGS__); \ 51 } while (0) 52 #else 53 #define PHY_PRINTF(fmt, ...) do {} while (0) 54 #endif 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[%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[FEC_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 & FEC_BD_R) == 0) { 281 /* Run out of descriptors to transmit. */ 282 break; 283 } 284 len = bd.length; 285 if (frame_size + len > FEC_MAX_FRAME_SIZE) { 286 len = FEC_MAX_FRAME_SIZE - frame_size; 287 s->eir |= FEC_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 & FEC_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 |= FEC_INT_TXF; 298 } 299 s->eir |= FEC_INT_TXB; 300 bd.flags &= ~FEC_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 & FEC_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 & FEC_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 = 0; 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%03x\n", (int)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 %d\n", 421 TYPE_IMX_FEC, __func__, (int)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%03x\n", (int)value, (int)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 & FEC_EN) && !s->rx_enabled) { 442 imx_fec_enable_rx(s); 443 } 444 break; 445 case 0x014: /* TDAR */ 446 if (s->ecr & FEC_EN) { 447 imx_fec_do_tx(s); 448 } 449 break; 450 case 0x024: /* ECR */ 451 s->ecr = value; 452 if (value & FEC_RESET) { 453 imx_fec_reset(DEVICE(s)); 454 } 455 if ((s->ecr & FEC_EN) == 0) { 456 s->rx_enabled = 0; 457 } 458 break; 459 case 0x040: /* MMFR */ 460 /* store the value */ 461 s->mmfr = value; 462 if (extract32(value, 28, 1)) { 463 do_phy_write(s, extract32(value, 18, 9), extract32(value, 0, 16)); 464 } else { 465 s->mmfr = do_phy_read(s, extract32(value, 18, 9)); 466 } 467 /* raise the interrupt as the PHY operation is done */ 468 s->eir |= FEC_INT_MII; 469 break; 470 case 0x044: /* MSCR */ 471 s->mscr = value & 0xfe; 472 break; 473 case 0x064: /* MIBC */ 474 /* TODO: Implement MIB. */ 475 s->mibc = (value & 0x80000000) ? 0xc0000000 : 0; 476 break; 477 case 0x084: /* RCR */ 478 s->rcr = value & 0x07ff003f; 479 /* TODO: Implement LOOP mode. */ 480 break; 481 case 0x0c4: /* TCR */ 482 /* We transmit immediately, so raise GRA immediately. */ 483 s->tcr = value; 484 if (value & 1) { 485 s->eir |= FEC_INT_GRA; 486 } 487 break; 488 case 0x0e4: /* PALR */ 489 s->conf.macaddr.a[0] = value >> 24; 490 s->conf.macaddr.a[1] = value >> 16; 491 s->conf.macaddr.a[2] = value >> 8; 492 s->conf.macaddr.a[3] = value; 493 break; 494 case 0x0e8: /* PAUR */ 495 s->conf.macaddr.a[4] = value >> 24; 496 s->conf.macaddr.a[5] = value >> 16; 497 break; 498 case 0x0ec: /* OPDR */ 499 break; 500 case 0x118: /* IAUR */ 501 case 0x11c: /* IALR */ 502 case 0x120: /* GAUR */ 503 case 0x124: /* GALR */ 504 /* TODO: implement MAC hash filtering. */ 505 break; 506 case 0x144: /* TFWR */ 507 s->tfwr = value & 3; 508 break; 509 case 0x14c: /* FRBR */ 510 /* FRBR writes ignored. */ 511 break; 512 case 0x150: /* FRSR */ 513 s->frsr = (value & 0x3fc) | 0x400; 514 break; 515 case 0x180: /* ERDSR */ 516 s->erdsr = value & ~3; 517 s->rx_descriptor = s->erdsr; 518 break; 519 case 0x184: /* ETDSR */ 520 s->etdsr = value & ~3; 521 s->tx_descriptor = s->etdsr; 522 break; 523 case 0x188: /* EMRBR */ 524 s->emrbr = value & 0x7f0; 525 break; 526 case 0x300: /* MIIGSK_CFGR */ 527 s->miigsk_cfgr = value & 0x53; 528 break; 529 case 0x308: /* MIIGSK_ENR */ 530 s->miigsk_enr = (value & 0x2) ? 0x6 : 0; 531 break; 532 default: 533 qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Bad address at offset %d\n", 534 TYPE_IMX_FEC, __func__, (int)addr); 535 break; 536 } 537 538 imx_fec_update(s); 539 } 540 541 static int imx_fec_can_receive(NetClientState *nc) 542 { 543 IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); 544 545 return s->rx_enabled; 546 } 547 548 static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, 549 size_t len) 550 { 551 IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); 552 IMXFECBufDesc bd; 553 uint32_t flags = 0; 554 uint32_t addr; 555 uint32_t crc; 556 uint32_t buf_addr; 557 uint8_t *crc_ptr; 558 unsigned int buf_len; 559 size_t size = len; 560 561 FEC_PRINTF("len %d\n", (int)size); 562 563 if (!s->rx_enabled) { 564 qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Unexpected packet\n", 565 TYPE_IMX_FEC, __func__); 566 return 0; 567 } 568 569 /* 4 bytes for the CRC. */ 570 size += 4; 571 crc = cpu_to_be32(crc32(~0, buf, size)); 572 crc_ptr = (uint8_t *) &crc; 573 574 /* Huge frames are truncted. */ 575 if (size > FEC_MAX_FRAME_SIZE) { 576 size = FEC_MAX_FRAME_SIZE; 577 flags |= FEC_BD_TR | FEC_BD_LG; 578 } 579 580 /* Frames larger than the user limit just set error flags. */ 581 if (size > (s->rcr >> 16)) { 582 flags |= FEC_BD_LG; 583 } 584 585 addr = s->rx_descriptor; 586 while (size > 0) { 587 imx_fec_read_bd(&bd, addr); 588 if ((bd.flags & FEC_BD_E) == 0) { 589 /* No descriptors available. Bail out. */ 590 /* 591 * FIXME: This is wrong. We should probably either 592 * save the remainder for when more RX buffers are 593 * available, or flag an error. 594 */ 595 qemu_log_mask(LOG_GUEST_ERROR, "%s[%s]: Lost end of frame\n", 596 TYPE_IMX_FEC, __func__); 597 break; 598 } 599 buf_len = (size <= s->emrbr) ? size : s->emrbr; 600 bd.length = buf_len; 601 size -= buf_len; 602 FEC_PRINTF("rx_bd %x length %d\n", addr, bd.length); 603 /* The last 4 bytes are the CRC. */ 604 if (size < 4) { 605 buf_len += size - 4; 606 } 607 buf_addr = bd.data; 608 dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); 609 buf += buf_len; 610 if (size < 4) { 611 dma_memory_write(&address_space_memory, buf_addr + buf_len, 612 crc_ptr, 4 - size); 613 crc_ptr += 4 - size; 614 } 615 bd.flags &= ~FEC_BD_E; 616 if (size == 0) { 617 /* Last buffer in frame. */ 618 bd.flags |= flags | FEC_BD_L; 619 FEC_PRINTF("rx frame flags %04x\n", bd.flags); 620 s->eir |= FEC_INT_RXF; 621 } else { 622 s->eir |= FEC_INT_RXB; 623 } 624 imx_fec_write_bd(&bd, addr); 625 /* Advance to the next descriptor. */ 626 if ((bd.flags & FEC_BD_W) != 0) { 627 addr = s->erdsr; 628 } else { 629 addr += 8; 630 } 631 } 632 s->rx_descriptor = addr; 633 imx_fec_enable_rx(s); 634 imx_fec_update(s); 635 return len; 636 } 637 638 static const MemoryRegionOps imx_fec_ops = { 639 .read = imx_fec_read, 640 .write = imx_fec_write, 641 .valid.min_access_size = 4, 642 .valid.max_access_size = 4, 643 .endianness = DEVICE_NATIVE_ENDIAN, 644 }; 645 646 static void imx_fec_cleanup(NetClientState *nc) 647 { 648 IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); 649 650 s->nic = NULL; 651 } 652 653 static NetClientInfo net_imx_fec_info = { 654 .type = NET_CLIENT_OPTIONS_KIND_NIC, 655 .size = sizeof(NICState), 656 .can_receive = imx_fec_can_receive, 657 .receive = imx_fec_receive, 658 .cleanup = imx_fec_cleanup, 659 .link_status_changed = imx_fec_set_link, 660 }; 661 662 663 static void imx_fec_realize(DeviceState *dev, Error **errp) 664 { 665 IMXFECState *s = IMX_FEC(dev); 666 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 667 668 memory_region_init_io(&s->iomem, OBJECT(dev), &imx_fec_ops, s, 669 TYPE_IMX_FEC, 0x400); 670 sysbus_init_mmio(sbd, &s->iomem); 671 sysbus_init_irq(sbd, &s->irq); 672 qemu_macaddr_default_if_unset(&s->conf.macaddr); 673 674 s->conf.peers.ncs[0] = nd_table[0].netdev; 675 676 s->nic = qemu_new_nic(&net_imx_fec_info, &s->conf, 677 object_get_typename(OBJECT(dev)), DEVICE(dev)->id, 678 s); 679 qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); 680 } 681 682 static Property imx_fec_properties[] = { 683 DEFINE_NIC_PROPERTIES(IMXFECState, conf), 684 DEFINE_PROP_END_OF_LIST(), 685 }; 686 687 static void imx_fec_class_init(ObjectClass *klass, void *data) 688 { 689 DeviceClass *dc = DEVICE_CLASS(klass); 690 691 dc->vmsd = &vmstate_imx_fec; 692 dc->reset = imx_fec_reset; 693 dc->props = imx_fec_properties; 694 dc->realize = imx_fec_realize; 695 } 696 697 static const TypeInfo imx_fec_info = { 698 .name = TYPE_IMX_FEC, 699 .parent = TYPE_SYS_BUS_DEVICE, 700 .instance_size = sizeof(IMXFECState), 701 .class_init = imx_fec_class_init, 702 }; 703 704 static void imx_fec_register_types(void) 705 { 706 type_register_static(&imx_fec_info); 707 } 708 709 type_init(imx_fec_register_types) 710