diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-05-14 15:23:35 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-05-14 15:23:35 +0100 |
commit | 0ffd3d64bd1bb8b84950e52159a0062fdab34628 (patch) | |
tree | 6c546aa031c5e4b4536494e534ff431d1d1026ab /hw | |
parent | 035b448b84f3557206abc44d786c5d3db2638f7d (diff) | |
parent | 2ead1b18ca1bbc41c09a82d980e1e5f53afa08eb (diff) | |
download | qemu-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.c | 4 | ||||
-rw-r--r-- | hw/dma/xilinx_axidma.c | 75 | ||||
-rw-r--r-- | hw/net/xilinx_axienet.c | 70 | ||||
-rw-r--r-- | hw/ssi/xilinx_spips.c | 2 |
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); } |