qemu/hw/net/msf2-emac.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the Smartfusion2 Ethernet MAC.
   3 *
   4 * Copyright (c) 2020 Subbaraya Sundeep <sundeep.lkml@gmail.com>.
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 *
  24 * Refer to section Ethernet MAC in the document:
  25 * UG0331: SmartFusion2 Microcontroller Subsystem User Guide
  26 * Datasheet URL:
  27 * https://www.microsemi.com/document-portal/cat_view/56661-internal-documents/
  28 * 56758-soc?lang=en&limit=20&limitstart=220
  29 */
  30
  31#include "qemu/osdep.h"
  32#include "qemu-common.h"
  33#include "qemu/log.h"
  34#include "qapi/error.h"
  35#include "exec/address-spaces.h"
  36#include "hw/registerfields.h"
  37#include "hw/net/msf2-emac.h"
  38#include "hw/net/mii.h"
  39#include "hw/irq.h"
  40#include "hw/qdev-properties.h"
  41#include "migration/vmstate.h"
  42
  43REG32(CFG1, 0x0)
  44    FIELD(CFG1, RESET, 31, 1)
  45    FIELD(CFG1, RX_EN, 2, 1)
  46    FIELD(CFG1, TX_EN, 0, 1)
  47    FIELD(CFG1, LB_EN, 8, 1)
  48REG32(CFG2, 0x4)
  49REG32(IFG, 0x8)
  50REG32(HALF_DUPLEX, 0xc)
  51REG32(MAX_FRAME_LENGTH, 0x10)
  52REG32(MII_CMD, 0x24)
  53    FIELD(MII_CMD, READ, 0, 1)
  54REG32(MII_ADDR, 0x28)
  55    FIELD(MII_ADDR, REGADDR, 0, 5)
  56    FIELD(MII_ADDR, PHYADDR, 8, 5)
  57REG32(MII_CTL, 0x2c)
  58REG32(MII_STS, 0x30)
  59REG32(STA1, 0x40)
  60REG32(STA2, 0x44)
  61REG32(FIFO_CFG0, 0x48)
  62REG32(FIFO_CFG4, 0x58)
  63    FIELD(FIFO_CFG4, BCAST, 9, 1)
  64    FIELD(FIFO_CFG4, MCAST, 8, 1)
  65REG32(FIFO_CFG5, 0x5C)
  66    FIELD(FIFO_CFG5, BCAST, 9, 1)
  67    FIELD(FIFO_CFG5, MCAST, 8, 1)
  68REG32(DMA_TX_CTL, 0x180)
  69    FIELD(DMA_TX_CTL, EN, 0, 1)
  70REG32(DMA_TX_DESC, 0x184)
  71REG32(DMA_TX_STATUS, 0x188)
  72    FIELD(DMA_TX_STATUS, PKTCNT, 16, 8)
  73    FIELD(DMA_TX_STATUS, UNDERRUN, 1, 1)
  74    FIELD(DMA_TX_STATUS, PKT_SENT, 0, 1)
  75REG32(DMA_RX_CTL, 0x18c)
  76    FIELD(DMA_RX_CTL, EN, 0, 1)
  77REG32(DMA_RX_DESC, 0x190)
  78REG32(DMA_RX_STATUS, 0x194)
  79    FIELD(DMA_RX_STATUS, PKTCNT, 16, 8)
  80    FIELD(DMA_RX_STATUS, OVERFLOW, 2, 1)
  81    FIELD(DMA_RX_STATUS, PKT_RCVD, 0, 1)
  82REG32(DMA_IRQ_MASK, 0x198)
  83REG32(DMA_IRQ, 0x19c)
  84
  85#define EMPTY_MASK              (1 << 31)
  86#define PKT_SIZE                0x7FF
  87#define PHYADDR                 0x1
  88#define MAX_PKT_SIZE            2048
  89
  90typedef struct {
  91    uint32_t pktaddr;
  92    uint32_t pktsize;
  93    uint32_t next;
  94} EmacDesc;
  95
  96static uint32_t emac_get_isr(MSF2EmacState *s)
  97{
  98    uint32_t ier = s->regs[R_DMA_IRQ_MASK];
  99    uint32_t tx = s->regs[R_DMA_TX_STATUS] & 0xF;
 100    uint32_t rx = s->regs[R_DMA_RX_STATUS] & 0xF;
 101    uint32_t isr = (rx << 4) | tx;
 102
 103    s->regs[R_DMA_IRQ] = ier & isr;
 104    return s->regs[R_DMA_IRQ];
 105}
 106
 107static void emac_update_irq(MSF2EmacState *s)
 108{
 109    bool intr = emac_get_isr(s);
 110
 111    qemu_set_irq(s->irq, intr);
 112}
 113
 114static void emac_load_desc(MSF2EmacState *s, EmacDesc *d, hwaddr desc)
 115{
 116    address_space_read(&s->dma_as, desc, MEMTXATTRS_UNSPECIFIED, d, sizeof *d);
 117    /* Convert from LE into host endianness. */
 118    d->pktaddr = le32_to_cpu(d->pktaddr);
 119    d->pktsize = le32_to_cpu(d->pktsize);
 120    d->next = le32_to_cpu(d->next);
 121}
 122
 123static void emac_store_desc(MSF2EmacState *s, EmacDesc *d, hwaddr desc)
 124{
 125    /* Convert from host endianness into LE. */
 126    d->pktaddr = cpu_to_le32(d->pktaddr);
 127    d->pktsize = cpu_to_le32(d->pktsize);
 128    d->next = cpu_to_le32(d->next);
 129
 130    address_space_write(&s->dma_as, desc, MEMTXATTRS_UNSPECIFIED, d, sizeof *d);
 131}
 132
 133static void msf2_dma_tx(MSF2EmacState *s)
 134{
 135    NetClientState *nc = qemu_get_queue(s->nic);
 136    hwaddr desc = s->regs[R_DMA_TX_DESC];
 137    uint8_t buf[MAX_PKT_SIZE];
 138    EmacDesc d;
 139    int size;
 140    uint8_t pktcnt;
 141    uint32_t status;
 142
 143    if (!(s->regs[R_CFG1] & R_CFG1_TX_EN_MASK)) {
 144        return;
 145    }
 146
 147    while (1) {
 148        emac_load_desc(s, &d, desc);
 149        if (d.pktsize & EMPTY_MASK) {
 150            break;
 151        }
 152        size = d.pktsize & PKT_SIZE;
 153        address_space_read(&s->dma_as, d.pktaddr, MEMTXATTRS_UNSPECIFIED,
 154                           buf, size);
 155        /*
 156         * This is very basic way to send packets. Ideally there should be
 157         * a FIFO and packets should be sent out from FIFO only when
 158         * R_CFG1 bit 0 is set.
 159         */
 160        if (s->regs[R_CFG1] & R_CFG1_LB_EN_MASK) {
 161            qemu_receive_packet(nc, buf, size);
 162        } else {
 163            qemu_send_packet(nc, buf, size);
 164        }
 165        d.pktsize |= EMPTY_MASK;
 166        emac_store_desc(s, &d, desc);
 167        /* update sent packets count */
 168        status = s->regs[R_DMA_TX_STATUS];
 169        pktcnt = FIELD_EX32(status, DMA_TX_STATUS, PKTCNT);
 170        pktcnt++;
 171        s->regs[R_DMA_TX_STATUS] = FIELD_DP32(status, DMA_TX_STATUS,
 172                                              PKTCNT, pktcnt);
 173        s->regs[R_DMA_TX_STATUS] |= R_DMA_TX_STATUS_PKT_SENT_MASK;
 174        desc = d.next;
 175    }
 176    s->regs[R_DMA_TX_STATUS] |= R_DMA_TX_STATUS_UNDERRUN_MASK;
 177    s->regs[R_DMA_TX_CTL] &= ~R_DMA_TX_CTL_EN_MASK;
 178}
 179
 180static void msf2_phy_update_link(MSF2EmacState *s)
 181{
 182    /* Autonegotiation status mirrors link status. */
 183    if (qemu_get_queue(s->nic)->link_down) {
 184        s->phy_regs[MII_BMSR] &= ~(MII_BMSR_AN_COMP |
 185                                   MII_BMSR_LINK_ST);
 186    } else {
 187        s->phy_regs[MII_BMSR] |= (MII_BMSR_AN_COMP |
 188                                  MII_BMSR_LINK_ST);
 189    }
 190}
 191
 192static void msf2_phy_reset(MSF2EmacState *s)
 193{
 194    memset(&s->phy_regs[0], 0, sizeof(s->phy_regs));
 195    s->phy_regs[MII_BMCR] = 0x1140;
 196    s->phy_regs[MII_BMSR] = 0x7968;
 197    s->phy_regs[MII_PHYID1] = 0x0022;
 198    s->phy_regs[MII_PHYID2] = 0x1550;
 199    s->phy_regs[MII_ANAR] = 0x01E1;
 200    s->phy_regs[MII_ANLPAR] = 0xCDE1;
 201
 202    msf2_phy_update_link(s);
 203}
 204
 205static void write_to_phy(MSF2EmacState *s)
 206{
 207    uint8_t reg_addr = s->regs[R_MII_ADDR] & R_MII_ADDR_REGADDR_MASK;
 208    uint8_t phy_addr = (s->regs[R_MII_ADDR] >> R_MII_ADDR_PHYADDR_SHIFT) &
 209                       R_MII_ADDR_REGADDR_MASK;
 210    uint16_t data = s->regs[R_MII_CTL] & 0xFFFF;
 211
 212    if (phy_addr != PHYADDR) {
 213        return;
 214    }
 215
 216    switch (reg_addr) {
 217    case MII_BMCR:
 218        if (data & MII_BMCR_RESET) {
 219            /* Phy reset */
 220            msf2_phy_reset(s);
 221            data &= ~MII_BMCR_RESET;
 222        }
 223        if (data & MII_BMCR_AUTOEN) {
 224            /* Complete autonegotiation immediately */
 225            data &= ~MII_BMCR_AUTOEN;
 226            s->phy_regs[MII_BMSR] |= MII_BMSR_AN_COMP;
 227        }
 228        break;
 229    }
 230
 231    s->phy_regs[reg_addr] = data;
 232}
 233
 234static uint16_t read_from_phy(MSF2EmacState *s)
 235{
 236    uint8_t reg_addr = s->regs[R_MII_ADDR] & R_MII_ADDR_REGADDR_MASK;
 237    uint8_t phy_addr = (s->regs[R_MII_ADDR] >> R_MII_ADDR_PHYADDR_SHIFT) &
 238                       R_MII_ADDR_REGADDR_MASK;
 239
 240    if (phy_addr == PHYADDR) {
 241        return s->phy_regs[reg_addr];
 242    } else {
 243        return 0xFFFF;
 244    }
 245}
 246
 247static void msf2_emac_do_reset(MSF2EmacState *s)
 248{
 249    memset(&s->regs[0], 0, sizeof(s->regs));
 250    s->regs[R_CFG1] = 0x80000000;
 251    s->regs[R_CFG2] = 0x00007000;
 252    s->regs[R_IFG] = 0x40605060;
 253    s->regs[R_HALF_DUPLEX] = 0x00A1F037;
 254    s->regs[R_MAX_FRAME_LENGTH] = 0x00000600;
 255    s->regs[R_FIFO_CFG5] = 0X3FFFF;
 256
 257    msf2_phy_reset(s);
 258}
 259
 260static uint64_t emac_read(void *opaque, hwaddr addr, unsigned int size)
 261{
 262    MSF2EmacState *s = opaque;
 263    uint32_t r = 0;
 264
 265    addr >>= 2;
 266
 267    switch (addr) {
 268    case R_DMA_IRQ:
 269        r = emac_get_isr(s);
 270        break;
 271    default:
 272        if (addr >= ARRAY_SIZE(s->regs)) {
 273            qemu_log_mask(LOG_GUEST_ERROR,
 274                          "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__,
 275                          addr * 4);
 276            return r;
 277        }
 278        r = s->regs[addr];
 279        break;
 280    }
 281    return r;
 282}
 283
 284static void emac_write(void *opaque, hwaddr addr, uint64_t val64,
 285        unsigned int size)
 286{
 287    MSF2EmacState *s = opaque;
 288    uint32_t value = val64;
 289    uint32_t enreqbits;
 290    uint8_t pktcnt;
 291
 292    addr >>= 2;
 293    switch (addr) {
 294    case R_DMA_TX_CTL:
 295        s->regs[addr] = value;
 296        if (value & R_DMA_TX_CTL_EN_MASK) {
 297            msf2_dma_tx(s);
 298        }
 299        break;
 300    case R_DMA_RX_CTL:
 301        s->regs[addr] = value;
 302        if (value & R_DMA_RX_CTL_EN_MASK) {
 303            s->rx_desc = s->regs[R_DMA_RX_DESC];
 304            qemu_flush_queued_packets(qemu_get_queue(s->nic));
 305        }
 306        break;
 307    case R_CFG1:
 308        s->regs[addr] = value;
 309        if (value & R_CFG1_RESET_MASK) {
 310            msf2_emac_do_reset(s);
 311        }
 312        break;
 313    case R_FIFO_CFG0:
 314       /*
 315        * For our implementation, turning on modules is instantaneous,
 316        * so the states requested via the *ENREQ bits appear in the
 317        * *ENRPLY bits immediately. Also the reset bits to reset PE-MCXMAC
 318        * module are not emulated here since it deals with start of frames,
 319        * inter-packet gap and control frames.
 320        */
 321        enreqbits = extract32(value, 8, 5);
 322        s->regs[addr] = deposit32(value, 16, 5, enreqbits);
 323        break;
 324    case R_DMA_TX_DESC:
 325        if (value & 0x3) {
 326            qemu_log_mask(LOG_GUEST_ERROR, "Tx Descriptor address should be"
 327                          " 32 bit aligned\n");
 328        }
 329        /* Ignore [1:0] bits */
 330        s->regs[addr] = value & ~3;
 331        break;
 332    case R_DMA_RX_DESC:
 333        if (value & 0x3) {
 334            qemu_log_mask(LOG_GUEST_ERROR, "Rx Descriptor address should be"
 335                          " 32 bit aligned\n");
 336        }
 337        /* Ignore [1:0] bits */
 338        s->regs[addr] = value & ~3;
 339        break;
 340    case R_DMA_TX_STATUS:
 341        if (value & R_DMA_TX_STATUS_UNDERRUN_MASK) {
 342            s->regs[addr] &= ~R_DMA_TX_STATUS_UNDERRUN_MASK;
 343        }
 344        if (value & R_DMA_TX_STATUS_PKT_SENT_MASK) {
 345            pktcnt = FIELD_EX32(s->regs[addr], DMA_TX_STATUS, PKTCNT);
 346            pktcnt--;
 347            s->regs[addr] = FIELD_DP32(s->regs[addr], DMA_TX_STATUS,
 348                                       PKTCNT, pktcnt);
 349            if (pktcnt == 0) {
 350                s->regs[addr] &= ~R_DMA_TX_STATUS_PKT_SENT_MASK;
 351            }
 352        }
 353        break;
 354    case R_DMA_RX_STATUS:
 355        if (value & R_DMA_RX_STATUS_OVERFLOW_MASK) {
 356            s->regs[addr] &= ~R_DMA_RX_STATUS_OVERFLOW_MASK;
 357        }
 358        if (value & R_DMA_RX_STATUS_PKT_RCVD_MASK) {
 359            pktcnt = FIELD_EX32(s->regs[addr], DMA_RX_STATUS, PKTCNT);
 360            pktcnt--;
 361            s->regs[addr] = FIELD_DP32(s->regs[addr], DMA_RX_STATUS,
 362                                       PKTCNT, pktcnt);
 363            if (pktcnt == 0) {
 364                s->regs[addr] &= ~R_DMA_RX_STATUS_PKT_RCVD_MASK;
 365            }
 366        }
 367        break;
 368    case R_DMA_IRQ:
 369        break;
 370    case R_MII_CMD:
 371        if (value & R_MII_CMD_READ_MASK) {
 372            s->regs[R_MII_STS] = read_from_phy(s);
 373        }
 374        break;
 375    case R_MII_CTL:
 376        s->regs[addr] = value;
 377        write_to_phy(s);
 378        break;
 379    case R_STA1:
 380        s->regs[addr] = value;
 381       /*
 382        * R_STA1 [31:24] : octet 1 of mac address
 383        * R_STA1 [23:16] : octet 2 of mac address
 384        * R_STA1 [15:8] : octet 3 of mac address
 385        * R_STA1 [7:0] : octet 4 of mac address
 386        */
 387        stl_be_p(s->mac_addr, value);
 388        break;
 389    case R_STA2:
 390        s->regs[addr] = value;
 391       /*
 392        * R_STA2 [31:24] : octet 5 of mac address
 393        * R_STA2 [23:16] : octet 6 of mac address
 394        */
 395        stw_be_p(s->mac_addr + 4, value >> 16);
 396        break;
 397    default:
 398        if (addr >= ARRAY_SIZE(s->regs)) {
 399            qemu_log_mask(LOG_GUEST_ERROR,
 400                          "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__,
 401                          addr * 4);
 402            return;
 403        }
 404        s->regs[addr] = value;
 405        break;
 406    }
 407    emac_update_irq(s);
 408}
 409
 410static const MemoryRegionOps emac_ops = {
 411    .read = emac_read,
 412    .write = emac_write,
 413    .endianness = DEVICE_NATIVE_ENDIAN,
 414    .impl = {
 415        .min_access_size = 4,
 416        .max_access_size = 4
 417    }
 418};
 419
 420static bool emac_can_rx(NetClientState *nc)
 421{
 422    MSF2EmacState *s = qemu_get_nic_opaque(nc);
 423
 424    return (s->regs[R_CFG1] & R_CFG1_RX_EN_MASK) &&
 425           (s->regs[R_DMA_RX_CTL] & R_DMA_RX_CTL_EN_MASK);
 426}
 427
 428static bool addr_filter_ok(MSF2EmacState *s, const uint8_t *buf)
 429{
 430    /* The broadcast MAC address: FF:FF:FF:FF:FF:FF */
 431    const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF,
 432                                              0xFF, 0xFF };
 433    bool bcast_en = true;
 434    bool mcast_en = true;
 435
 436    if (s->regs[R_FIFO_CFG5] & R_FIFO_CFG5_BCAST_MASK) {
 437        bcast_en = true; /* Broadcast dont care for drop circuitry */
 438    } else if (s->regs[R_FIFO_CFG4] & R_FIFO_CFG4_BCAST_MASK) {
 439        bcast_en = false;
 440    }
 441
 442    if (s->regs[R_FIFO_CFG5] & R_FIFO_CFG5_MCAST_MASK) {
 443        mcast_en = true; /* Multicast dont care for drop circuitry */
 444    } else if (s->regs[R_FIFO_CFG4] & R_FIFO_CFG4_MCAST_MASK) {
 445        mcast_en = false;
 446    }
 447
 448    if (!memcmp(buf, broadcast_addr, sizeof(broadcast_addr))) {
 449        return bcast_en;
 450    }
 451
 452    if (buf[0] & 1) {
 453        return mcast_en;
 454    }
 455
 456    return !memcmp(buf, s->mac_addr, sizeof(s->mac_addr));
 457}
 458
 459static ssize_t emac_rx(NetClientState *nc, const uint8_t *buf, size_t size)
 460{
 461    MSF2EmacState *s = qemu_get_nic_opaque(nc);
 462    EmacDesc d;
 463    uint8_t pktcnt;
 464    uint32_t status;
 465
 466    if (size > (s->regs[R_MAX_FRAME_LENGTH] & 0xFFFF)) {
 467        return size;
 468    }
 469    if (!addr_filter_ok(s, buf)) {
 470        return size;
 471    }
 472
 473    emac_load_desc(s, &d, s->rx_desc);
 474
 475    if (d.pktsize & EMPTY_MASK) {
 476        address_space_write(&s->dma_as, d.pktaddr, MEMTXATTRS_UNSPECIFIED,
 477                            buf, size & PKT_SIZE);
 478        d.pktsize = size & PKT_SIZE;
 479        emac_store_desc(s, &d, s->rx_desc);
 480        /* update received packets count */
 481        status = s->regs[R_DMA_RX_STATUS];
 482        pktcnt = FIELD_EX32(status, DMA_RX_STATUS, PKTCNT);
 483        pktcnt++;
 484        s->regs[R_DMA_RX_STATUS] = FIELD_DP32(status, DMA_RX_STATUS,
 485                                              PKTCNT, pktcnt);
 486        s->regs[R_DMA_RX_STATUS] |= R_DMA_RX_STATUS_PKT_RCVD_MASK;
 487        s->rx_desc = d.next;
 488    } else {
 489        s->regs[R_DMA_RX_CTL] &= ~R_DMA_RX_CTL_EN_MASK;
 490        s->regs[R_DMA_RX_STATUS] |= R_DMA_RX_STATUS_OVERFLOW_MASK;
 491    }
 492    emac_update_irq(s);
 493    return size;
 494}
 495
 496static void msf2_emac_reset(DeviceState *dev)
 497{
 498    MSF2EmacState *s = MSS_EMAC(dev);
 499
 500    msf2_emac_do_reset(s);
 501}
 502
 503static void emac_set_link(NetClientState *nc)
 504{
 505    MSF2EmacState *s = qemu_get_nic_opaque(nc);
 506
 507    msf2_phy_update_link(s);
 508}
 509
 510static NetClientInfo net_msf2_emac_info = {
 511    .type = NET_CLIENT_DRIVER_NIC,
 512    .size = sizeof(NICState),
 513    .can_receive = emac_can_rx,
 514    .receive = emac_rx,
 515    .link_status_changed = emac_set_link,
 516};
 517
 518static void msf2_emac_realize(DeviceState *dev, Error **errp)
 519{
 520    MSF2EmacState *s = MSS_EMAC(dev);
 521
 522    if (!s->dma_mr) {
 523        error_setg(errp, "MSS_EMAC 'ahb-bus' link not set");
 524        return;
 525    }
 526
 527    address_space_init(&s->dma_as, s->dma_mr, "emac-ahb");
 528
 529    qemu_macaddr_default_if_unset(&s->conf.macaddr);
 530    s->nic = qemu_new_nic(&net_msf2_emac_info, &s->conf,
 531                          object_get_typename(OBJECT(dev)), dev->id, s);
 532    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
 533}
 534
 535static void msf2_emac_init(Object *obj)
 536{
 537    MSF2EmacState *s = MSS_EMAC(obj);
 538
 539    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
 540
 541    memory_region_init_io(&s->mmio, obj, &emac_ops, s,
 542                          "msf2-emac", R_MAX * 4);
 543    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
 544}
 545
 546static Property msf2_emac_properties[] = {
 547    DEFINE_PROP_LINK("ahb-bus", MSF2EmacState, dma_mr,
 548                     TYPE_MEMORY_REGION, MemoryRegion *),
 549    DEFINE_NIC_PROPERTIES(MSF2EmacState, conf),
 550    DEFINE_PROP_END_OF_LIST(),
 551};
 552
 553static const VMStateDescription vmstate_msf2_emac = {
 554    .name = TYPE_MSS_EMAC,
 555    .version_id = 1,
 556    .minimum_version_id = 1,
 557    .fields = (VMStateField[]) {
 558        VMSTATE_UINT8_ARRAY(mac_addr, MSF2EmacState, ETH_ALEN),
 559        VMSTATE_UINT32(rx_desc, MSF2EmacState),
 560        VMSTATE_UINT16_ARRAY(phy_regs, MSF2EmacState, PHY_MAX_REGS),
 561        VMSTATE_UINT32_ARRAY(regs, MSF2EmacState, R_MAX),
 562        VMSTATE_END_OF_LIST()
 563    }
 564};
 565
 566static void msf2_emac_class_init(ObjectClass *klass, void *data)
 567{
 568    DeviceClass *dc = DEVICE_CLASS(klass);
 569
 570    dc->realize = msf2_emac_realize;
 571    dc->reset = msf2_emac_reset;
 572    dc->vmsd = &vmstate_msf2_emac;
 573    device_class_set_props(dc, msf2_emac_properties);
 574}
 575
 576static const TypeInfo msf2_emac_info = {
 577    .name          = TYPE_MSS_EMAC,
 578    .parent        = TYPE_SYS_BUS_DEVICE,
 579    .instance_size = sizeof(MSF2EmacState),
 580    .instance_init = msf2_emac_init,
 581    .class_init    = msf2_emac_class_init,
 582};
 583
 584static void msf2_emac_register_types(void)
 585{
 586    type_register_static(&msf2_emac_info);
 587}
 588
 589type_init(msf2_emac_register_types)
 590