On Mon, Aug 06, 2012 at 01:07:15PM +1000, Peter A. G. Crosthwaite wrote: > Re-implemented the interconnect between the Xilinx AXI ethernet and DMA > controllers. A QOM interface "stream" is created, for the two stream > interfaces. > > As per Edgars request, this is designed to be more generic than AXI-stream, > so in the future we may see more clients of this interface beyond AXI stream. > > This is based primarily on Paolos original refactoring of the interconnect.
Hi Peter, Can we drop the axi_ prefix from stream.c? Also the *app arg is xilinx specific but it can maybe refactored when more users of the interface come along as those might have similar needs. A scatter-gathering data interface might do. Cheers, Edgar > > Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> > Signed-off-by: Peter A.G. Crosthwaite <peter.crosthwa...@petalogix.com> > --- > hw/Makefile.objs | 1 + > hw/petalogix_ml605_mmu.c | 24 +++++++++------ > hw/stream.c | 23 ++++++++++++++ > hw/stream.h | 31 +++++++++++++++++++ > hw/xilinx.h | 22 +++++-------- > hw/xilinx_axidma.c | 74 +++++++++++++++++++++++++-------------------- > hw/xilinx_axidma.h | 39 ------------------------ > hw/xilinx_axienet.c | 32 ++++++++++++------- > 8 files changed, 139 insertions(+), 107 deletions(-) > create mode 100644 hw/stream.c > create mode 100644 hw/stream.h > delete mode 100644 hw/xilinx_axidma.h > > diff --git a/hw/Makefile.objs b/hw/Makefile.objs > index 8327e55..a2d537d 100644 > --- a/hw/Makefile.objs > +++ b/hw/Makefile.objs > @@ -65,6 +65,7 @@ hw-obj-$(CONFIG_XILINX) += xilinx_timer.o > hw-obj-$(CONFIG_XILINX) += xilinx_uartlite.o > hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o > hw-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o > +hw-obj-$(CONFIG_XILINX_AXI) += stream.o > > # PCI watchdog devices > hw-obj-$(CONFIG_PCI) += wdt_i6300esb.o > diff --git a/hw/petalogix_ml605_mmu.c b/hw/petalogix_ml605_mmu.c > index 6a7d0c0..dced648 100644 > --- a/hw/petalogix_ml605_mmu.c > +++ b/hw/petalogix_ml605_mmu.c > @@ -39,7 +39,8 @@ > > #include "microblaze_boot.h" > #include "microblaze_pic_cpu.h" > -#include "xilinx_axidma.h" > + > +#include "stream.h" > > #define LMB_BRAM_SIZE (128 * 1024) > #define FLASH_SIZE (32 * 1024 * 1024) > @@ -76,7 +77,7 @@ petalogix_ml605_init(ram_addr_t ram_size, > const char *initrd_filename, const char *cpu_model) > { > MemoryRegion *address_space_mem = get_system_memory(); > - DeviceState *dev; > + DeviceState *dev, *dma, *eth0; > MicroBlazeCPU *cpu; > CPUMBState *env; > DriveInfo *dinfo; > @@ -125,15 +126,18 @@ petalogix_ml605_init(ram_addr_t ram_size, > /* 2 timers at irq 2 @ 100 Mhz. */ > xilinx_timer_create(TIMER_BASEADDR, irq[2], 0, 100 * 1000000); > > - /* axi ethernet and dma initialization. TODO: Dynamically connect them. > */ > - { > - static struct XilinxDMAConnection dmach; > + /* axi ethernet and dma initialization. */ > + dma = qdev_create(NULL, "xlnx.axi-dma"); > > - xilinx_axiethernet_create(&dmach, &nd_table[0], 0x82780000, > - irq[3], 0x1000, 0x1000); > - xilinx_axiethernetdma_create(&dmach, 0x84600000, > - irq[1], irq[0], 100 * 1000000); > - } > + /* FIXME: attach to the sysbus instead */ > + object_property_add_child(container_get(qdev_get_machine(), > "/unattached"), > + "xilinx-dma", OBJECT(dma), NULL); > + > + eth0 = xilinx_axiethernet_create(&nd_table[0], STREAM_SLAVE(dma), > + 0x82780000, irq[3], 0x1000, 0x1000); > + > + xilinx_axiethernetdma_init(dma, STREAM_SLAVE(eth0), > + 0x84600000, irq[1], irq[0], 100 * 1000000); > > microblaze_load_kernel(cpu, ddr_base, ram_size, BINARY_DEVICE_TREE_FILE, > > machine_cpu_reset); > diff --git a/hw/stream.c b/hw/stream.c > new file mode 100644 > index 0000000..001e2bd > --- /dev/null > +++ b/hw/stream.c > @@ -0,0 +1,23 @@ > +#include "stream.h" > + > +void > +axi_stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app) > +{ > + StreamSlaveClass *k = STREAM_SLAVE_GET_CLASS(sink); > + > + k->push(sink, buf, len, app); > +} > + > +static TypeInfo axi_stream_slave_info = { > + .name = TYPE_STREAM_SLAVE, > + .parent = TYPE_INTERFACE, > + .class_size = sizeof(StreamSlaveClass), > +}; > + > + > +static void axi_stream_slave_register_types(void) > +{ > + type_register_static(&axi_stream_slave_info); > +} > + > +type_init(axi_stream_slave_register_types) > diff --git a/hw/stream.h b/hw/stream.h > new file mode 100644 > index 0000000..b7f3b3e > --- /dev/null > +++ b/hw/stream.h > @@ -0,0 +1,31 @@ > +#ifndef STREAM_H > +#define STREAM_H 1 > + > +#include "qemu-common.h" > +#include "qemu/object.h" > + > +/* AXI stream slave. Used until qdev provides a generic way. */ > +#define TYPE_STREAM_SLAVE "stream-slave" > + > +#define STREAM_SLAVE_CLASS(klass) \ > + OBJECT_CLASS_CHECK(StreamSlaveClass, (klass), TYPE_STREAM_SLAVE) > +#define STREAM_SLAVE_GET_CLASS(obj) \ > + OBJECT_GET_CLASS(StreamSlaveClass, (obj), TYPE_STREAM_SLAVE) > +#define STREAM_SLAVE(obj) \ > + INTERFACE_CHECK(StreamSlave, (obj), TYPE_STREAM_SLAVE) > + > +typedef struct StreamSlave { > + Object Parent; > +} StreamSlave; > + > +typedef struct StreamSlaveClass { > + InterfaceClass parent; > + > + void (*push)(StreamSlave *obj, unsigned char *buf, size_t len, > + uint32_t *app); > +} StreamSlaveClass; > + > +void > +axi_stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app); > + > +#endif /* STREAM_H */ > diff --git a/hw/xilinx.h b/hw/xilinx.h > index 7df21eb..556c5aa 100644 > --- a/hw/xilinx.h > +++ b/hw/xilinx.h > @@ -1,3 +1,4 @@ > +#include "stream.h" > #include "qemu-common.h" > #include "net.h" > > @@ -49,8 +50,8 @@ xilinx_ethlite_create(NICInfo *nd, target_phys_addr_t base, > qemu_irq irq, > } > > static inline DeviceState * > -xilinx_axiethernet_create(void *dmach, > - NICInfo *nd, target_phys_addr_t base, qemu_irq irq, > +xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer, > + target_phys_addr_t base, qemu_irq irq, > int txmem, int rxmem) > { > DeviceState *dev; > @@ -60,7 +61,7 @@ xilinx_axiethernet_create(void *dmach, > qdev_set_nic_properties(dev, nd); > qdev_prop_set_uint32(dev, "rxmem", rxmem); > qdev_prop_set_uint32(dev, "txmem", txmem); > - qdev_prop_set_ptr(dev, "dmach", dmach); > + object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL); > qdev_init_nofail(dev); > sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); > sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); > @@ -68,21 +69,16 @@ xilinx_axiethernet_create(void *dmach, > return dev; > } > > -static inline DeviceState * > -xilinx_axiethernetdma_create(void *dmach, > - target_phys_addr_t base, qemu_irq irq, > - qemu_irq irq2, int freqhz) > +static inline void > +xilinx_axiethernetdma_init(DeviceState *dev, StreamSlave *peer, > + target_phys_addr_t base, qemu_irq irq, > + qemu_irq irq2, int freqhz) > { > - DeviceState *dev = NULL; > - > - dev = qdev_create(NULL, "xlnx.axi-dma"); > qdev_prop_set_uint32(dev, "freqhz", freqhz); > - qdev_prop_set_ptr(dev, "dmach", dmach); > + object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL); > qdev_init_nofail(dev); > > sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); > sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); > sysbus_connect_irq(sysbus_from_qdev(dev), 1, irq2); > - > - return dev; > } > diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c > index f4bec37..d38bf6f 100644 > --- a/hw/xilinx_axidma.c > +++ b/hw/xilinx_axidma.c > @@ -29,7 +29,7 @@ > #include "qemu-log.h" > #include "qdev-addr.h" > > -#include "xilinx_axidma.h" > +#include "stream.h" > > #define D(x) > > @@ -77,7 +77,7 @@ enum { > SDESC_STATUS_COMPLETE = (1 << 31) > }; > > -struct AXIStream { > +struct Stream { > QEMUBH *bh; > ptimer_state *ptimer; > qemu_irq irq; > @@ -94,9 +94,9 @@ struct XilinxAXIDMA { > SysBusDevice busdev; > MemoryRegion iomem; > uint32_t freqhz; > - void *dmach; > + StreamSlave *tx_dev; > > - struct AXIStream streams[2]; > + struct Stream streams[2]; > }; > > /* > @@ -113,27 +113,27 @@ static inline int stream_desc_eof(struct SDesc *d) > return d->control & SDESC_CTRL_EOF; > } > > -static inline int stream_resetting(struct AXIStream *s) > +static inline int stream_resetting(struct Stream *s) > { > return !!(s->regs[R_DMACR] & DMACR_RESET); > } > > -static inline int stream_running(struct AXIStream *s) > +static inline int stream_running(struct Stream *s) > { > return s->regs[R_DMACR] & DMACR_RUNSTOP; > } > > -static inline int stream_halted(struct AXIStream *s) > +static inline int stream_halted(struct Stream *s) > { > return s->regs[R_DMASR] & DMASR_HALTED; > } > > -static inline int stream_idle(struct AXIStream *s) > +static inline int stream_idle(struct Stream *s) > { > return !!(s->regs[R_DMASR] & DMASR_IDLE); > } > > -static void stream_reset(struct AXIStream *s) > +static void stream_reset(struct Stream *s) > { > s->regs[R_DMASR] = DMASR_HALTED; /* starts up halted. */ > s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold. */ > @@ -159,7 +159,7 @@ static void stream_desc_show(struct SDesc *d) > } > #endif > > -static void stream_desc_load(struct AXIStream *s, target_phys_addr_t addr) > +static void stream_desc_load(struct Stream *s, target_phys_addr_t addr) > { > struct SDesc *d = &s->desc; > int i; > @@ -176,7 +176,7 @@ static void stream_desc_load(struct AXIStream *s, > target_phys_addr_t addr) > } > } > > -static void stream_desc_store(struct AXIStream *s, target_phys_addr_t addr) > +static void stream_desc_store(struct Stream *s, target_phys_addr_t addr) > { > struct SDesc *d = &s->desc; > int i; > @@ -192,7 +192,7 @@ static void stream_desc_store(struct AXIStream *s, > target_phys_addr_t addr) > cpu_physical_memory_write(addr, (void *) d, sizeof *d); > } > > -static void stream_update_irq(struct AXIStream *s) > +static void stream_update_irq(struct Stream *s) > { > unsigned int pending, mask, irq; > > @@ -204,7 +204,7 @@ static void stream_update_irq(struct AXIStream *s) > qemu_set_irq(s->irq, !!irq); > } > > -static void stream_reload_complete_cnt(struct AXIStream *s) > +static void stream_reload_complete_cnt(struct Stream *s) > { > unsigned int comp_th; > comp_th = (s->regs[R_DMACR] >> 16) & 0xff; > @@ -213,14 +213,14 @@ static void stream_reload_complete_cnt(struct AXIStream > *s) > > static void timer_hit(void *opaque) > { > - struct AXIStream *s = opaque; > + struct Stream *s = opaque; > > stream_reload_complete_cnt(s); > s->regs[R_DMASR] |= DMASR_DLY_IRQ; > stream_update_irq(s); > } > > -static void stream_complete(struct AXIStream *s) > +static void stream_complete(struct Stream *s) > { > unsigned int comp_delay; > > @@ -240,8 +240,8 @@ static void stream_complete(struct AXIStream *s) > } > } > > -static void stream_process_mem2s(struct AXIStream *s, > - struct XilinxDMAConnection *dmach) > +static void stream_process_mem2s(struct Stream *s, > + StreamSlave *tx_dev) > { > uint32_t prev_d; > unsigned char txbuf[16 * 1024]; > @@ -276,7 +276,7 @@ static void stream_process_mem2s(struct AXIStream *s, > s->pos += txlen; > > if (stream_desc_eof(&s->desc)) { > - xlx_dma_push_to_client(dmach, txbuf, s->pos, app); > + axi_stream_push(tx_dev, txbuf, s->pos, app); > s->pos = 0; > stream_complete(s); > } > @@ -295,7 +295,7 @@ static void stream_process_mem2s(struct AXIStream *s, > } > } > > -static void stream_process_s2mem(struct AXIStream *s, > +static void stream_process_s2mem(struct Stream *s, > unsigned char *buf, size_t len, uint32_t > *app) > { > uint32_t prev_d; > @@ -351,11 +351,11 @@ static void stream_process_s2mem(struct AXIStream *s, > } > } > > -static > -void axidma_push(void *opaque, unsigned char *buf, size_t len, uint32_t *app) > +static void > +axidma_push(StreamSlave *obj, unsigned char *buf, size_t len, uint32_t *app) > { > - struct XilinxAXIDMA *d = opaque; > - struct AXIStream *s = &d->streams[1]; > + struct XilinxAXIDMA *d = FROM_SYSBUS(typeof(*d), SYS_BUS_DEVICE(obj)); > + struct Stream *s = &d->streams[1]; > > if (!app) { > hw_error("No stream app data!\n"); > @@ -368,7 +368,7 @@ static uint64_t axidma_read(void *opaque, > target_phys_addr_t addr, > unsigned size) > { > struct XilinxAXIDMA *d = opaque; > - struct AXIStream *s; > + struct Stream *s; > uint32_t r = 0; > int sid; > > @@ -403,7 +403,7 @@ static void axidma_write(void *opaque, target_phys_addr_t > addr, > uint64_t value, unsigned size) > { > struct XilinxAXIDMA *d = opaque; > - struct AXIStream *s; > + struct Stream *s; > int sid; > > sid = streamid_from_addr(addr); > @@ -440,7 +440,7 @@ static void axidma_write(void *opaque, target_phys_addr_t > addr, > s->regs[addr] = value; > s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle. */ > if (!sid) { > - stream_process_mem2s(s, d->dmach); > + stream_process_mem2s(s, d->tx_dev); > } > break; > default: > @@ -466,12 +466,6 @@ static int xilinx_axidma_init(SysBusDevice *dev) > sysbus_init_irq(dev, &s->streams[0].irq); > sysbus_init_irq(dev, &s->streams[1].irq); > > - if (!s->dmach) { > - hw_error("Unconnected DMA channel.\n"); > - } > - > - xlx_dma_connect_dma(s->dmach, s, axidma_push); > - > memory_region_init_io(&s->iomem, &axidma_ops, s, > "xlnx.axi-dma", R_MAX * 4 * 2); > sysbus_init_mmio(dev, &s->iomem); > @@ -486,9 +480,16 @@ static int xilinx_axidma_init(SysBusDevice *dev) > return 0; > } > > +static void xilinx_axidma_initfn(Object *obj) > +{ > + struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj)); > + > + object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE, > + (Object **) &s->tx_dev, NULL); > +} > + > static Property axidma_properties[] = { > DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000), > - DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach), > DEFINE_PROP_END_OF_LIST(), > }; > > @@ -496,9 +497,11 @@ static void axidma_class_init(ObjectClass *klass, void > *data) > { > DeviceClass *dc = DEVICE_CLASS(klass); > SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); > + StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass); > > k->init = xilinx_axidma_init; > dc->props = axidma_properties; > + ssc->push = axidma_push; > } > > static TypeInfo axidma_info = { > @@ -506,6 +509,11 @@ static TypeInfo axidma_info = { > .parent = TYPE_SYS_BUS_DEVICE, > .instance_size = sizeof(struct XilinxAXIDMA), > .class_init = axidma_class_init, > + .instance_init = xilinx_axidma_initfn, > + .interfaces = (InterfaceInfo[]) { > + { TYPE_STREAM_SLAVE }, > + { } > + } > }; > > static void xilinx_axidma_register_types(void) > diff --git a/hw/xilinx_axidma.h b/hw/xilinx_axidma.h > deleted file mode 100644 > index 37cb6f0..0000000 > --- a/hw/xilinx_axidma.h > +++ /dev/null > @@ -1,39 +0,0 @@ > -/* AXI DMA connection. Used until qdev provides a generic way. */ > -typedef void (*DMAPushFn)(void *opaque, > - unsigned char *buf, size_t len, uint32_t *app); > - > -struct XilinxDMAConnection { > - void *dma; > - void *client; > - > - DMAPushFn to_dma; > - DMAPushFn to_client; > -}; > - > -static inline void xlx_dma_connect_client(struct XilinxDMAConnection *dmach, > - void *c, DMAPushFn f) > -{ > - dmach->client = c; > - dmach->to_client = f; > -} > - > -static inline void xlx_dma_connect_dma(struct XilinxDMAConnection *dmach, > - void *d, DMAPushFn f) > -{ > - dmach->dma = d; > - dmach->to_dma = f; > -} > - > -static inline > -void xlx_dma_push_to_dma(struct XilinxDMAConnection *dmach, > - uint8_t *buf, size_t len, uint32_t *app) > -{ > - dmach->to_dma(dmach->dma, buf, len, app); > -} > -static inline > -void xlx_dma_push_to_client(struct XilinxDMAConnection *dmach, > - uint8_t *buf, size_t len, uint32_t *app) > -{ > - dmach->to_client(dmach->client, buf, len, app); > -} > - > diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c > index adfaf2c..5e59c3d 100644 > --- a/hw/xilinx_axienet.c > +++ b/hw/xilinx_axienet.c > @@ -28,7 +28,7 @@ > #include "net.h" > #include "net/checksum.h" > > -#include "xilinx_axidma.h" > +#include "stream.h" > > #define DPHY(x) > > @@ -310,7 +310,7 @@ struct XilinxAXIEnet { > SysBusDevice busdev; > MemoryRegion iomem; > qemu_irq irq; > - void *dmach; > + StreamSlave *tx_dev; > NICState *nic; > NICConf conf; > > @@ -773,7 +773,7 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t > *buf, size_t size) > /* Good frame. */ > app[2] |= 1 << 6; > > - xlx_dma_push_to_dma(s->dmach, (void *)s->rxmem, size, app); > + axi_stream_push(s->tx_dev, (void *)s->rxmem, size, app); > > s->regs[R_IS] |= IS_RX_COMPLETE; > enet_update_irq(s); > @@ -789,9 +789,9 @@ static void eth_cleanup(NetClientState *nc) > } > > static void > -axienet_stream_push(void *opaque, uint8_t *buf, size_t size, uint32_t *hdr) > +axienet_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t > *hdr) > { > - struct XilinxAXIEnet *s = opaque; > + struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj)); > > /* TX enable ? */ > if (!(s->tc & TC_TX)) { > @@ -845,12 +845,6 @@ static int xilinx_enet_init(SysBusDevice *dev) > > sysbus_init_irq(dev, &s->irq); > > - if (!s->dmach) { > - hw_error("Unconnected Xilinx Ethernet MAC.\n"); > - } > - > - xlx_dma_connect_client(s->dmach, s, axienet_stream_push); > - > memory_region_init_io(&s->iomem, &enet_ops, s, "enet", 0x40000); > sysbus_init_mmio(dev, &s->iomem); > > @@ -870,11 +864,18 @@ static int xilinx_enet_init(SysBusDevice *dev) > return 0; > } > > +static void xilinx_enet_initfn(Object *obj) > +{ > + struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj)); > + > + object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE, > + (Object **) &s->tx_dev, NULL); > +} > + > static Property xilinx_enet_properties[] = { > DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7), > DEFINE_PROP_UINT32("rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000), > DEFINE_PROP_UINT32("txmem", struct XilinxAXIEnet, c_txmem, 0x1000), > - DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach), > DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf), > DEFINE_PROP_END_OF_LIST(), > }; > @@ -883,9 +884,11 @@ static void xilinx_enet_class_init(ObjectClass *klass, > void *data) > { > DeviceClass *dc = DEVICE_CLASS(klass); > SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); > + StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass); > > k->init = xilinx_enet_init; > dc->props = xilinx_enet_properties; > + ssc->push = axienet_stream_push; > } > > static TypeInfo xilinx_enet_info = { > @@ -893,6 +896,11 @@ static TypeInfo xilinx_enet_info = { > .parent = TYPE_SYS_BUS_DEVICE, > .instance_size = sizeof(struct XilinxAXIEnet), > .class_init = xilinx_enet_class_init, > + .instance_init = xilinx_enet_initfn, > + .interfaces = (InterfaceInfo[]) { > + { TYPE_STREAM_SLAVE }, > + { } > + } > }; > > static void xilinx_enet_register_types(void) > -- > 1.7.0.4 >