1eea589ccSpbrook /* 2eea589ccSpbrook * Luminary Micro Stellaris Ethernet Controller 3eea589ccSpbrook * 4eea589ccSpbrook * Copyright (c) 2007 CodeSourcery. 5eea589ccSpbrook * Written by Paul Brook 6eea589ccSpbrook * 78e31bf38SMatthew Fernandez * This code is licensed under the GPL. 8eea589ccSpbrook */ 983c9f4caSPaolo Bonzini #include "hw/sysbus.h" 101422e32dSPaolo Bonzini #include "net/net.h" 11eea589ccSpbrook #include <zlib.h> 12eea589ccSpbrook 13eea589ccSpbrook //#define DEBUG_STELLARIS_ENET 1 14eea589ccSpbrook 15eea589ccSpbrook #ifdef DEBUG_STELLARIS_ENET 16001faf32SBlue Swirl #define DPRINTF(fmt, ...) \ 17001faf32SBlue Swirl do { printf("stellaris_enet: " fmt , ## __VA_ARGS__); } while (0) 18001faf32SBlue Swirl #define BADF(fmt, ...) \ 19001faf32SBlue Swirl do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__); exit(1);} while (0) 20eea589ccSpbrook #else 21001faf32SBlue Swirl #define DPRINTF(fmt, ...) do {} while(0) 22001faf32SBlue Swirl #define BADF(fmt, ...) \ 23001faf32SBlue Swirl do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__);} while (0) 24eea589ccSpbrook #endif 25eea589ccSpbrook 26eea589ccSpbrook #define SE_INT_RX 0x01 27eea589ccSpbrook #define SE_INT_TXER 0x02 28eea589ccSpbrook #define SE_INT_TXEMP 0x04 29eea589ccSpbrook #define SE_INT_FOV 0x08 30eea589ccSpbrook #define SE_INT_RXER 0x10 31eea589ccSpbrook #define SE_INT_MD 0x20 32eea589ccSpbrook #define SE_INT_PHY 0x40 33eea589ccSpbrook 34eea589ccSpbrook #define SE_RCTL_RXEN 0x01 35eea589ccSpbrook #define SE_RCTL_AMUL 0x02 36eea589ccSpbrook #define SE_RCTL_PRMS 0x04 37eea589ccSpbrook #define SE_RCTL_BADCRC 0x08 38eea589ccSpbrook #define SE_RCTL_RSTFIFO 0x10 39eea589ccSpbrook 40eea589ccSpbrook #define SE_TCTL_TXEN 0x01 41eea589ccSpbrook #define SE_TCTL_PADEN 0x02 42eea589ccSpbrook #define SE_TCTL_CRC 0x04 43eea589ccSpbrook #define SE_TCTL_DUPLEX 0x08 44eea589ccSpbrook 452fa30abaSAndreas Färber #define TYPE_STELLARIS_ENET "stellaris_enet" 462fa30abaSAndreas Färber #define STELLARIS_ENET(obj) \ 472fa30abaSAndreas Färber OBJECT_CHECK(stellaris_enet_state, (obj), TYPE_STELLARIS_ENET) 482fa30abaSAndreas Färber 49eea589ccSpbrook typedef struct { 502fa30abaSAndreas Färber SysBusDevice parent_obj; 512fa30abaSAndreas Färber 52eea589ccSpbrook uint32_t ris; 53eea589ccSpbrook uint32_t im; 54eea589ccSpbrook uint32_t rctl; 55eea589ccSpbrook uint32_t tctl; 56eea589ccSpbrook uint32_t thr; 57eea589ccSpbrook uint32_t mctl; 58eea589ccSpbrook uint32_t mdv; 59eea589ccSpbrook uint32_t mtxd; 60eea589ccSpbrook uint32_t mrxd; 61eea589ccSpbrook uint32_t np; 62eea589ccSpbrook int tx_frame_len; 63eea589ccSpbrook int tx_fifo_len; 64eea589ccSpbrook uint8_t tx_fifo[2048]; 65eea589ccSpbrook /* Real hardware has a 2k fifo, which works out to be at most 31 packets. 66eea589ccSpbrook We implement a full 31 packet fifo. */ 67eea589ccSpbrook struct { 68eea589ccSpbrook uint8_t data[2048]; 69eea589ccSpbrook int len; 70eea589ccSpbrook } rx[31]; 71eea589ccSpbrook uint8_t *rx_fifo; 72eea589ccSpbrook int rx_fifo_len; 73eea589ccSpbrook int next_packet; 748c9b63b9SMark McLoughlin NICState *nic; 75540f006aSGerd Hoffmann NICConf conf; 76eea589ccSpbrook qemu_irq irq; 77f070e1e2SAvi Kivity MemoryRegion mmio; 78eea589ccSpbrook } stellaris_enet_state; 79eea589ccSpbrook 80eea589ccSpbrook static void stellaris_enet_update(stellaris_enet_state *s) 81eea589ccSpbrook { 82eea589ccSpbrook qemu_set_irq(s->irq, (s->ris & s->im) != 0); 83eea589ccSpbrook } 84eea589ccSpbrook 85eea589ccSpbrook /* TODO: Implement MAC address filtering. */ 864e68f7a0SStefan Hajnoczi static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, size_t size) 87eea589ccSpbrook { 88cc1f0f45SJason Wang stellaris_enet_state *s = qemu_get_nic_opaque(nc); 89eea589ccSpbrook int n; 90eea589ccSpbrook uint8_t *p; 91eea589ccSpbrook uint32_t crc; 92eea589ccSpbrook 93eea589ccSpbrook if ((s->rctl & SE_RCTL_RXEN) == 0) 944f1c942bSMark McLoughlin return -1; 95eea589ccSpbrook if (s->np >= 31) { 96eea589ccSpbrook DPRINTF("Packet dropped\n"); 974f1c942bSMark McLoughlin return -1; 98eea589ccSpbrook } 99eea589ccSpbrook 100eea589ccSpbrook DPRINTF("Received packet len=%d\n", size); 101eea589ccSpbrook n = s->next_packet + s->np; 102eea589ccSpbrook if (n >= 31) 103eea589ccSpbrook n -= 31; 104eea589ccSpbrook s->np++; 105eea589ccSpbrook 106eea589ccSpbrook s->rx[n].len = size + 6; 107eea589ccSpbrook p = s->rx[n].data; 108eea589ccSpbrook *(p++) = (size + 6); 109eea589ccSpbrook *(p++) = (size + 6) >> 8; 110eea589ccSpbrook memcpy (p, buf, size); 111eea589ccSpbrook p += size; 112eea589ccSpbrook crc = crc32(~0, buf, size); 113eea589ccSpbrook *(p++) = crc; 114eea589ccSpbrook *(p++) = crc >> 8; 115eea589ccSpbrook *(p++) = crc >> 16; 116eea589ccSpbrook *(p++) = crc >> 24; 117eea589ccSpbrook /* Clear the remaining bytes in the last word. */ 118eea589ccSpbrook if ((size & 3) != 2) { 119eea589ccSpbrook memset(p, 0, (6 - size) & 3); 120eea589ccSpbrook } 121eea589ccSpbrook 122eea589ccSpbrook s->ris |= SE_INT_RX; 123eea589ccSpbrook stellaris_enet_update(s); 1244f1c942bSMark McLoughlin 1254f1c942bSMark McLoughlin return size; 126eea589ccSpbrook } 127eea589ccSpbrook 1284e68f7a0SStefan Hajnoczi static int stellaris_enet_can_receive(NetClientState *nc) 129eea589ccSpbrook { 130cc1f0f45SJason Wang stellaris_enet_state *s = qemu_get_nic_opaque(nc); 131eea589ccSpbrook 132eea589ccSpbrook if ((s->rctl & SE_RCTL_RXEN) == 0) 133eea589ccSpbrook return 1; 134eea589ccSpbrook 135eea589ccSpbrook return (s->np < 31); 136eea589ccSpbrook } 137eea589ccSpbrook 138a8170e5eSAvi Kivity static uint64_t stellaris_enet_read(void *opaque, hwaddr offset, 139f070e1e2SAvi Kivity unsigned size) 140eea589ccSpbrook { 14157b452a8SPaul Brook stellaris_enet_state *s = (stellaris_enet_state *)opaque; 142eea589ccSpbrook uint32_t val; 143eea589ccSpbrook 144eea589ccSpbrook switch (offset) { 145eea589ccSpbrook case 0x00: /* RIS */ 146eea589ccSpbrook DPRINTF("IRQ status %02x\n", s->ris); 147eea589ccSpbrook return s->ris; 148eea589ccSpbrook case 0x04: /* IM */ 149eea589ccSpbrook return s->im; 150eea589ccSpbrook case 0x08: /* RCTL */ 151eea589ccSpbrook return s->rctl; 152eea589ccSpbrook case 0x0c: /* TCTL */ 153eea589ccSpbrook return s->tctl; 154eea589ccSpbrook case 0x10: /* DATA */ 155eea589ccSpbrook if (s->rx_fifo_len == 0) { 156eea589ccSpbrook if (s->np == 0) { 157eea589ccSpbrook BADF("RX underflow\n"); 158eea589ccSpbrook return 0; 159eea589ccSpbrook } 160eea589ccSpbrook s->rx_fifo_len = s->rx[s->next_packet].len; 161eea589ccSpbrook s->rx_fifo = s->rx[s->next_packet].data; 162eea589ccSpbrook DPRINTF("RX FIFO start packet len=%d\n", s->rx_fifo_len); 163eea589ccSpbrook } 164eea589ccSpbrook val = s->rx_fifo[0] | (s->rx_fifo[1] << 8) | (s->rx_fifo[2] << 16) 165eea589ccSpbrook | (s->rx_fifo[3] << 24); 166eea589ccSpbrook s->rx_fifo += 4; 167eea589ccSpbrook s->rx_fifo_len -= 4; 168eea589ccSpbrook if (s->rx_fifo_len <= 0) { 169eea589ccSpbrook s->rx_fifo_len = 0; 170eea589ccSpbrook s->next_packet++; 171eea589ccSpbrook if (s->next_packet >= 31) 172eea589ccSpbrook s->next_packet = 0; 173eea589ccSpbrook s->np--; 174eea589ccSpbrook DPRINTF("RX done np=%d\n", s->np); 175eea589ccSpbrook } 176eea589ccSpbrook return val; 177eea589ccSpbrook case 0x14: /* IA0 */ 178540f006aSGerd Hoffmann return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8) 179540f006aSGerd Hoffmann | (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24); 180eea589ccSpbrook case 0x18: /* IA1 */ 181540f006aSGerd Hoffmann return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8); 182eea589ccSpbrook case 0x1c: /* THR */ 183eea589ccSpbrook return s->thr; 184eea589ccSpbrook case 0x20: /* MCTL */ 185eea589ccSpbrook return s->mctl; 186eea589ccSpbrook case 0x24: /* MDV */ 187eea589ccSpbrook return s->mdv; 188eea589ccSpbrook case 0x28: /* MADD */ 189eea589ccSpbrook return 0; 190eea589ccSpbrook case 0x2c: /* MTXD */ 191eea589ccSpbrook return s->mtxd; 192eea589ccSpbrook case 0x30: /* MRXD */ 193eea589ccSpbrook return s->mrxd; 194eea589ccSpbrook case 0x34: /* NP */ 195eea589ccSpbrook return s->np; 196eea589ccSpbrook case 0x38: /* TR */ 197eea589ccSpbrook return 0; 198eea589ccSpbrook case 0x3c: /* Undocuented: Timestamp? */ 199eea589ccSpbrook return 0; 200eea589ccSpbrook default: 2012ac71179SPaul Brook hw_error("stellaris_enet_read: Bad offset %x\n", (int)offset); 202eea589ccSpbrook return 0; 203eea589ccSpbrook } 204eea589ccSpbrook } 205eea589ccSpbrook 206a8170e5eSAvi Kivity static void stellaris_enet_write(void *opaque, hwaddr offset, 207f070e1e2SAvi Kivity uint64_t value, unsigned size) 208eea589ccSpbrook { 209eea589ccSpbrook stellaris_enet_state *s = (stellaris_enet_state *)opaque; 210eea589ccSpbrook 211eea589ccSpbrook switch (offset) { 212eea589ccSpbrook case 0x00: /* IACK */ 213eea589ccSpbrook s->ris &= ~value; 214eea589ccSpbrook DPRINTF("IRQ ack %02x/%02x\n", value, s->ris); 215eea589ccSpbrook stellaris_enet_update(s); 216eea589ccSpbrook /* Clearing TXER also resets the TX fifo. */ 217eea589ccSpbrook if (value & SE_INT_TXER) 218eea589ccSpbrook s->tx_frame_len = -1; 219eea589ccSpbrook break; 220eea589ccSpbrook case 0x04: /* IM */ 221eea589ccSpbrook DPRINTF("IRQ mask %02x/%02x\n", value, s->ris); 222eea589ccSpbrook s->im = value; 223eea589ccSpbrook stellaris_enet_update(s); 224eea589ccSpbrook break; 225eea589ccSpbrook case 0x08: /* RCTL */ 226eea589ccSpbrook s->rctl = value; 227eea589ccSpbrook if (value & SE_RCTL_RSTFIFO) { 228eea589ccSpbrook s->rx_fifo_len = 0; 229eea589ccSpbrook s->np = 0; 230eea589ccSpbrook stellaris_enet_update(s); 231eea589ccSpbrook } 232eea589ccSpbrook break; 233eea589ccSpbrook case 0x0c: /* TCTL */ 234eea589ccSpbrook s->tctl = value; 235eea589ccSpbrook break; 236eea589ccSpbrook case 0x10: /* DATA */ 237eea589ccSpbrook if (s->tx_frame_len == -1) { 238eea589ccSpbrook s->tx_frame_len = value & 0xffff; 239eea589ccSpbrook if (s->tx_frame_len > 2032) { 240eea589ccSpbrook DPRINTF("TX frame too long (%d)\n", s->tx_frame_len); 241eea589ccSpbrook s->tx_frame_len = 0; 242eea589ccSpbrook s->ris |= SE_INT_TXER; 243eea589ccSpbrook stellaris_enet_update(s); 244eea589ccSpbrook } else { 245eea589ccSpbrook DPRINTF("Start TX frame len=%d\n", s->tx_frame_len); 246eea589ccSpbrook /* The value written does not include the ethernet header. */ 247eea589ccSpbrook s->tx_frame_len += 14; 248eea589ccSpbrook if ((s->tctl & SE_TCTL_CRC) == 0) 249eea589ccSpbrook s->tx_frame_len += 4; 250eea589ccSpbrook s->tx_fifo_len = 0; 251eea589ccSpbrook s->tx_fifo[s->tx_fifo_len++] = value >> 16; 252eea589ccSpbrook s->tx_fifo[s->tx_fifo_len++] = value >> 24; 253eea589ccSpbrook } 254eea589ccSpbrook } else { 255eea589ccSpbrook s->tx_fifo[s->tx_fifo_len++] = value; 256eea589ccSpbrook s->tx_fifo[s->tx_fifo_len++] = value >> 8; 257eea589ccSpbrook s->tx_fifo[s->tx_fifo_len++] = value >> 16; 258eea589ccSpbrook s->tx_fifo[s->tx_fifo_len++] = value >> 24; 259eea589ccSpbrook if (s->tx_fifo_len >= s->tx_frame_len) { 260eea589ccSpbrook /* We don't implement explicit CRC, so just chop it off. */ 261eea589ccSpbrook if ((s->tctl & SE_TCTL_CRC) == 0) 262eea589ccSpbrook s->tx_frame_len -= 4; 263eea589ccSpbrook if ((s->tctl & SE_TCTL_PADEN) && s->tx_frame_len < 60) { 264eea589ccSpbrook memset(&s->tx_fifo[s->tx_frame_len], 0, 60 - s->tx_frame_len); 265eea589ccSpbrook s->tx_fifo_len = 60; 266eea589ccSpbrook } 267b356f76dSJason Wang qemu_send_packet(qemu_get_queue(s->nic), s->tx_fifo, 268b356f76dSJason Wang s->tx_frame_len); 269eea589ccSpbrook s->tx_frame_len = -1; 270eea589ccSpbrook s->ris |= SE_INT_TXEMP; 271eea589ccSpbrook stellaris_enet_update(s); 272eea589ccSpbrook DPRINTF("Done TX\n"); 273eea589ccSpbrook } 274eea589ccSpbrook } 275eea589ccSpbrook break; 276eea589ccSpbrook case 0x14: /* IA0 */ 277540f006aSGerd Hoffmann s->conf.macaddr.a[0] = value; 278540f006aSGerd Hoffmann s->conf.macaddr.a[1] = value >> 8; 279540f006aSGerd Hoffmann s->conf.macaddr.a[2] = value >> 16; 280540f006aSGerd Hoffmann s->conf.macaddr.a[3] = value >> 24; 281eea589ccSpbrook break; 282eea589ccSpbrook case 0x18: /* IA1 */ 283540f006aSGerd Hoffmann s->conf.macaddr.a[4] = value; 284540f006aSGerd Hoffmann s->conf.macaddr.a[5] = value >> 8; 285eea589ccSpbrook break; 286eea589ccSpbrook case 0x1c: /* THR */ 287eea589ccSpbrook s->thr = value; 288eea589ccSpbrook break; 289eea589ccSpbrook case 0x20: /* MCTL */ 290eea589ccSpbrook s->mctl = value; 291eea589ccSpbrook break; 292eea589ccSpbrook case 0x24: /* MDV */ 293eea589ccSpbrook s->mdv = value; 294eea589ccSpbrook break; 295eea589ccSpbrook case 0x28: /* MADD */ 296eea589ccSpbrook /* ignored. */ 297eea589ccSpbrook break; 298eea589ccSpbrook case 0x2c: /* MTXD */ 299eea589ccSpbrook s->mtxd = value & 0xff; 300eea589ccSpbrook break; 301eea589ccSpbrook case 0x30: /* MRXD */ 302eea589ccSpbrook case 0x34: /* NP */ 303eea589ccSpbrook case 0x38: /* TR */ 304eea589ccSpbrook /* Ignored. */ 305eea589ccSpbrook case 0x3c: /* Undocuented: Timestamp? */ 306eea589ccSpbrook /* Ignored. */ 307eea589ccSpbrook break; 308eea589ccSpbrook default: 3092ac71179SPaul Brook hw_error("stellaris_enet_write: Bad offset %x\n", (int)offset); 310eea589ccSpbrook } 311eea589ccSpbrook } 312eea589ccSpbrook 313f070e1e2SAvi Kivity static const MemoryRegionOps stellaris_enet_ops = { 314f070e1e2SAvi Kivity .read = stellaris_enet_read, 315f070e1e2SAvi Kivity .write = stellaris_enet_write, 316f070e1e2SAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 317eea589ccSpbrook }; 318eea589ccSpbrook 319eea589ccSpbrook static void stellaris_enet_reset(stellaris_enet_state *s) 320eea589ccSpbrook { 321eea589ccSpbrook s->mdv = 0x80; 322eea589ccSpbrook s->rctl = SE_RCTL_BADCRC; 323eea589ccSpbrook s->im = SE_INT_PHY | SE_INT_MD | SE_INT_RXER | SE_INT_FOV | SE_INT_TXEMP 324eea589ccSpbrook | SE_INT_TXER | SE_INT_RX; 325eea589ccSpbrook s->thr = 0x3f; 326eea589ccSpbrook s->tx_frame_len = -1; 327eea589ccSpbrook } 328eea589ccSpbrook 32923e39294Spbrook static void stellaris_enet_save(QEMUFile *f, void *opaque) 33023e39294Spbrook { 33123e39294Spbrook stellaris_enet_state *s = (stellaris_enet_state *)opaque; 33223e39294Spbrook int i; 33323e39294Spbrook 33423e39294Spbrook qemu_put_be32(f, s->ris); 33523e39294Spbrook qemu_put_be32(f, s->im); 33623e39294Spbrook qemu_put_be32(f, s->rctl); 33723e39294Spbrook qemu_put_be32(f, s->tctl); 33823e39294Spbrook qemu_put_be32(f, s->thr); 33923e39294Spbrook qemu_put_be32(f, s->mctl); 34023e39294Spbrook qemu_put_be32(f, s->mdv); 34123e39294Spbrook qemu_put_be32(f, s->mtxd); 34223e39294Spbrook qemu_put_be32(f, s->mrxd); 34323e39294Spbrook qemu_put_be32(f, s->np); 34423e39294Spbrook qemu_put_be32(f, s->tx_frame_len); 34523e39294Spbrook qemu_put_be32(f, s->tx_fifo_len); 34623e39294Spbrook qemu_put_buffer(f, s->tx_fifo, sizeof(s->tx_fifo)); 34723e39294Spbrook for (i = 0; i < 31; i++) { 34823e39294Spbrook qemu_put_be32(f, s->rx[i].len); 34923e39294Spbrook qemu_put_buffer(f, s->rx[i].data, sizeof(s->rx[i].data)); 35023e39294Spbrook 35123e39294Spbrook } 35223e39294Spbrook qemu_put_be32(f, s->next_packet); 35323e39294Spbrook qemu_put_be32(f, s->rx_fifo - s->rx[s->next_packet].data); 35423e39294Spbrook qemu_put_be32(f, s->rx_fifo_len); 35523e39294Spbrook } 35623e39294Spbrook 35723e39294Spbrook static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id) 35823e39294Spbrook { 35923e39294Spbrook stellaris_enet_state *s = (stellaris_enet_state *)opaque; 36023e39294Spbrook int i; 36123e39294Spbrook 36223e39294Spbrook if (version_id != 1) 36323e39294Spbrook return -EINVAL; 36423e39294Spbrook 36523e39294Spbrook s->ris = qemu_get_be32(f); 36623e39294Spbrook s->im = qemu_get_be32(f); 36723e39294Spbrook s->rctl = qemu_get_be32(f); 36823e39294Spbrook s->tctl = qemu_get_be32(f); 36923e39294Spbrook s->thr = qemu_get_be32(f); 37023e39294Spbrook s->mctl = qemu_get_be32(f); 37123e39294Spbrook s->mdv = qemu_get_be32(f); 37223e39294Spbrook s->mtxd = qemu_get_be32(f); 37323e39294Spbrook s->mrxd = qemu_get_be32(f); 37423e39294Spbrook s->np = qemu_get_be32(f); 37523e39294Spbrook s->tx_frame_len = qemu_get_be32(f); 37623e39294Spbrook s->tx_fifo_len = qemu_get_be32(f); 37723e39294Spbrook qemu_get_buffer(f, s->tx_fifo, sizeof(s->tx_fifo)); 37823e39294Spbrook for (i = 0; i < 31; i++) { 37923e39294Spbrook s->rx[i].len = qemu_get_be32(f); 38023e39294Spbrook qemu_get_buffer(f, s->rx[i].data, sizeof(s->rx[i].data)); 38123e39294Spbrook 38223e39294Spbrook } 38323e39294Spbrook s->next_packet = qemu_get_be32(f); 38423e39294Spbrook s->rx_fifo = s->rx[s->next_packet].data + qemu_get_be32(f); 38523e39294Spbrook s->rx_fifo_len = qemu_get_be32(f); 38623e39294Spbrook 38723e39294Spbrook return 0; 38823e39294Spbrook } 38923e39294Spbrook 3904e68f7a0SStefan Hajnoczi static void stellaris_enet_cleanup(NetClientState *nc) 391b946a153Saliguori { 392cc1f0f45SJason Wang stellaris_enet_state *s = qemu_get_nic_opaque(nc); 393b946a153Saliguori 394*0618db44SAndreas Färber s->nic = NULL; 395b946a153Saliguori } 396b946a153Saliguori 3978c9b63b9SMark McLoughlin static NetClientInfo net_stellaris_enet_info = { 3982be64a68SLaszlo Ersek .type = NET_CLIENT_OPTIONS_KIND_NIC, 3998c9b63b9SMark McLoughlin .size = sizeof(NICState), 4008c9b63b9SMark McLoughlin .can_receive = stellaris_enet_can_receive, 4018c9b63b9SMark McLoughlin .receive = stellaris_enet_receive, 4028c9b63b9SMark McLoughlin .cleanup = stellaris_enet_cleanup, 4038c9b63b9SMark McLoughlin }; 4048c9b63b9SMark McLoughlin 4052fa30abaSAndreas Färber static int stellaris_enet_init(SysBusDevice *sbd) 406eea589ccSpbrook { 4072fa30abaSAndreas Färber DeviceState *dev = DEVICE(sbd); 4082fa30abaSAndreas Färber stellaris_enet_state *s = STELLARIS_ENET(dev); 409eea589ccSpbrook 410eedfac6fSPaolo Bonzini memory_region_init_io(&s->mmio, OBJECT(s), &stellaris_enet_ops, s, 411eedfac6fSPaolo Bonzini "stellaris_enet", 0x1000); 4122fa30abaSAndreas Färber sysbus_init_mmio(sbd, &s->mmio); 4132fa30abaSAndreas Färber sysbus_init_irq(sbd, &s->irq); 414540f006aSGerd Hoffmann qemu_macaddr_default_if_unset(&s->conf.macaddr); 415eea589ccSpbrook 4168c9b63b9SMark McLoughlin s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf, 4172fa30abaSAndreas Färber object_get_typename(OBJECT(dev)), dev->id, s); 418b356f76dSJason Wang qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); 419eea589ccSpbrook 420eea589ccSpbrook stellaris_enet_reset(s); 4212fa30abaSAndreas Färber register_savevm(dev, "stellaris_enet", -1, 1, 42223e39294Spbrook stellaris_enet_save, stellaris_enet_load, s); 42381a322d4SGerd Hoffmann return 0; 424eea589ccSpbrook } 425a5580466SPaul Brook 426*0618db44SAndreas Färber static void stellaris_enet_unrealize(DeviceState *dev, Error **errp) 427*0618db44SAndreas Färber { 428*0618db44SAndreas Färber stellaris_enet_state *s = STELLARIS_ENET(dev); 429*0618db44SAndreas Färber 430*0618db44SAndreas Färber unregister_savevm(DEVICE(s), "stellaris_enet", s); 431*0618db44SAndreas Färber 432*0618db44SAndreas Färber memory_region_destroy(&s->mmio); 433*0618db44SAndreas Färber } 434*0618db44SAndreas Färber 435999e12bbSAnthony Liguori static Property stellaris_enet_properties[] = { 436540f006aSGerd Hoffmann DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf), 437540f006aSGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 438999e12bbSAnthony Liguori }; 439999e12bbSAnthony Liguori 440999e12bbSAnthony Liguori static void stellaris_enet_class_init(ObjectClass *klass, void *data) 441999e12bbSAnthony Liguori { 44239bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 443999e12bbSAnthony Liguori SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 444999e12bbSAnthony Liguori 445999e12bbSAnthony Liguori k->init = stellaris_enet_init; 446*0618db44SAndreas Färber dc->unrealize = stellaris_enet_unrealize; 44739bffca2SAnthony Liguori dc->props = stellaris_enet_properties; 448540f006aSGerd Hoffmann } 449999e12bbSAnthony Liguori 4508c43a6f0SAndreas Färber static const TypeInfo stellaris_enet_info = { 4512fa30abaSAndreas Färber .name = TYPE_STELLARIS_ENET, 45239bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 45339bffca2SAnthony Liguori .instance_size = sizeof(stellaris_enet_state), 454999e12bbSAnthony Liguori .class_init = stellaris_enet_class_init, 455540f006aSGerd Hoffmann }; 456540f006aSGerd Hoffmann 45783f7d43aSAndreas Färber static void stellaris_enet_register_types(void) 458a5580466SPaul Brook { 45939bffca2SAnthony Liguori type_register_static(&stellaris_enet_info); 460a5580466SPaul Brook } 461a5580466SPaul Brook 46283f7d43aSAndreas Färber type_init(stellaris_enet_register_types) 463