Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 1 | /* |
| 2 | * QEMU model of XGMAC Ethernet. |
| 3 | * |
| 4 | * derived from the Xilinx AXI-Ethernet by Edgar E. Iglesias. |
| 5 | * |
| 6 | * Copyright (c) 2011 Calxeda, Inc. |
| 7 | * |
| 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 9 | * of this software and associated documentation files (the "Software"), to deal |
| 10 | * in the Software without restriction, including without limitation the rights |
| 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 12 | * copies of the Software, and to permit persons to whom the Software is |
| 13 | * furnished to do so, subject to the following conditions: |
| 14 | * |
| 15 | * The above copyright notice and this permission notice shall be included in |
| 16 | * all copies or substantial portions of the Software. |
| 17 | * |
| 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 21 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 24 | * THE SOFTWARE. |
| 25 | */ |
| 26 | |
Paolo Bonzini | 83c9f4c | 2013-02-04 15:40:22 +0100 | [diff] [blame] | 27 | #include "hw/sysbus.h" |
Paolo Bonzini | dccfcd0 | 2013-04-08 16:55:25 +0200 | [diff] [blame] | 28 | #include "sysemu/char.h" |
Paolo Bonzini | 1de7afc | 2012-12-17 18:20:00 +0100 | [diff] [blame] | 29 | #include "qemu/log.h" |
Paolo Bonzini | 1422e32 | 2012-10-24 08:43:34 +0200 | [diff] [blame] | 30 | #include "net/net.h" |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 31 | #include "net/checksum.h" |
| 32 | |
| 33 | #ifdef DEBUG_XGMAC |
| 34 | #define DEBUGF_BRK(message, args...) do { \ |
| 35 | fprintf(stderr, (message), ## args); \ |
| 36 | } while (0) |
| 37 | #else |
| 38 | #define DEBUGF_BRK(message, args...) do { } while (0) |
| 39 | #endif |
| 40 | |
| 41 | #define XGMAC_CONTROL 0x00000000 /* MAC Configuration */ |
| 42 | #define XGMAC_FRAME_FILTER 0x00000001 /* MAC Frame Filter */ |
| 43 | #define XGMAC_FLOW_CTRL 0x00000006 /* MAC Flow Control */ |
| 44 | #define XGMAC_VLAN_TAG 0x00000007 /* VLAN Tags */ |
| 45 | #define XGMAC_VERSION 0x00000008 /* Version */ |
| 46 | /* VLAN tag for insertion or replacement into tx frames */ |
| 47 | #define XGMAC_VLAN_INCL 0x00000009 |
| 48 | #define XGMAC_LPI_CTRL 0x0000000a /* LPI Control and Status */ |
| 49 | #define XGMAC_LPI_TIMER 0x0000000b /* LPI Timers Control */ |
| 50 | #define XGMAC_TX_PACE 0x0000000c /* Transmit Pace and Stretch */ |
| 51 | #define XGMAC_VLAN_HASH 0x0000000d /* VLAN Hash Table */ |
| 52 | #define XGMAC_DEBUG 0x0000000e /* Debug */ |
| 53 | #define XGMAC_INT_STATUS 0x0000000f /* Interrupt and Control */ |
| 54 | /* HASH table registers */ |
| 55 | #define XGMAC_HASH(n) ((0x00000300/4) + (n)) |
| 56 | #define XGMAC_NUM_HASH 16 |
| 57 | /* Operation Mode */ |
| 58 | #define XGMAC_OPMODE (0x00000400/4) |
| 59 | /* Remote Wake-Up Frame Filter */ |
| 60 | #define XGMAC_REMOTE_WAKE (0x00000700/4) |
| 61 | /* PMT Control and Status */ |
| 62 | #define XGMAC_PMT (0x00000704/4) |
| 63 | |
| 64 | #define XGMAC_ADDR_HIGH(reg) (0x00000010+((reg) * 2)) |
| 65 | #define XGMAC_ADDR_LOW(reg) (0x00000011+((reg) * 2)) |
| 66 | |
| 67 | #define DMA_BUS_MODE 0x000003c0 /* Bus Mode */ |
| 68 | #define DMA_XMT_POLL_DEMAND 0x000003c1 /* Transmit Poll Demand */ |
| 69 | #define DMA_RCV_POLL_DEMAND 0x000003c2 /* Received Poll Demand */ |
| 70 | #define DMA_RCV_BASE_ADDR 0x000003c3 /* Receive List Base */ |
| 71 | #define DMA_TX_BASE_ADDR 0x000003c4 /* Transmit List Base */ |
| 72 | #define DMA_STATUS 0x000003c5 /* Status Register */ |
| 73 | #define DMA_CONTROL 0x000003c6 /* Ctrl (Operational Mode) */ |
| 74 | #define DMA_INTR_ENA 0x000003c7 /* Interrupt Enable */ |
| 75 | #define DMA_MISSED_FRAME_CTR 0x000003c8 /* Missed Frame Counter */ |
| 76 | /* Receive Interrupt Watchdog Timer */ |
| 77 | #define DMA_RI_WATCHDOG_TIMER 0x000003c9 |
| 78 | #define DMA_AXI_BUS 0x000003ca /* AXI Bus Mode */ |
| 79 | #define DMA_AXI_STATUS 0x000003cb /* AXI Status */ |
| 80 | #define DMA_CUR_TX_DESC_ADDR 0x000003d2 /* Current Host Tx Descriptor */ |
| 81 | #define DMA_CUR_RX_DESC_ADDR 0x000003d3 /* Current Host Rx Descriptor */ |
| 82 | #define DMA_CUR_TX_BUF_ADDR 0x000003d4 /* Current Host Tx Buffer */ |
| 83 | #define DMA_CUR_RX_BUF_ADDR 0x000003d5 /* Current Host Rx Buffer */ |
| 84 | #define DMA_HW_FEATURE 0x000003d6 /* Enabled Hardware Features */ |
| 85 | |
| 86 | /* DMA Status register defines */ |
| 87 | #define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */ |
| 88 | #define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */ |
| 89 | #define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */ |
| 90 | #define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */ |
| 91 | #define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */ |
| 92 | #define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */ |
| 93 | #define DMA_STATUS_TS_SHIFT 20 |
| 94 | #define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */ |
| 95 | #define DMA_STATUS_RS_SHIFT 17 |
| 96 | #define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */ |
| 97 | #define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */ |
| 98 | #define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */ |
| 99 | #define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */ |
| 100 | #define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */ |
| 101 | #define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */ |
| 102 | #define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */ |
| 103 | #define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */ |
| 104 | #define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */ |
| 105 | #define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */ |
| 106 | #define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */ |
| 107 | #define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */ |
| 108 | #define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */ |
| 109 | #define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */ |
| 110 | #define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */ |
| 111 | |
| 112 | /* DMA Control register defines */ |
| 113 | #define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */ |
| 114 | #define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */ |
| 115 | #define DMA_CONTROL_DFF 0x01000000 /* Disable flush of rx frames */ |
| 116 | |
| 117 | struct desc { |
| 118 | uint32_t ctl_stat; |
| 119 | uint16_t buffer1_size; |
| 120 | uint16_t buffer2_size; |
| 121 | uint32_t buffer1_addr; |
| 122 | uint32_t buffer2_addr; |
| 123 | uint32_t ext_stat; |
| 124 | uint32_t res[3]; |
| 125 | }; |
| 126 | |
| 127 | #define R_MAX 0x400 |
| 128 | |
| 129 | typedef struct RxTxStats { |
| 130 | uint64_t rx_bytes; |
| 131 | uint64_t tx_bytes; |
| 132 | |
| 133 | uint64_t rx; |
| 134 | uint64_t rx_bcast; |
| 135 | uint64_t rx_mcast; |
| 136 | } RxTxStats; |
| 137 | |
| 138 | typedef struct XgmacState { |
| 139 | SysBusDevice busdev; |
| 140 | MemoryRegion iomem; |
| 141 | qemu_irq sbd_irq; |
| 142 | qemu_irq pmt_irq; |
| 143 | qemu_irq mci_irq; |
| 144 | NICState *nic; |
| 145 | NICConf conf; |
| 146 | |
| 147 | struct RxTxStats stats; |
| 148 | uint32_t regs[R_MAX]; |
| 149 | } XgmacState; |
| 150 | |
| 151 | const VMStateDescription vmstate_rxtx_stats = { |
| 152 | .name = "xgmac_stats", |
| 153 | .version_id = 1, |
| 154 | .minimum_version_id = 1, |
| 155 | .fields = (VMStateField[]) { |
| 156 | VMSTATE_UINT64(rx_bytes, RxTxStats), |
| 157 | VMSTATE_UINT64(tx_bytes, RxTxStats), |
| 158 | VMSTATE_UINT64(rx, RxTxStats), |
| 159 | VMSTATE_UINT64(rx_bcast, RxTxStats), |
| 160 | VMSTATE_UINT64(rx_mcast, RxTxStats), |
| 161 | VMSTATE_END_OF_LIST() |
| 162 | } |
| 163 | }; |
| 164 | |
| 165 | static const VMStateDescription vmstate_xgmac = { |
| 166 | .name = "xgmac", |
| 167 | .version_id = 1, |
| 168 | .minimum_version_id = 1, |
| 169 | .fields = (VMStateField[]) { |
| 170 | VMSTATE_STRUCT(stats, XgmacState, 0, vmstate_rxtx_stats, RxTxStats), |
| 171 | VMSTATE_UINT32_ARRAY(regs, XgmacState, R_MAX), |
| 172 | VMSTATE_END_OF_LIST() |
| 173 | } |
| 174 | }; |
| 175 | |
| 176 | static void xgmac_read_desc(struct XgmacState *s, struct desc *d, int rx) |
| 177 | { |
| 178 | uint32_t addr = rx ? s->regs[DMA_CUR_RX_DESC_ADDR] : |
| 179 | s->regs[DMA_CUR_TX_DESC_ADDR]; |
| 180 | cpu_physical_memory_read(addr, d, sizeof(*d)); |
| 181 | } |
| 182 | |
| 183 | static void xgmac_write_desc(struct XgmacState *s, struct desc *d, int rx) |
| 184 | { |
| 185 | int reg = rx ? DMA_CUR_RX_DESC_ADDR : DMA_CUR_TX_DESC_ADDR; |
| 186 | uint32_t addr = s->regs[reg]; |
| 187 | |
| 188 | if (!rx && (d->ctl_stat & 0x00200000)) { |
| 189 | s->regs[reg] = s->regs[DMA_TX_BASE_ADDR]; |
| 190 | } else if (rx && (d->buffer1_size & 0x8000)) { |
| 191 | s->regs[reg] = s->regs[DMA_RCV_BASE_ADDR]; |
| 192 | } else { |
| 193 | s->regs[reg] += sizeof(*d); |
| 194 | } |
| 195 | cpu_physical_memory_write(addr, d, sizeof(*d)); |
| 196 | } |
| 197 | |
| 198 | static void xgmac_enet_send(struct XgmacState *s) |
| 199 | { |
| 200 | struct desc bd; |
| 201 | int frame_size; |
| 202 | int len; |
| 203 | uint8_t frame[8192]; |
| 204 | uint8_t *ptr; |
| 205 | |
| 206 | ptr = frame; |
| 207 | frame_size = 0; |
| 208 | while (1) { |
| 209 | xgmac_read_desc(s, &bd, 0); |
| 210 | if ((bd.ctl_stat & 0x80000000) == 0) { |
| 211 | /* Run out of descriptors to transmit. */ |
| 212 | break; |
| 213 | } |
| 214 | len = (bd.buffer1_size & 0xfff) + (bd.buffer2_size & 0xfff); |
| 215 | |
| 216 | if ((bd.buffer1_size & 0xfff) > 2048) { |
| 217 | DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- " |
| 218 | "xgmac buffer 1 len on send > 2048 (0x%x)\n", |
| 219 | __func__, bd.buffer1_size & 0xfff); |
| 220 | } |
| 221 | if ((bd.buffer2_size & 0xfff) != 0) { |
| 222 | DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- " |
| 223 | "xgmac buffer 2 len on send != 0 (0x%x)\n", |
| 224 | __func__, bd.buffer2_size & 0xfff); |
| 225 | } |
| 226 | if (len >= sizeof(frame)) { |
| 227 | DEBUGF_BRK("qemu:%s: buffer overflow %d read into %zu " |
| 228 | "buffer\n" , __func__, len, sizeof(frame)); |
| 229 | DEBUGF_BRK("qemu:%s: buffer1.size=%d; buffer2.size=%d\n", |
| 230 | __func__, bd.buffer1_size, bd.buffer2_size); |
| 231 | } |
| 232 | |
| 233 | cpu_physical_memory_read(bd.buffer1_addr, ptr, len); |
| 234 | ptr += len; |
| 235 | frame_size += len; |
| 236 | if (bd.ctl_stat & 0x20000000) { |
| 237 | /* Last buffer in frame. */ |
Jason Wang | b356f76 | 2013-01-30 19:12:22 +0800 | [diff] [blame] | 238 | qemu_send_packet(qemu_get_queue(s->nic), frame, len); |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 239 | ptr = frame; |
| 240 | frame_size = 0; |
| 241 | s->regs[DMA_STATUS] |= DMA_STATUS_TI | DMA_STATUS_NIS; |
| 242 | } |
| 243 | bd.ctl_stat &= ~0x80000000; |
| 244 | /* Write back the modified descriptor. */ |
| 245 | xgmac_write_desc(s, &bd, 0); |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | static void enet_update_irq(struct XgmacState *s) |
| 250 | { |
| 251 | int stat = s->regs[DMA_STATUS] & s->regs[DMA_INTR_ENA]; |
| 252 | qemu_set_irq(s->sbd_irq, !!stat); |
| 253 | } |
| 254 | |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 255 | static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size) |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 256 | { |
| 257 | struct XgmacState *s = opaque; |
| 258 | uint64_t r = 0; |
| 259 | addr >>= 2; |
| 260 | |
| 261 | switch (addr) { |
| 262 | case XGMAC_VERSION: |
| 263 | r = 0x1012; |
| 264 | break; |
| 265 | default: |
| 266 | if (addr < ARRAY_SIZE(s->regs)) { |
| 267 | r = s->regs[addr]; |
| 268 | } |
| 269 | break; |
| 270 | } |
| 271 | return r; |
| 272 | } |
| 273 | |
Avi Kivity | a8170e5 | 2012-10-23 12:30:10 +0200 | [diff] [blame] | 274 | static void enet_write(void *opaque, hwaddr addr, |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 275 | uint64_t value, unsigned size) |
| 276 | { |
| 277 | struct XgmacState *s = opaque; |
| 278 | |
| 279 | addr >>= 2; |
| 280 | switch (addr) { |
| 281 | case DMA_BUS_MODE: |
| 282 | s->regs[DMA_BUS_MODE] = value & ~0x1; |
| 283 | break; |
| 284 | case DMA_XMT_POLL_DEMAND: |
| 285 | xgmac_enet_send(s); |
| 286 | break; |
| 287 | case DMA_STATUS: |
| 288 | s->regs[DMA_STATUS] = s->regs[DMA_STATUS] & ~value; |
| 289 | break; |
| 290 | case DMA_RCV_BASE_ADDR: |
| 291 | s->regs[DMA_RCV_BASE_ADDR] = s->regs[DMA_CUR_RX_DESC_ADDR] = value; |
| 292 | break; |
| 293 | case DMA_TX_BASE_ADDR: |
| 294 | s->regs[DMA_TX_BASE_ADDR] = s->regs[DMA_CUR_TX_DESC_ADDR] = value; |
| 295 | break; |
| 296 | default: |
| 297 | if (addr < ARRAY_SIZE(s->regs)) { |
| 298 | s->regs[addr] = value; |
| 299 | } |
| 300 | break; |
| 301 | } |
| 302 | enet_update_irq(s); |
| 303 | } |
| 304 | |
| 305 | static const MemoryRegionOps enet_mem_ops = { |
| 306 | .read = enet_read, |
| 307 | .write = enet_write, |
| 308 | .endianness = DEVICE_LITTLE_ENDIAN, |
| 309 | }; |
| 310 | |
Stefan Hajnoczi | 4e68f7a | 2012-07-24 16:35:13 +0100 | [diff] [blame] | 311 | static int eth_can_rx(NetClientState *nc) |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 312 | { |
Jason Wang | cc1f0f4 | 2013-01-30 19:12:23 +0800 | [diff] [blame] | 313 | struct XgmacState *s = qemu_get_nic_opaque(nc); |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 314 | |
| 315 | /* RX enabled? */ |
| 316 | return s->regs[DMA_CONTROL] & DMA_CONTROL_SR; |
| 317 | } |
| 318 | |
Stefan Hajnoczi | 4e68f7a | 2012-07-24 16:35:13 +0100 | [diff] [blame] | 319 | static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 320 | { |
Jason Wang | cc1f0f4 | 2013-01-30 19:12:23 +0800 | [diff] [blame] | 321 | struct XgmacState *s = qemu_get_nic_opaque(nc); |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 322 | static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, |
| 323 | 0xff, 0xff, 0xff}; |
| 324 | int unicast, broadcast, multicast; |
| 325 | struct desc bd; |
| 326 | ssize_t ret; |
| 327 | |
| 328 | unicast = ~buf[0] & 0x1; |
| 329 | broadcast = memcmp(buf, sa_bcast, 6) == 0; |
| 330 | multicast = !unicast && !broadcast; |
| 331 | if (size < 12) { |
| 332 | s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS; |
| 333 | ret = -1; |
| 334 | goto out; |
| 335 | } |
| 336 | |
| 337 | xgmac_read_desc(s, &bd, 1); |
| 338 | if ((bd.ctl_stat & 0x80000000) == 0) { |
| 339 | s->regs[DMA_STATUS] |= DMA_STATUS_RU | DMA_STATUS_AIS; |
| 340 | ret = size; |
| 341 | goto out; |
| 342 | } |
| 343 | |
| 344 | cpu_physical_memory_write(bd.buffer1_addr, buf, size); |
| 345 | |
| 346 | /* Add in the 4 bytes for crc (the real hw returns length incl crc) */ |
| 347 | size += 4; |
| 348 | bd.ctl_stat = (size << 16) | 0x300; |
| 349 | xgmac_write_desc(s, &bd, 1); |
| 350 | |
| 351 | s->stats.rx_bytes += size; |
| 352 | s->stats.rx++; |
| 353 | if (multicast) { |
| 354 | s->stats.rx_mcast++; |
| 355 | } else if (broadcast) { |
| 356 | s->stats.rx_bcast++; |
| 357 | } |
| 358 | |
| 359 | s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS; |
| 360 | ret = size; |
| 361 | |
| 362 | out: |
| 363 | enet_update_irq(s); |
| 364 | return ret; |
| 365 | } |
| 366 | |
Stefan Hajnoczi | 4e68f7a | 2012-07-24 16:35:13 +0100 | [diff] [blame] | 367 | static void eth_cleanup(NetClientState *nc) |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 368 | { |
Jason Wang | cc1f0f4 | 2013-01-30 19:12:23 +0800 | [diff] [blame] | 369 | struct XgmacState *s = qemu_get_nic_opaque(nc); |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 370 | s->nic = NULL; |
| 371 | } |
| 372 | |
| 373 | static NetClientInfo net_xgmac_enet_info = { |
Laszlo Ersek | 2be64a6 | 2012-07-17 16:17:12 +0200 | [diff] [blame] | 374 | .type = NET_CLIENT_OPTIONS_KIND_NIC, |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 375 | .size = sizeof(NICState), |
| 376 | .can_receive = eth_can_rx, |
| 377 | .receive = eth_rx, |
| 378 | .cleanup = eth_cleanup, |
| 379 | }; |
| 380 | |
| 381 | static int xgmac_enet_init(SysBusDevice *dev) |
| 382 | { |
| 383 | struct XgmacState *s = FROM_SYSBUS(typeof(*s), dev); |
| 384 | |
Paolo Bonzini | eedfac6 | 2013-06-06 21:25:08 -0400 | [diff] [blame] | 385 | memory_region_init_io(&s->iomem, OBJECT(s), &enet_mem_ops, s, |
| 386 | "xgmac", 0x1000); |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 387 | sysbus_init_mmio(dev, &s->iomem); |
| 388 | sysbus_init_irq(dev, &s->sbd_irq); |
| 389 | sysbus_init_irq(dev, &s->pmt_irq); |
| 390 | sysbus_init_irq(dev, &s->mci_irq); |
| 391 | |
| 392 | qemu_macaddr_default_if_unset(&s->conf.macaddr); |
| 393 | s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf, |
Anthony Liguori | f79f2bf | 2011-12-04 11:17:51 -0600 | [diff] [blame] | 394 | object_get_typename(OBJECT(dev)), dev->qdev.id, s); |
Jason Wang | b356f76 | 2013-01-30 19:12:22 +0800 | [diff] [blame] | 395 | qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 396 | |
| 397 | s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) | |
| 398 | s->conf.macaddr.a[4]; |
| 399 | s->regs[XGMAC_ADDR_LOW(0)] = (s->conf.macaddr.a[3] << 24) | |
| 400 | (s->conf.macaddr.a[2] << 16) | |
| 401 | (s->conf.macaddr.a[1] << 8) | |
| 402 | s->conf.macaddr.a[0]; |
| 403 | |
| 404 | return 0; |
| 405 | } |
| 406 | |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 407 | static Property xgmac_properties[] = { |
| 408 | DEFINE_NIC_PROPERTIES(struct XgmacState, conf), |
| 409 | DEFINE_PROP_END_OF_LIST(), |
| 410 | }; |
| 411 | |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 412 | static void xgmac_enet_class_init(ObjectClass *klass, void *data) |
| 413 | { |
| 414 | SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 415 | DeviceClass *dc = DEVICE_CLASS(klass); |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 416 | |
| 417 | sbc->init = xgmac_enet_init; |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 418 | dc->vmsd = &vmstate_xgmac; |
| 419 | dc->props = xgmac_properties; |
Anthony Liguori | 999e12b | 2012-01-24 13:12:29 -0600 | [diff] [blame] | 420 | } |
| 421 | |
Andreas Färber | 8c43a6f | 2013-01-10 16:19:07 +0100 | [diff] [blame] | 422 | static const TypeInfo xgmac_enet_info = { |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 423 | .name = "xgmac", |
| 424 | .parent = TYPE_SYS_BUS_DEVICE, |
| 425 | .instance_size = sizeof(struct XgmacState), |
| 426 | .class_init = xgmac_enet_class_init, |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 427 | }; |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 428 | |
Andreas Färber | 83f7d43 | 2012-02-09 15:20:55 +0100 | [diff] [blame] | 429 | static void xgmac_enet_register_types(void) |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 430 | { |
Anthony Liguori | 39bffca | 2011-12-07 21:34:16 -0600 | [diff] [blame] | 431 | type_register_static(&xgmac_enet_info); |
Rob Herring | 4c0e167 | 2012-01-26 11:43:47 +0000 | [diff] [blame] | 432 | } |
| 433 | |
Andreas Färber | 83f7d43 | 2012-02-09 15:20:55 +0100 | [diff] [blame] | 434 | type_init(xgmac_enet_register_types) |