xref: /openbmc/qemu/hw/dma/xilinx_axidma.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * QEMU model of Xilinx AXI-DMA block.
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2011 Edgar E. Iglesias.
549ab747fSPaolo Bonzini  *
649ab747fSPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
749ab747fSPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
849ab747fSPaolo Bonzini  * in the Software without restriction, including without limitation the rights
949ab747fSPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1049ab747fSPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1149ab747fSPaolo Bonzini  * furnished to do so, subject to the following conditions:
1249ab747fSPaolo Bonzini  *
1349ab747fSPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1449ab747fSPaolo Bonzini  * all copies or substantial portions of the Software.
1549ab747fSPaolo Bonzini  *
1649ab747fSPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1749ab747fSPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1849ab747fSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1949ab747fSPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2049ab747fSPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2149ab747fSPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2249ab747fSPaolo Bonzini  * THE SOFTWARE.
2349ab747fSPaolo Bonzini  */
2449ab747fSPaolo Bonzini 
2517b7f2dbSPeter Maydell #include "qemu/osdep.h"
2649ab747fSPaolo Bonzini #include "hw/sysbus.h"
27da34e65cSMarkus Armbruster #include "qapi/error.h"
2849ab747fSPaolo Bonzini #include "qemu/timer.h"
29650d103dSMarkus Armbruster #include "hw/hw.h"
3064552b6bSMarkus Armbruster #include "hw/irq.h"
3149ab747fSPaolo Bonzini #include "hw/ptimer.h"
32a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
3349ab747fSPaolo Bonzini #include "qemu/log.h"
340b8fa32fSMarkus Armbruster #include "qemu/module.h"
3549ab747fSPaolo Bonzini 
36e3a8926dSEdgar E. Iglesias #include "sysemu/dma.h"
3749ab747fSPaolo Bonzini #include "hw/stream.h"
38db1015e9SEduardo Habkost #include "qom/object.h"
398e25dddaSFea.Wang #include "trace.h"
4049ab747fSPaolo Bonzini 
4149ab747fSPaolo Bonzini #define D(x)
4249ab747fSPaolo Bonzini 
43cbde584fSPeter Crosthwaite #define TYPE_XILINX_AXI_DMA "xlnx.axi-dma"
44e1500e35SPeter Crosthwaite #define TYPE_XILINX_AXI_DMA_DATA_STREAM "xilinx-axi-dma-data-stream"
4542bb9c91SPeter Crosthwaite #define TYPE_XILINX_AXI_DMA_CONTROL_STREAM "xilinx-axi-dma-control-stream"
46cbde584fSPeter Crosthwaite 
478063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(XilinxAXIDMA, XILINX_AXI_DMA)
48cbde584fSPeter Crosthwaite 
49484f86deSPhilippe Mathieu-Daudé typedef struct XilinxAXIDMAStreamSink XilinxAXIDMAStreamSink;
50484f86deSPhilippe Mathieu-Daudé DECLARE_INSTANCE_CHECKER(XilinxAXIDMAStreamSink, XILINX_AXI_DMA_DATA_STREAM,
51e1500e35SPeter Crosthwaite                          TYPE_XILINX_AXI_DMA_DATA_STREAM)
52e1500e35SPeter Crosthwaite 
53484f86deSPhilippe Mathieu-Daudé DECLARE_INSTANCE_CHECKER(XilinxAXIDMAStreamSink, XILINX_AXI_DMA_CONTROL_STREAM,
5442bb9c91SPeter Crosthwaite                          TYPE_XILINX_AXI_DMA_CONTROL_STREAM)
5542bb9c91SPeter Crosthwaite 
5649ab747fSPaolo Bonzini #define R_DMACR             (0x00 / 4)
5749ab747fSPaolo Bonzini #define R_DMASR             (0x04 / 4)
5849ab747fSPaolo Bonzini #define R_CURDESC           (0x08 / 4)
5949ab747fSPaolo Bonzini #define R_TAILDESC          (0x10 / 4)
6049ab747fSPaolo Bonzini #define R_MAX               (0x30 / 4)
6149ab747fSPaolo Bonzini 
6242bb9c91SPeter Crosthwaite #define CONTROL_PAYLOAD_WORDS 5
6342bb9c91SPeter Crosthwaite #define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t)))
6442bb9c91SPeter Crosthwaite 
6542e8a283SPeter Crosthwaite 
6649ab747fSPaolo Bonzini enum {
6749ab747fSPaolo Bonzini     DMACR_RUNSTOP = 1,
6849ab747fSPaolo Bonzini     DMACR_TAILPTR_MODE = 2,
6949ab747fSPaolo Bonzini     DMACR_RESET = 4
7049ab747fSPaolo Bonzini };
7149ab747fSPaolo Bonzini 
7249ab747fSPaolo Bonzini enum {
7349ab747fSPaolo Bonzini     DMASR_HALTED = 1,
7449ab747fSPaolo Bonzini     DMASR_IDLE  = 2,
75e6b45b6bSFea.Wang     DMASR_SLVERR = 1 << 5,
76e6b45b6bSFea.Wang     DMASR_DECERR = 1 << 6,
7749ab747fSPaolo Bonzini     DMASR_IOC_IRQ  = 1 << 12,
7849ab747fSPaolo Bonzini     DMASR_DLY_IRQ  = 1 << 13,
79e6b45b6bSFea.Wang     DMASR_ERR_IRQ  = 1 << 14,
8049ab747fSPaolo Bonzini 
8149ab747fSPaolo Bonzini     DMASR_IRQ_MASK = 7 << 12
8249ab747fSPaolo Bonzini };
8349ab747fSPaolo Bonzini 
8449ab747fSPaolo Bonzini struct SDesc {
8549ab747fSPaolo Bonzini     uint64_t nxtdesc;
8649ab747fSPaolo Bonzini     uint64_t buffer_address;
8749ab747fSPaolo Bonzini     uint64_t reserved;
8849ab747fSPaolo Bonzini     uint32_t control;
8949ab747fSPaolo Bonzini     uint32_t status;
9042bb9c91SPeter Crosthwaite     uint8_t app[CONTROL_PAYLOAD_SIZE];
9149ab747fSPaolo Bonzini };
9249ab747fSPaolo Bonzini 
9349ab747fSPaolo Bonzini enum {
9449ab747fSPaolo Bonzini     SDESC_CTRL_EOF = (1 << 26),
9549ab747fSPaolo Bonzini     SDESC_CTRL_SOF = (1 << 27),
9649ab747fSPaolo Bonzini 
9749ab747fSPaolo Bonzini     SDESC_CTRL_LEN_MASK = (1 << 23) - 1
9849ab747fSPaolo Bonzini };
9949ab747fSPaolo Bonzini 
10049ab747fSPaolo Bonzini enum {
10149ab747fSPaolo Bonzini     SDESC_STATUS_EOF = (1 << 26),
10249ab747fSPaolo Bonzini     SDESC_STATUS_SOF_BIT = 27,
10349ab747fSPaolo Bonzini     SDESC_STATUS_SOF = (1 << SDESC_STATUS_SOF_BIT),
10449ab747fSPaolo Bonzini     SDESC_STATUS_COMPLETE = (1 << 31)
10549ab747fSPaolo Bonzini };
10649ab747fSPaolo Bonzini 
10749ab747fSPaolo Bonzini struct Stream {
108e3a8926dSEdgar E. Iglesias     struct XilinxAXIDMA *dma;
10949ab747fSPaolo Bonzini     ptimer_state *ptimer;
11049ab747fSPaolo Bonzini     qemu_irq irq;
11149ab747fSPaolo Bonzini 
11249ab747fSPaolo Bonzini     int nr;
11349ab747fSPaolo Bonzini 
114734e3befSEdgar E. Iglesias     bool sof;
11549ab747fSPaolo Bonzini     struct SDesc desc;
11649ab747fSPaolo Bonzini     unsigned int complete_cnt;
11749ab747fSPaolo Bonzini     uint32_t regs[R_MAX];
11842bb9c91SPeter Crosthwaite     uint8_t app[20];
119cabbcca0SRutuja Shah     unsigned char txbuf[16 * 1024];
12049ab747fSPaolo Bonzini };
12149ab747fSPaolo Bonzini 
122484f86deSPhilippe Mathieu-Daudé struct XilinxAXIDMAStreamSink {
123e1500e35SPeter Crosthwaite     Object parent;
124e1500e35SPeter Crosthwaite 
125e1500e35SPeter Crosthwaite     struct XilinxAXIDMA *dma;
126e1500e35SPeter Crosthwaite };
127e1500e35SPeter Crosthwaite 
12849ab747fSPaolo Bonzini struct XilinxAXIDMA {
12949ab747fSPaolo Bonzini     SysBusDevice busdev;
13049ab747fSPaolo Bonzini     MemoryRegion iomem;
131e3a8926dSEdgar E. Iglesias     MemoryRegion *dma_mr;
132e3a8926dSEdgar E. Iglesias     AddressSpace as;
133e3a8926dSEdgar E. Iglesias 
13449ab747fSPaolo Bonzini     uint32_t freqhz;
135cfbef3f4SPhilippe Mathieu-Daudé     StreamSink *tx_data_dev;
136cfbef3f4SPhilippe Mathieu-Daudé     StreamSink *tx_control_dev;
137484f86deSPhilippe Mathieu-Daudé     XilinxAXIDMAStreamSink rx_data_dev;
138484f86deSPhilippe Mathieu-Daudé     XilinxAXIDMAStreamSink rx_control_dev;
13949ab747fSPaolo Bonzini 
14049ab747fSPaolo Bonzini     struct Stream streams[2];
1413630ae95SPeter Crosthwaite 
1423630ae95SPeter Crosthwaite     StreamCanPushNotifyFn notify;
1433630ae95SPeter Crosthwaite     void *notify_opaque;
14449ab747fSPaolo Bonzini };
14549ab747fSPaolo Bonzini 
14649ab747fSPaolo Bonzini /*
14767cc32ebSVeres Lajos  * Helper calls to extract info from descriptors and other trivial
14849ab747fSPaolo Bonzini  * state from regs.
14949ab747fSPaolo Bonzini  */
stream_desc_sof(struct SDesc * d)15049ab747fSPaolo Bonzini static inline int stream_desc_sof(struct SDesc *d)
15149ab747fSPaolo Bonzini {
15249ab747fSPaolo Bonzini     return d->control & SDESC_CTRL_SOF;
15349ab747fSPaolo Bonzini }
15449ab747fSPaolo Bonzini 
stream_desc_eof(struct SDesc * d)15549ab747fSPaolo Bonzini static inline int stream_desc_eof(struct SDesc *d)
15649ab747fSPaolo Bonzini {
15749ab747fSPaolo Bonzini     return d->control & SDESC_CTRL_EOF;
15849ab747fSPaolo Bonzini }
15949ab747fSPaolo Bonzini 
stream_resetting(struct Stream * s)16049ab747fSPaolo Bonzini static inline int stream_resetting(struct Stream *s)
16149ab747fSPaolo Bonzini {
16249ab747fSPaolo Bonzini     return !!(s->regs[R_DMACR] & DMACR_RESET);
16349ab747fSPaolo Bonzini }
16449ab747fSPaolo Bonzini 
stream_running(struct Stream * s)16549ab747fSPaolo Bonzini static inline int stream_running(struct Stream *s)
16649ab747fSPaolo Bonzini {
16749ab747fSPaolo Bonzini     return s->regs[R_DMACR] & DMACR_RUNSTOP;
16849ab747fSPaolo Bonzini }
16949ab747fSPaolo Bonzini 
stream_idle(struct Stream * s)17049ab747fSPaolo Bonzini static inline int stream_idle(struct Stream *s)
17149ab747fSPaolo Bonzini {
17249ab747fSPaolo Bonzini     return !!(s->regs[R_DMASR] & DMASR_IDLE);
17349ab747fSPaolo Bonzini }
17449ab747fSPaolo Bonzini 
stream_halted(struct Stream * s)17531afe045STommy Wu static inline int stream_halted(struct Stream *s)
17631afe045STommy Wu {
17731afe045STommy Wu     return !!(s->regs[R_DMASR] & DMASR_HALTED);
17831afe045STommy Wu }
17931afe045STommy Wu 
stream_reset(struct Stream * s)18049ab747fSPaolo Bonzini static void stream_reset(struct Stream *s)
18149ab747fSPaolo Bonzini {
18249ab747fSPaolo Bonzini     s->regs[R_DMASR] = DMASR_HALTED;  /* starts up halted.  */
18349ab747fSPaolo Bonzini     s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold.  */
184734e3befSEdgar E. Iglesias     s->sof = true;
18549ab747fSPaolo Bonzini }
18649ab747fSPaolo Bonzini 
18749ab747fSPaolo Bonzini /* Map an offset addr into a channel index.  */
streamid_from_addr(hwaddr addr)18849ab747fSPaolo Bonzini static inline int streamid_from_addr(hwaddr addr)
18949ab747fSPaolo Bonzini {
19049ab747fSPaolo Bonzini     int sid;
19149ab747fSPaolo Bonzini 
19249ab747fSPaolo Bonzini     sid = addr / (0x30);
19349ab747fSPaolo Bonzini     sid &= 1;
19449ab747fSPaolo Bonzini     return sid;
19549ab747fSPaolo Bonzini }
19649ab747fSPaolo Bonzini 
stream_desc_load(struct Stream * s,hwaddr addr)197e6b45b6bSFea.Wang static MemTxResult stream_desc_load(struct Stream *s, hwaddr addr)
19849ab747fSPaolo Bonzini {
19949ab747fSPaolo Bonzini     struct SDesc *d = &s->desc;
20049ab747fSPaolo Bonzini 
201e6b45b6bSFea.Wang     MemTxResult result = address_space_read(&s->dma->as,
202e6b45b6bSFea.Wang                                             addr, MEMTXATTRS_UNSPECIFIED,
203e6b45b6bSFea.Wang                                             d, sizeof *d);
204e6b45b6bSFea.Wang     if (result != MEMTX_OK) {
2058e25dddaSFea.Wang         trace_xilinx_axidma_loading_desc_fail(result);
2068e25dddaSFea.Wang 
207e6b45b6bSFea.Wang         if (result == MEMTX_DECODE_ERROR) {
208e6b45b6bSFea.Wang             s->regs[R_DMASR] |= DMASR_DECERR;
209e6b45b6bSFea.Wang         } else {
210e6b45b6bSFea.Wang             s->regs[R_DMASR] |= DMASR_SLVERR;
211e6b45b6bSFea.Wang         }
212e6b45b6bSFea.Wang 
213e6b45b6bSFea.Wang         s->regs[R_DMACR] &= ~DMACR_RUNSTOP;
214e6b45b6bSFea.Wang         s->regs[R_DMASR] |= DMASR_HALTED;
215e6b45b6bSFea.Wang         s->regs[R_DMASR] |= DMASR_ERR_IRQ;
216e6b45b6bSFea.Wang         return result;
217e6b45b6bSFea.Wang     }
21849ab747fSPaolo Bonzini 
21949ab747fSPaolo Bonzini     /* Convert from LE into host endianness.  */
22049ab747fSPaolo Bonzini     d->buffer_address = le64_to_cpu(d->buffer_address);
22149ab747fSPaolo Bonzini     d->nxtdesc = le64_to_cpu(d->nxtdesc);
22249ab747fSPaolo Bonzini     d->control = le32_to_cpu(d->control);
22349ab747fSPaolo Bonzini     d->status = le32_to_cpu(d->status);
224e6b45b6bSFea.Wang     return result;
22549ab747fSPaolo Bonzini }
22649ab747fSPaolo Bonzini 
stream_desc_store(struct Stream * s,hwaddr addr)22749ab747fSPaolo Bonzini static void stream_desc_store(struct Stream *s, hwaddr addr)
22849ab747fSPaolo Bonzini {
22949ab747fSPaolo Bonzini     struct SDesc *d = &s->desc;
23049ab747fSPaolo Bonzini 
23149ab747fSPaolo Bonzini     /* Convert from host endianness into LE.  */
23249ab747fSPaolo Bonzini     d->buffer_address = cpu_to_le64(d->buffer_address);
23349ab747fSPaolo Bonzini     d->nxtdesc = cpu_to_le64(d->nxtdesc);
23449ab747fSPaolo Bonzini     d->control = cpu_to_le32(d->control);
23549ab747fSPaolo Bonzini     d->status = cpu_to_le32(d->status);
236e3a8926dSEdgar E. Iglesias     address_space_write(&s->dma->as, addr, MEMTXATTRS_UNSPECIFIED,
237e3a8926dSEdgar E. Iglesias                         d, sizeof *d);
23849ab747fSPaolo Bonzini }
23949ab747fSPaolo Bonzini 
stream_update_irq(struct Stream * s)24049ab747fSPaolo Bonzini static void stream_update_irq(struct Stream *s)
24149ab747fSPaolo Bonzini {
24249ab747fSPaolo Bonzini     unsigned int pending, mask, irq;
24349ab747fSPaolo Bonzini 
24449ab747fSPaolo Bonzini     pending = s->regs[R_DMASR] & DMASR_IRQ_MASK;
24549ab747fSPaolo Bonzini     mask = s->regs[R_DMACR] & DMASR_IRQ_MASK;
24649ab747fSPaolo Bonzini 
24749ab747fSPaolo Bonzini     irq = pending & mask;
24849ab747fSPaolo Bonzini 
24949ab747fSPaolo Bonzini     qemu_set_irq(s->irq, !!irq);
25049ab747fSPaolo Bonzini }
25149ab747fSPaolo Bonzini 
stream_reload_complete_cnt(struct Stream * s)25249ab747fSPaolo Bonzini static void stream_reload_complete_cnt(struct Stream *s)
25349ab747fSPaolo Bonzini {
25449ab747fSPaolo Bonzini     unsigned int comp_th;
25549ab747fSPaolo Bonzini     comp_th = (s->regs[R_DMACR] >> 16) & 0xff;
25649ab747fSPaolo Bonzini     s->complete_cnt = comp_th;
25749ab747fSPaolo Bonzini }
25849ab747fSPaolo Bonzini 
timer_hit(void * opaque)25949ab747fSPaolo Bonzini static void timer_hit(void *opaque)
26049ab747fSPaolo Bonzini {
26149ab747fSPaolo Bonzini     struct Stream *s = opaque;
26249ab747fSPaolo Bonzini 
26349ab747fSPaolo Bonzini     stream_reload_complete_cnt(s);
26449ab747fSPaolo Bonzini     s->regs[R_DMASR] |= DMASR_DLY_IRQ;
26549ab747fSPaolo Bonzini     stream_update_irq(s);
26649ab747fSPaolo Bonzini }
26749ab747fSPaolo Bonzini 
stream_complete(struct Stream * s)26849ab747fSPaolo Bonzini static void stream_complete(struct Stream *s)
26949ab747fSPaolo Bonzini {
27049ab747fSPaolo Bonzini     unsigned int comp_delay;
27149ab747fSPaolo Bonzini 
27249ab747fSPaolo Bonzini     /* Start the delayed timer.  */
273e982ba05SPeter Maydell     ptimer_transaction_begin(s->ptimer);
27449ab747fSPaolo Bonzini     comp_delay = s->regs[R_DMACR] >> 24;
27549ab747fSPaolo Bonzini     if (comp_delay) {
27649ab747fSPaolo Bonzini         ptimer_stop(s->ptimer);
27749ab747fSPaolo Bonzini         ptimer_set_count(s->ptimer, comp_delay);
27849ab747fSPaolo Bonzini         ptimer_run(s->ptimer, 1);
27949ab747fSPaolo Bonzini     }
28049ab747fSPaolo Bonzini 
28149ab747fSPaolo Bonzini     s->complete_cnt--;
28249ab747fSPaolo Bonzini     if (s->complete_cnt == 0) {
28349ab747fSPaolo Bonzini         /* Raise the IOC irq.  */
28449ab747fSPaolo Bonzini         s->regs[R_DMASR] |= DMASR_IOC_IRQ;
28549ab747fSPaolo Bonzini         stream_reload_complete_cnt(s);
28649ab747fSPaolo Bonzini     }
287e982ba05SPeter Maydell     ptimer_transaction_commit(s->ptimer);
28849ab747fSPaolo Bonzini }
28949ab747fSPaolo Bonzini 
stream_process_mem2s(struct Stream * s,StreamSink * tx_data_dev,StreamSink * tx_control_dev)290cfbef3f4SPhilippe Mathieu-Daudé static void stream_process_mem2s(struct Stream *s, StreamSink *tx_data_dev,
291cfbef3f4SPhilippe Mathieu-Daudé                                  StreamSink *tx_control_dev)
29249ab747fSPaolo Bonzini {
29349ab747fSPaolo Bonzini     uint32_t prev_d;
294471fe8a2SEdgar E. Iglesias     uint32_t txlen;
295471fe8a2SEdgar E. Iglesias     uint64_t addr;
296471fe8a2SEdgar E. Iglesias     bool eop;
29749ab747fSPaolo Bonzini 
29831afe045STommy Wu     if (!stream_running(s) || stream_idle(s) || stream_halted(s)) {
29949ab747fSPaolo Bonzini         return;
30049ab747fSPaolo Bonzini     }
30149ab747fSPaolo Bonzini 
30249ab747fSPaolo Bonzini     while (1) {
303e6b45b6bSFea.Wang         if (MEMTX_OK != stream_desc_load(s, s->regs[R_CURDESC])) {
304e6b45b6bSFea.Wang             break;
305e6b45b6bSFea.Wang         }
30649ab747fSPaolo Bonzini 
30749ab747fSPaolo Bonzini         if (s->desc.status & SDESC_STATUS_COMPLETE) {
308210914e2SPeter Crosthwaite             s->regs[R_DMASR] |= DMASR_HALTED;
30949ab747fSPaolo Bonzini             break;
31049ab747fSPaolo Bonzini         }
31149ab747fSPaolo Bonzini 
31249ab747fSPaolo Bonzini         if (stream_desc_sof(&s->desc)) {
31351b19950SEdgar E. Iglesias             stream_push(tx_control_dev, s->desc.app, sizeof(s->desc.app), true);
31449ab747fSPaolo Bonzini         }
31549ab747fSPaolo Bonzini 
31649ab747fSPaolo Bonzini         txlen = s->desc.control & SDESC_CTRL_LEN_MASK;
317471fe8a2SEdgar E. Iglesias 
318471fe8a2SEdgar E. Iglesias         eop = stream_desc_eof(&s->desc);
319471fe8a2SEdgar E. Iglesias         addr = s->desc.buffer_address;
320471fe8a2SEdgar E. Iglesias         while (txlen) {
321471fe8a2SEdgar E. Iglesias             unsigned int len;
322471fe8a2SEdgar E. Iglesias 
323471fe8a2SEdgar E. Iglesias             len = txlen > sizeof s->txbuf ? sizeof s->txbuf : txlen;
324471fe8a2SEdgar E. Iglesias             address_space_read(&s->dma->as, addr,
325471fe8a2SEdgar E. Iglesias                                MEMTXATTRS_UNSPECIFIED,
326471fe8a2SEdgar E. Iglesias                                s->txbuf, len);
327471fe8a2SEdgar E. Iglesias             stream_push(tx_data_dev, s->txbuf, len, eop && len == txlen);
328471fe8a2SEdgar E. Iglesias             txlen -= len;
329471fe8a2SEdgar E. Iglesias             addr += len;
33049ab747fSPaolo Bonzini         }
33149ab747fSPaolo Bonzini 
332471fe8a2SEdgar E. Iglesias         if (eop) {
33349ab747fSPaolo Bonzini             stream_complete(s);
33449ab747fSPaolo Bonzini         }
33549ab747fSPaolo Bonzini 
33649ab747fSPaolo Bonzini         /* Update the descriptor.  */
33749ab747fSPaolo Bonzini         s->desc.status = txlen | SDESC_STATUS_COMPLETE;
33849ab747fSPaolo Bonzini         stream_desc_store(s, s->regs[R_CURDESC]);
33949ab747fSPaolo Bonzini 
34049ab747fSPaolo Bonzini         /* Advance.  */
34149ab747fSPaolo Bonzini         prev_d = s->regs[R_CURDESC];
34249ab747fSPaolo Bonzini         s->regs[R_CURDESC] = s->desc.nxtdesc;
34349ab747fSPaolo Bonzini         if (prev_d == s->regs[R_TAILDESC]) {
34449ab747fSPaolo Bonzini             s->regs[R_DMASR] |= DMASR_IDLE;
34549ab747fSPaolo Bonzini             break;
34649ab747fSPaolo Bonzini         }
34749ab747fSPaolo Bonzini     }
34849ab747fSPaolo Bonzini }
34949ab747fSPaolo Bonzini 
stream_process_s2mem(struct Stream * s,unsigned char * buf,size_t len,bool eop)3503630ae95SPeter Crosthwaite static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf,
351734e3befSEdgar E. Iglesias                                    size_t len, bool eop)
35249ab747fSPaolo Bonzini {
35349ab747fSPaolo Bonzini     uint32_t prev_d;
35449ab747fSPaolo Bonzini     unsigned int rxlen;
3553630ae95SPeter Crosthwaite     size_t pos = 0;
35649ab747fSPaolo Bonzini 
35731afe045STommy Wu     if (!stream_running(s) || stream_idle(s) || stream_halted(s)) {
3583630ae95SPeter Crosthwaite         return 0;
35949ab747fSPaolo Bonzini     }
36049ab747fSPaolo Bonzini 
36149ab747fSPaolo Bonzini     while (len) {
362e6b45b6bSFea.Wang         if (MEMTX_OK != stream_desc_load(s, s->regs[R_CURDESC])) {
363e6b45b6bSFea.Wang             break;
364e6b45b6bSFea.Wang         }
36549ab747fSPaolo Bonzini 
36649ab747fSPaolo Bonzini         if (s->desc.status & SDESC_STATUS_COMPLETE) {
367210914e2SPeter Crosthwaite             s->regs[R_DMASR] |= DMASR_HALTED;
36849ab747fSPaolo Bonzini             break;
36949ab747fSPaolo Bonzini         }
37049ab747fSPaolo Bonzini 
37149ab747fSPaolo Bonzini         rxlen = s->desc.control & SDESC_CTRL_LEN_MASK;
37249ab747fSPaolo Bonzini         if (rxlen > len) {
37349ab747fSPaolo Bonzini             /* It fits.  */
37449ab747fSPaolo Bonzini             rxlen = len;
37549ab747fSPaolo Bonzini         }
37649ab747fSPaolo Bonzini 
377e3a8926dSEdgar E. Iglesias         address_space_write(&s->dma->as, s->desc.buffer_address,
378e3a8926dSEdgar E. Iglesias                             MEMTXATTRS_UNSPECIFIED, buf + pos, rxlen);
37949ab747fSPaolo Bonzini         len -= rxlen;
38049ab747fSPaolo Bonzini         pos += rxlen;
38149ab747fSPaolo Bonzini 
38249ab747fSPaolo Bonzini         /* Update the descriptor.  */
383734e3befSEdgar E. Iglesias         if (eop) {
38449ab747fSPaolo Bonzini             stream_complete(s);
38542bb9c91SPeter Crosthwaite             memcpy(s->desc.app, s->app, sizeof(s->desc.app));
38649ab747fSPaolo Bonzini             s->desc.status |= SDESC_STATUS_EOF;
38749ab747fSPaolo Bonzini         }
38849ab747fSPaolo Bonzini 
389734e3befSEdgar E. Iglesias         s->desc.status |= s->sof << SDESC_STATUS_SOF_BIT;
39049ab747fSPaolo Bonzini         s->desc.status |= SDESC_STATUS_COMPLETE;
39149ab747fSPaolo Bonzini         stream_desc_store(s, s->regs[R_CURDESC]);
392734e3befSEdgar E. Iglesias         s->sof = eop;
39349ab747fSPaolo Bonzini 
39449ab747fSPaolo Bonzini         /* Advance.  */
39549ab747fSPaolo Bonzini         prev_d = s->regs[R_CURDESC];
39649ab747fSPaolo Bonzini         s->regs[R_CURDESC] = s->desc.nxtdesc;
39749ab747fSPaolo Bonzini         if (prev_d == s->regs[R_TAILDESC]) {
39849ab747fSPaolo Bonzini             s->regs[R_DMASR] |= DMASR_IDLE;
39949ab747fSPaolo Bonzini             break;
40049ab747fSPaolo Bonzini         }
40149ab747fSPaolo Bonzini     }
4023630ae95SPeter Crosthwaite 
4033630ae95SPeter Crosthwaite     return pos;
40449ab747fSPaolo Bonzini }
40549ab747fSPaolo Bonzini 
xilinx_axidma_reset(DeviceState * dev)406897374dbSPeter Crosthwaite static void xilinx_axidma_reset(DeviceState *dev)
407897374dbSPeter Crosthwaite {
408897374dbSPeter Crosthwaite     int i;
409897374dbSPeter Crosthwaite     XilinxAXIDMA *s = XILINX_AXI_DMA(dev);
410897374dbSPeter Crosthwaite 
411897374dbSPeter Crosthwaite     for (i = 0; i < 2; i++) {
412897374dbSPeter Crosthwaite         stream_reset(&s->streams[i]);
413897374dbSPeter Crosthwaite     }
414897374dbSPeter Crosthwaite }
415897374dbSPeter Crosthwaite 
41642bb9c91SPeter Crosthwaite static size_t
xilinx_axidma_control_stream_push(StreamSink * obj,unsigned char * buf,size_t len,bool eop)417cfbef3f4SPhilippe Mathieu-Daudé xilinx_axidma_control_stream_push(StreamSink *obj, unsigned char *buf,
41851b19950SEdgar E. Iglesias                                   size_t len, bool eop)
41942bb9c91SPeter Crosthwaite {
420484f86deSPhilippe Mathieu-Daudé     XilinxAXIDMAStreamSink *cs = XILINX_AXI_DMA_CONTROL_STREAM(obj);
42142bb9c91SPeter Crosthwaite     struct Stream *s = &cs->dma->streams[1];
42242bb9c91SPeter Crosthwaite 
42342bb9c91SPeter Crosthwaite     if (len != CONTROL_PAYLOAD_SIZE) {
42442bb9c91SPeter Crosthwaite         hw_error("AXI DMA requires %d byte control stream payload\n",
42542bb9c91SPeter Crosthwaite                  (int)CONTROL_PAYLOAD_SIZE);
42642bb9c91SPeter Crosthwaite     }
42742bb9c91SPeter Crosthwaite 
42842bb9c91SPeter Crosthwaite     memcpy(s->app, buf, len);
42942bb9c91SPeter Crosthwaite     return len;
43042bb9c91SPeter Crosthwaite }
43142bb9c91SPeter Crosthwaite 
4323630ae95SPeter Crosthwaite static bool
xilinx_axidma_data_stream_can_push(StreamSink * obj,StreamCanPushNotifyFn notify,void * notify_opaque)433cfbef3f4SPhilippe Mathieu-Daudé xilinx_axidma_data_stream_can_push(StreamSink *obj,
4343630ae95SPeter Crosthwaite                                    StreamCanPushNotifyFn notify,
4353630ae95SPeter Crosthwaite                                    void *notify_opaque)
4363630ae95SPeter Crosthwaite {
437484f86deSPhilippe Mathieu-Daudé     XilinxAXIDMAStreamSink *ds = XILINX_AXI_DMA_DATA_STREAM(obj);
4383630ae95SPeter Crosthwaite     struct Stream *s = &ds->dma->streams[1];
4393630ae95SPeter Crosthwaite 
44031afe045STommy Wu     if (!stream_running(s) || stream_idle(s) || stream_halted(s)) {
4413630ae95SPeter Crosthwaite         ds->dma->notify = notify;
4423630ae95SPeter Crosthwaite         ds->dma->notify_opaque = notify_opaque;
4433630ae95SPeter Crosthwaite         return false;
4443630ae95SPeter Crosthwaite     }
4453630ae95SPeter Crosthwaite 
4463630ae95SPeter Crosthwaite     return true;
4473630ae95SPeter Crosthwaite }
4483630ae95SPeter Crosthwaite 
44935e60bfdSPeter Crosthwaite static size_t
xilinx_axidma_data_stream_push(StreamSink * obj,unsigned char * buf,size_t len,bool eop)450cfbef3f4SPhilippe Mathieu-Daudé xilinx_axidma_data_stream_push(StreamSink *obj, unsigned char *buf, size_t len,
45151b19950SEdgar E. Iglesias                                bool eop)
45249ab747fSPaolo Bonzini {
453484f86deSPhilippe Mathieu-Daudé     XilinxAXIDMAStreamSink *ds = XILINX_AXI_DMA_DATA_STREAM(obj);
454e1500e35SPeter Crosthwaite     struct Stream *s = &ds->dma->streams[1];
4553630ae95SPeter Crosthwaite     size_t ret;
45649ab747fSPaolo Bonzini 
457734e3befSEdgar E. Iglesias     ret = stream_process_s2mem(s, buf, len, eop);
45849ab747fSPaolo Bonzini     stream_update_irq(s);
4593630ae95SPeter Crosthwaite     return ret;
46049ab747fSPaolo Bonzini }
46149ab747fSPaolo Bonzini 
axidma_read(void * opaque,hwaddr addr,unsigned size)46249ab747fSPaolo Bonzini static uint64_t axidma_read(void *opaque, hwaddr addr,
46349ab747fSPaolo Bonzini                             unsigned size)
46449ab747fSPaolo Bonzini {
46542e8a283SPeter Crosthwaite     XilinxAXIDMA *d = opaque;
46649ab747fSPaolo Bonzini     struct Stream *s;
46749ab747fSPaolo Bonzini     uint32_t r = 0;
46849ab747fSPaolo Bonzini     int sid;
46949ab747fSPaolo Bonzini 
47049ab747fSPaolo Bonzini     sid = streamid_from_addr(addr);
47149ab747fSPaolo Bonzini     s = &d->streams[sid];
47249ab747fSPaolo Bonzini 
47349ab747fSPaolo Bonzini     addr = addr % 0x30;
47449ab747fSPaolo Bonzini     addr >>= 2;
47549ab747fSPaolo Bonzini     switch (addr) {
47649ab747fSPaolo Bonzini         case R_DMACR:
47749ab747fSPaolo Bonzini             /* Simulate one cycles reset delay.  */
47849ab747fSPaolo Bonzini             s->regs[addr] &= ~DMACR_RESET;
47949ab747fSPaolo Bonzini             r = s->regs[addr];
48049ab747fSPaolo Bonzini             break;
48149ab747fSPaolo Bonzini         case R_DMASR:
48249ab747fSPaolo Bonzini             s->regs[addr] &= 0xffff;
48349ab747fSPaolo Bonzini             s->regs[addr] |= (s->complete_cnt & 0xff) << 16;
48449ab747fSPaolo Bonzini             s->regs[addr] |= (ptimer_get_count(s->ptimer) & 0xff) << 24;
48549ab747fSPaolo Bonzini             r = s->regs[addr];
48649ab747fSPaolo Bonzini             break;
48749ab747fSPaolo Bonzini         default:
48849ab747fSPaolo Bonzini             r = s->regs[addr];
489883f2c59SPhilippe Mathieu-Daudé             D(qemu_log("%s ch=%d addr=" HWADDR_FMT_plx " v=%x\n",
49049ab747fSPaolo Bonzini                            __func__, sid, addr * 4, r));
49149ab747fSPaolo Bonzini             break;
49249ab747fSPaolo Bonzini     }
49349ab747fSPaolo Bonzini     return r;
49449ab747fSPaolo Bonzini 
49549ab747fSPaolo Bonzini }
49649ab747fSPaolo Bonzini 
axidma_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)49749ab747fSPaolo Bonzini static void axidma_write(void *opaque, hwaddr addr,
49849ab747fSPaolo Bonzini                          uint64_t value, unsigned size)
49949ab747fSPaolo Bonzini {
50042e8a283SPeter Crosthwaite     XilinxAXIDMA *d = opaque;
50149ab747fSPaolo Bonzini     struct Stream *s;
50249ab747fSPaolo Bonzini     int sid;
50349ab747fSPaolo Bonzini 
50449ab747fSPaolo Bonzini     sid = streamid_from_addr(addr);
50549ab747fSPaolo Bonzini     s = &d->streams[sid];
50649ab747fSPaolo Bonzini 
50749ab747fSPaolo Bonzini     addr = addr % 0x30;
50849ab747fSPaolo Bonzini     addr >>= 2;
50949ab747fSPaolo Bonzini     switch (addr) {
51049ab747fSPaolo Bonzini         case R_DMACR:
51149ab747fSPaolo Bonzini             /* Tailptr mode is always on.  */
51249ab747fSPaolo Bonzini             value |= DMACR_TAILPTR_MODE;
51349ab747fSPaolo Bonzini             /* Remember our previous reset state.  */
51449ab747fSPaolo Bonzini             value |= (s->regs[addr] & DMACR_RESET);
51549ab747fSPaolo Bonzini             s->regs[addr] = value;
51649ab747fSPaolo Bonzini 
51749ab747fSPaolo Bonzini             if (value & DMACR_RESET) {
51849ab747fSPaolo Bonzini                 stream_reset(s);
51949ab747fSPaolo Bonzini             }
52049ab747fSPaolo Bonzini 
52149ab747fSPaolo Bonzini             if ((value & 1) && !stream_resetting(s)) {
52249ab747fSPaolo Bonzini                 /* Start processing.  */
52349ab747fSPaolo Bonzini                 s->regs[R_DMASR] &= ~(DMASR_HALTED | DMASR_IDLE);
52449ab747fSPaolo Bonzini             }
52549ab747fSPaolo Bonzini             stream_reload_complete_cnt(s);
52649ab747fSPaolo Bonzini             break;
52749ab747fSPaolo Bonzini 
52849ab747fSPaolo Bonzini         case R_DMASR:
52949ab747fSPaolo Bonzini             /* Mask away write to clear irq lines.  */
53049ab747fSPaolo Bonzini             value &= ~(value & DMASR_IRQ_MASK);
53149ab747fSPaolo Bonzini             s->regs[addr] = value;
53249ab747fSPaolo Bonzini             break;
53349ab747fSPaolo Bonzini 
53449ab747fSPaolo Bonzini         case R_TAILDESC:
53549ab747fSPaolo Bonzini             s->regs[addr] = value;
53649ab747fSPaolo Bonzini             s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle.  */
53749ab747fSPaolo Bonzini             if (!sid) {
53842bb9c91SPeter Crosthwaite                 stream_process_mem2s(s, d->tx_data_dev, d->tx_control_dev);
53949ab747fSPaolo Bonzini             }
54049ab747fSPaolo Bonzini             break;
54149ab747fSPaolo Bonzini         default:
542883f2c59SPhilippe Mathieu-Daudé             D(qemu_log("%s: ch=%d addr=" HWADDR_FMT_plx " v=%x\n",
54349ab747fSPaolo Bonzini                   __func__, sid, addr * 4, (unsigned)value));
54449ab747fSPaolo Bonzini             s->regs[addr] = value;
54549ab747fSPaolo Bonzini             break;
54649ab747fSPaolo Bonzini     }
5473630ae95SPeter Crosthwaite     if (sid == 1 && d->notify) {
5484f293bd6SWendy Liang         StreamCanPushNotifyFn notifytmp = d->notify;
5493630ae95SPeter Crosthwaite         d->notify = NULL;
5504f293bd6SWendy Liang         notifytmp(d->notify_opaque);
5513630ae95SPeter Crosthwaite     }
55249ab747fSPaolo Bonzini     stream_update_irq(s);
55349ab747fSPaolo Bonzini }
55449ab747fSPaolo Bonzini 
55549ab747fSPaolo Bonzini static const MemoryRegionOps axidma_ops = {
55649ab747fSPaolo Bonzini     .read = axidma_read,
55749ab747fSPaolo Bonzini     .write = axidma_write,
55849ab747fSPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
55949ab747fSPaolo Bonzini };
56049ab747fSPaolo Bonzini 
xilinx_axidma_realize(DeviceState * dev,Error ** errp)561e6543663SPeter Crosthwaite static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
56249ab747fSPaolo Bonzini {
563cbde584fSPeter Crosthwaite     XilinxAXIDMA *s = XILINX_AXI_DMA(dev);
564484f86deSPhilippe Mathieu-Daudé     XilinxAXIDMAStreamSink *ds = XILINX_AXI_DMA_DATA_STREAM(&s->rx_data_dev);
565484f86deSPhilippe Mathieu-Daudé     XilinxAXIDMAStreamSink *cs = XILINX_AXI_DMA_CONTROL_STREAM(
56642bb9c91SPeter Crosthwaite                                                             &s->rx_control_dev);
567e3a8926dSEdgar E. Iglesias     int i;
568e1500e35SPeter Crosthwaite 
569e1500e35SPeter Crosthwaite     object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA,
5709561fda8SStefan Hajnoczi                              (Object **)&ds->dma,
57139f72ef9SStefan Hajnoczi                              object_property_allow_set_link,
572d2623129SMarkus Armbruster                              OBJ_PROP_LINK_STRONG);
57342bb9c91SPeter Crosthwaite     object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA,
5749561fda8SStefan Hajnoczi                              (Object **)&cs->dma,
57539f72ef9SStefan Hajnoczi                              object_property_allow_set_link,
576d2623129SMarkus Armbruster                              OBJ_PROP_LINK_STRONG);
5775325cc34SMarkus Armbruster     object_property_set_link(OBJECT(ds), "dma", OBJECT(s), &error_abort);
5785325cc34SMarkus Armbruster     object_property_set_link(OBJECT(cs), "dma", OBJECT(s), &error_abort);
579e1500e35SPeter Crosthwaite 
58049ab747fSPaolo Bonzini     for (i = 0; i < 2; i++) {
5816a07a695SPeter Crosthwaite         struct Stream *st = &s->streams[i];
5826a07a695SPeter Crosthwaite 
583e3a8926dSEdgar E. Iglesias         st->dma = s;
5846a07a695SPeter Crosthwaite         st->nr = i;
5859598c1bbSPeter Maydell         st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_LEGACY);
586e982ba05SPeter Maydell         ptimer_transaction_begin(st->ptimer);
5876a07a695SPeter Crosthwaite         ptimer_set_freq(st->ptimer, s->freqhz);
588e982ba05SPeter Maydell         ptimer_transaction_commit(st->ptimer);
58949ab747fSPaolo Bonzini     }
590e3a8926dSEdgar E. Iglesias 
591e3a8926dSEdgar E. Iglesias     address_space_init(&s->as,
592e3a8926dSEdgar E. Iglesias                        s->dma_mr ? s->dma_mr : get_system_memory(), "dma");
59349ab747fSPaolo Bonzini }
59449ab747fSPaolo Bonzini 
xilinx_axidma_init(Object * obj)595e6543663SPeter Crosthwaite static void xilinx_axidma_init(Object *obj)
59649ab747fSPaolo Bonzini {
597cbde584fSPeter Crosthwaite     XilinxAXIDMA *s = XILINX_AXI_DMA(obj);
598e6543663SPeter Crosthwaite     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
59949ab747fSPaolo Bonzini 
60000b0fd48SPhilippe Mathieu-Daudé     object_initialize_child(OBJECT(s), "axistream-connected-target",
6019fc7fc4dSMarkus Armbruster                             &s->rx_data_dev, TYPE_XILINX_AXI_DMA_DATA_STREAM);
60200b0fd48SPhilippe Mathieu-Daudé     object_initialize_child(OBJECT(s), "axistream-control-connected-target",
6039fc7fc4dSMarkus Armbruster                             &s->rx_control_dev,
6049fc7fc4dSMarkus Armbruster                             TYPE_XILINX_AXI_DMA_CONTROL_STREAM);
605e1500e35SPeter Crosthwaite 
606e6543663SPeter Crosthwaite     sysbus_init_irq(sbd, &s->streams[0].irq);
607e6543663SPeter Crosthwaite     sysbus_init_irq(sbd, &s->streams[1].irq);
608e6543663SPeter Crosthwaite 
6093eadad55SPaolo Bonzini     memory_region_init_io(&s->iomem, obj, &axidma_ops, s,
610e6543663SPeter Crosthwaite                           "xlnx.axi-dma", R_MAX * 4 * 2);
611e6543663SPeter Crosthwaite     sysbus_init_mmio(sbd, &s->iomem);
61249ab747fSPaolo Bonzini }
61349ab747fSPaolo Bonzini 
61449ab747fSPaolo Bonzini static Property axidma_properties[] = {
61542e8a283SPeter Crosthwaite     DEFINE_PROP_UINT32("freqhz", XilinxAXIDMA, freqhz, 50000000),
61639d3d808SFam Zheng     DEFINE_PROP_LINK("axistream-connected", XilinxAXIDMA,
617cfbef3f4SPhilippe Mathieu-Daudé                      tx_data_dev, TYPE_STREAM_SINK, StreamSink *),
61839d3d808SFam Zheng     DEFINE_PROP_LINK("axistream-control-connected", XilinxAXIDMA,
619cfbef3f4SPhilippe Mathieu-Daudé                      tx_control_dev, TYPE_STREAM_SINK, StreamSink *),
6201f9d714eSPhilippe Mathieu-Daudé     DEFINE_PROP_LINK("dma", XilinxAXIDMA, dma_mr,
6211f9d714eSPhilippe Mathieu-Daudé                      TYPE_MEMORY_REGION, MemoryRegion *),
62249ab747fSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
62349ab747fSPaolo Bonzini };
62449ab747fSPaolo Bonzini 
axidma_class_init(ObjectClass * klass,void * data)62549ab747fSPaolo Bonzini static void axidma_class_init(ObjectClass *klass, void *data)
62649ab747fSPaolo Bonzini {
62749ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
62849ab747fSPaolo Bonzini 
629dfad8421SPeter Maydell     dc->realize = xilinx_axidma_realize;
630*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, xilinx_axidma_reset);
6314f67d30bSMarc-André Lureau     device_class_set_props(dc, axidma_properties);
632e1500e35SPeter Crosthwaite }
633e1500e35SPeter Crosthwaite 
634cfbef3f4SPhilippe Mathieu-Daudé static StreamSinkClass xilinx_axidma_data_stream_class = {
6353630ae95SPeter Crosthwaite     .push = xilinx_axidma_data_stream_push,
6363630ae95SPeter Crosthwaite     .can_push = xilinx_axidma_data_stream_can_push,
6373630ae95SPeter Crosthwaite };
6383630ae95SPeter Crosthwaite 
639cfbef3f4SPhilippe Mathieu-Daudé static StreamSinkClass xilinx_axidma_control_stream_class = {
64042bb9c91SPeter Crosthwaite     .push = xilinx_axidma_control_stream_push,
64142bb9c91SPeter Crosthwaite };
64242bb9c91SPeter Crosthwaite 
xilinx_axidma_stream_class_init(ObjectClass * klass,void * data)643e1500e35SPeter Crosthwaite static void xilinx_axidma_stream_class_init(ObjectClass *klass, void *data)
644e1500e35SPeter Crosthwaite {
645cfbef3f4SPhilippe Mathieu-Daudé     StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
646e1500e35SPeter Crosthwaite 
647cfbef3f4SPhilippe Mathieu-Daudé     ssc->push = ((StreamSinkClass *)data)->push;
648cfbef3f4SPhilippe Mathieu-Daudé     ssc->can_push = ((StreamSinkClass *)data)->can_push;
64949ab747fSPaolo Bonzini }
65049ab747fSPaolo Bonzini 
65149ab747fSPaolo Bonzini static const TypeInfo axidma_info = {
652cbde584fSPeter Crosthwaite     .name          = TYPE_XILINX_AXI_DMA,
65349ab747fSPaolo Bonzini     .parent        = TYPE_SYS_BUS_DEVICE,
65442e8a283SPeter Crosthwaite     .instance_size = sizeof(XilinxAXIDMA),
65549ab747fSPaolo Bonzini     .class_init    = axidma_class_init,
656e6543663SPeter Crosthwaite     .instance_init = xilinx_axidma_init,
657e1500e35SPeter Crosthwaite };
658e1500e35SPeter Crosthwaite 
659e1500e35SPeter Crosthwaite static const TypeInfo xilinx_axidma_data_stream_info = {
660e1500e35SPeter Crosthwaite     .name          = TYPE_XILINX_AXI_DMA_DATA_STREAM,
661e1500e35SPeter Crosthwaite     .parent        = TYPE_OBJECT,
662484f86deSPhilippe Mathieu-Daudé     .instance_size = sizeof(XilinxAXIDMAStreamSink),
663e1500e35SPeter Crosthwaite     .class_init    = xilinx_axidma_stream_class_init,
6643630ae95SPeter Crosthwaite     .class_data    = &xilinx_axidma_data_stream_class,
66549ab747fSPaolo Bonzini     .interfaces = (InterfaceInfo[]) {
666cfbef3f4SPhilippe Mathieu-Daudé         { TYPE_STREAM_SINK },
66749ab747fSPaolo Bonzini         { }
66849ab747fSPaolo Bonzini     }
66949ab747fSPaolo Bonzini };
67049ab747fSPaolo Bonzini 
67142bb9c91SPeter Crosthwaite static const TypeInfo xilinx_axidma_control_stream_info = {
67242bb9c91SPeter Crosthwaite     .name          = TYPE_XILINX_AXI_DMA_CONTROL_STREAM,
67342bb9c91SPeter Crosthwaite     .parent        = TYPE_OBJECT,
674484f86deSPhilippe Mathieu-Daudé     .instance_size = sizeof(XilinxAXIDMAStreamSink),
67542bb9c91SPeter Crosthwaite     .class_init    = xilinx_axidma_stream_class_init,
67642bb9c91SPeter Crosthwaite     .class_data    = &xilinx_axidma_control_stream_class,
67742bb9c91SPeter Crosthwaite     .interfaces = (InterfaceInfo[]) {
678cfbef3f4SPhilippe Mathieu-Daudé         { TYPE_STREAM_SINK },
67942bb9c91SPeter Crosthwaite         { }
68042bb9c91SPeter Crosthwaite     }
68142bb9c91SPeter Crosthwaite };
68242bb9c91SPeter Crosthwaite 
xilinx_axidma_register_types(void)68349ab747fSPaolo Bonzini static void xilinx_axidma_register_types(void)
68449ab747fSPaolo Bonzini {
68549ab747fSPaolo Bonzini     type_register_static(&axidma_info);
686e1500e35SPeter Crosthwaite     type_register_static(&xilinx_axidma_data_stream_info);
68742bb9c91SPeter Crosthwaite     type_register_static(&xilinx_axidma_control_stream_info);
68849ab747fSPaolo Bonzini }
68949ab747fSPaolo Bonzini 
69049ab747fSPaolo Bonzini type_init(xilinx_axidma_register_types)
691