xilinx_axidma.c (18874B)
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 "qemu/osdep.h" 26#include "hw/sysbus.h" 27#include "qapi/error.h" 28#include "qemu/timer.h" 29#include "hw/hw.h" 30#include "hw/irq.h" 31#include "hw/ptimer.h" 32#include "hw/qdev-properties.h" 33#include "qemu/log.h" 34#include "qemu/module.h" 35 36#include "sysemu/dma.h" 37#include "hw/stream.h" 38#include "qom/object.h" 39 40#define D(x) 41 42#define TYPE_XILINX_AXI_DMA "xlnx.axi-dma" 43#define TYPE_XILINX_AXI_DMA_DATA_STREAM "xilinx-axi-dma-data-stream" 44#define TYPE_XILINX_AXI_DMA_CONTROL_STREAM "xilinx-axi-dma-control-stream" 45 46OBJECT_DECLARE_SIMPLE_TYPE(XilinxAXIDMA, XILINX_AXI_DMA) 47 48typedef struct XilinxAXIDMAStreamSink XilinxAXIDMAStreamSink; 49DECLARE_INSTANCE_CHECKER(XilinxAXIDMAStreamSink, XILINX_AXI_DMA_DATA_STREAM, 50 TYPE_XILINX_AXI_DMA_DATA_STREAM) 51 52DECLARE_INSTANCE_CHECKER(XilinxAXIDMAStreamSink, XILINX_AXI_DMA_CONTROL_STREAM, 53 TYPE_XILINX_AXI_DMA_CONTROL_STREAM) 54 55#define R_DMACR (0x00 / 4) 56#define R_DMASR (0x04 / 4) 57#define R_CURDESC (0x08 / 4) 58#define R_TAILDESC (0x10 / 4) 59#define R_MAX (0x30 / 4) 60 61#define CONTROL_PAYLOAD_WORDS 5 62#define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t))) 63 64 65enum { 66 DMACR_RUNSTOP = 1, 67 DMACR_TAILPTR_MODE = 2, 68 DMACR_RESET = 4 69}; 70 71enum { 72 DMASR_HALTED = 1, 73 DMASR_IDLE = 2, 74 DMASR_IOC_IRQ = 1 << 12, 75 DMASR_DLY_IRQ = 1 << 13, 76 77 DMASR_IRQ_MASK = 7 << 12 78}; 79 80struct SDesc { 81 uint64_t nxtdesc; 82 uint64_t buffer_address; 83 uint64_t reserved; 84 uint32_t control; 85 uint32_t status; 86 uint8_t app[CONTROL_PAYLOAD_SIZE]; 87}; 88 89enum { 90 SDESC_CTRL_EOF = (1 << 26), 91 SDESC_CTRL_SOF = (1 << 27), 92 93 SDESC_CTRL_LEN_MASK = (1 << 23) - 1 94}; 95 96enum { 97 SDESC_STATUS_EOF = (1 << 26), 98 SDESC_STATUS_SOF_BIT = 27, 99 SDESC_STATUS_SOF = (1 << SDESC_STATUS_SOF_BIT), 100 SDESC_STATUS_COMPLETE = (1 << 31) 101}; 102 103struct Stream { 104 struct XilinxAXIDMA *dma; 105 ptimer_state *ptimer; 106 qemu_irq irq; 107 108 int nr; 109 110 bool sof; 111 struct SDesc desc; 112 unsigned int complete_cnt; 113 uint32_t regs[R_MAX]; 114 uint8_t app[20]; 115 unsigned char txbuf[16 * 1024]; 116}; 117 118struct XilinxAXIDMAStreamSink { 119 Object parent; 120 121 struct XilinxAXIDMA *dma; 122}; 123 124struct XilinxAXIDMA { 125 SysBusDevice busdev; 126 MemoryRegion iomem; 127 MemoryRegion *dma_mr; 128 AddressSpace as; 129 130 uint32_t freqhz; 131 StreamSink *tx_data_dev; 132 StreamSink *tx_control_dev; 133 XilinxAXIDMAStreamSink rx_data_dev; 134 XilinxAXIDMAStreamSink rx_control_dev; 135 136 struct Stream streams[2]; 137 138 StreamCanPushNotifyFn notify; 139 void *notify_opaque; 140}; 141 142/* 143 * Helper calls to extract info from descriptors and other trivial 144 * state from regs. 145 */ 146static inline int stream_desc_sof(struct SDesc *d) 147{ 148 return d->control & SDESC_CTRL_SOF; 149} 150 151static inline int stream_desc_eof(struct SDesc *d) 152{ 153 return d->control & SDESC_CTRL_EOF; 154} 155 156static inline int stream_resetting(struct Stream *s) 157{ 158 return !!(s->regs[R_DMACR] & DMACR_RESET); 159} 160 161static inline int stream_running(struct Stream *s) 162{ 163 return s->regs[R_DMACR] & DMACR_RUNSTOP; 164} 165 166static inline int stream_idle(struct Stream *s) 167{ 168 return !!(s->regs[R_DMASR] & DMASR_IDLE); 169} 170 171static void stream_reset(struct Stream *s) 172{ 173 s->regs[R_DMASR] = DMASR_HALTED; /* starts up halted. */ 174 s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold. */ 175 s->sof = true; 176} 177 178/* Map an offset addr into a channel index. */ 179static inline int streamid_from_addr(hwaddr addr) 180{ 181 int sid; 182 183 sid = addr / (0x30); 184 sid &= 1; 185 return sid; 186} 187 188static void stream_desc_load(struct Stream *s, hwaddr addr) 189{ 190 struct SDesc *d = &s->desc; 191 192 address_space_read(&s->dma->as, addr, MEMTXATTRS_UNSPECIFIED, d, sizeof *d); 193 194 /* Convert from LE into host endianness. */ 195 d->buffer_address = le64_to_cpu(d->buffer_address); 196 d->nxtdesc = le64_to_cpu(d->nxtdesc); 197 d->control = le32_to_cpu(d->control); 198 d->status = le32_to_cpu(d->status); 199} 200 201static void stream_desc_store(struct Stream *s, hwaddr addr) 202{ 203 struct SDesc *d = &s->desc; 204 205 /* Convert from host endianness into LE. */ 206 d->buffer_address = cpu_to_le64(d->buffer_address); 207 d->nxtdesc = cpu_to_le64(d->nxtdesc); 208 d->control = cpu_to_le32(d->control); 209 d->status = cpu_to_le32(d->status); 210 address_space_write(&s->dma->as, addr, MEMTXATTRS_UNSPECIFIED, 211 d, sizeof *d); 212} 213 214static void stream_update_irq(struct Stream *s) 215{ 216 unsigned int pending, mask, irq; 217 218 pending = s->regs[R_DMASR] & DMASR_IRQ_MASK; 219 mask = s->regs[R_DMACR] & DMASR_IRQ_MASK; 220 221 irq = pending & mask; 222 223 qemu_set_irq(s->irq, !!irq); 224} 225 226static void stream_reload_complete_cnt(struct Stream *s) 227{ 228 unsigned int comp_th; 229 comp_th = (s->regs[R_DMACR] >> 16) & 0xff; 230 s->complete_cnt = comp_th; 231} 232 233static void timer_hit(void *opaque) 234{ 235 struct Stream *s = opaque; 236 237 stream_reload_complete_cnt(s); 238 s->regs[R_DMASR] |= DMASR_DLY_IRQ; 239 stream_update_irq(s); 240} 241 242static void stream_complete(struct Stream *s) 243{ 244 unsigned int comp_delay; 245 246 /* Start the delayed timer. */ 247 ptimer_transaction_begin(s->ptimer); 248 comp_delay = s->regs[R_DMACR] >> 24; 249 if (comp_delay) { 250 ptimer_stop(s->ptimer); 251 ptimer_set_count(s->ptimer, comp_delay); 252 ptimer_run(s->ptimer, 1); 253 } 254 255 s->complete_cnt--; 256 if (s->complete_cnt == 0) { 257 /* Raise the IOC irq. */ 258 s->regs[R_DMASR] |= DMASR_IOC_IRQ; 259 stream_reload_complete_cnt(s); 260 } 261 ptimer_transaction_commit(s->ptimer); 262} 263 264static void stream_process_mem2s(struct Stream *s, StreamSink *tx_data_dev, 265 StreamSink *tx_control_dev) 266{ 267 uint32_t prev_d; 268 uint32_t txlen; 269 uint64_t addr; 270 bool eop; 271 272 if (!stream_running(s) || stream_idle(s)) { 273 return; 274 } 275 276 while (1) { 277 stream_desc_load(s, s->regs[R_CURDESC]); 278 279 if (s->desc.status & SDESC_STATUS_COMPLETE) { 280 s->regs[R_DMASR] |= DMASR_HALTED; 281 break; 282 } 283 284 if (stream_desc_sof(&s->desc)) { 285 stream_push(tx_control_dev, s->desc.app, sizeof(s->desc.app), true); 286 } 287 288 txlen = s->desc.control & SDESC_CTRL_LEN_MASK; 289 290 eop = stream_desc_eof(&s->desc); 291 addr = s->desc.buffer_address; 292 while (txlen) { 293 unsigned int len; 294 295 len = txlen > sizeof s->txbuf ? sizeof s->txbuf : txlen; 296 address_space_read(&s->dma->as, addr, 297 MEMTXATTRS_UNSPECIFIED, 298 s->txbuf, len); 299 stream_push(tx_data_dev, s->txbuf, len, eop && len == txlen); 300 txlen -= len; 301 addr += len; 302 } 303 304 if (eop) { 305 stream_complete(s); 306 } 307 308 /* Update the descriptor. */ 309 s->desc.status = txlen | SDESC_STATUS_COMPLETE; 310 stream_desc_store(s, s->regs[R_CURDESC]); 311 312 /* Advance. */ 313 prev_d = s->regs[R_CURDESC]; 314 s->regs[R_CURDESC] = s->desc.nxtdesc; 315 if (prev_d == s->regs[R_TAILDESC]) { 316 s->regs[R_DMASR] |= DMASR_IDLE; 317 break; 318 } 319 } 320} 321 322static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf, 323 size_t len, bool eop) 324{ 325 uint32_t prev_d; 326 unsigned int rxlen; 327 size_t pos = 0; 328 329 if (!stream_running(s) || stream_idle(s)) { 330 return 0; 331 } 332 333 while (len) { 334 stream_desc_load(s, s->regs[R_CURDESC]); 335 336 if (s->desc.status & SDESC_STATUS_COMPLETE) { 337 s->regs[R_DMASR] |= DMASR_HALTED; 338 break; 339 } 340 341 rxlen = s->desc.control & SDESC_CTRL_LEN_MASK; 342 if (rxlen > len) { 343 /* It fits. */ 344 rxlen = len; 345 } 346 347 address_space_write(&s->dma->as, s->desc.buffer_address, 348 MEMTXATTRS_UNSPECIFIED, buf + pos, rxlen); 349 len -= rxlen; 350 pos += rxlen; 351 352 /* Update the descriptor. */ 353 if (eop) { 354 stream_complete(s); 355 memcpy(s->desc.app, s->app, sizeof(s->desc.app)); 356 s->desc.status |= SDESC_STATUS_EOF; 357 } 358 359 s->desc.status |= s->sof << SDESC_STATUS_SOF_BIT; 360 s->desc.status |= SDESC_STATUS_COMPLETE; 361 stream_desc_store(s, s->regs[R_CURDESC]); 362 s->sof = eop; 363 364 /* Advance. */ 365 prev_d = s->regs[R_CURDESC]; 366 s->regs[R_CURDESC] = s->desc.nxtdesc; 367 if (prev_d == s->regs[R_TAILDESC]) { 368 s->regs[R_DMASR] |= DMASR_IDLE; 369 break; 370 } 371 } 372 373 return pos; 374} 375 376static void xilinx_axidma_reset(DeviceState *dev) 377{ 378 int i; 379 XilinxAXIDMA *s = XILINX_AXI_DMA(dev); 380 381 for (i = 0; i < 2; i++) { 382 stream_reset(&s->streams[i]); 383 } 384} 385 386static size_t 387xilinx_axidma_control_stream_push(StreamSink *obj, unsigned char *buf, 388 size_t len, bool eop) 389{ 390 XilinxAXIDMAStreamSink *cs = XILINX_AXI_DMA_CONTROL_STREAM(obj); 391 struct Stream *s = &cs->dma->streams[1]; 392 393 if (len != CONTROL_PAYLOAD_SIZE) { 394 hw_error("AXI DMA requires %d byte control stream payload\n", 395 (int)CONTROL_PAYLOAD_SIZE); 396 } 397 398 memcpy(s->app, buf, len); 399 return len; 400} 401 402static bool 403xilinx_axidma_data_stream_can_push(StreamSink *obj, 404 StreamCanPushNotifyFn notify, 405 void *notify_opaque) 406{ 407 XilinxAXIDMAStreamSink *ds = XILINX_AXI_DMA_DATA_STREAM(obj); 408 struct Stream *s = &ds->dma->streams[1]; 409 410 if (!stream_running(s) || stream_idle(s)) { 411 ds->dma->notify = notify; 412 ds->dma->notify_opaque = notify_opaque; 413 return false; 414 } 415 416 return true; 417} 418 419static size_t 420xilinx_axidma_data_stream_push(StreamSink *obj, unsigned char *buf, size_t len, 421 bool eop) 422{ 423 XilinxAXIDMAStreamSink *ds = XILINX_AXI_DMA_DATA_STREAM(obj); 424 struct Stream *s = &ds->dma->streams[1]; 425 size_t ret; 426 427 ret = stream_process_s2mem(s, buf, len, eop); 428 stream_update_irq(s); 429 return ret; 430} 431 432static uint64_t axidma_read(void *opaque, hwaddr addr, 433 unsigned size) 434{ 435 XilinxAXIDMA *d = opaque; 436 struct Stream *s; 437 uint32_t r = 0; 438 int sid; 439 440 sid = streamid_from_addr(addr); 441 s = &d->streams[sid]; 442 443 addr = addr % 0x30; 444 addr >>= 2; 445 switch (addr) { 446 case R_DMACR: 447 /* Simulate one cycles reset delay. */ 448 s->regs[addr] &= ~DMACR_RESET; 449 r = s->regs[addr]; 450 break; 451 case R_DMASR: 452 s->regs[addr] &= 0xffff; 453 s->regs[addr] |= (s->complete_cnt & 0xff) << 16; 454 s->regs[addr] |= (ptimer_get_count(s->ptimer) & 0xff) << 24; 455 r = s->regs[addr]; 456 break; 457 default: 458 r = s->regs[addr]; 459 D(qemu_log("%s ch=%d addr=" TARGET_FMT_plx " v=%x\n", 460 __func__, sid, addr * 4, r)); 461 break; 462 } 463 return r; 464 465} 466 467static void axidma_write(void *opaque, hwaddr addr, 468 uint64_t value, unsigned size) 469{ 470 XilinxAXIDMA *d = opaque; 471 struct Stream *s; 472 int sid; 473 474 sid = streamid_from_addr(addr); 475 s = &d->streams[sid]; 476 477 addr = addr % 0x30; 478 addr >>= 2; 479 switch (addr) { 480 case R_DMACR: 481 /* Tailptr mode is always on. */ 482 value |= DMACR_TAILPTR_MODE; 483 /* Remember our previous reset state. */ 484 value |= (s->regs[addr] & DMACR_RESET); 485 s->regs[addr] = value; 486 487 if (value & DMACR_RESET) { 488 stream_reset(s); 489 } 490 491 if ((value & 1) && !stream_resetting(s)) { 492 /* Start processing. */ 493 s->regs[R_DMASR] &= ~(DMASR_HALTED | DMASR_IDLE); 494 } 495 stream_reload_complete_cnt(s); 496 break; 497 498 case R_DMASR: 499 /* Mask away write to clear irq lines. */ 500 value &= ~(value & DMASR_IRQ_MASK); 501 s->regs[addr] = value; 502 break; 503 504 case R_TAILDESC: 505 s->regs[addr] = value; 506 s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle. */ 507 if (!sid) { 508 stream_process_mem2s(s, d->tx_data_dev, d->tx_control_dev); 509 } 510 break; 511 default: 512 D(qemu_log("%s: ch=%d addr=" TARGET_FMT_plx " v=%x\n", 513 __func__, sid, addr * 4, (unsigned)value)); 514 s->regs[addr] = value; 515 break; 516 } 517 if (sid == 1 && d->notify) { 518 StreamCanPushNotifyFn notifytmp = d->notify; 519 d->notify = NULL; 520 notifytmp(d->notify_opaque); 521 } 522 stream_update_irq(s); 523} 524 525static const MemoryRegionOps axidma_ops = { 526 .read = axidma_read, 527 .write = axidma_write, 528 .endianness = DEVICE_NATIVE_ENDIAN, 529}; 530 531static void xilinx_axidma_realize(DeviceState *dev, Error **errp) 532{ 533 XilinxAXIDMA *s = XILINX_AXI_DMA(dev); 534 XilinxAXIDMAStreamSink *ds = XILINX_AXI_DMA_DATA_STREAM(&s->rx_data_dev); 535 XilinxAXIDMAStreamSink *cs = XILINX_AXI_DMA_CONTROL_STREAM( 536 &s->rx_control_dev); 537 int i; 538 539 object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA, 540 (Object **)&ds->dma, 541 object_property_allow_set_link, 542 OBJ_PROP_LINK_STRONG); 543 object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA, 544 (Object **)&cs->dma, 545 object_property_allow_set_link, 546 OBJ_PROP_LINK_STRONG); 547 object_property_set_link(OBJECT(ds), "dma", OBJECT(s), &error_abort); 548 object_property_set_link(OBJECT(cs), "dma", OBJECT(s), &error_abort); 549 550 for (i = 0; i < 2; i++) { 551 struct Stream *st = &s->streams[i]; 552 553 st->dma = s; 554 st->nr = i; 555 st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_DEFAULT); 556 ptimer_transaction_begin(st->ptimer); 557 ptimer_set_freq(st->ptimer, s->freqhz); 558 ptimer_transaction_commit(st->ptimer); 559 } 560 561 address_space_init(&s->as, 562 s->dma_mr ? s->dma_mr : get_system_memory(), "dma"); 563} 564 565static void xilinx_axidma_init(Object *obj) 566{ 567 XilinxAXIDMA *s = XILINX_AXI_DMA(obj); 568 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 569 570 object_initialize_child(OBJECT(s), "axistream-connected-target", 571 &s->rx_data_dev, TYPE_XILINX_AXI_DMA_DATA_STREAM); 572 object_initialize_child(OBJECT(s), "axistream-control-connected-target", 573 &s->rx_control_dev, 574 TYPE_XILINX_AXI_DMA_CONTROL_STREAM); 575 object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, 576 (Object **)&s->dma_mr, 577 qdev_prop_allow_set_link_before_realize, 578 OBJ_PROP_LINK_STRONG); 579 580 sysbus_init_irq(sbd, &s->streams[0].irq); 581 sysbus_init_irq(sbd, &s->streams[1].irq); 582 583 memory_region_init_io(&s->iomem, obj, &axidma_ops, s, 584 "xlnx.axi-dma", R_MAX * 4 * 2); 585 sysbus_init_mmio(sbd, &s->iomem); 586} 587 588static Property axidma_properties[] = { 589 DEFINE_PROP_UINT32("freqhz", XilinxAXIDMA, freqhz, 50000000), 590 DEFINE_PROP_LINK("axistream-connected", XilinxAXIDMA, 591 tx_data_dev, TYPE_STREAM_SINK, StreamSink *), 592 DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIDMA, 593 tx_control_dev, TYPE_STREAM_SINK, StreamSink *), 594 DEFINE_PROP_END_OF_LIST(), 595}; 596 597static void axidma_class_init(ObjectClass *klass, void *data) 598{ 599 DeviceClass *dc = DEVICE_CLASS(klass); 600 601 dc->realize = xilinx_axidma_realize, 602 dc->reset = xilinx_axidma_reset; 603 device_class_set_props(dc, axidma_properties); 604} 605 606static StreamSinkClass xilinx_axidma_data_stream_class = { 607 .push = xilinx_axidma_data_stream_push, 608 .can_push = xilinx_axidma_data_stream_can_push, 609}; 610 611static StreamSinkClass xilinx_axidma_control_stream_class = { 612 .push = xilinx_axidma_control_stream_push, 613}; 614 615static void xilinx_axidma_stream_class_init(ObjectClass *klass, void *data) 616{ 617 StreamSinkClass *ssc = STREAM_SINK_CLASS(klass); 618 619 ssc->push = ((StreamSinkClass *)data)->push; 620 ssc->can_push = ((StreamSinkClass *)data)->can_push; 621} 622 623static const TypeInfo axidma_info = { 624 .name = TYPE_XILINX_AXI_DMA, 625 .parent = TYPE_SYS_BUS_DEVICE, 626 .instance_size = sizeof(XilinxAXIDMA), 627 .class_init = axidma_class_init, 628 .instance_init = xilinx_axidma_init, 629}; 630 631static const TypeInfo xilinx_axidma_data_stream_info = { 632 .name = TYPE_XILINX_AXI_DMA_DATA_STREAM, 633 .parent = TYPE_OBJECT, 634 .instance_size = sizeof(XilinxAXIDMAStreamSink), 635 .class_init = xilinx_axidma_stream_class_init, 636 .class_data = &xilinx_axidma_data_stream_class, 637 .interfaces = (InterfaceInfo[]) { 638 { TYPE_STREAM_SINK }, 639 { } 640 } 641}; 642 643static const TypeInfo xilinx_axidma_control_stream_info = { 644 .name = TYPE_XILINX_AXI_DMA_CONTROL_STREAM, 645 .parent = TYPE_OBJECT, 646 .instance_size = sizeof(XilinxAXIDMAStreamSink), 647 .class_init = xilinx_axidma_stream_class_init, 648 .class_data = &xilinx_axidma_control_stream_class, 649 .interfaces = (InterfaceInfo[]) { 650 { TYPE_STREAM_SINK }, 651 { } 652 } 653}; 654 655static void xilinx_axidma_register_types(void) 656{ 657 type_register_static(&axidma_info); 658 type_register_static(&xilinx_axidma_data_stream_info); 659 type_register_static(&xilinx_axidma_control_stream_info); 660} 661 662type_init(xilinx_axidma_register_types)