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 DEBUG_IMX_FEC 31 #define DEBUG_IMX_FEC 0 32 #endif 33 34 #define FEC_PRINTF(fmt, args...) \ 35 do { \ 36 if (DEBUG_IMX_FEC) { \ 37 fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_FEC, \ 38 __func__, ##args); \ 39 } \ 40 } while (0) 41 42 #ifndef DEBUG_IMX_PHY 43 #define DEBUG_IMX_PHY 0 44 #endif 45 46 #define PHY_PRINTF(fmt, args...) \ 47 do { \ 48 if (DEBUG_IMX_PHY) { \ 49 fprintf(stderr, "[%s.phy]%s: " fmt , TYPE_IMX_FEC, \ 50 __func__, ##args); \ 51 } \ 52 } while (0) 53 54 static const VMStateDescription vmstate_imx_fec = { 55 .name = TYPE_IMX_FEC, 56 .version_id = 1, 57 .minimum_version_id = 1, 58 .fields = (VMStateField[]) { 59 VMSTATE_UINT32(irq_state, IMXFECState), 60 VMSTATE_UINT32(eir, IMXFECState), 61 VMSTATE_UINT32(eimr, IMXFECState), 62 VMSTATE_UINT32(rx_enabled, IMXFECState), 63 VMSTATE_UINT32(rx_descriptor, IMXFECState), 64 VMSTATE_UINT32(tx_descriptor, IMXFECState), 65 VMSTATE_UINT32(ecr, IMXFECState), 66 VMSTATE_UINT32(mmfr, IMXFECState), 67 VMSTATE_UINT32(mscr, IMXFECState), 68 VMSTATE_UINT32(mibc, IMXFECState), 69 VMSTATE_UINT32(rcr, IMXFECState), 70 VMSTATE_UINT32(tcr, IMXFECState), 71 VMSTATE_UINT32(tfwr, IMXFECState), 72 VMSTATE_UINT32(frsr, IMXFECState), 73 VMSTATE_UINT32(erdsr, IMXFECState), 74 VMSTATE_UINT32(etdsr, IMXFECState), 75 VMSTATE_UINT32(emrbr, IMXFECState), 76 VMSTATE_UINT32(miigsk_cfgr, IMXFECState), 77 VMSTATE_UINT32(miigsk_enr, IMXFECState), 78 79 VMSTATE_UINT32(phy_status, IMXFECState), 80 VMSTATE_UINT32(phy_control, IMXFECState), 81 VMSTATE_UINT32(phy_advertise, IMXFECState), 82 VMSTATE_UINT32(phy_int, IMXFECState), 83 VMSTATE_UINT32(phy_int_mask, IMXFECState), 84 VMSTATE_END_OF_LIST() 85 } 86 }; 87 88 #define PHY_INT_ENERGYON (1 << 7) 89 #define PHY_INT_AUTONEG_COMPLETE (1 << 6) 90 #define PHY_INT_FAULT (1 << 5) 91 #define PHY_INT_DOWN (1 << 4) 92 #define PHY_INT_AUTONEG_LP (1 << 3) 93 #define PHY_INT_PARFAULT (1 << 2) 94 #define PHY_INT_AUTONEG_PAGE (1 << 1) 95 96 static void imx_fec_update(IMXFECState *s); 97 98 /* 99 * The MII phy could raise a GPIO to the processor which in turn 100 * could be handled as an interrpt by the OS. 101 * For now we don't handle any GPIO/interrupt line, so the OS will 102 * have to poll for the PHY status. 103 */ 104 static void phy_update_irq(IMXFECState *s) 105 { 106 imx_fec_update(s); 107 } 108 109 static void phy_update_link(IMXFECState *s) 110 { 111 /* Autonegotiation status mirrors link status. */ 112 if (qemu_get_queue(s->nic)->link_down) { 113 PHY_PRINTF("link is down\n"); 114 s->phy_status &= ~0x0024; 115 s->phy_int |= PHY_INT_DOWN; 116 } else { 117 PHY_PRINTF("link is up\n"); 118 s->phy_status |= 0x0024; 119 s->phy_int |= PHY_INT_ENERGYON; 120 s->phy_int |= PHY_INT_AUTONEG_COMPLETE; 121 } 122 phy_update_irq(s); 123 } 124 125 static void imx_fec_set_link(NetClientState *nc) 126 { 127 phy_update_link(IMX_FEC(qemu_get_nic_opaque(nc))); 128 } 129 130 static void phy_reset(IMXFECState *s) 131 { 132 s->phy_status = 0x7809; 133 s->phy_control = 0x3000; 134 s->phy_advertise = 0x01e1; 135 s->phy_int_mask = 0; 136 s->phy_int = 0; 137 phy_update_link(s); 138 } 139 140 static uint32_t do_phy_read(IMXFECState *s, int reg) 141 { 142 uint32_t val; 143 144 if (reg > 31) { 145 /* we only advertise one phy */ 146 return 0; 147 } 148 149 switch (reg) { 150 case 0: /* Basic Control */ 151 val = s->phy_control; 152 break; 153 case 1: /* Basic Status */ 154 val = s->phy_status; 155 break; 156 case 2: /* ID1 */ 157 val = 0x0007; 158 break; 159 case 3: /* ID2 */ 160 val = 0xc0d1; 161 break; 162 case 4: /* Auto-neg advertisement */ 163 val = s->phy_advertise; 164 break; 165 case 5: /* Auto-neg Link Partner Ability */ 166 val = 0x0f71; 167 break; 168 case 6: /* Auto-neg Expansion */ 169 val = 1; 170 break; 171 case 29: /* Interrupt source. */ 172 val = s->phy_int; 173 s->phy_int = 0; 174 phy_update_irq(s); 175 break; 176 case 30: /* Interrupt mask */ 177 val = s->phy_int_mask; 178 break; 179 case 17: 180 case 18: 181 case 27: 182 case 31: 183 qemu_log_mask(LOG_UNIMP, "[%s.phy]%s: reg %d not implemented\n", 184 TYPE_IMX_FEC, __func__, reg); 185 val = 0; 186 break; 187 default: 188 qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n", 189 TYPE_IMX_FEC, __func__, reg); 190 val = 0; 191 break; 192 } 193 194 PHY_PRINTF("read 0x%04x @ %d\n", val, reg); 195 196 return val; 197 } 198 199 static void do_phy_write(IMXFECState *s, int reg, uint32_t val) 200 { 201 PHY_PRINTF("write 0x%04x @ %d\n", val, reg); 202 203 if (reg > 31) { 204 /* we only advertise one phy */ 205 return; 206 } 207 208 switch (reg) { 209 case 0: /* Basic Control */ 210 if (val & 0x8000) { 211 phy_reset(s); 212 } else { 213 s->phy_control = val & 0x7980; 214 /* Complete autonegotiation immediately. */ 215 if (val & 0x1000) { 216 s->phy_status |= 0x0020; 217 } 218 } 219 break; 220 case 4: /* Auto-neg advertisement */ 221 s->phy_advertise = (val & 0x2d7f) | 0x80; 222 break; 223 case 30: /* Interrupt mask */ 224 s->phy_int_mask = val & 0xff; 225 phy_update_irq(s); 226 break; 227 case 17: 228 case 18: 229 case 27: 230 case 31: 231 qemu_log_mask(LOG_UNIMP, "[%s.phy)%s: reg %d not implemented\n", 232 TYPE_IMX_FEC, __func__, reg); 233 break; 234 default: 235 qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad address at offset %d\n", 236 TYPE_IMX_FEC, __func__, reg); 237 break; 238 } 239 } 240 241 static void imx_fec_read_bd(IMXFECBufDesc *bd, dma_addr_t addr) 242 { 243 dma_memory_read(&address_space_memory, addr, bd, sizeof(*bd)); 244 } 245 246 static void imx_fec_write_bd(IMXFECBufDesc *bd, dma_addr_t addr) 247 { 248 dma_memory_write(&address_space_memory, addr, bd, sizeof(*bd)); 249 } 250 251 static void imx_fec_update(IMXFECState *s) 252 { 253 uint32_t active; 254 uint32_t changed; 255 256 active = s->eir & s->eimr; 257 changed = active ^ s->irq_state; 258 if (changed) { 259 qemu_set_irq(s->irq, active); 260 } 261 s->irq_state = active; 262 } 263 264 static void imx_fec_do_tx(IMXFECState *s) 265 { 266 int frame_size = 0; 267 uint8_t frame[FEC_MAX_FRAME_SIZE]; 268 uint8_t *ptr = frame; 269 uint32_t addr = s->tx_descriptor; 270 271 while (1) { 272 IMXFECBufDesc bd; 273 int len; 274 275 imx_fec_read_bd(&bd, addr); 276 FEC_PRINTF("tx_bd %x flags %04x len %d data %08x\n", 277 addr, bd.flags, bd.length, bd.data); 278 if ((bd.flags & FEC_BD_R) == 0) { 279 /* Run out of descriptors to transmit. */ 280 break; 281 } 282 len = bd.length; 283 if (frame_size + len > FEC_MAX_FRAME_SIZE) { 284 len = FEC_MAX_FRAME_SIZE - frame_size; 285 s->eir |= FEC_INT_BABT; 286 } 287 dma_memory_read(&address_space_memory, bd.data, ptr, len); 288 ptr += len; 289 frame_size += len; 290 if (bd.flags & FEC_BD_L) { 291 /* Last buffer in frame. */ 292 qemu_send_packet(qemu_get_queue(s->nic), frame, len); 293 ptr = frame; 294 frame_size = 0; 295 s->eir |= FEC_INT_TXF; 296 } 297 s->eir |= FEC_INT_TXB; 298 bd.flags &= ~FEC_BD_R; 299 /* Write back the modified descriptor. */ 300 imx_fec_write_bd(&bd, addr); 301 /* Advance to the next descriptor. */ 302 if ((bd.flags & FEC_BD_W) != 0) { 303 addr = s->etdsr; 304 } else { 305 addr += 8; 306 } 307 } 308 309 s->tx_descriptor = addr; 310 311 imx_fec_update(s); 312 } 313 314 static void imx_fec_enable_rx(IMXFECState *s) 315 { 316 IMXFECBufDesc bd; 317 uint32_t tmp; 318 319 imx_fec_read_bd(&bd, s->rx_descriptor); 320 321 tmp = ((bd.flags & FEC_BD_E) != 0); 322 323 if (!tmp) { 324 FEC_PRINTF("RX buffer full\n"); 325 } else if (!s->rx_enabled) { 326 qemu_flush_queued_packets(qemu_get_queue(s->nic)); 327 } 328 329 s->rx_enabled = tmp; 330 } 331 332 static void imx_fec_reset(DeviceState *d) 333 { 334 IMXFECState *s = IMX_FEC(d); 335 336 /* Reset the FEC */ 337 s->eir = 0; 338 s->eimr = 0; 339 s->rx_enabled = 0; 340 s->ecr = 0; 341 s->mscr = 0; 342 s->mibc = 0xc0000000; 343 s->rcr = 0x05ee0001; 344 s->tcr = 0; 345 s->tfwr = 0; 346 s->frsr = 0x500; 347 s->miigsk_cfgr = 0; 348 s->miigsk_enr = 0x6; 349 350 /* We also reset the PHY */ 351 phy_reset(s); 352 } 353 354 static uint64_t imx_fec_read(void *opaque, hwaddr addr, unsigned size) 355 { 356 IMXFECState *s = IMX_FEC(opaque); 357 358 FEC_PRINTF("reading from @ 0x%" HWADDR_PRIx "\n", addr); 359 360 switch (addr & 0x3ff) { 361 case 0x004: 362 return s->eir; 363 case 0x008: 364 return s->eimr; 365 case 0x010: 366 return s->rx_enabled ? (1 << 24) : 0; /* RDAR */ 367 case 0x014: 368 return 0; /* TDAR */ 369 case 0x024: 370 return s->ecr; 371 case 0x040: 372 return s->mmfr; 373 case 0x044: 374 return s->mscr; 375 case 0x064: 376 return s->mibc; /* MIBC */ 377 case 0x084: 378 return s->rcr; 379 case 0x0c4: 380 return s->tcr; 381 case 0x0e4: /* PALR */ 382 return (s->conf.macaddr.a[0] << 24) 383 | (s->conf.macaddr.a[1] << 16) 384 | (s->conf.macaddr.a[2] << 8) 385 | s->conf.macaddr.a[3]; 386 break; 387 case 0x0e8: /* PAUR */ 388 return (s->conf.macaddr.a[4] << 24) 389 | (s->conf.macaddr.a[5] << 16) 390 | 0x8808; 391 case 0x0ec: 392 return 0x10000; /* OPD */ 393 case 0x118: 394 return 0; 395 case 0x11c: 396 return 0; 397 case 0x120: 398 return 0; 399 case 0x124: 400 return 0; 401 case 0x144: 402 return s->tfwr; 403 case 0x14c: 404 return 0x600; 405 case 0x150: 406 return s->frsr; 407 case 0x180: 408 return s->erdsr; 409 case 0x184: 410 return s->etdsr; 411 case 0x188: 412 return s->emrbr; 413 case 0x300: 414 return s->miigsk_cfgr; 415 case 0x308: 416 return s->miigsk_enr; 417 default: 418 qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" 419 HWADDR_PRIx "\n", TYPE_IMX_FEC, __func__, addr); 420 return 0; 421 } 422 } 423 424 static void imx_fec_write(void *opaque, hwaddr addr, 425 uint64_t value, unsigned size) 426 { 427 IMXFECState *s = IMX_FEC(opaque); 428 429 FEC_PRINTF("writing 0x%08x @ 0x%" HWADDR_PRIx "\n", (int)value, addr); 430 431 switch (addr & 0x3ff) { 432 case 0x004: /* EIR */ 433 s->eir &= ~value; 434 break; 435 case 0x008: /* EIMR */ 436 s->eimr = value; 437 break; 438 case 0x010: /* RDAR */ 439 if ((s->ecr & FEC_EN) && !s->rx_enabled) { 440 imx_fec_enable_rx(s); 441 } 442 break; 443 case 0x014: /* TDAR */ 444 if (s->ecr & FEC_EN) { 445 imx_fec_do_tx(s); 446 } 447 break; 448 case 0x024: /* ECR */ 449 s->ecr = value; 450 if (value & FEC_RESET) { 451 imx_fec_reset(DEVICE(s)); 452 } 453 if ((s->ecr & FEC_EN) == 0) { 454 s->rx_enabled = 0; 455 } 456 break; 457 case 0x040: /* MMFR */ 458 /* store the value */ 459 s->mmfr = value; 460 if (extract32(value, 28, 1)) { 461 do_phy_write(s, extract32(value, 18, 9), extract32(value, 0, 16)); 462 } else { 463 s->mmfr = do_phy_read(s, extract32(value, 18, 9)); 464 } 465 /* raise the interrupt as the PHY operation is done */ 466 s->eir |= FEC_INT_MII; 467 break; 468 case 0x044: /* MSCR */ 469 s->mscr = value & 0xfe; 470 break; 471 case 0x064: /* MIBC */ 472 /* TODO: Implement MIB. */ 473 s->mibc = (value & 0x80000000) ? 0xc0000000 : 0; 474 break; 475 case 0x084: /* RCR */ 476 s->rcr = value & 0x07ff003f; 477 /* TODO: Implement LOOP mode. */ 478 break; 479 case 0x0c4: /* TCR */ 480 /* We transmit immediately, so raise GRA immediately. */ 481 s->tcr = value; 482 if (value & 1) { 483 s->eir |= FEC_INT_GRA; 484 } 485 break; 486 case 0x0e4: /* PALR */ 487 s->conf.macaddr.a[0] = value >> 24; 488 s->conf.macaddr.a[1] = value >> 16; 489 s->conf.macaddr.a[2] = value >> 8; 490 s->conf.macaddr.a[3] = value; 491 break; 492 case 0x0e8: /* PAUR */ 493 s->conf.macaddr.a[4] = value >> 24; 494 s->conf.macaddr.a[5] = value >> 16; 495 break; 496 case 0x0ec: /* OPDR */ 497 break; 498 case 0x118: /* IAUR */ 499 case 0x11c: /* IALR */ 500 case 0x120: /* GAUR */ 501 case 0x124: /* GALR */ 502 /* TODO: implement MAC hash filtering. */ 503 break; 504 case 0x144: /* TFWR */ 505 s->tfwr = value & 3; 506 break; 507 case 0x14c: /* FRBR */ 508 /* FRBR writes ignored. */ 509 break; 510 case 0x150: /* FRSR */ 511 s->frsr = (value & 0x3fc) | 0x400; 512 break; 513 case 0x180: /* ERDSR */ 514 s->erdsr = value & ~3; 515 s->rx_descriptor = s->erdsr; 516 break; 517 case 0x184: /* ETDSR */ 518 s->etdsr = value & ~3; 519 s->tx_descriptor = s->etdsr; 520 break; 521 case 0x188: /* EMRBR */ 522 s->emrbr = value & 0x7f0; 523 break; 524 case 0x300: /* MIIGSK_CFGR */ 525 s->miigsk_cfgr = value & 0x53; 526 break; 527 case 0x308: /* MIIGSK_ENR */ 528 s->miigsk_enr = (value & 0x2) ? 0x6 : 0; 529 break; 530 default: 531 qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" 532 HWADDR_PRIx "\n", TYPE_IMX_FEC, __func__, addr); 533 break; 534 } 535 536 imx_fec_update(s); 537 } 538 539 static int imx_fec_can_receive(NetClientState *nc) 540 { 541 IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); 542 543 return s->rx_enabled; 544 } 545 546 static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, 547 size_t len) 548 { 549 IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); 550 IMXFECBufDesc bd; 551 uint32_t flags = 0; 552 uint32_t addr; 553 uint32_t crc; 554 uint32_t buf_addr; 555 uint8_t *crc_ptr; 556 unsigned int buf_len; 557 size_t size = len; 558 559 FEC_PRINTF("len %d\n", (int)size); 560 561 if (!s->rx_enabled) { 562 qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Unexpected packet\n", 563 TYPE_IMX_FEC, __func__); 564 return 0; 565 } 566 567 /* 4 bytes for the CRC. */ 568 size += 4; 569 crc = cpu_to_be32(crc32(~0, buf, size)); 570 crc_ptr = (uint8_t *) &crc; 571 572 /* Huge frames are truncted. */ 573 if (size > FEC_MAX_FRAME_SIZE) { 574 size = FEC_MAX_FRAME_SIZE; 575 flags |= FEC_BD_TR | FEC_BD_LG; 576 } 577 578 /* Frames larger than the user limit just set error flags. */ 579 if (size > (s->rcr >> 16)) { 580 flags |= FEC_BD_LG; 581 } 582 583 addr = s->rx_descriptor; 584 while (size > 0) { 585 imx_fec_read_bd(&bd, addr); 586 if ((bd.flags & FEC_BD_E) == 0) { 587 /* No descriptors available. Bail out. */ 588 /* 589 * FIXME: This is wrong. We should probably either 590 * save the remainder for when more RX buffers are 591 * available, or flag an error. 592 */ 593 qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Lost end of frame\n", 594 TYPE_IMX_FEC, __func__); 595 break; 596 } 597 buf_len = (size <= s->emrbr) ? size : s->emrbr; 598 bd.length = buf_len; 599 size -= buf_len; 600 601 FEC_PRINTF("rx_bd 0x%x length %d\n", addr, bd.length); 602 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