summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-05-14 15:23:35 +0100
committerPeter Maydell <peter.maydell@linaro.org>2020-05-14 15:23:35 +0100
commit0ffd3d64bd1bb8b84950e52159a0062fdab34628 (patch)
tree6c546aa031c5e4b4536494e534ff431d1d1026ab /hw
parent035b448b84f3557206abc44d786c5d3db2638f7d (diff)
parent2ead1b18ca1bbc41c09a82d980e1e5f53afa08eb (diff)
downloadqemu-0ffd3d64bd1bb8b84950e52159a0062fdab34628.zip
Merge remote-tracking branch 'remotes/edgar/tags/edgar/xilinx-next-2020-05-14.for-upstream' into staging
Upstream # gpg: Signature made Thu 14 May 2020 15:04:44 BST # gpg: using RSA key AC44FEDC14F7F1EBEDBF415129C596780F6BCA83 # gpg: Good signature from "Edgar E. Iglesias (Xilinx key) <edgar.iglesias@xilinx.com>" [unknown] # gpg: aka "Edgar E. Iglesias <edgar.iglesias@gmail.com>" [full] # Primary key fingerprint: AC44 FEDC 14F7 F1EB EDBF 4151 29C5 9678 0F6B CA83 * remotes/edgar/tags/edgar/xilinx-next-2020-05-14.for-upstream: target/microblaze: monitor: Increase the number of registers reported target/microblaze: gdb: Fix incorrect SReg reporting target/microblaze: gdb: Extend the number of registers presented to GDB target/microblaze: Fix FPU2 instruction check target/microblaze: Add MFS Rd,EDR translation MAINTAINERS: Add myself as streams maintainer hw/dma/xilinx_axidma: s2mm: Support stream fragments hw/dma/xilinx_axidma: mm2s: Stream descriptor by descriptor hw/net/xilinx_axienet: Handle fragmented packets from DMA hw/core: stream: Add an end-of-packet flag hw/dma/xilinx_axidma: Add DMA memory-region property hw/net/xilinx_axienet: Remove unncessary cast hw/net/xilinx_axienet: Cleanup stream->push assignment hw/net/xilinx_axienet: Auto-clear PHY Autoneg Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/core/stream.c4
-rw-r--r--hw/dma/xilinx_axidma.c75
-rw-r--r--hw/net/xilinx_axienet.c70
-rw-r--r--hw/ssi/xilinx_spips.c2
4 files changed, 104 insertions, 47 deletions
diff --git a/hw/core/stream.c b/hw/core/stream.c
index 39b1e595cd..a65ad1208d 100644
--- a/hw/core/stream.c
+++ b/hw/core/stream.c
@@ -3,11 +3,11 @@
#include "qemu/module.h"
size_t
-stream_push(StreamSlave *sink, uint8_t *buf, size_t len)
+stream_push(StreamSlave *sink, uint8_t *buf, size_t len, bool eop)
{
StreamSlaveClass *k = STREAM_SLAVE_GET_CLASS(sink);
- return k->push(sink, buf, len);
+ return k->push(sink, buf, len, eop);
}
bool
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
index 018f36991b..87be9cade7 100644
--- a/hw/dma/xilinx_axidma.c
+++ b/hw/dma/xilinx_axidma.c
@@ -33,6 +33,7 @@
#include "qemu/log.h"
#include "qemu/module.h"
+#include "sysemu/dma.h"
#include "hw/stream.h"
#define D(x)
@@ -103,13 +104,14 @@ enum {
};
struct Stream {
+ struct XilinxAXIDMA *dma;
ptimer_state *ptimer;
qemu_irq irq;
int nr;
+ bool sof;
struct SDesc desc;
- int pos;
unsigned int complete_cnt;
uint32_t regs[R_MAX];
uint8_t app[20];
@@ -125,6 +127,9 @@ struct XilinxAXIDMAStreamSlave {
struct XilinxAXIDMA {
SysBusDevice busdev;
MemoryRegion iomem;
+ MemoryRegion *dma_mr;
+ AddressSpace as;
+
uint32_t freqhz;
StreamSlave *tx_data_dev;
StreamSlave *tx_control_dev;
@@ -170,6 +175,7 @@ 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. */
+ s->sof = true;
}
/* Map an offset addr into a channel index. */
@@ -186,7 +192,7 @@ static void stream_desc_load(struct Stream *s, hwaddr addr)
{
struct SDesc *d = &s->desc;
- cpu_physical_memory_read(addr, d, sizeof *d);
+ address_space_read(&s->dma->as, addr, MEMTXATTRS_UNSPECIFIED, d, sizeof *d);
/* Convert from LE into host endianness. */
d->buffer_address = le64_to_cpu(d->buffer_address);
@@ -204,7 +210,8 @@ static void stream_desc_store(struct Stream *s, hwaddr addr)
d->nxtdesc = cpu_to_le64(d->nxtdesc);
d->control = cpu_to_le32(d->control);
d->status = cpu_to_le32(d->status);
- cpu_physical_memory_write(addr, d, sizeof *d);
+ address_space_write(&s->dma->as, addr, MEMTXATTRS_UNSPECIFIED,
+ d, sizeof *d);
}
static void stream_update_irq(struct Stream *s)
@@ -261,7 +268,9 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev,
StreamSlave *tx_control_dev)
{
uint32_t prev_d;
- unsigned int txlen;
+ uint32_t txlen;
+ uint64_t addr;
+ bool eop;
if (!stream_running(s) || stream_idle(s)) {
return;
@@ -276,23 +285,26 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev,
}
if (stream_desc_sof(&s->desc)) {
- s->pos = 0;
- stream_push(tx_control_dev, s->desc.app, sizeof(s->desc.app));
+ stream_push(tx_control_dev, s->desc.app, sizeof(s->desc.app), true);
}
txlen = s->desc.control & SDESC_CTRL_LEN_MASK;
- if ((txlen + s->pos) > sizeof s->txbuf) {
- hw_error("%s: too small internal txbuf! %d\n", __func__,
- txlen + s->pos);
- }
- cpu_physical_memory_read(s->desc.buffer_address,
- s->txbuf + s->pos, txlen);
- s->pos += txlen;
+ eop = stream_desc_eof(&s->desc);
+ addr = s->desc.buffer_address;
+ while (txlen) {
+ unsigned int len;
+
+ len = txlen > sizeof s->txbuf ? sizeof s->txbuf : txlen;
+ address_space_read(&s->dma->as, addr,
+ MEMTXATTRS_UNSPECIFIED,
+ s->txbuf, len);
+ stream_push(tx_data_dev, s->txbuf, len, eop && len == txlen);
+ txlen -= len;
+ addr += len;
+ }
- if (stream_desc_eof(&s->desc)) {
- stream_push(tx_data_dev, s->txbuf, s->pos);
- s->pos = 0;
+ if (eop) {
stream_complete(s);
}
@@ -311,12 +323,11 @@ static void stream_process_mem2s(struct Stream *s, StreamSlave *tx_data_dev,
}
static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf,
- size_t len)
+ size_t len, bool eop)
{
uint32_t prev_d;
unsigned int rxlen;
size_t pos = 0;
- int sof = 1;
if (!stream_running(s) || stream_idle(s)) {
return 0;
@@ -336,21 +347,22 @@ static size_t stream_process_s2mem(struct Stream *s, unsigned char *buf,
rxlen = len;
}
- cpu_physical_memory_write(s->desc.buffer_address, buf + pos, rxlen);
+ address_space_write(&s->dma->as, s->desc.buffer_address,
+ MEMTXATTRS_UNSPECIFIED, buf + pos, rxlen);
len -= rxlen;
pos += rxlen;
/* Update the descriptor. */
- if (!len) {
+ if (eop) {
stream_complete(s);
memcpy(s->desc.app, s->app, sizeof(s->desc.app));
s->desc.status |= SDESC_STATUS_EOF;
}
- s->desc.status |= sof << SDESC_STATUS_SOF_BIT;
+ s->desc.status |= s->sof << SDESC_STATUS_SOF_BIT;
s->desc.status |= SDESC_STATUS_COMPLETE;
stream_desc_store(s, s->regs[R_CURDESC]);
- sof = 0;
+ s->sof = eop;
/* Advance. */
prev_d = s->regs[R_CURDESC];
@@ -376,7 +388,7 @@ static void xilinx_axidma_reset(DeviceState *dev)
static size_t
xilinx_axidma_control_stream_push(StreamSlave *obj, unsigned char *buf,
- size_t len)
+ size_t len, bool eop)
{
XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(obj);
struct Stream *s = &cs->dma->streams[1];
@@ -408,13 +420,14 @@ xilinx_axidma_data_stream_can_push(StreamSlave *obj,
}
static size_t
-xilinx_axidma_data_stream_push(StreamSlave *obj, unsigned char *buf, size_t len)
+xilinx_axidma_data_stream_push(StreamSlave *obj, unsigned char *buf, size_t len,
+ bool eop)
{
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);
+ ret = stream_process_s2mem(s, buf, len, eop);
stream_update_irq(s);
return ret;
}
@@ -525,6 +538,7 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(
&s->rx_control_dev);
Error *local_err = NULL;
+ int i;
object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA,
(Object **)&ds->dma,
@@ -545,17 +559,19 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
goto xilinx_axidma_realize_fail;
}
- int i;
-
for (i = 0; i < 2; i++) {
struct Stream *st = &s->streams[i];
+ st->dma = s;
st->nr = i;
st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_DEFAULT);
ptimer_transaction_begin(st->ptimer);
ptimer_set_freq(st->ptimer, s->freqhz);
ptimer_transaction_commit(st->ptimer);
}
+
+ address_space_init(&s->as,
+ s->dma_mr ? s->dma_mr : get_system_memory(), "dma");
return;
xilinx_axidma_realize_fail:
@@ -575,6 +591,11 @@ static void xilinx_axidma_init(Object *obj)
&s->rx_control_dev, sizeof(s->rx_control_dev),
TYPE_XILINX_AXI_DMA_CONTROL_STREAM, &error_abort,
NULL);
+ object_property_add_link(obj, "dma", TYPE_MEMORY_REGION,
+ (Object **)&s->dma_mr,
+ qdev_prop_allow_set_link_before_realize,
+ OBJ_PROP_LINK_STRONG,
+ &error_abort);
sysbus_init_irq(sbd, &s->streams[0].irq);
sysbus_init_irq(sbd, &s->streams[1].irq);
diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c
index 704788811a..498afe2f54 100644
--- a/hw/net/xilinx_axienet.c
+++ b/hw/net/xilinx_axienet.c
@@ -149,8 +149,8 @@ tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
break;
}
- /* Unconditionally clear regs[BMCR][BMCR_RESET] */
- phy->regs[0] &= ~0x8000;
+ /* Unconditionally clear regs[BMCR][BMCR_RESET] and auto-neg */
+ phy->regs[0] &= ~0x8200;
}
static void
@@ -402,6 +402,9 @@ struct XilinxAXIEnet {
uint32_t hdr[CONTROL_PAYLOAD_WORDS];
+ uint8_t *txmem;
+ uint32_t txpos;
+
uint8_t *rxmem;
uint32_t rxsize;
uint32_t rxpos;
@@ -421,6 +424,7 @@ static void axienet_rx_reset(XilinxAXIEnet *s)
static void axienet_tx_reset(XilinxAXIEnet *s)
{
s->tc = TC_JUM | TC_TX | TC_VLAN;
+ s->txpos = 0;
}
static inline int axienet_rx_resetting(XilinxAXIEnet *s)
@@ -697,14 +701,14 @@ static void axienet_eth_rx_notify(void *opaque)
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, s->rxappsize, true);
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, true);
s->rxsize -= ret;
s->rxpos += ret;
if (!s->rxsize) {
@@ -874,12 +878,14 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
}
static size_t
-xilinx_axienet_control_stream_push(StreamSlave *obj, uint8_t *buf, size_t len)
+xilinx_axienet_control_stream_push(StreamSlave *obj, uint8_t *buf, size_t len,
+ bool eop)
{
int i;
XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM(obj);
XilinxAXIEnet *s = cs->enet;
+ assert(eop);
if (len != CONTROL_PAYLOAD_SIZE) {
hw_error("AXI Enet requires %d byte control stream payload\n",
(int)CONTROL_PAYLOAD_SIZE);
@@ -894,7 +900,8 @@ xilinx_axienet_control_stream_push(StreamSlave *obj, uint8_t *buf, size_t len)
}
static size_t
-xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size)
+xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size,
+ bool eop)
{
XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(obj);
XilinxAXIEnet *s = ds->enet;
@@ -904,9 +911,30 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size)
return size;
}
+ if (s->txpos + size > s->c_txmem) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Packet larger than txmem\n",
+ TYPE_XILINX_AXI_ENET);
+ s->txpos = 0;
+ return size;
+ }
+
+ if (s->txpos == 0 && eop) {
+ /* Fast path single fragment. */
+ s->txpos = size;
+ } else {
+ memcpy(s->txmem + s->txpos, buf, size);
+ buf = s->txmem;
+ s->txpos += size;
+
+ if (!eop) {
+ return size;
+ }
+ }
+
/* Jumbo or vlan sizes ? */
if (!(s->tc & TC_JUM)) {
- if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) {
+ if (s->txpos > 1518 && s->txpos <= 1522 && !(s->tc & TC_VLAN)) {
+ s->txpos = 0;
return size;
}
}
@@ -917,8 +945,8 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size)
uint32_t tmp_csum;
uint16_t csum;
- tmp_csum = net_checksum_add(size - start_off,
- (uint8_t *)buf + start_off);
+ tmp_csum = net_checksum_add(s->txpos - start_off,
+ buf + start_off);
/* Accumulate the seed. */
tmp_csum += s->hdr[2] & 0xffff;
@@ -930,12 +958,13 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size)
buf[write_off + 1] = csum & 0xff;
}
- qemu_send_packet(qemu_get_queue(s->nic), buf, size);
+ qemu_send_packet(qemu_get_queue(s->nic), buf, s->txpos);
- s->stats.tx_bytes += size;
+ s->stats.tx_bytes += s->txpos;
s->regs[R_IS] |= IS_TX_COMPLETE;
enet_update_irq(s);
+ s->txpos = 0;
return size;
}
@@ -983,6 +1012,7 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp)
s->TEMAC.parent = s;
s->rxmem = g_malloc(s->c_rxmem);
+ s->txmem = g_malloc(s->c_txmem);
return;
xilinx_enet_realize_fail:
@@ -1029,11 +1059,19 @@ static void xilinx_enet_class_init(ObjectClass *klass, void *data)
dc->reset = xilinx_axienet_reset;
}
-static void xilinx_enet_stream_class_init(ObjectClass *klass, void *data)
+static void xilinx_enet_control_stream_class_init(ObjectClass *klass,
+ void *data)
+{
+ StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
+
+ ssc->push = xilinx_axienet_control_stream_push;
+}
+
+static void xilinx_enet_data_stream_class_init(ObjectClass *klass, void *data)
{
StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
- ssc->push = data;
+ ssc->push = xilinx_axienet_data_stream_push;
}
static const TypeInfo xilinx_enet_info = {
@@ -1048,8 +1086,7 @@ 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,
+ .class_init = xilinx_enet_data_stream_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_STREAM_SLAVE },
{ }
@@ -1060,8 +1097,7 @@ 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,
+ .class_init = xilinx_enet_control_stream_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_STREAM_SLAVE },
{ }
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
index c57850a505..4cfce882ab 100644
--- a/hw/ssi/xilinx_spips.c
+++ b/hw/ssi/xilinx_spips.c
@@ -868,7 +868,7 @@ static void xlnx_zynqmp_qspips_notify(void *opaque)
memcpy(rq->dma_buf, rxd, num);
- ret = stream_push(rq->dma, rq->dma_buf, num);
+ ret = stream_push(rq->dma, rq->dma_buf, num, false);
assert(ret == num);
xlnx_zynqmp_qspips_check_flush(rq);
}