qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

xilinx: Add AXIENET & DMA models

Signed-off-by: Edgar E. Iglesias <edgar.iglesias@petalogix.com>

+1448
+2
Makefile.target
··· 272 272 obj-microblaze-y += xilinx_timer.o 273 273 obj-microblaze-y += xilinx_uartlite.o 274 274 obj-microblaze-y += xilinx_ethlite.o 275 + obj-microblaze-y += xilinx_axidma.o 276 + obj-microblaze-y += xilinx_axienet.o 275 277 276 278 obj-microblaze-$(CONFIG_FDT) += device_tree.o 277 279
+509
hw/xilinx_axidma.c
··· 1 + /* 2 + * QEMU model of Xilinx AXI-DMA block. 3 + * 4 + * Copyright (c) 2011 Edgar E. Iglesias. 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 + 25 + #include "sysbus.h" 26 + #include "qemu-char.h" 27 + #include "qemu-timer.h" 28 + #include "qemu-log.h" 29 + #include "qdev-addr.h" 30 + 31 + #include "xilinx_axidma.h" 32 + 33 + #define D(x) 34 + 35 + #define R_DMACR (0x00 / 4) 36 + #define R_DMASR (0x04 / 4) 37 + #define R_CURDESC (0x08 / 4) 38 + #define R_TAILDESC (0x10 / 4) 39 + #define R_MAX (0x30 / 4) 40 + 41 + enum { 42 + DMACR_RUNSTOP = 1, 43 + DMACR_TAILPTR_MODE = 2, 44 + DMACR_RESET = 4 45 + }; 46 + 47 + enum { 48 + DMASR_HALTED = 1, 49 + DMASR_IDLE = 2, 50 + DMASR_IOC_IRQ = 1 << 12, 51 + DMASR_DLY_IRQ = 1 << 13, 52 + 53 + DMASR_IRQ_MASK = 7 << 12 54 + }; 55 + 56 + struct SDesc { 57 + uint64_t nxtdesc; 58 + uint64_t buffer_address; 59 + uint64_t reserved; 60 + uint32_t control; 61 + uint32_t status; 62 + uint32_t app[6]; 63 + }; 64 + 65 + enum { 66 + SDESC_CTRL_EOF = (1 << 26), 67 + SDESC_CTRL_SOF = (1 << 27), 68 + 69 + SDESC_CTRL_LEN_MASK = (1 << 23) - 1 70 + }; 71 + 72 + enum { 73 + SDESC_STATUS_EOF = (1 << 26), 74 + SDESC_STATUS_SOF_BIT = 27, 75 + SDESC_STATUS_SOF = (1 << SDESC_STATUS_SOF_BIT), 76 + SDESC_STATUS_COMPLETE = (1 << 31) 77 + }; 78 + 79 + struct AXIStream { 80 + QEMUBH *bh; 81 + ptimer_state *ptimer; 82 + qemu_irq irq; 83 + 84 + int nr; 85 + 86 + struct SDesc desc; 87 + int pos; 88 + unsigned int complete_cnt; 89 + uint32_t regs[R_MAX]; 90 + }; 91 + 92 + struct XilinxAXIDMA { 93 + SysBusDevice busdev; 94 + uint32_t freqhz; 95 + void *dmach; 96 + 97 + struct AXIStream streams[2]; 98 + }; 99 + 100 + /* 101 + * Helper calls to extract info from desriptors and other trivial 102 + * state from regs. 103 + */ 104 + static inline int stream_desc_sof(struct SDesc *d) 105 + { 106 + return d->control & SDESC_CTRL_SOF; 107 + } 108 + 109 + static inline int stream_desc_eof(struct SDesc *d) 110 + { 111 + return d->control & SDESC_CTRL_EOF; 112 + } 113 + 114 + static inline int stream_resetting(struct AXIStream *s) 115 + { 116 + return !!(s->regs[R_DMACR] & DMACR_RESET); 117 + } 118 + 119 + static inline int stream_running(struct AXIStream *s) 120 + { 121 + return s->regs[R_DMACR] & DMACR_RUNSTOP; 122 + } 123 + 124 + static inline int stream_halted(struct AXIStream *s) 125 + { 126 + return s->regs[R_DMASR] & DMASR_HALTED; 127 + } 128 + 129 + static inline int stream_idle(struct AXIStream *s) 130 + { 131 + return !!(s->regs[R_DMASR] & DMASR_IDLE); 132 + } 133 + 134 + static void stream_reset(struct AXIStream *s) 135 + { 136 + s->regs[R_DMASR] = DMASR_HALTED; /* starts up halted. */ 137 + s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshhold. */ 138 + } 139 + 140 + /* Mapp an offset addr into a channel index. */ 141 + static inline int streamid_from_addr(target_phys_addr_t addr) 142 + { 143 + int sid; 144 + 145 + sid = addr / (0x30); 146 + sid &= 1; 147 + return sid; 148 + } 149 + 150 + #ifdef DEBUG_ENET 151 + static void stream_desc_show(struct SDesc *d) 152 + { 153 + qemu_log("buffer_addr = " PRIx64 "\n", d->buffer_address); 154 + qemu_log("nxtdesc = " PRIx64 "\n", d->nxtdesc); 155 + qemu_log("control = %x\n", d->control); 156 + qemu_log("status = %x\n", d->status); 157 + } 158 + #endif 159 + 160 + static void stream_desc_load(struct AXIStream *s, target_phys_addr_t addr) 161 + { 162 + struct SDesc *d = &s->desc; 163 + int i; 164 + 165 + cpu_physical_memory_read(addr, (void *) d, sizeof *d); 166 + 167 + /* Convert from LE into host endianness. */ 168 + d->buffer_address = le64_to_cpu(d->buffer_address); 169 + d->nxtdesc = le64_to_cpu(d->nxtdesc); 170 + d->control = le32_to_cpu(d->control); 171 + d->status = le32_to_cpu(d->status); 172 + for (i = 0; i < ARRAY_SIZE(d->app); i++) { 173 + d->app[i] = le32_to_cpu(d->app[i]); 174 + } 175 + } 176 + 177 + static void stream_desc_store(struct AXIStream *s, target_phys_addr_t addr) 178 + { 179 + struct SDesc *d = &s->desc; 180 + int i; 181 + 182 + /* Convert from host endianness into LE. */ 183 + d->buffer_address = cpu_to_le64(d->buffer_address); 184 + d->nxtdesc = cpu_to_le64(d->nxtdesc); 185 + d->control = cpu_to_le32(d->control); 186 + d->status = cpu_to_le32(d->status); 187 + for (i = 0; i < ARRAY_SIZE(d->app); i++) { 188 + d->app[i] = cpu_to_le32(d->app[i]); 189 + } 190 + cpu_physical_memory_write(addr, (void *) d, sizeof *d); 191 + } 192 + 193 + static void stream_update_irq(struct AXIStream *s) 194 + { 195 + unsigned int pending, mask, irq; 196 + 197 + pending = s->regs[R_DMASR] & DMASR_IRQ_MASK; 198 + mask = s->regs[R_DMACR] & DMASR_IRQ_MASK; 199 + 200 + irq = pending & mask; 201 + 202 + qemu_set_irq(s->irq, !!irq); 203 + } 204 + 205 + static void stream_reload_complete_cnt(struct AXIStream *s) 206 + { 207 + unsigned int comp_th; 208 + comp_th = (s->regs[R_DMACR] >> 16) & 0xff; 209 + s->complete_cnt = comp_th; 210 + } 211 + 212 + static void timer_hit(void *opaque) 213 + { 214 + struct AXIStream *s = opaque; 215 + 216 + stream_reload_complete_cnt(s); 217 + s->regs[R_DMASR] |= DMASR_DLY_IRQ; 218 + stream_update_irq(s); 219 + } 220 + 221 + static void stream_complete(struct AXIStream *s) 222 + { 223 + unsigned int comp_delay; 224 + 225 + /* Start the delayed timer. */ 226 + comp_delay = s->regs[R_DMACR] >> 24; 227 + if (comp_delay) { 228 + ptimer_stop(s->ptimer); 229 + ptimer_set_count(s->ptimer, comp_delay); 230 + ptimer_run(s->ptimer, 1); 231 + } 232 + 233 + s->complete_cnt--; 234 + if (s->complete_cnt == 0) { 235 + /* Raise the IOC irq. */ 236 + s->regs[R_DMASR] |= DMASR_IOC_IRQ; 237 + stream_reload_complete_cnt(s); 238 + } 239 + } 240 + 241 + static void stream_process_mem2s(struct AXIStream *s, 242 + struct XilinxDMAConnection *dmach) 243 + { 244 + uint32_t prev_d; 245 + unsigned char txbuf[16 * 1024]; 246 + unsigned int txlen; 247 + uint32_t app[6]; 248 + 249 + if (!stream_running(s) || stream_idle(s)) { 250 + return; 251 + } 252 + 253 + while (1) { 254 + stream_desc_load(s, s->regs[R_CURDESC]); 255 + 256 + if (s->desc.status & SDESC_STATUS_COMPLETE) { 257 + s->regs[R_DMASR] |= DMASR_IDLE; 258 + break; 259 + } 260 + 261 + if (stream_desc_sof(&s->desc)) { 262 + s->pos = 0; 263 + memcpy(app, s->desc.app, sizeof app); 264 + } 265 + 266 + txlen = s->desc.control & SDESC_CTRL_LEN_MASK; 267 + if ((txlen + s->pos) > sizeof txbuf) { 268 + hw_error("%s: too small internal txbuf! %d\n", __func__, 269 + txlen + s->pos); 270 + } 271 + 272 + cpu_physical_memory_read(s->desc.buffer_address, 273 + txbuf + s->pos, txlen); 274 + s->pos += txlen; 275 + 276 + if (stream_desc_eof(&s->desc)) { 277 + xlx_dma_push_to_client(dmach, txbuf, s->pos, app); 278 + s->pos = 0; 279 + stream_complete(s); 280 + } 281 + 282 + /* Update the descriptor. */ 283 + s->desc.status = txlen | SDESC_STATUS_COMPLETE; 284 + stream_desc_store(s, s->regs[R_CURDESC]); 285 + 286 + /* Advance. */ 287 + prev_d = s->regs[R_CURDESC]; 288 + s->regs[R_CURDESC] = s->desc.nxtdesc; 289 + if (prev_d == s->regs[R_TAILDESC]) { 290 + s->regs[R_DMASR] |= DMASR_IDLE; 291 + break; 292 + } 293 + } 294 + } 295 + 296 + static void stream_process_s2mem(struct AXIStream *s, 297 + unsigned char *buf, size_t len, uint32_t *app) 298 + { 299 + uint32_t prev_d; 300 + unsigned int rxlen; 301 + int pos = 0; 302 + int sof = 1; 303 + 304 + if (!stream_running(s) || stream_idle(s)) { 305 + return; 306 + } 307 + 308 + while (len) { 309 + stream_desc_load(s, s->regs[R_CURDESC]); 310 + 311 + if (s->desc.status & SDESC_STATUS_COMPLETE) { 312 + s->regs[R_DMASR] |= DMASR_IDLE; 313 + break; 314 + } 315 + 316 + rxlen = s->desc.control & SDESC_CTRL_LEN_MASK; 317 + if (rxlen > len) { 318 + /* It fits. */ 319 + rxlen = len; 320 + } 321 + 322 + cpu_physical_memory_write(s->desc.buffer_address, buf + pos, rxlen); 323 + len -= rxlen; 324 + pos += rxlen; 325 + 326 + /* Update the descriptor. */ 327 + if (!len) { 328 + int i; 329 + 330 + stream_complete(s); 331 + for (i = 0; i < 5; i++) { 332 + s->desc.app[i] = app[i]; 333 + } 334 + s->desc.status |= SDESC_STATUS_EOF; 335 + } 336 + 337 + s->desc.status |= sof << SDESC_STATUS_SOF_BIT; 338 + s->desc.status |= SDESC_STATUS_COMPLETE; 339 + stream_desc_store(s, s->regs[R_CURDESC]); 340 + sof = 0; 341 + 342 + /* Advance. */ 343 + prev_d = s->regs[R_CURDESC]; 344 + s->regs[R_CURDESC] = s->desc.nxtdesc; 345 + if (prev_d == s->regs[R_TAILDESC]) { 346 + s->regs[R_DMASR] |= DMASR_IDLE; 347 + break; 348 + } 349 + } 350 + } 351 + 352 + static 353 + void axidma_push(void *opaque, unsigned char *buf, size_t len, uint32_t *app) 354 + { 355 + struct XilinxAXIDMA *d = opaque; 356 + struct AXIStream *s = &d->streams[1]; 357 + 358 + if (!app) { 359 + hw_error("No stream app data!\n"); 360 + } 361 + stream_process_s2mem(s, buf, len, app); 362 + stream_update_irq(s); 363 + } 364 + 365 + static uint32_t axidma_readl(void *opaque, target_phys_addr_t addr) 366 + { 367 + struct XilinxAXIDMA *d = opaque; 368 + struct AXIStream *s; 369 + uint32_t r = 0; 370 + int sid; 371 + 372 + sid = streamid_from_addr(addr); 373 + s = &d->streams[sid]; 374 + 375 + addr = addr % 0x30; 376 + addr >>= 2; 377 + switch (addr) { 378 + case R_DMACR: 379 + /* Simulate one cycles reset delay. */ 380 + s->regs[addr] &= ~DMACR_RESET; 381 + r = s->regs[addr]; 382 + break; 383 + case R_DMASR: 384 + s->regs[addr] &= 0xffff; 385 + s->regs[addr] |= (s->complete_cnt & 0xff) << 16; 386 + s->regs[addr] |= (ptimer_get_count(s->ptimer) & 0xff) << 24; 387 + r = s->regs[addr]; 388 + break; 389 + default: 390 + r = s->regs[addr]; 391 + D(qemu_log("%s ch=%d addr=" TARGET_FMT_plx " v=%x\n", 392 + __func__, sid, addr * 4, r)); 393 + break; 394 + } 395 + return r; 396 + 397 + } 398 + 399 + static void 400 + axidma_writel(void *opaque, target_phys_addr_t addr, uint32_t value) 401 + { 402 + struct XilinxAXIDMA *d = opaque; 403 + struct AXIStream *s; 404 + int sid; 405 + 406 + sid = streamid_from_addr(addr); 407 + s = &d->streams[sid]; 408 + 409 + addr = addr % 0x30; 410 + addr >>= 2; 411 + switch (addr) { 412 + case R_DMACR: 413 + /* Tailptr mode is always on. */ 414 + value |= DMACR_TAILPTR_MODE; 415 + /* Remember our previous reset state. */ 416 + value |= (s->regs[addr] & DMACR_RESET); 417 + s->regs[addr] = value; 418 + 419 + if (value & DMACR_RESET) { 420 + stream_reset(s); 421 + } 422 + 423 + if ((value & 1) && !stream_resetting(s)) { 424 + /* Start processing. */ 425 + s->regs[R_DMASR] &= ~(DMASR_HALTED | DMASR_IDLE); 426 + } 427 + stream_reload_complete_cnt(s); 428 + break; 429 + 430 + case R_DMASR: 431 + /* Mask away write to clear irq lines. */ 432 + value &= ~(value & DMASR_IRQ_MASK); 433 + s->regs[addr] = value; 434 + break; 435 + 436 + case R_TAILDESC: 437 + s->regs[addr] = value; 438 + s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle. */ 439 + if (!sid) { 440 + stream_process_mem2s(s, d->dmach); 441 + } 442 + break; 443 + default: 444 + D(qemu_log("%s: ch=%d addr=" TARGET_FMT_plx " v=%x\n", 445 + __func__, sid, addr * 4, value)); 446 + s->regs[addr] = value; 447 + break; 448 + } 449 + stream_update_irq(s); 450 + } 451 + 452 + static CPUReadMemoryFunc * const axidma_read[] = { 453 + &axidma_readl, 454 + &axidma_readl, 455 + &axidma_readl, 456 + }; 457 + 458 + static CPUWriteMemoryFunc * const axidma_write[] = { 459 + &axidma_writel, 460 + &axidma_writel, 461 + &axidma_writel, 462 + }; 463 + 464 + static int xilinx_axidma_init(SysBusDevice *dev) 465 + { 466 + struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), dev); 467 + int axidma_regs; 468 + int i; 469 + 470 + sysbus_init_irq(dev, &s->streams[1].irq); 471 + sysbus_init_irq(dev, &s->streams[0].irq); 472 + 473 + if (!s->dmach) { 474 + hw_error("Unconnected DMA channel.\n"); 475 + } 476 + 477 + xlx_dma_connect_dma(s->dmach, s, axidma_push); 478 + 479 + axidma_regs = cpu_register_io_memory(axidma_read, axidma_write, s, 480 + DEVICE_NATIVE_ENDIAN); 481 + sysbus_init_mmio(dev, R_MAX * 4 * 2, axidma_regs); 482 + 483 + for (i = 0; i < 2; i++) { 484 + stream_reset(&s->streams[i]); 485 + s->streams[i].nr = i; 486 + s->streams[i].bh = qemu_bh_new(timer_hit, &s->streams[i]); 487 + s->streams[i].ptimer = ptimer_init(s->streams[i].bh); 488 + ptimer_set_freq(s->streams[i].ptimer, s->freqhz); 489 + } 490 + return 0; 491 + } 492 + 493 + static SysBusDeviceInfo axidma_info = { 494 + .init = xilinx_axidma_init, 495 + .qdev.name = "xilinx,axidma", 496 + .qdev.size = sizeof(struct XilinxAXIDMA), 497 + .qdev.props = (Property[]) { 498 + DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000), 499 + DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach), 500 + DEFINE_PROP_END_OF_LIST(), 501 + } 502 + }; 503 + 504 + static void xilinx_axidma_register(void) 505 + { 506 + sysbus_register_withprop(&axidma_info); 507 + } 508 + 509 + device_init(xilinx_axidma_register)
+39
hw/xilinx_axidma.h
··· 1 + /* AXI DMA connection. Used until qdev provides a generic way. */ 2 + typedef void (*DMAPushFn)(void *opaque, 3 + unsigned char *buf, size_t len, uint32_t *app); 4 + 5 + struct XilinxDMAConnection { 6 + void *dma; 7 + void *client; 8 + 9 + DMAPushFn to_dma; 10 + DMAPushFn to_client; 11 + }; 12 + 13 + static inline void xlx_dma_connect_client(struct XilinxDMAConnection *dmach, 14 + void *c, DMAPushFn f) 15 + { 16 + dmach->client = c; 17 + dmach->to_client = f; 18 + } 19 + 20 + static inline void xlx_dma_connect_dma(struct XilinxDMAConnection *dmach, 21 + void *d, DMAPushFn f) 22 + { 23 + dmach->dma = d; 24 + dmach->to_dma = f; 25 + } 26 + 27 + static inline 28 + void xlx_dma_push_to_dma(struct XilinxDMAConnection *dmach, 29 + uint8_t *buf, size_t len, uint32_t *app) 30 + { 31 + dmach->to_dma(dmach->dma, buf, len, app); 32 + } 33 + static inline 34 + void xlx_dma_push_to_client(struct XilinxDMAConnection *dmach, 35 + uint8_t *buf, size_t len, uint32_t *app) 36 + { 37 + dmach->to_client(dmach->client, buf, len, app); 38 + } 39 +
+898
hw/xilinx_axienet.c
··· 1 + /* 2 + * QEMU model of Xilinx AXI-Ethernet. 3 + * 4 + * Copyright (c) 2011 Edgar E. Iglesias. 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 + 25 + #include "sysbus.h" 26 + #include "qemu-char.h" 27 + #include "qemu-log.h" 28 + #include "net.h" 29 + #include "net/checksum.h" 30 + 31 + #include "xilinx_axidma.h" 32 + 33 + #define DPHY(x) 34 + 35 + /* Advertisement control register. */ 36 + #define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ 37 + #define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ 38 + #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ 39 + #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ 40 + 41 + struct PHY { 42 + uint32_t regs[32]; 43 + 44 + int link; 45 + 46 + unsigned int (*read)(struct PHY *phy, unsigned int req); 47 + void (*write)(struct PHY *phy, unsigned int req, 48 + unsigned int data); 49 + }; 50 + 51 + static unsigned int tdk_read(struct PHY *phy, unsigned int req) 52 + { 53 + int regnum; 54 + unsigned r = 0; 55 + 56 + regnum = req & 0x1f; 57 + 58 + switch (regnum) { 59 + case 1: 60 + if (!phy->link) { 61 + break; 62 + } 63 + /* MR1. */ 64 + /* Speeds and modes. */ 65 + r |= (1 << 13) | (1 << 14); 66 + r |= (1 << 11) | (1 << 12); 67 + r |= (1 << 5); /* Autoneg complete. */ 68 + r |= (1 << 3); /* Autoneg able. */ 69 + r |= (1 << 2); /* link. */ 70 + r |= (1 << 1); /* link. */ 71 + break; 72 + case 5: 73 + /* Link partner ability. 74 + We are kind; always agree with whatever best mode 75 + the guest advertises. */ 76 + r = 1 << 14; /* Success. */ 77 + /* Copy advertised modes. */ 78 + r |= phy->regs[4] & (15 << 5); 79 + /* Autoneg support. */ 80 + r |= 1; 81 + break; 82 + case 17: 83 + /* Marvel PHY on many xilinx boards. */ 84 + r = 0x8000; /* 1000Mb */ 85 + break; 86 + case 18: 87 + { 88 + /* Diagnostics reg. */ 89 + int duplex = 0; 90 + int speed_100 = 0; 91 + 92 + if (!phy->link) { 93 + break; 94 + } 95 + 96 + /* Are we advertising 100 half or 100 duplex ? */ 97 + speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); 98 + speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); 99 + 100 + /* Are we advertising 10 duplex or 100 duplex ? */ 101 + duplex = !!(phy->regs[4] & ADVERTISE_100FULL); 102 + duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); 103 + r = (speed_100 << 10) | (duplex << 11); 104 + } 105 + break; 106 + 107 + default: 108 + r = phy->regs[regnum]; 109 + break; 110 + } 111 + DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum)); 112 + return r; 113 + } 114 + 115 + static void 116 + tdk_write(struct PHY *phy, unsigned int req, unsigned int data) 117 + { 118 + int regnum; 119 + 120 + regnum = req & 0x1f; 121 + DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data)); 122 + switch (regnum) { 123 + default: 124 + phy->regs[regnum] = data; 125 + break; 126 + } 127 + } 128 + 129 + static void 130 + tdk_init(struct PHY *phy) 131 + { 132 + phy->regs[0] = 0x3100; 133 + /* PHY Id. */ 134 + phy->regs[2] = 0x0300; 135 + phy->regs[3] = 0xe400; 136 + /* Autonegotiation advertisement reg. */ 137 + phy->regs[4] = 0x01E1; 138 + phy->link = 1; 139 + 140 + phy->read = tdk_read; 141 + phy->write = tdk_write; 142 + } 143 + 144 + struct MDIOBus { 145 + /* bus. */ 146 + int mdc; 147 + int mdio; 148 + 149 + /* decoder. */ 150 + enum { 151 + PREAMBLE, 152 + SOF, 153 + OPC, 154 + ADDR, 155 + REQ, 156 + TURNAROUND, 157 + DATA 158 + } state; 159 + unsigned int drive; 160 + 161 + unsigned int cnt; 162 + unsigned int addr; 163 + unsigned int opc; 164 + unsigned int req; 165 + unsigned int data; 166 + 167 + struct PHY *devs[32]; 168 + }; 169 + 170 + static void 171 + mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr) 172 + { 173 + bus->devs[addr & 0x1f] = phy; 174 + } 175 + 176 + #ifdef USE_THIS_DEAD_CODE 177 + static void 178 + mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr) 179 + { 180 + bus->devs[addr & 0x1f] = NULL; 181 + } 182 + #endif 183 + 184 + static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr, 185 + unsigned int reg) 186 + { 187 + struct PHY *phy; 188 + uint16_t data; 189 + 190 + phy = bus->devs[addr]; 191 + if (phy && phy->read) { 192 + data = phy->read(phy, reg); 193 + } else { 194 + data = 0xffff; 195 + } 196 + DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data)); 197 + return data; 198 + } 199 + 200 + static void mdio_write_req(struct MDIOBus *bus, unsigned int addr, 201 + unsigned int reg, uint16_t data) 202 + { 203 + struct PHY *phy; 204 + 205 + DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data)); 206 + phy = bus->devs[addr]; 207 + if (phy && phy->write) { 208 + phy->write(phy, reg, data); 209 + } 210 + } 211 + 212 + #define DENET(x) 213 + 214 + #define R_RAF (0x000 / 4) 215 + enum { 216 + RAF_MCAST_REJ = (1 << 1), 217 + RAF_BCAST_REJ = (1 << 2), 218 + RAF_EMCF_EN = (1 << 12), 219 + RAF_NEWFUNC_EN = (1 << 11) 220 + }; 221 + 222 + #define R_IS (0x00C / 4) 223 + enum { 224 + IS_HARD_ACCESS_COMPLETE = 1, 225 + IS_AUTONEG = (1 << 1), 226 + IS_RX_COMPLETE = (1 << 2), 227 + IS_RX_REJECT = (1 << 3), 228 + IS_TX_COMPLETE = (1 << 5), 229 + IS_RX_DCM_LOCK = (1 << 6), 230 + IS_MGM_RDY = (1 << 7), 231 + IS_PHY_RST_DONE = (1 << 8), 232 + }; 233 + 234 + #define R_IP (0x010 / 4) 235 + #define R_IE (0x014 / 4) 236 + #define R_UAWL (0x020 / 4) 237 + #define R_UAWU (0x024 / 4) 238 + #define R_PPST (0x030 / 4) 239 + enum { 240 + PPST_LINKSTATUS = (1 << 0), 241 + PPST_PHY_LINKSTATUS = (1 << 7), 242 + }; 243 + 244 + #define R_STATS_RX_BYTESL (0x200 / 4) 245 + #define R_STATS_RX_BYTESH (0x204 / 4) 246 + #define R_STATS_TX_BYTESL (0x208 / 4) 247 + #define R_STATS_TX_BYTESH (0x20C / 4) 248 + #define R_STATS_RXL (0x290 / 4) 249 + #define R_STATS_RXH (0x294 / 4) 250 + #define R_STATS_RX_BCASTL (0x2a0 / 4) 251 + #define R_STATS_RX_BCASTH (0x2a4 / 4) 252 + #define R_STATS_RX_MCASTL (0x2a8 / 4) 253 + #define R_STATS_RX_MCASTH (0x2ac / 4) 254 + 255 + #define R_RCW0 (0x400 / 4) 256 + #define R_RCW1 (0x404 / 4) 257 + enum { 258 + RCW1_VLAN = (1 << 27), 259 + RCW1_RX = (1 << 28), 260 + RCW1_FCS = (1 << 29), 261 + RCW1_JUM = (1 << 30), 262 + RCW1_RST = (1 << 31), 263 + }; 264 + 265 + #define R_TC (0x408 / 4) 266 + enum { 267 + TC_VLAN = (1 << 27), 268 + TC_TX = (1 << 28), 269 + TC_FCS = (1 << 29), 270 + TC_JUM = (1 << 30), 271 + TC_RST = (1 << 31), 272 + }; 273 + 274 + #define R_EMMC (0x410 / 4) 275 + enum { 276 + EMMC_LINKSPEED_10MB = (0 << 30), 277 + EMMC_LINKSPEED_100MB = (1 << 30), 278 + EMMC_LINKSPEED_1000MB = (2 << 30), 279 + }; 280 + 281 + #define R_PHYC (0x414 / 4) 282 + 283 + #define R_MC (0x500 / 4) 284 + #define MC_EN (1 << 6) 285 + 286 + #define R_MCR (0x504 / 4) 287 + #define R_MWD (0x508 / 4) 288 + #define R_MRD (0x50c / 4) 289 + #define R_MIS (0x600 / 4) 290 + #define R_MIP (0x620 / 4) 291 + #define R_MIE (0x640 / 4) 292 + #define R_MIC (0x640 / 4) 293 + 294 + #define R_UAW0 (0x700 / 4) 295 + #define R_UAW1 (0x704 / 4) 296 + #define R_FMI (0x708 / 4) 297 + #define R_AF0 (0x710 / 4) 298 + #define R_AF1 (0x714 / 4) 299 + #define R_MAX (0x34 / 4) 300 + 301 + /* Indirect registers. */ 302 + struct TEMAC { 303 + struct MDIOBus mdio_bus; 304 + struct PHY phy; 305 + 306 + void *parent; 307 + }; 308 + 309 + struct XilinxAXIEnet { 310 + SysBusDevice busdev; 311 + qemu_irq irq; 312 + void *dmach; 313 + NICState *nic; 314 + NICConf conf; 315 + 316 + 317 + uint32_t c_rxmem; 318 + uint32_t c_txmem; 319 + uint32_t c_phyaddr; 320 + 321 + struct TEMAC TEMAC; 322 + 323 + /* MII regs. */ 324 + union { 325 + uint32_t regs[4]; 326 + struct { 327 + uint32_t mc; 328 + uint32_t mcr; 329 + uint32_t mwd; 330 + uint32_t mrd; 331 + }; 332 + } mii; 333 + 334 + struct { 335 + uint64_t rx_bytes; 336 + uint64_t tx_bytes; 337 + 338 + uint64_t rx; 339 + uint64_t rx_bcast; 340 + uint64_t rx_mcast; 341 + } stats; 342 + 343 + /* Receive configuration words. */ 344 + uint32_t rcw[2]; 345 + /* Transmit config. */ 346 + uint32_t tc; 347 + uint32_t emmc; 348 + uint32_t phyc; 349 + 350 + /* Unicast Address Word. */ 351 + uint32_t uaw[2]; 352 + /* Unicast address filter used with extended mcast. */ 353 + uint32_t ext_uaw[2]; 354 + uint32_t fmi; 355 + 356 + uint32_t regs[R_MAX]; 357 + 358 + /* Multicast filter addrs. */ 359 + uint32_t maddr[4][2]; 360 + /* 32K x 1 lookup filter. */ 361 + uint32_t ext_mtable[1024]; 362 + 363 + 364 + uint8_t *rxmem; 365 + }; 366 + 367 + static void axienet_rx_reset(struct XilinxAXIEnet *s) 368 + { 369 + s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN; 370 + } 371 + 372 + static void axienet_tx_reset(struct XilinxAXIEnet *s) 373 + { 374 + s->tc = TC_JUM | TC_TX | TC_VLAN; 375 + } 376 + 377 + static inline int axienet_rx_resetting(struct XilinxAXIEnet *s) 378 + { 379 + return s->rcw[1] & RCW1_RST; 380 + } 381 + 382 + static inline int axienet_rx_enabled(struct XilinxAXIEnet *s) 383 + { 384 + return s->rcw[1] & RCW1_RX; 385 + } 386 + 387 + static inline int axienet_extmcf_enabled(struct XilinxAXIEnet *s) 388 + { 389 + return !!(s->regs[R_RAF] & RAF_EMCF_EN); 390 + } 391 + 392 + static inline int axienet_newfunc_enabled(struct XilinxAXIEnet *s) 393 + { 394 + return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN); 395 + } 396 + 397 + static void axienet_reset(struct XilinxAXIEnet *s) 398 + { 399 + axienet_rx_reset(s); 400 + axienet_tx_reset(s); 401 + 402 + s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS; 403 + s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE; 404 + 405 + s->emmc = EMMC_LINKSPEED_100MB; 406 + } 407 + 408 + static void enet_update_irq(struct XilinxAXIEnet *s) 409 + { 410 + s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE]; 411 + qemu_set_irq(s->irq, !!s->regs[R_IP]); 412 + } 413 + 414 + static uint32_t enet_readl(void *opaque, target_phys_addr_t addr) 415 + { 416 + struct XilinxAXIEnet *s = opaque; 417 + uint32_t r = 0; 418 + addr >>= 2; 419 + 420 + switch (addr) { 421 + case R_RCW0: 422 + case R_RCW1: 423 + r = s->rcw[addr & 1]; 424 + break; 425 + 426 + case R_TC: 427 + r = s->tc; 428 + break; 429 + 430 + case R_EMMC: 431 + r = s->emmc; 432 + break; 433 + 434 + case R_PHYC: 435 + r = s->phyc; 436 + break; 437 + 438 + case R_MCR: 439 + r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready. */ 440 + break; 441 + 442 + case R_STATS_RX_BYTESL: 443 + case R_STATS_RX_BYTESH: 444 + r = s->stats.rx_bytes >> (32 * (addr & 1)); 445 + break; 446 + 447 + case R_STATS_TX_BYTESL: 448 + case R_STATS_TX_BYTESH: 449 + r = s->stats.tx_bytes >> (32 * (addr & 1)); 450 + break; 451 + 452 + case R_STATS_RXL: 453 + case R_STATS_RXH: 454 + r = s->stats.rx >> (32 * (addr & 1)); 455 + break; 456 + case R_STATS_RX_BCASTL: 457 + case R_STATS_RX_BCASTH: 458 + r = s->stats.rx_bcast >> (32 * (addr & 1)); 459 + break; 460 + case R_STATS_RX_MCASTL: 461 + case R_STATS_RX_MCASTH: 462 + r = s->stats.rx_mcast >> (32 * (addr & 1)); 463 + break; 464 + 465 + case R_MC: 466 + case R_MWD: 467 + case R_MRD: 468 + r = s->mii.regs[addr & 3]; 469 + break; 470 + 471 + case R_UAW0: 472 + case R_UAW1: 473 + r = s->uaw[addr & 1]; 474 + break; 475 + 476 + case R_UAWU: 477 + case R_UAWL: 478 + r = s->ext_uaw[addr & 1]; 479 + break; 480 + 481 + case R_FMI: 482 + r = s->fmi; 483 + break; 484 + 485 + case R_AF0: 486 + case R_AF1: 487 + r = s->maddr[s->fmi & 3][addr & 1]; 488 + break; 489 + 490 + case 0x8000 ... 0x83ff: 491 + r = s->ext_mtable[addr - 0x8000]; 492 + break; 493 + 494 + default: 495 + if (addr < ARRAY_SIZE(s->regs)) { 496 + r = s->regs[addr]; 497 + } 498 + DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n", 499 + __func__, addr * 4, r)); 500 + break; 501 + } 502 + return r; 503 + } 504 + 505 + static void 506 + enet_writel(void *opaque, target_phys_addr_t addr, uint32_t value) 507 + { 508 + struct XilinxAXIEnet *s = opaque; 509 + struct TEMAC *t = &s->TEMAC; 510 + 511 + addr >>= 2; 512 + switch (addr) { 513 + case R_RCW0: 514 + case R_RCW1: 515 + s->rcw[addr & 1] = value; 516 + if ((addr & 1) && value & RCW1_RST) { 517 + axienet_rx_reset(s); 518 + } 519 + break; 520 + 521 + case R_TC: 522 + s->tc = value; 523 + if (value & TC_RST) { 524 + axienet_tx_reset(s); 525 + } 526 + break; 527 + 528 + case R_EMMC: 529 + s->emmc = value; 530 + break; 531 + 532 + case R_PHYC: 533 + s->phyc = value; 534 + break; 535 + 536 + case R_MC: 537 + value &= ((1 < 7) - 1); 538 + 539 + /* Enable the MII. */ 540 + if (value & MC_EN) { 541 + unsigned int miiclkdiv = value & ((1 << 6) - 1); 542 + if (!miiclkdiv) { 543 + qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n"); 544 + } 545 + } 546 + s->mii.mc = value; 547 + break; 548 + 549 + case R_MCR: { 550 + unsigned int phyaddr = (value >> 24) & 0x1f; 551 + unsigned int regaddr = (value >> 16) & 0x1f; 552 + unsigned int op = (value >> 14) & 3; 553 + unsigned int initiate = (value >> 11) & 1; 554 + 555 + if (initiate) { 556 + if (op == 1) { 557 + mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd); 558 + } else if (op == 2) { 559 + s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr); 560 + } else { 561 + qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op); 562 + } 563 + } 564 + s->mii.mcr = value; 565 + break; 566 + } 567 + 568 + case R_MWD: 569 + case R_MRD: 570 + s->mii.regs[addr & 3] = value; 571 + break; 572 + 573 + 574 + case R_UAW0: 575 + case R_UAW1: 576 + s->uaw[addr & 1] = value; 577 + break; 578 + 579 + case R_UAWL: 580 + case R_UAWU: 581 + s->ext_uaw[addr & 1] = value; 582 + break; 583 + 584 + case R_FMI: 585 + s->fmi = value; 586 + break; 587 + 588 + case R_AF0: 589 + case R_AF1: 590 + s->maddr[s->fmi & 3][addr & 1] = value; 591 + break; 592 + 593 + case 0x8000 ... 0x83ff: 594 + s->ext_mtable[addr - 0x8000] = value; 595 + break; 596 + 597 + default: 598 + DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n", 599 + __func__, addr * 4, value)); 600 + if (addr < ARRAY_SIZE(s->regs)) { 601 + s->regs[addr] = value; 602 + } 603 + break; 604 + } 605 + enet_update_irq(s); 606 + } 607 + 608 + static CPUReadMemoryFunc * const enet_read[] = { 609 + &enet_readl, 610 + &enet_readl, 611 + &enet_readl, 612 + }; 613 + 614 + static CPUWriteMemoryFunc * const enet_write[] = { 615 + &enet_writel, 616 + &enet_writel, 617 + &enet_writel, 618 + }; 619 + 620 + static int eth_can_rx(VLANClientState *nc) 621 + { 622 + struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque; 623 + 624 + /* RX enabled? */ 625 + return !axienet_rx_resetting(s) && axienet_rx_enabled(s); 626 + } 627 + 628 + static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1) 629 + { 630 + int match = 1; 631 + 632 + if (memcmp(buf, &f0, 4)) { 633 + match = 0; 634 + } 635 + 636 + if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) { 637 + match = 0; 638 + } 639 + 640 + return match; 641 + } 642 + 643 + static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size) 644 + { 645 + struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque; 646 + static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 647 + 0xff, 0xff, 0xff}; 648 + static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52}; 649 + uint32_t app[6] = {0}; 650 + int promisc = s->fmi & (1 << 31); 651 + int unicast, broadcast, multicast, ip_multicast = 0; 652 + uint32_t csum32; 653 + uint16_t csum16; 654 + int i; 655 + 656 + s = s; 657 + DENET(qemu_log("%s: %zd bytes\n", __func__, size)); 658 + 659 + unicast = ~buf[0] & 0x1; 660 + broadcast = memcmp(buf, sa_bcast, 6) == 0; 661 + multicast = !unicast && !broadcast; 662 + if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) { 663 + ip_multicast = 1; 664 + } 665 + 666 + /* Jumbo or vlan sizes ? */ 667 + if (!(s->rcw[1] & RCW1_JUM)) { 668 + if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) { 669 + return size; 670 + } 671 + } 672 + 673 + /* Basic Address filters. If you want to use the extended filters 674 + you'll generally have to place the ethernet mac into promiscuous mode 675 + to avoid the basic filtering from dropping most frames. */ 676 + if (!promisc) { 677 + if (unicast) { 678 + if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) { 679 + return size; 680 + } 681 + } else { 682 + if (broadcast) { 683 + /* Broadcast. */ 684 + if (s->regs[R_RAF] & RAF_BCAST_REJ) { 685 + return size; 686 + } 687 + } else { 688 + int drop = 1; 689 + 690 + /* Multicast. */ 691 + if (s->regs[R_RAF] & RAF_MCAST_REJ) { 692 + return size; 693 + } 694 + 695 + for (i = 0; i < 4; i++) { 696 + if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) { 697 + drop = 0; 698 + break; 699 + } 700 + } 701 + 702 + if (drop) { 703 + return size; 704 + } 705 + } 706 + } 707 + } 708 + 709 + /* Extended mcast filtering enabled? */ 710 + if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) { 711 + if (unicast) { 712 + if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) { 713 + return size; 714 + } 715 + } else { 716 + if (broadcast) { 717 + /* Broadcast. ??? */ 718 + if (s->regs[R_RAF] & RAF_BCAST_REJ) { 719 + return size; 720 + } 721 + } else { 722 + int idx, bit; 723 + 724 + /* Multicast. */ 725 + if (!memcmp(buf, sa_ipmcast, 3)) { 726 + return size; 727 + } 728 + 729 + idx = (buf[4] & 0x7f) << 8; 730 + idx |= buf[5]; 731 + 732 + bit = 1 << (idx & 0x1f); 733 + idx >>= 5; 734 + 735 + if (!(s->ext_mtable[idx] & bit)) { 736 + return size; 737 + } 738 + } 739 + } 740 + } 741 + 742 + if (size < 12) { 743 + s->regs[R_IS] |= IS_RX_REJECT; 744 + enet_update_irq(s); 745 + return -1; 746 + } 747 + 748 + if (size > (s->c_rxmem - 4)) { 749 + size = s->c_rxmem - 4; 750 + } 751 + 752 + memcpy(s->rxmem, buf, size); 753 + memset(s->rxmem + size, 0, 4); /* Clear the FCS. */ 754 + 755 + if (s->rcw[1] & RCW1_FCS) { 756 + size += 4; /* fcs is inband. */ 757 + } 758 + 759 + app[0] = 5 << 28; 760 + csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14); 761 + /* Fold it once. */ 762 + csum32 = (csum32 & 0xffff) + (csum32 >> 16); 763 + /* And twice to get rid of possible carries. */ 764 + csum16 = (csum32 & 0xffff) + (csum32 >> 16); 765 + app[3] = csum16; 766 + app[4] = size & 0xffff; 767 + 768 + s->stats.rx_bytes += size; 769 + s->stats.rx++; 770 + if (multicast) { 771 + s->stats.rx_mcast++; 772 + app[2] |= 1 | (ip_multicast << 1); 773 + } else if (broadcast) { 774 + s->stats.rx_bcast++; 775 + app[2] |= 1 << 3; 776 + } 777 + 778 + /* Good frame. */ 779 + app[2] |= 1 << 6; 780 + 781 + xlx_dma_push_to_dma(s->dmach, (void *)s->rxmem, size, app); 782 + 783 + s->regs[R_IS] |= IS_RX_COMPLETE; 784 + enet_update_irq(s); 785 + return size; 786 + } 787 + 788 + static void eth_cleanup(VLANClientState *nc) 789 + { 790 + /* FIXME. */ 791 + struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque; 792 + qemu_free(s->rxmem); 793 + qemu_free(s); 794 + } 795 + 796 + static void 797 + axienet_stream_push(void *opaque, uint8_t *buf, size_t size, uint32_t *hdr) 798 + { 799 + struct XilinxAXIEnet *s = opaque; 800 + 801 + /* TX enable ? */ 802 + if (!(s->tc & TC_TX)) { 803 + return; 804 + } 805 + 806 + /* Jumbo or vlan sizes ? */ 807 + if (!(s->tc & TC_JUM)) { 808 + if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) { 809 + return; 810 + } 811 + } 812 + 813 + if (hdr[0] & 1) { 814 + unsigned int start_off = hdr[1] >> 16; 815 + unsigned int write_off = hdr[1] & 0xffff; 816 + uint32_t tmp_csum; 817 + uint16_t csum; 818 + 819 + tmp_csum = net_checksum_add(size - start_off, 820 + (uint8_t *)buf + start_off); 821 + /* Accumulate the seed. */ 822 + tmp_csum += hdr[2] & 0xffff; 823 + 824 + /* Fold the 32bit partial checksum. */ 825 + csum = net_checksum_finish(tmp_csum); 826 + 827 + /* Writeback. */ 828 + buf[write_off] = csum >> 8; 829 + buf[write_off + 1] = csum & 0xff; 830 + } 831 + 832 + qemu_send_packet(&s->nic->nc, buf, size); 833 + 834 + s->stats.tx_bytes += size; 835 + s->regs[R_IS] |= IS_TX_COMPLETE; 836 + enet_update_irq(s); 837 + } 838 + 839 + static NetClientInfo net_xilinx_enet_info = { 840 + .type = NET_CLIENT_TYPE_NIC, 841 + .size = sizeof(NICState), 842 + .can_receive = eth_can_rx, 843 + .receive = eth_rx, 844 + .cleanup = eth_cleanup, 845 + }; 846 + 847 + static int xilinx_enet_init(SysBusDevice *dev) 848 + { 849 + struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), dev); 850 + int enet_regs; 851 + 852 + sysbus_init_irq(dev, &s->irq); 853 + 854 + if (!s->dmach) { 855 + hw_error("Unconnected Xilinx Ethernet MAC.\n"); 856 + } 857 + 858 + xlx_dma_connect_client(s->dmach, s, axienet_stream_push); 859 + 860 + enet_regs = cpu_register_io_memory(enet_read, enet_write, s, 861 + DEVICE_LITTLE_ENDIAN); 862 + sysbus_init_mmio(dev, 0x40000, enet_regs); 863 + 864 + qemu_macaddr_default_if_unset(&s->conf.macaddr); 865 + s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf, 866 + dev->qdev.info->name, dev->qdev.id, s); 867 + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); 868 + 869 + tdk_init(&s->TEMAC.phy); 870 + mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr); 871 + 872 + s->TEMAC.parent = s; 873 + 874 + s->rxmem = qemu_malloc(s->c_rxmem); 875 + axienet_reset(s); 876 + 877 + return 0; 878 + } 879 + 880 + static SysBusDeviceInfo xilinx_enet_info = { 881 + .init = xilinx_enet_init, 882 + .qdev.name = "xilinx,axienet", 883 + .qdev.size = sizeof(struct XilinxAXIEnet), 884 + .qdev.props = (Property[]) { 885 + DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7), 886 + DEFINE_PROP_UINT32("c_rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000), 887 + DEFINE_PROP_UINT32("c_txmem", struct XilinxAXIEnet, c_txmem, 0x1000), 888 + DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach), 889 + DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf), 890 + DEFINE_PROP_END_OF_LIST(), 891 + } 892 + }; 893 + static void xilinx_enet_register(void) 894 + { 895 + sysbus_register_withprop(&xilinx_enet_info); 896 + } 897 + 898 + device_init(xilinx_enet_register)