aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/block/m25p80.c52
-rw-r--r--hw/core/stream.c15
-rw-r--r--hw/dma/xilinx_axidma.c261
-rw-r--r--hw/microblaze/petalogix_ml605_mmu.c28
-rw-r--r--hw/net/xilinx_axienet.c255
5 files changed, 468 insertions, 143 deletions
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 55e9d0d37a..efcc7f4c83 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -26,15 +26,17 @@
#include "hw/ssi.h"
#include "hw/devices.h"
-#ifdef M25P80_ERR_DEBUG
-#define DB_PRINT(...) do { \
- fprintf(stderr, ": %s: ", __func__); \
- fprintf(stderr, ## __VA_ARGS__); \
- } while (0);
-#else
- #define DB_PRINT(...)
+#ifndef M25P80_ERR_DEBUG
+#define M25P80_ERR_DEBUG 0
#endif
+#define DB_PRINT_L(level, ...) do { \
+ if (M25P80_ERR_DEBUG > (level)) { \
+ fprintf(stderr, ": %s: ", __func__); \
+ fprintf(stderr, ## __VA_ARGS__); \
+ } \
+} while (0);
+
/* Fields for FlashPartInfo->flags */
/* erase capabilities */
@@ -317,13 +319,14 @@ static void flash_erase(Flash *s, int offset, FlashCMD cmd)
abort();
}
- DB_PRINT("offset = %#x, len = %d\n", offset, len);
+ DB_PRINT_L(0, "offset = %#x, len = %d\n", offset, len);
if ((s->pi->flags & capa_to_assert) != capa_to_assert) {
- hw_error("m25p80: %dk erase size not supported by device\n", len);
+ qemu_log_mask(LOG_GUEST_ERROR, "M25P80: %d erase size not supported by"
+ " device\n", len);
}
if (!s->write_enable) {
- DB_PRINT("erase with write protect!\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "M25P80: erase with write protect!\n");
return;
}
memset(s->storage + offset, 0xff, len);
@@ -345,12 +348,12 @@ void flash_write8(Flash *s, uint64_t addr, uint8_t data)
uint8_t prev = s->storage[s->cur_addr];
if (!s->write_enable) {
- DB_PRINT("write with write protect!\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "M25P80: write with write protect!\n");
}
if ((prev ^ data) & data) {
- DB_PRINT("programming zero to one! addr=%lx %x -> %x\n",
- addr, prev, data);
+ DB_PRINT_L(1, "programming zero to one! addr=%" PRIx64 " %" PRIx8
+ " -> %" PRIx8 "\n", addr, prev, data);
}
if (s->pi->flags & WR_1) {
@@ -403,7 +406,7 @@ static void complete_collecting_data(Flash *s)
static void decode_new_cmd(Flash *s, uint32_t value)
{
s->cmd_in_progress = value;
- DB_PRINT("decoded new command:%x\n", value);
+ DB_PRINT_L(0, "decoded new command:%x\n", value);
switch (value) {
@@ -483,7 +486,7 @@ static void decode_new_cmd(Flash *s, uint32_t value)
break;
case JEDEC_READ:
- DB_PRINT("populated jedec code\n");
+ DB_PRINT_L(0, "populated jedec code\n");
s->data[0] = (s->pi->jedec >> 16) & 0xff;
s->data[1] = (s->pi->jedec >> 8) & 0xff;
s->data[2] = s->pi->jedec & 0xff;
@@ -500,16 +503,17 @@ static void decode_new_cmd(Flash *s, uint32_t value)
case BULK_ERASE:
if (s->write_enable) {
- DB_PRINT("chip erase\n");
+ DB_PRINT_L(0, "chip erase\n");
flash_erase(s, 0, BULK_ERASE);
} else {
- DB_PRINT("chip erase with write protect!\n");
+ qemu_log_mask(LOG_GUEST_ERROR, "M25P80: chip erase with write "
+ "protect!\n");
}
break;
case NOP:
break;
default:
- DB_PRINT("Unknown cmd %x\n", value);
+ qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value);
break;
}
}
@@ -525,7 +529,7 @@ static int m25p80_cs(SSISlave *ss, bool select)
flash_sync_dirty(s, -1);
}
- DB_PRINT("%sselect\n", select ? "de" : "");
+ DB_PRINT_L(0, "%sselect\n", select ? "de" : "");
return 0;
}
@@ -538,15 +542,16 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
switch (s->state) {
case STATE_PAGE_PROGRAM:
- DB_PRINT("page program cur_addr=%lx data=%x\n", s->cur_addr,
- (uint8_t)tx);
+ DB_PRINT_L(1, "page program cur_addr=%#" PRIx64 " data=%" PRIx8 "\n",
+ s->cur_addr, (uint8_t)tx);
flash_write8(s, s->cur_addr, (uint8_t)tx);
s->cur_addr++;
break;
case STATE_READ:
r = s->storage[s->cur_addr];
- DB_PRINT("READ 0x%lx=%x\n", s->cur_addr, r);
+ DB_PRINT_L(1, "READ 0x%" PRIx64 "=%" PRIx8 "\n", s->cur_addr,
+ (uint8_t)r);
s->cur_addr = (s->cur_addr + 1) % s->size;
break;
@@ -592,7 +597,7 @@ static int m25p80_init(SSISlave *ss)
dinfo = drive_get_next(IF_MTD);
if (dinfo && dinfo->bdrv) {
- DB_PRINT("Binding to IF_MTD drive\n");
+ DB_PRINT_L(0, "Binding to IF_MTD drive\n");
s->bdrv = dinfo->bdrv;
/* FIXME: Move to late init */
if (bdrv_read(s->bdrv, 0, s->storage, DIV_ROUND_UP(s->size,
@@ -601,6 +606,7 @@ static int m25p80_init(SSISlave *ss)
return 1;
}
} else {
+ DB_PRINT_L(0, "No BDRV - binding to RAM\n");
memset(s->storage, 0xFF, s->size);
}
diff --git a/hw/core/stream.c b/hw/core/stream.c
index a07d6a56d3..e6a05a543e 100644
--- a/hw/core/stream.c
+++ b/hw/core/stream.c
@@ -1,11 +1,20 @@
#include "hw/stream.h"
-void
-stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app)
+size_t
+stream_push(StreamSlave *sink, uint8_t *buf, size_t len)
{
StreamSlaveClass *k = STREAM_SLAVE_GET_CLASS(sink);
- k->push(sink, buf, len, app);
+ return k->push(sink, buf, len);
+}
+
+bool
+stream_can_push(StreamSlave *sink, StreamCanPushNotifyFn notify,
+ void *notify_opaque)
+{
+ StreamSlaveClass *k = STREAM_SLAVE_GET_CLASS(sink);
+
+ return k->can_push ? k->can_push(sink, notify, notify_opaque) : true;
}
static const TypeInfo stream_slave_info = {
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
index 8db1a74acf..1c23762210 100644
--- a/hw/dma/xilinx_axidma.c
+++ b/hw/dma/xilinx_axidma.c
@@ -27,17 +27,39 @@
#include "hw/ptimer.h"
#include "qemu/log.h"
#include "hw/qdev-addr.h"
+#include "qapi/qmp/qerror.h"
#include "hw/stream.h"
#define D(x)
+#define TYPE_XILINX_AXI_DMA "xlnx.axi-dma"
+#define TYPE_XILINX_AXI_DMA_DATA_STREAM "xilinx-axi-dma-data-stream"
+#define TYPE_XILINX_AXI_DMA_CONTROL_STREAM "xilinx-axi-dma-control-stream"
+
+#define XILINX_AXI_DMA(obj) \
+ OBJECT_CHECK(XilinxAXIDMA, (obj), TYPE_XILINX_AXI_DMA)
+
+#define XILINX_AXI_DMA_DATA_STREAM(obj) \
+ OBJECT_CHECK(XilinxAXIDMAStreamSlave, (obj),\
+ TYPE_XILINX_AXI_DMA_DATA_STREAM)
+
+#define XILINX_AXI_DMA_CONTROL_STREAM(obj) \
+ OBJECT_CHECK(XilinxAXIDMAStreamSlave, (obj),\
+ TYPE_XILINX_AXI_DMA_CONTROL_STREAM)
+
#define R_DMACR (0x00 / 4)
#define R_DMASR (0x04 / 4)
#define R_CURDESC (0x08 / 4)
#define R_TAILDESC (0x10 / 4)
#define R_MAX (0x30 / 4)
+#define CONTROL_PAYLOAD_WORDS 5
+#define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t)))
+
+typedef struct XilinxAXIDMA XilinxAXIDMA;
+typedef struct XilinxAXIDMAStreamSlave XilinxAXIDMAStreamSlave;
+
enum {
DMACR_RUNSTOP = 1,
DMACR_TAILPTR_MODE = 2,
@@ -59,7 +81,7 @@ struct SDesc {
uint64_t reserved;
uint32_t control;
uint32_t status;
- uint32_t app[6];
+ uint8_t app[CONTROL_PAYLOAD_SIZE];
};
enum {
@@ -87,15 +109,28 @@ struct Stream {
int pos;
unsigned int complete_cnt;
uint32_t regs[R_MAX];
+ uint8_t app[20];
+};
+
+struct XilinxAXIDMAStreamSlave {
+ Object parent;
+
+ struct XilinxAXIDMA *dma;
};
struct XilinxAXIDMA {
SysBusDevice busdev;
MemoryRegion iomem;
uint32_t freqhz;
- StreamSlave *tx_dev;
+ StreamSlave *tx_data_dev;
+ StreamSlave *tx_control_dev;
+ XilinxAXIDMAStreamSlave rx_data_dev;
+ XilinxAXIDMAStreamSlave rx_control_dev;
struct Stream streams[2];
+
+ StreamCanPushNotifyFn notify;
+ void *notify_opaque;
};
/*
@@ -161,7 +196,6 @@ static void stream_desc_show(struct SDesc *d)
static void stream_desc_load(struct Stream *s, hwaddr addr)
{
struct SDesc *d = &s->desc;
- int i;
cpu_physical_memory_read(addr, (void *) d, sizeof *d);
@@ -170,24 +204,17 @@ static void stream_desc_load(struct Stream *s, hwaddr addr)
d->nxtdesc = le64_to_cpu(d->nxtdesc);
d->control = le32_to_cpu(d->control);
d->status = le32_to_cpu(d->status);
- for (i = 0; i < ARRAY_SIZE(d->app); i++) {
- d->app[i] = le32_to_cpu(d->app[i]);
- }
}
static void stream_desc_store(struct Stream *s, hwaddr addr)
{
struct SDesc *d = &s->desc;
- int i;
/* Convert from host endianness into LE. */
d->buffer_address = cpu_to_le64(d->buffer_address);
d->nxtdesc = cpu_to_le64(d->nxtdesc);
d->control = cpu_to_le32(d->control);
d->status = cpu_to_le32(d->status);
- for (i = 0; i < ARRAY_SIZE(d->app); i++) {
- d->app[i] = cpu_to_le32(d->app[i]);
- }
cpu_physical_memory_write(addr, (void *) d, sizeof *d);
}
@@ -239,13 +266,12 @@ static void stream_complete(struct Stream *s)
}
}
-static void stream_process_mem2s(struct Stream *s,
- StreamSlave *tx_dev)
+static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev,
+ StreamSlave *tx_control_dev)
{
uint32_t prev_d;
unsigned char txbuf[16 * 1024];
unsigned int txlen;
- uint32_t app[6];
if (!stream_running(s) || stream_idle(s)) {
return;
@@ -255,13 +281,13 @@ static void stream_process_mem2s(struct Stream *s,
stream_desc_load(s, s->regs[R_CURDESC]);
if (s->desc.status & SDESC_STATUS_COMPLETE) {
- s->regs[R_DMASR] |= DMASR_IDLE;
+ s->regs[R_DMASR] |= DMASR_HALTED;
break;
}
if (stream_desc_sof(&s->desc)) {
s->pos = 0;
- memcpy(app, s->desc.app, sizeof app);
+ stream_push(tx_control_dev, s->desc.app, sizeof(s->desc.app));
}
txlen = s->desc.control & SDESC_CTRL_LEN_MASK;
@@ -275,7 +301,7 @@ static void stream_process_mem2s(struct Stream *s,
s->pos += txlen;
if (stream_desc_eof(&s->desc)) {
- stream_push(tx_dev, txbuf, s->pos, app);
+ stream_push(tx_data_dev, txbuf, s->pos);
s->pos = 0;
stream_complete(s);
}
@@ -294,23 +320,23 @@ static void stream_process_mem2s(struct Stream *s,
}
}
-static void stream_process_s2mem(struct Stream *s,
- unsigned char *buf, size_t len, uint32_t *app)
+static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf,
+ size_t len)
{
uint32_t prev_d;
unsigned int rxlen;
- int pos = 0;
+ size_t pos = 0;
int sof = 1;
if (!stream_running(s) || stream_idle(s)) {
- return;
+ return 0;
}
while (len) {
stream_desc_load(s, s->regs[R_CURDESC]);
if (s->desc.status & SDESC_STATUS_COMPLETE) {
- s->regs[R_DMASR] |= DMASR_IDLE;
+ s->regs[R_DMASR] |= DMASR_HALTED;
break;
}
@@ -326,12 +352,8 @@ static void stream_process_s2mem(struct Stream *s,
/* Update the descriptor. */
if (!len) {
- int i;
-
stream_complete(s);
- for (i = 0; i < 5; i++) {
- s->desc.app[i] = app[i];
- }
+ memcpy(s->desc.app, s->app, sizeof(s->desc.app));
s->desc.status |= SDESC_STATUS_EOF;
}
@@ -348,25 +370,69 @@ static void stream_process_s2mem(struct Stream *s,
break;
}
}
+
+ return pos;
+}
+
+static void xilinx_axidma_reset(DeviceState *dev)
+{
+ int i;
+ XilinxAXIDMA *s = XILINX_AXI_DMA(dev);
+
+ for (i = 0; i < 2; i++) {
+ stream_reset(&s->streams[i]);
+ }
}
-static void
-axidma_push(StreamSlave *obj, unsigned char *buf, size_t len, uint32_t *app)
+static size_t
+xilinx_axidma_control_stream_push(StreamSlave *obj, unsigned char *buf,
+ size_t len)
{
- struct XilinxAXIDMA *d = FROM_SYSBUS(typeof(*d), SYS_BUS_DEVICE(obj));
- struct Stream *s = &d->streams[1];
+ XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(obj);
+ struct Stream *s = &cs->dma->streams[1];
- if (!app) {
- hw_error("No stream app data!\n");
+ if (len != CONTROL_PAYLOAD_SIZE) {
+ hw_error("AXI DMA requires %d byte control stream payload\n",
+ (int)CONTROL_PAYLOAD_SIZE);
}
- stream_process_s2mem(s, buf, len, app);
+
+ memcpy(s->app, buf, len);
+ return len;
+}
+
+static bool
+xilinx_axidma_data_stream_can_push(StreamSlave *obj,
+ StreamCanPushNotifyFn notify,
+ void *notify_opaque)
+{
+ XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(obj);
+ struct Stream *s = &ds->dma->streams[1];
+
+ if (!stream_running(s) || stream_idle(s)) {
+ ds->dma->notify = notify;
+ ds->dma->notify_opaque = notify_opaque;
+ return false;
+ }
+
+ return true;
+}
+
+static size_t
+xilinx_axidma_data_stream_push(StreamSlave *obj, unsigned char *buf, size_t len)
+{
+ XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(obj);
+ struct Stream *s = &ds->dma->streams[1];
+ size_t ret;
+
+ ret = stream_process_s2mem(s, buf, len);
stream_update_irq(s);
+ return ret;
}
static uint64_t axidma_read(void *opaque, hwaddr addr,
unsigned size)
{
- struct XilinxAXIDMA *d = opaque;
+ XilinxAXIDMA *d = opaque;
struct Stream *s;
uint32_t r = 0;
int sid;
@@ -401,7 +467,7 @@ static uint64_t axidma_read(void *opaque, hwaddr addr,
static void axidma_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
- struct XilinxAXIDMA *d = opaque;
+ XilinxAXIDMA *d = opaque;
struct Stream *s;
int sid;
@@ -439,7 +505,7 @@ static void axidma_write(void *opaque, hwaddr addr,
s->regs[addr] = value;
s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle. */
if (!sid) {
- stream_process_mem2s(s, d->tx_dev);
+ stream_process_mem2s(s, d->tx_data_dev, d->tx_control_dev);
}
break;
default:
@@ -448,6 +514,10 @@ static void axidma_write(void *opaque, hwaddr addr,
s->regs[addr] = value;
break;
}
+ if (sid == 1 && d->notify) {
+ d->notify(d->notify_opaque);
+ d->notify = NULL;
+ }
stream_update_irq(s);
}
@@ -457,58 +527,131 @@ static const MemoryRegionOps axidma_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int xilinx_axidma_init(SysBusDevice *dev)
+static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
{
- struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), dev);
- int i;
-
- sysbus_init_irq(dev, &s->streams[0].irq);
- sysbus_init_irq(dev, &s->streams[1].irq);
+ XilinxAXIDMA *s = XILINX_AXI_DMA(dev);
+ XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(&s->rx_data_dev);
+ XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(
+ &s->rx_control_dev);
+ Error *local_errp = NULL;
+
+ object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA,
+ (Object **)&ds->dma, &local_errp);
+ object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA,
+ (Object **)&cs->dma, &local_errp);
+ if (local_errp) {
+ goto xilinx_axidma_realize_fail;
+ }
+ object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_errp);
+ object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_errp);
+ if (local_errp) {
+ goto xilinx_axidma_realize_fail;
+ }
- memory_region_init_io(&s->iomem, &axidma_ops, s,
- "xlnx.axi-dma", R_MAX * 4 * 2);
- sysbus_init_mmio(dev, &s->iomem);
+ int i;
for (i = 0; i < 2; i++) {
- stream_reset(&s->streams[i]);
s->streams[i].nr = i;
s->streams[i].bh = qemu_bh_new(timer_hit, &s->streams[i]);
s->streams[i].ptimer = ptimer_init(s->streams[i].bh);
ptimer_set_freq(s->streams[i].ptimer, s->freqhz);
}
- return 0;
+ return;
+
+xilinx_axidma_realize_fail:
+ if (!*errp) {
+ *errp = local_errp;
+ }
}
-static void xilinx_axidma_initfn(Object *obj)
+static void xilinx_axidma_init(Object *obj)
{
- struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+ XilinxAXIDMA *s = XILINX_AXI_DMA(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ Error *errp = NULL;
object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
- (Object **) &s->tx_dev, NULL);
+ (Object **) &s->tx_data_dev, &errp);
+ assert_no_error(errp);
+ object_property_add_link(obj, "axistream-control-connected",
+ TYPE_STREAM_SLAVE,
+ (Object **) &s->tx_control_dev, &errp);
+ assert_no_error(errp);
+
+ object_initialize(&s->rx_data_dev, TYPE_XILINX_AXI_DMA_DATA_STREAM);
+ object_initialize(&s->rx_control_dev, TYPE_XILINX_AXI_DMA_CONTROL_STREAM);
+ object_property_add_child(OBJECT(s), "axistream-connected-target",
+ (Object *)&s->rx_data_dev, &errp);
+ assert_no_error(errp);
+ object_property_add_child(OBJECT(s), "axistream-control-connected-target",
+ (Object *)&s->rx_control_dev, &errp);
+ assert_no_error(errp);
+
+ sysbus_init_irq(sbd, &s->streams[0].irq);
+ sysbus_init_irq(sbd, &s->streams[1].irq);
+
+ memory_region_init_io(&s->iomem, &axidma_ops, s,
+ "xlnx.axi-dma", R_MAX * 4 * 2);
+ sysbus_init_mmio(sbd, &s->iomem);
}
static Property axidma_properties[] = {
- DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
+ DEFINE_PROP_UINT32("freqhz", XilinxAXIDMA, freqhz, 50000000),
DEFINE_PROP_END_OF_LIST(),
};
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->realize = xilinx_axidma_realize,
+ dc->reset = xilinx_axidma_reset;
dc->props = axidma_properties;
- ssc->push = axidma_push;
+}
+
+static StreamSlaveClass xilinx_axidma_data_stream_class = {
+ .push = xilinx_axidma_data_stream_push,
+ .can_push = xilinx_axidma_data_stream_can_push,
+};
+
+static StreamSlaveClass xilinx_axidma_control_stream_class = {
+ .push = xilinx_axidma_control_stream_push,
+};
+
+static void xilinx_axidma_stream_class_init(ObjectClass *klass, void *data)
+{
+ StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
+
+ ssc->push = ((StreamSlaveClass *)data)->push;
+ ssc->can_push = ((StreamSlaveClass *)data)->can_push;
}
static const TypeInfo axidma_info = {
- .name = "xlnx.axi-dma",
+ .name = TYPE_XILINX_AXI_DMA,
.parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct XilinxAXIDMA),
+ .instance_size = sizeof(XilinxAXIDMA),
.class_init = axidma_class_init,
- .instance_init = xilinx_axidma_initfn,
+ .instance_init = xilinx_axidma_init,
+};
+
+static const TypeInfo xilinx_axidma_data_stream_info = {
+ .name = TYPE_XILINX_AXI_DMA_DATA_STREAM,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(struct XilinxAXIDMAStreamSlave),
+ .class_init = xilinx_axidma_stream_class_init,
+ .class_data = &xilinx_axidma_data_stream_class,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_STREAM_SLAVE },
+ { }
+ }
+};
+
+static const TypeInfo xilinx_axidma_control_stream_info = {
+ .name = TYPE_XILINX_AXI_DMA_CONTROL_STREAM,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(struct XilinxAXIDMAStreamSlave),
+ .class_init = xilinx_axidma_stream_class_init,
+ .class_data = &xilinx_axidma_control_stream_class,
.interfaces = (InterfaceInfo[]) {
{ TYPE_STREAM_SLAVE },
{ }
@@ -518,6 +661,8 @@ static const TypeInfo axidma_info = {
static void xilinx_axidma_register_types(void)
{
type_register_static(&axidma_info);
+ type_register_static(&xilinx_axidma_data_stream_info);
+ type_register_static(&xilinx_axidma_control_stream_info);
}
type_init(xilinx_axidma_register_types)
diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c
index ae7ff44423..334046808f 100644
--- a/hw/microblaze/petalogix_ml605_mmu.c
+++ b/hw/microblaze/petalogix_ml605_mmu.c
@@ -79,6 +79,7 @@ petalogix_ml605_init(QEMUMachineInitArgs *args)
const char *cpu_model = args->cpu_model;
MemoryRegion *address_space_mem = get_system_memory();
DeviceState *dev, *dma, *eth0;
+ Object *ds, *cs;
MicroBlazeCPU *cpu;
SysBusDevice *busdev;
CPUMBState *env;
@@ -134,14 +135,25 @@ petalogix_ml605_init(QEMUMachineInitArgs *args)
dma = qdev_create(NULL, "xlnx.axi-dma");
/* FIXME: attach to the sysbus instead */
- object_property_add_child(container_get(qdev_get_machine(), "/unattached"),
- "xilinx-dma", OBJECT(dma), NULL);
-
- xilinx_axiethernet_init(eth0, &nd_table[0], STREAM_SLAVE(dma),
- 0x82780000, irq[3], 0x1000, 0x1000);
-
- xilinx_axidma_init(dma, STREAM_SLAVE(eth0), 0x84600000, irq[1], irq[0],
- 100 * 1000000);
+ object_property_add_child(qdev_get_machine(), "xilinx-eth", OBJECT(eth0),
+ NULL);
+ object_property_add_child(qdev_get_machine(), "xilinx-dma", OBJECT(dma),
+ NULL);
+
+ ds = object_property_get_link(OBJECT(dma),
+ "axistream-connected-target", NULL);
+ cs = object_property_get_link(OBJECT(dma),
+ "axistream-control-connected-target", NULL);
+ xilinx_axiethernet_init(eth0, &nd_table[0], STREAM_SLAVE(ds),
+ STREAM_SLAVE(cs), 0x82780000, irq[3], 0x1000,
+ 0x1000);
+
+ ds = object_property_get_link(OBJECT(eth0),
+ "axistream-connected-target", NULL);
+ cs = object_property_get_link(OBJECT(eth0),
+ "axistream-control-connected-target", NULL);
+ xilinx_axidma_init(dma, STREAM_SLAVE(ds), STREAM_SLAVE(cs), 0x84600000,
+ irq[1], irq[0], 100 * 1000000);
{
SSIBus *spi;
diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c
index 07c4badd98..8989e95297 100644
--- a/hw/net/xilinx_axienet.c
+++ b/hw/net/xilinx_axienet.c
@@ -32,12 +32,30 @@
#define DPHY(x)
+#define TYPE_XILINX_AXI_ENET "xlnx.axi-ethernet"
+#define TYPE_XILINX_AXI_ENET_DATA_STREAM "xilinx-axienet-data-stream"
+#define TYPE_XILINX_AXI_ENET_CONTROL_STREAM "xilinx-axienet-control-stream"
+
+#define XILINX_AXI_ENET(obj) \
+ OBJECT_CHECK(XilinxAXIEnet, (obj), TYPE_XILINX_AXI_ENET)
+
+#define XILINX_AXI_ENET_DATA_STREAM(obj) \
+ OBJECT_CHECK(XilinxAXIEnetStreamSlave, (obj),\
+ TYPE_XILINX_AXI_ENET_DATA_STREAM)
+
+#define XILINX_AXI_ENET_CONTROL_STREAM(obj) \
+ OBJECT_CHECK(XilinxAXIEnetStreamSlave, (obj),\
+ TYPE_XILINX_AXI_ENET_CONTROL_STREAM)
+
/* Advertisement control register. */
#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
+#define CONTROL_PAYLOAD_WORDS 5
+#define CONTROL_PAYLOAD_SIZE (CONTROL_PAYLOAD_WORDS * (sizeof(uint32_t)))
+
struct PHY {
uint32_t regs[32];
@@ -306,11 +324,23 @@ struct TEMAC {
void *parent;
};
+typedef struct XilinxAXIEnetStreamSlave XilinxAXIEnetStreamSlave;
+typedef struct XilinxAXIEnet XilinxAXIEnet;
+
+struct XilinxAXIEnetStreamSlave {
+ Object parent;
+
+ struct XilinxAXIEnet *enet;
+} ;
+
struct XilinxAXIEnet {
SysBusDevice busdev;
MemoryRegion iomem;
qemu_irq irq;
- StreamSlave *tx_dev;
+ StreamSlave *tx_data_dev;
+ StreamSlave *tx_control_dev;
+ XilinxAXIEnetStreamSlave rx_data_dev;
+ XilinxAXIEnetStreamSlave rx_control_dev;
NICState *nic;
NICConf conf;
@@ -361,42 +391,50 @@ struct XilinxAXIEnet {
/* 32K x 1 lookup filter. */
uint32_t ext_mtable[1024];
+ uint32_t hdr[CONTROL_PAYLOAD_WORDS];
uint8_t *rxmem;
+ uint32_t rxsize;
+ uint32_t rxpos;
+
+ uint8_t rxapp[CONTROL_PAYLOAD_SIZE];
+ uint32_t rxappsize;
};
-static void axienet_rx_reset(struct XilinxAXIEnet *s)
+static void axienet_rx_reset(XilinxAXIEnet *s)
{
s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN;
}
-static void axienet_tx_reset(struct XilinxAXIEnet *s)
+static void axienet_tx_reset(XilinxAXIEnet *s)
{
s->tc = TC_JUM | TC_TX | TC_VLAN;
}
-static inline int axienet_rx_resetting(struct XilinxAXIEnet *s)
+static inline int axienet_rx_resetting(XilinxAXIEnet *s)
{
return s->rcw[1] & RCW1_RST;
}
-static inline int axienet_rx_enabled(struct XilinxAXIEnet *s)
+static inline int axienet_rx_enabled(XilinxAXIEnet *s)
{
return s->rcw[1] & RCW1_RX;
}
-static inline int axienet_extmcf_enabled(struct XilinxAXIEnet *s)
+static inline int axienet_extmcf_enabled(XilinxAXIEnet *s)
{
return !!(s->regs[R_RAF] & RAF_EMCF_EN);
}
-static inline int axienet_newfunc_enabled(struct XilinxAXIEnet *s)
+static inline int axienet_newfunc_enabled(XilinxAXIEnet *s)
{
return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN);
}
-static void axienet_reset(struct XilinxAXIEnet *s)
+static void xilinx_axienet_reset(DeviceState *d)
{
+ XilinxAXIEnet *s = XILINX_AXI_ENET(d);
+
axienet_rx_reset(s);
axienet_tx_reset(s);
@@ -406,7 +444,7 @@ static void axienet_reset(struct XilinxAXIEnet *s)
s->emmc = EMMC_LINKSPEED_100MB;
}
-static void enet_update_irq(struct XilinxAXIEnet *s)
+static void enet_update_irq(XilinxAXIEnet *s)
{
s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE];
qemu_set_irq(s->irq, !!s->regs[R_IP]);
@@ -414,7 +452,7 @@ static void enet_update_irq(struct XilinxAXIEnet *s)
static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size)
{
- struct XilinxAXIEnet *s = opaque;
+ XilinxAXIEnet *s = opaque;
uint32_t r = 0;
addr >>= 2;
@@ -506,7 +544,7 @@ static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size)
static void enet_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
- struct XilinxAXIEnet *s = opaque;
+ XilinxAXIEnet *s = opaque;
struct TEMAC *t = &s->TEMAC;
addr >>= 2;
@@ -620,10 +658,10 @@ static const MemoryRegionOps enet_ops = {
static int eth_can_rx(NetClientState *nc)
{
- struct XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
+ XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
/* RX enabled? */
- return !axienet_rx_resetting(s) && axienet_rx_enabled(s);
+ return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s);
}
static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1)
@@ -641,13 +679,38 @@ static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1)
return match;
}
+static void axienet_eth_rx_notify(void *opaque)
+{
+ XilinxAXIEnet *s = XILINX_AXI_ENET(opaque);
+
+ while (s->rxappsize && stream_can_push(s->tx_control_dev,
+ axienet_eth_rx_notify, s)) {
+ size_t ret = stream_push(s->tx_control_dev,
+ (void *)s->rxapp + CONTROL_PAYLOAD_SIZE
+ - s->rxappsize, s->rxappsize);
+ s->rxappsize -= ret;
+ }
+
+ while (s->rxsize && stream_can_push(s->tx_data_dev,
+ axienet_eth_rx_notify, s)) {
+ size_t ret = stream_push(s->tx_data_dev, (void *)s->rxmem + s->rxpos,
+ s->rxsize);
+ s->rxsize -= ret;
+ s->rxpos += ret;
+ if (!s->rxsize) {
+ s->regs[R_IS] |= IS_RX_COMPLETE;
+ }
+ }
+ enet_update_irq(s);
+}
+
static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
{
- struct XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
+ XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
0xff, 0xff, 0xff};
static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52};
- uint32_t app[6] = {0};
+ uint32_t app[CONTROL_PAYLOAD_WORDS] = {0};
int promisc = s->fmi & (1 << 31);
int unicast, broadcast, multicast, ip_multicast = 0;
uint32_t csum32;
@@ -778,9 +841,15 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
/* Good frame. */
app[2] |= 1 << 6;
- stream_push(s->tx_dev, (void *)s->rxmem, size, app);
+ s->rxsize = size;
+ s->rxpos = 0;
+ for (i = 0; i < ARRAY_SIZE(app); ++i) {
+ app[i] = cpu_to_le32(app[i]);
+ }
+ s->rxappsize = CONTROL_PAYLOAD_SIZE;
+ memcpy(s->rxapp, app, s->rxappsize);
+ axienet_eth_rx_notify(s);
- s->regs[R_IS] |= IS_RX_COMPLETE;
enet_update_irq(s);
return size;
}
@@ -788,38 +857,59 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
static void eth_cleanup(NetClientState *nc)
{
/* FIXME. */
- struct XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
+ XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
g_free(s->rxmem);
g_free(s);
}
-static void
-axienet_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t *hdr)
+static size_t
+xilinx_axienet_control_stream_push(StreamSlave *obj, uint8_t *buf, size_t len)
{
- struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+ int i;
+ XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM(obj);
+ XilinxAXIEnet *s = cs->enet;
+
+ if (len != CONTROL_PAYLOAD_SIZE) {
+ hw_error("AXI Enet requires %d byte control stream payload\n",
+ (int)CONTROL_PAYLOAD_SIZE);
+ }
+
+ memcpy(s->hdr, buf, len);
+
+ for (i = 0; i < ARRAY_SIZE(s->hdr); ++i) {
+ s->hdr[i] = le32_to_cpu(s->hdr[i]);
+ }
+ return len;
+}
+
+static size_t
+xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size)
+{
+ XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(obj);
+ XilinxAXIEnet *s = ds->enet;
/* TX enable ? */
if (!(s->tc & TC_TX)) {
- return;
+ return size;
}
/* Jumbo or vlan sizes ? */
if (!(s->tc & TC_JUM)) {
if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) {
- return;
+ return size;
}
}
- if (hdr[0] & 1) {
- unsigned int start_off = hdr[1] >> 16;
- unsigned int write_off = hdr[1] & 0xffff;
+ if (s->hdr[0] & 1) {
+ unsigned int start_off = s->hdr[1] >> 16;
+ unsigned int write_off = s->hdr[1] & 0xffff;
uint32_t tmp_csum;
uint16_t csum;
tmp_csum = net_checksum_add(size - start_off,
(uint8_t *)buf + start_off);
/* Accumulate the seed. */
- tmp_csum += hdr[2] & 0xffff;
+ tmp_csum += s->hdr[2] & 0xffff;
/* Fold the 32bit partial checksum. */
csum = net_checksum_finish(tmp_csum);
@@ -834,6 +924,8 @@ axienet_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t *hdr)
s->stats.tx_bytes += size;
s->regs[R_IS] |= IS_TX_COMPLETE;
enet_update_irq(s);
+
+ return size;
}
static NetClientInfo net_xilinx_enet_info = {
@@ -844,18 +936,30 @@ static NetClientInfo net_xilinx_enet_info = {
.cleanup = eth_cleanup,
};
-static int xilinx_enet_init(SysBusDevice *dev)
+static void xilinx_enet_realize(DeviceState *dev, Error **errp)
{
- struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), dev);
-
- sysbus_init_irq(dev, &s->irq);
-
- memory_region_init_io(&s->iomem, &enet_ops, s, "enet", 0x40000);
- sysbus_init_mmio(dev, &s->iomem);
+ XilinxAXIEnet *s = XILINX_AXI_ENET(dev);
+ XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(&s->rx_data_dev);
+ XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM(
+ &s->rx_control_dev);
+ Error *local_errp = NULL;
+
+ object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet",
+ (Object **) &ds->enet, &local_errp);
+ object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet",
+ (Object **) &cs->enet, &local_errp);
+ if (local_errp) {
+ goto xilinx_enet_realize_fail;
+ }
+ object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_errp);
+ object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_errp);
+ if (local_errp) {
+ goto xilinx_enet_realize_fail;
+ }
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->id, s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
tdk_init(&s->TEMAC.phy);
@@ -864,46 +968,93 @@ static int xilinx_enet_init(SysBusDevice *dev)
s->TEMAC.parent = s;
s->rxmem = g_malloc(s->c_rxmem);
- axienet_reset(s);
+ return;
- return 0;
+xilinx_enet_realize_fail:
+ if (!*errp) {
+ *errp = local_errp;
+ }
}
-static void xilinx_enet_initfn(Object *obj)
+static void xilinx_enet_init(Object *obj)
{
- struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+ XilinxAXIEnet *s = XILINX_AXI_ENET(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
Error *errp = NULL;
object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
- (Object **) &s->tx_dev, &errp);
+ (Object **) &s->tx_data_dev, &errp);
assert_no_error(errp);
+ object_property_add_link(obj, "axistream-control-connected",
+ TYPE_STREAM_SLAVE,
+ (Object **) &s->tx_control_dev, &errp);
+ assert_no_error(errp);
+
+ object_initialize(&s->rx_data_dev, TYPE_XILINX_AXI_ENET_DATA_STREAM);
+ object_initialize(&s->rx_control_dev, TYPE_XILINX_AXI_ENET_CONTROL_STREAM);
+ object_property_add_child(OBJECT(s), "axistream-connected-target",
+ (Object *)&s->rx_data_dev, &errp);
+ assert_no_error(errp);
+ object_property_add_child(OBJECT(s), "axistream-control-connected-target",
+ (Object *)&s->rx_control_dev, &errp);
+ assert_no_error(errp);
+
+ sysbus_init_irq(sbd, &s->irq);
+
+ memory_region_init_io(&s->iomem, &enet_ops, s, "enet", 0x40000);
+ sysbus_init_mmio(sbd, &s->iomem);
}
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_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
+ DEFINE_PROP_UINT32("phyaddr", XilinxAXIEnet, c_phyaddr, 7),
+ DEFINE_PROP_UINT32("rxmem", XilinxAXIEnet, c_rxmem, 0x1000),
+ DEFINE_PROP_UINT32("txmem", XilinxAXIEnet, c_txmem, 0x1000),
+ DEFINE_NIC_PROPERTIES(XilinxAXIEnet, conf),
DEFINE_PROP_END_OF_LIST(),
};
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->realize = xilinx_enet_realize;
dc->props = xilinx_enet_properties;
- ssc->push = axienet_stream_push;
+ dc->reset = xilinx_axienet_reset;
+}
+
+static void xilinx_enet_stream_class_init(ObjectClass *klass, void *data)
+{
+ StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
+
+ ssc->push = data;
}
static const TypeInfo xilinx_enet_info = {
- .name = "xlnx.axi-ethernet",
+ .name = TYPE_XILINX_AXI_ENET,
.parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct XilinxAXIEnet),
+ .instance_size = sizeof(XilinxAXIEnet),
.class_init = xilinx_enet_class_init,
- .instance_init = xilinx_enet_initfn,
+ .instance_init = xilinx_enet_init,
+};
+
+static const TypeInfo xilinx_enet_data_stream_info = {
+ .name = TYPE_XILINX_AXI_ENET_DATA_STREAM,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(struct XilinxAXIEnetStreamSlave),
+ .class_init = xilinx_enet_stream_class_init,
+ .class_data = xilinx_axienet_data_stream_push,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_STREAM_SLAVE },
+ { }
+ }
+};
+
+static const TypeInfo xilinx_enet_control_stream_info = {
+ .name = TYPE_XILINX_AXI_ENET_CONTROL_STREAM,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(struct XilinxAXIEnetStreamSlave),
+ .class_init = xilinx_enet_stream_class_init,
+ .class_data = xilinx_axienet_control_stream_push,
.interfaces = (InterfaceInfo[]) {
{ TYPE_STREAM_SLAVE },
{ }
@@ -913,6 +1064,8 @@ static const TypeInfo xilinx_enet_info = {
static void xilinx_enet_register_types(void)
{
type_register_static(&xilinx_enet_info);
+ type_register_static(&xilinx_enet_data_stream_info);
+ type_register_static(&xilinx_enet_control_stream_info);
}
type_init(xilinx_enet_register_types)