* [PATCH v3 0/8] Fix Exynos4210 DMA support
@ 2020-01-23 5:25 Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 1/8] dma/pl330: Convert to support tracing Guenter Roeck
` (8 more replies)
0 siblings, 9 replies; 14+ messages in thread
From: Guenter Roeck @ 2020-01-23 5:25 UTC (permalink / raw)
To: Peter Maydell; +Cc: Paolo Bonzini, qemu-arm, qemu-devel, Guenter Roeck
Commit 59520dc65e ("hw/arm/exynos4210: Add DMA support for the Exynos4210")
introduced DMA support for Exynos4210. Unfortunately, it never really
worked. DMA interrupt line and polarity was wrong, and the serial port
needs extra code to support DMA. This patch series fixes the problem.
The series also converts pl330 and exynos4210_uart code to support tracing.
While not strictly necessary, this was very useful for debugging,
and it seemed too valuable to drop it from the final series. Similar,
improved support for receive FIFO handling is not strictly necessary
to fix DMA handling, but I initially thought that it was and added the
code. Like tracing support it seemed too valuable to drop it.
The series was tested with qemu's smdkc210 and nuri emulations and with
exynos4210-smdkv310.dtb. Without the series, the emulation does not react
to serial line input, and serial line output stalls when using DMA. With
this series in place, serial line input is handled correctly, serial
output does not stall, and DMA interrupts are observed and handled.
v3: Increased number of or-irq-lines to 48 to support the full number
of lines needed. Simplifications in handling UCON register when
handling receive timeouts. Don't save timer state in VMSTATE.
Added Reviewed-by: tags as received.
v2: Addressed all feedback comments but one (see last patch of series).
Please see individual patches for details.
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 1/8] dma/pl330: Convert to support tracing
2020-01-23 5:25 [PATCH v3 0/8] Fix Exynos4210 DMA support Guenter Roeck
@ 2020-01-23 5:25 ` Guenter Roeck
2020-01-23 15:51 ` Peter Maydell
2020-01-23 5:25 ` [PATCH v3 2/8] hw/core/or-irq: Increase limit of or-lines to 48 Guenter Roeck
` (7 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Guenter Roeck @ 2020-01-23 5:25 UTC (permalink / raw)
To: Peter Maydell; +Cc: Paolo Bonzini, qemu-arm, qemu-devel, Guenter Roeck
Replace debug logging code with tracing.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
v3: Added Reviewed-by: tag
v2: Make call to pl330_hexdump() conditional
hw/dma/pl330.c | 88 ++++++++++++++++++++++++---------------------
hw/dma/trace-events | 24 +++++++++++++
2 files changed, 72 insertions(+), 40 deletions(-)
diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c
index f2bb2d9ac1..64519971ef 100644
--- a/hw/dma/pl330.c
+++ b/hw/dma/pl330.c
@@ -25,19 +25,12 @@
#include "sysemu/dma.h"
#include "qemu/log.h"
#include "qemu/module.h"
+#include "trace.h"
#ifndef PL330_ERR_DEBUG
#define PL330_ERR_DEBUG 0
#endif
-#define DB_PRINT_L(lvl, fmt, args...) do {\
- if (PL330_ERR_DEBUG >= lvl) {\
- fprintf(stderr, "PL330: %s:" fmt, __func__, ## args);\
- } \
-} while (0)
-
-#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
-
#define PL330_PERIPH_NUM 32
#define PL330_MAX_BURST_LEN 128
#define PL330_INSN_MAXSIZE 6
@@ -319,6 +312,26 @@ typedef struct PL330InsnDesc {
void (*exec)(PL330Chan *, uint8_t opcode, uint8_t *args, int len);
} PL330InsnDesc;
+static void pl330_hexdump(uint8_t *buf, size_t size)
+{
+ unsigned int b, i, len;
+ char tmpbuf[80];
+
+ for (b = 0; b < size; b += 16) {
+ len = size - b;
+ if (len > 16) {
+ len = 16;
+ }
+ tmpbuf[0] = '\0';
+ for (i = 0; i < len; i++) {
+ if ((i % 4) == 0) {
+ strcat(tmpbuf, " ");
+ }
+ sprintf(tmpbuf + strlen(tmpbuf), " %02x", buf[b + i]);
+ }
+ trace_pl330_hexdump(b, tmpbuf);
+ }
+}
/* MFIFO Implementation
*
@@ -582,7 +595,7 @@ static inline void pl330_queue_remove_tagged(PL330Queue *s, uint8_t tag)
static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
{
- DB_PRINT("ch: %p, flags: %" PRIx32 "\n", ch, flags);
+ trace_pl330_fault(ch, flags);
ch->fault_type |= flags;
if (ch->state == pl330_chan_fault) {
return;
@@ -590,7 +603,7 @@ static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
ch->state = pl330_chan_fault;
ch->parent->num_faulting++;
if (ch->parent->num_faulting == 1) {
- DB_PRINT("abort interrupt raised\n");
+ trace_pl330_fault_abort();
qemu_irq_raise(ch->parent->irq_abort);
}
}
@@ -648,7 +661,7 @@ static void pl330_dmaend(PL330Chan *ch, uint8_t opcode,
return;
}
}
- DB_PRINT("DMA ending!\n");
+ trace_pl330_dmaend();
pl330_fifo_tagged_remove(&s->fifo, ch->tag);
pl330_queue_remove_tagged(&s->read_queue, ch->tag);
pl330_queue_remove_tagged(&s->write_queue, ch->tag);
@@ -683,7 +696,7 @@ static void pl330_dmago(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
uint32_t pc;
PL330Chan *s;
- DB_PRINT("\n");
+ trace_pl330_dmago();
if (!ch->is_manager) {
pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
@@ -740,9 +753,7 @@ static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src,
size, num, inc, 0, ch->tag);
if (!ch->stall) {
- DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32
- " num:%" PRId32 " %c\n",
- ch->tag, ch->src, size, num, inc ? 'Y' : 'N');
+ trace_pl330_dmald(ch->tag, ch->src, size, num, inc ? 'Y' : 'N');
ch->src += inc ? size * num - (ch->src & (size - 1)) : 0;
}
}
@@ -782,7 +793,7 @@ static void pl330_dmakill(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
ch->fault_type = 0;
ch->parent->num_faulting--;
if (ch->parent->num_faulting == 0) {
- DB_PRINT("abort interrupt lowered\n");
+ trace_pl330_dmakill();
qemu_irq_lower(ch->parent->irq_abort);
}
}
@@ -800,6 +811,8 @@ static void pl330_dmalpend(PL330Chan *ch, uint8_t opcode,
uint8_t bs = opcode & 3;
uint8_t lc = (opcode & 4) >> 2;
+ trace_pl330_dmalpend(nf, bs, lc, ch->lc[lc], ch->request_flag);
+
if (bs == 2) {
pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
return;
@@ -813,12 +826,12 @@ static void pl330_dmalpend(PL330Chan *ch, uint8_t opcode,
if (nf) {
ch->lc[lc]--;
}
- DB_PRINT("loop reiteration\n");
+ trace_pl330_dmalpiter();
ch->pc -= args[0];
ch->pc -= len + 1;
/* "ch->pc -= args[0] + len + 1" is incorrect when args[0] == 256 */
} else {
- DB_PRINT("loop fallthrough\n");
+ trace_pl330_dmalpfallthrough();
}
}
@@ -886,10 +899,10 @@ static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
}
if (ch->parent->inten & (1 << ev_id)) {
ch->parent->int_status |= (1 << ev_id);
- DB_PRINT("event interrupt raised %" PRId8 "\n", ev_id);
+ trace_pl330_dmasev_evirq(ev_id);
qemu_irq_raise(ch->parent->irq[ev_id]);
}
- DB_PRINT("event raised %" PRId8 "\n", ev_id);
+ trace_pl330_dmasev_event(ev_id);
ch->parent->ev_status |= (1 << ev_id);
}
@@ -914,9 +927,7 @@ static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
size, num, inc, 0, ch->tag);
if (!ch->stall) {
- DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32
- " num:%" PRId32 " %c\n",
- ch->tag, ch->dst, size, num, inc ? 'Y' : 'N');
+ trace_pl330_dmast(ch->tag, ch->dst, size, num, inc ? 'Y' : 'N');
ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0;
}
}
@@ -992,7 +1003,7 @@ static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode,
}
}
ch->parent->ev_status &= ~(1 << ev_id);
- DB_PRINT("event lowered %" PRIx8 "\n", ev_id);
+ trace_pl330_dmawfe(ev_id);
} else {
ch->stall = 1;
}
@@ -1135,7 +1146,7 @@ static int pl330_chan_exec(PL330Chan *ch)
ch->stall = 0;
insn = pl330_fetch_insn(ch);
if (!insn) {
- DB_PRINT("pl330 undefined instruction\n");
+ trace_pl330_chan_exec_undef();
pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
return 0;
}
@@ -1175,10 +1186,9 @@ static int pl330_exec_cycle(PL330Chan *channel)
int len = q->len - (q->addr & (q->len - 1));
dma_memory_read(&address_space_memory, q->addr, buf, len);
- if (PL330_ERR_DEBUG > 1) {
- DB_PRINT("PL330 read from memory @%08" PRIx32 " (size = %08x):\n",
- q->addr, len);
- qemu_hexdump((char *)buf, stderr, "", len);
+ trace_pl330_exec_cycle(q->addr, len);
+ if (trace_event_get_state_backends(TRACE_PL330_HEXDUMP)) {
+ pl330_hexdump(buf, len);
}
fifo_res = pl330_fifo_push(&s->fifo, buf, len, q->tag);
if (fifo_res == PL330_FIFO_OK) {
@@ -1207,10 +1217,9 @@ static int pl330_exec_cycle(PL330Chan *channel)
}
if (fifo_res == PL330_FIFO_OK || q->z) {
dma_memory_write(&address_space_memory, q->addr, buf, len);
- if (PL330_ERR_DEBUG > 1) {
- DB_PRINT("PL330 read from memory @%08" PRIx32
- " (size = %08x):\n", q->addr, len);
- qemu_hexdump((char *)buf, stderr, "", len);
+ trace_pl330_exec_cycle(q->addr, len);
+ if (trace_event_get_state_backends(TRACE_PL330_HEXDUMP)) {
+ pl330_hexdump(buf, len);
}
if (q->inc) {
q->addr += len;
@@ -1252,8 +1261,8 @@ static int pl330_exec_channel(PL330Chan *channel)
static inline void pl330_exec(PL330State *s)
{
- DB_PRINT("\n");
int i, insr_exec;
+ trace_pl330_exec();
do {
insr_exec = pl330_exec_channel(&s->manager);
@@ -1298,7 +1307,7 @@ static void pl330_debug_exec(PL330State *s)
args[2] = (s->dbg[1] >> 8) & 0xff;
args[3] = (s->dbg[1] >> 16) & 0xff;
args[4] = (s->dbg[1] >> 24) & 0xff;
- DB_PRINT("chan id: %" PRIx8 "\n", chan_id);
+ trace_pl330_debug_exec(chan_id);
if (s->dbg[0] & 1) {
ch = &s->chan[chan_id];
} else {
@@ -1320,6 +1329,7 @@ static void pl330_debug_exec(PL330State *s)
ch->fault_type |= PL330_FAULT_DBG_INSTR;
}
if (ch->stall) {
+ trace_pl330_debug_exec_stall();
qemu_log_mask(LOG_UNIMP, "pl330: stall of debug instruction not "
"implemented\n");
}
@@ -1334,7 +1344,7 @@ static void pl330_iomem_write(void *opaque, hwaddr offset,
PL330State *s = (PL330State *) opaque;
int i;
- DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value);
+ trace_pl330_iomem_write((unsigned)offset, (unsigned)value);
switch (offset) {
case PL330_REG_INTEN:
@@ -1343,7 +1353,7 @@ static void pl330_iomem_write(void *opaque, hwaddr offset,
case PL330_REG_INTCLR:
for (i = 0; i < s->num_events; i++) {
if (s->int_status & s->inten & value & (1 << i)) {
- DB_PRINT("event interrupt lowered %d\n", i);
+ trace_pl330_iomem_write_clr(i);
qemu_irq_lower(s->irq[i]);
}
}
@@ -1361,11 +1371,9 @@ static void pl330_iomem_write(void *opaque, hwaddr offset,
}
break;
case PL330_REG_DBGINST0:
- DB_PRINT("s->dbg[0] = %08x\n", (unsigned)value);
s->dbg[0] = value;
break;
case PL330_REG_DBGINST1:
- DB_PRINT("s->dbg[1] = %08x\n", (unsigned)value);
s->dbg[1] = value;
break;
default:
@@ -1489,7 +1497,7 @@ static uint64_t pl330_iomem_read(void *opaque, hwaddr offset,
unsigned size)
{
uint32_t ret = pl330_iomem_read_imp(opaque, offset);
- DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx32 "\n", offset, ret);
+ trace_pl330_iomem_read((uint32_t)offset, ret);
return ret;
}
diff --git a/hw/dma/trace-events b/hw/dma/trace-events
index e4498428c5..5902ac5969 100644
--- a/hw/dma/trace-events
+++ b/hw/dma/trace-events
@@ -20,3 +20,27 @@ sparc32_dma_enable_lower(void) "Lower DMA enable"
# i8257.c
i8257_unregistered_dma(int nchan, int dma_pos, int dma_len) "unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d"
+
+# pl330.c
+pl330_fault(void *ptr, uint32_t flags) "ch: %p, flags: 0x%"PRIx32
+pl330_fault_abort(void) "abort interrupt raised"
+pl330_dmaend(void) "DMA ending"
+pl330_dmago(void) "DMA run"
+pl330_dmald(uint32_t chan, uint32_t addr, uint32_t size, uint32_t num, uint32_t ch) "channel:%"PRId8" address:0x%08"PRIx32" size:0x%"PRIx32" num:%"PRId32"%c"
+pl330_dmakill(void) "abort interrupt lowered"
+pl330_dmalpend(uint8_t nf, uint8_t bs, uint8_t lc, uint8_t ch, uint8_t flag) "nf=0x%02x bs=0x%02x lc=0x%02x ch=0x%02x flag=0x%02x"
+pl330_dmalpiter(void) "loop reiteration"
+pl330_dmalpfallthrough(void) "loop fallthrough"
+pl330_dmasev_evirq(uint8_t ev_id) "event interrupt raised %"PRId8
+pl330_dmasev_event(uint8_t ev_id) "event raised %"PRId8
+pl330_dmast(uint32_t chn, uint32_t addr, uint32_t sz, uint32_t num, uint32_t c) "channel:%"PRId8" address:0x%08"PRIx32" size:0x%"PRIx32" num:%"PRId32" %c"
+pl330_dmawfe(uint8_t ev_id) "event lowered 0x%"PRIx8
+pl330_chan_exec_undef(void) "undefined instruction"
+pl330_exec_cycle(uint32_t addr, uint32_t size) "PL330 read from memory @0x%08"PRIx32" (size = 0x%08"PRIx32")"
+pl330_hexdump(uint32_t offset, char *str) " 0x%04"PRIx32":%s"
+pl330_exec(void) "pl330_exec"
+pl330_debug_exec(uint8_t ch) "chan id: 0x%"PRIx8
+pl330_debug_exec_stall(void) "stall of debug instruction not implemented"
+pl330_iomem_write(uint32_t offset, uint32_t value) "addr: 0x%08"PRIx32" data: 0x%08"PRIx32
+pl330_iomem_write_clr(int i) "event interrupt lowered %d"
+pl330_iomem_read(uint32_t addr, uint32_t data) "addr: 0x%08"PRIx32" data: 0x%08"PRIx32
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 2/8] hw/core/or-irq: Increase limit of or-lines to 48
2020-01-23 5:25 [PATCH v3 0/8] Fix Exynos4210 DMA support Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 1/8] dma/pl330: Convert to support tracing Guenter Roeck
@ 2020-01-23 5:25 ` Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 3/8] hw/arm/exynos4210: Fix DMA initialization Guenter Roeck
` (6 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Guenter Roeck @ 2020-01-23 5:25 UTC (permalink / raw)
To: Peter Maydell; +Cc: Paolo Bonzini, qemu-arm, qemu-devel, Guenter Roeck
Exynos DMA requires up to 33 interrupt lines (32 event interrupts
plus abort interrupt), which all need to be wired together. Increase
the maximum number of or-irq lines to 48 to support this configuration.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
v3: Added patch
include/hw/or-irq.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/hw/or-irq.h b/include/hw/or-irq.h
index 3a3230dd84..0038bfbe3d 100644
--- a/include/hw/or-irq.h
+++ b/include/hw/or-irq.h
@@ -33,7 +33,7 @@
/* This can safely be increased if necessary without breaking
* migration compatibility (as long as it remains greater than 15).
*/
-#define MAX_OR_LINES 32
+#define MAX_OR_LINES 48
typedef struct OrIRQState qemu_or_irq;
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 3/8] hw/arm/exynos4210: Fix DMA initialization
2020-01-23 5:25 [PATCH v3 0/8] Fix Exynos4210 DMA support Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 1/8] dma/pl330: Convert to support tracing Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 2/8] hw/core/or-irq: Increase limit of or-lines to 48 Guenter Roeck
@ 2020-01-23 5:25 ` Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 4/8] hw/char/exynos4210_uart: Convert to support tracing Guenter Roeck
` (5 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Guenter Roeck @ 2020-01-23 5:25 UTC (permalink / raw)
To: Peter Maydell; +Cc: Paolo Bonzini, qemu-arm, qemu-devel, Guenter Roeck
First parameter to exynos4210_get_irq() is not the SPI port number,
but the interrupt group number. Interrupt groups are 20 for mdma
and 21 for pdma. Interrupts are not inverted. Controllers support 32
events (pdma) or 31 events (mdma). Events must all be routed to a single
interrupt line. Set other parameters as documented in Exynos4210 datasheet,
section 8 (DMA controller).
Fixes: 59520dc65e ("hw/arm/exynos4210: Add DMA support for the Exynos4210")
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
v3: Back to 32+1 interrupts for pdma and 31+1 for mdma
v2: Use interrupt combiner instead of connecting all events to a
single interrupt. Limit number of events per DMA channel
to 31 to meet qemu interrupt combiner limitations.
[Not sure if "assert(s->num_lines < MAX_OR_LINES);" should be
"assert(s->num_lines <= MAX_OR_LINES);"]
Introduce exynos4210_init() to handle interrupt combiner
initialization.
hw/arm/exynos4210.c | 51 +++++++++++++++++++++++++++++++------
include/hw/arm/exynos4210.h | 4 +++
2 files changed, 47 insertions(+), 8 deletions(-)
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index 77fbe1baab..7701a3fa8b 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -166,17 +166,36 @@ static uint64_t exynos4210_calc_affinity(int cpu)
return (0x9 << ARM_AFF1_SHIFT) | cpu;
}
-static void pl330_create(uint32_t base, qemu_irq irq, int nreq)
+static void pl330_create(uint32_t base, qemu_or_irq *orgate, qemu_irq irq,
+ int nreq, int nevents, int width)
{
SysBusDevice *busdev;
DeviceState *dev;
+ int i;
dev = qdev_create(NULL, "pl330");
+ qdev_prop_set_uint8(dev, "num_events", nevents);
+ qdev_prop_set_uint8(dev, "num_chnls", 8);
qdev_prop_set_uint8(dev, "num_periph_req", nreq);
+
+ qdev_prop_set_uint8(dev, "wr_cap", 4);
+ qdev_prop_set_uint8(dev, "wr_q_dep", 8);
+ qdev_prop_set_uint8(dev, "rd_cap", 4);
+ qdev_prop_set_uint8(dev, "rd_q_dep", 8);
+ qdev_prop_set_uint8(dev, "data_width", width);
+ qdev_prop_set_uint16(dev, "data_buffer_dep", width);
qdev_init_nofail(dev);
busdev = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(busdev, 0, base);
- sysbus_connect_irq(busdev, 0, irq);
+
+ object_property_set_int(OBJECT(orgate), nevents + 1, "num-lines",
+ &error_abort);
+ object_property_set_bool(OBJECT(orgate), true, "realized", &error_abort);
+
+ for (i = 0; i < nevents + 1; i++) {
+ sysbus_connect_irq(busdev, i, qdev_get_gpio_in(DEVICE(orgate), i));
+ }
+ qdev_connect_gpio_out(DEVICE(orgate), 0, irq);
}
static void exynos4210_realize(DeviceState *socdev, Error **errp)
@@ -431,12 +450,27 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
s->irq_table[exynos4210_get_irq(28, 3)]);
/*** DMA controllers ***/
- pl330_create(EXYNOS4210_PL330_BASE0_ADDR,
- qemu_irq_invert(s->irq_table[exynos4210_get_irq(35, 1)]), 32);
- pl330_create(EXYNOS4210_PL330_BASE1_ADDR,
- qemu_irq_invert(s->irq_table[exynos4210_get_irq(36, 1)]), 32);
- pl330_create(EXYNOS4210_PL330_BASE2_ADDR,
- qemu_irq_invert(s->irq_table[exynos4210_get_irq(34, 1)]), 1);
+ pl330_create(EXYNOS4210_PL330_BASE0_ADDR, &s->pl330_irq_orgate[0],
+ s->irq_table[exynos4210_get_irq(21, 0)], 32, 32, 32);
+ pl330_create(EXYNOS4210_PL330_BASE1_ADDR, &s->pl330_irq_orgate[1],
+ s->irq_table[exynos4210_get_irq(21, 1)], 32, 32, 32);
+ pl330_create(EXYNOS4210_PL330_BASE2_ADDR, &s->pl330_irq_orgate[2],
+ s->irq_table[exynos4210_get_irq(20, 1)], 1, 31, 64);
+}
+
+static void exynos4210_init(Object *obj)
+{
+ Exynos4210State *s = EXYNOS4210_SOC(obj);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s->pl330_irq_orgate); i++) {
+ char *name = g_strdup_printf("pl330-irq-orgate%d", i);
+ qemu_or_irq *orgate = &s->pl330_irq_orgate[i];
+
+ object_initialize_child(obj, name, orgate, sizeof(*orgate),
+ TYPE_OR_IRQ, &error_abort, NULL);
+ g_free(name);
+ }
}
static void exynos4210_class_init(ObjectClass *klass, void *data)
@@ -450,6 +484,7 @@ static const TypeInfo exynos4210_info = {
.name = TYPE_EXYNOS4210_SOC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Exynos4210State),
+ .instance_init = exynos4210_init,
.class_init = exynos4210_class_init,
};
diff --git a/include/hw/arm/exynos4210.h b/include/hw/arm/exynos4210.h
index f0f23b0e9b..55260394af 100644
--- a/include/hw/arm/exynos4210.h
+++ b/include/hw/arm/exynos4210.h
@@ -24,6 +24,7 @@
#ifndef EXYNOS4210_H
#define EXYNOS4210_H
+#include "hw/or-irq.h"
#include "hw/sysbus.h"
#include "target/arm/cpu-qom.h"
@@ -74,6 +75,8 @@
#define EXYNOS4210_I2C_NUMBER 9
+#define EXYNOS4210_NUM_DMA 3
+
typedef struct Exynos4210Irq {
qemu_irq int_combiner_irq[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ];
qemu_irq ext_combiner_irq[EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ];
@@ -97,6 +100,7 @@ typedef struct Exynos4210State {
MemoryRegion boot_secondary;
MemoryRegion bootreg_mem;
I2CBus *i2c_if[EXYNOS4210_I2C_NUMBER];
+ qemu_or_irq pl330_irq_orgate[EXYNOS4210_NUM_DMA];
} Exynos4210State;
#define TYPE_EXYNOS4210_SOC "exynos4210"
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 4/8] hw/char/exynos4210_uart: Convert to support tracing
2020-01-23 5:25 [PATCH v3 0/8] Fix Exynos4210 DMA support Guenter Roeck
` (2 preceding siblings ...)
2020-01-23 5:25 ` [PATCH v3 3/8] hw/arm/exynos4210: Fix DMA initialization Guenter Roeck
@ 2020-01-23 5:25 ` Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 5/8] hw/char/exynos4210_uart: Implement post_load function Guenter Roeck
` (4 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Guenter Roeck @ 2020-01-23 5:25 UTC (permalink / raw)
To: Peter Maydell; +Cc: Paolo Bonzini, qemu-arm, qemu-devel, Guenter Roeck
Replace debug code with tracing to aid debugging.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
v3: No change
v2: Added Reviewed-by: tag
hw/char/exynos4210_uart.c | 96 ++++++++++++---------------------------
hw/char/trace-events | 17 +++++++
2 files changed, 47 insertions(+), 66 deletions(-)
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index d6b6b62366..fb7a3ebd09 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -31,45 +31,7 @@
#include "hw/irq.h"
#include "hw/qdev-properties.h"
-#undef DEBUG_UART
-#undef DEBUG_UART_EXTEND
-#undef DEBUG_IRQ
-#undef DEBUG_Rx_DATA
-#undef DEBUG_Tx_DATA
-
-#define DEBUG_UART 0
-#define DEBUG_UART_EXTEND 0
-#define DEBUG_IRQ 0
-#define DEBUG_Rx_DATA 0
-#define DEBUG_Tx_DATA 0
-
-#if DEBUG_UART
-#define PRINT_DEBUG(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-
-#if DEBUG_UART_EXTEND
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-#else
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do {} while (0)
-#endif /* EXTEND */
-
-#else
-#define PRINT_DEBUG(fmt, args...) \
- do {} while (0)
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do {} while (0)
-#endif
-
-#define PRINT_ERROR(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
+#include "trace.h"
/*
* Offsets for UART registers relative to SFR base address
@@ -193,8 +155,7 @@ typedef struct Exynos4210UartState {
} Exynos4210UartState;
-#if DEBUG_UART
-/* Used only for debugging inside PRINT_DEBUG_... macros */
+/* Used only for tracing */
static const char *exynos4210_uart_regname(hwaddr offset)
{
@@ -208,7 +169,6 @@ static const char *exynos4210_uart_regname(hwaddr offset)
return NULL;
}
-#endif
static void fifo_store(Exynos4210UartFIFO *q, uint8_t ch)
@@ -271,7 +231,7 @@ static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(const Exynos4210UartState
break;
default:
level = 0;
- PRINT_ERROR("Wrong UART channel number: %d\n", s->channel);
+ trace_exynos_uart_channel_error(s->channel);
}
return level;
@@ -297,14 +257,10 @@ static void exynos4210_uart_update_irq(Exynos4210UartState *s)
if (s->reg[I_(UINTP)]) {
qemu_irq_raise(s->irq);
-
-#if DEBUG_IRQ
- fprintf(stderr, "UART%d: IRQ has been raised: %08x\n",
- s->channel, s->reg[I_(UINTP)]);
-#endif
-
+ trace_exynos_uart_irq_raised(s->channel, s->reg[I_(UINTP)]);
} else {
qemu_irq_lower(s->irq);
+ trace_exynos_uart_irq_lowered(s->channel);
}
}
@@ -348,7 +304,7 @@ static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
- PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n",
+ trace_exynos_uart_update_params(
s->channel, speed, parity, data_bits, stop_bits);
}
@@ -358,8 +314,8 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
Exynos4210UartState *s = (Exynos4210UartState *)opaque;
uint8_t ch;
- PRINT_DEBUG_EXTEND("UART%d: <0x%04x> %s <- 0x%08llx\n", s->channel,
- offset, exynos4210_uart_regname(offset), (long long unsigned int)val);
+ trace_exynos_uart_write(s->channel, offset,
+ exynos4210_uart_regname(offset), val);
switch (offset) {
case ULCON:
@@ -373,12 +329,12 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
if (val & UFCON_Rx_FIFO_RESET) {
fifo_reset(&s->rx);
s->reg[I_(UFCON)] &= ~UFCON_Rx_FIFO_RESET;
- PRINT_DEBUG("UART%d: Rx FIFO Reset\n", s->channel);
+ trace_exynos_uart_rx_fifo_reset(s->channel);
}
if (val & UFCON_Tx_FIFO_RESET) {
fifo_reset(&s->tx);
s->reg[I_(UFCON)] &= ~UFCON_Tx_FIFO_RESET;
- PRINT_DEBUG("UART%d: Tx FIFO Reset\n", s->channel);
+ trace_exynos_uart_tx_fifo_reset(s->channel);
}
break;
@@ -390,9 +346,7 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&s->chr, &ch, 1);
-#if DEBUG_Tx_DATA
- fprintf(stderr, "%c", ch);
-#endif
+ trace_exynos_uart_tx(s->channel, ch);
s->reg[I_(UTRSTAT)] |= UTRSTAT_TRANSMITTER_EMPTY |
UTRSTAT_Tx_BUFFER_EMPTY;
s->reg[I_(UINTSP)] |= UINTSP_TXD;
@@ -403,8 +357,7 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
case UINTP:
s->reg[I_(UINTP)] &= ~val;
s->reg[I_(UINTSP)] &= ~val;
- PRINT_DEBUG("UART%d: UINTP [%04x] have been cleared: %08x\n",
- s->channel, offset, s->reg[I_(UINTP)]);
+ trace_exynos_uart_intclr(s->channel, s->reg[I_(UINTP)]);
exynos4210_uart_update_irq(s);
break;
case UTRSTAT:
@@ -412,7 +365,7 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
case UFSTAT:
case UMSTAT:
case URXH:
- PRINT_DEBUG("UART%d: Trying to write into RO register: %s [%04x]\n",
+ trace_exynos_uart_ro_write(
s->channel, exynos4210_uart_regname(offset), offset);
break;
case UINTSP:
@@ -439,6 +392,8 @@ static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
case UERSTAT: /* Read Only */
res = s->reg[I_(UERSTAT)];
s->reg[I_(UERSTAT)] = 0;
+ trace_exynos_uart_read(s->channel, offset,
+ exynos4210_uart_regname(offset), res);
return res;
case UFSTAT: /* Read Only */
s->reg[I_(UFSTAT)] = fifo_elements_number(&s->rx) & 0xff;
@@ -446,20 +401,22 @@ static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
s->reg[I_(UFSTAT)] |= UFSTAT_Rx_FIFO_FULL;
s->reg[I_(UFSTAT)] &= ~0xff;
}
+ trace_exynos_uart_read(s->channel, offset,
+ exynos4210_uart_regname(offset),
+ s->reg[I_(UFSTAT)]);
return s->reg[I_(UFSTAT)];
case URXH:
if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
if (fifo_elements_number(&s->rx)) {
res = fifo_retrieve(&s->rx);
-#if DEBUG_Rx_DATA
- fprintf(stderr, "%c", res);
-#endif
+ trace_exynos_uart_rx(s->channel, res);
if (!fifo_elements_number(&s->rx)) {
s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
} else {
s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
}
} else {
+ trace_exynos_uart_rx_error(s->channel);
s->reg[I_(UINTSP)] |= UINTSP_ERROR;
exynos4210_uart_update_irq(s);
res = 0;
@@ -468,15 +425,22 @@ static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
res = s->reg[I_(URXH)];
}
+ trace_exynos_uart_read(s->channel, offset,
+ exynos4210_uart_regname(offset), res);
return res;
case UTXH:
- PRINT_DEBUG("UART%d: Trying to read from WO register: %s [%04x]\n",
- s->channel, exynos4210_uart_regname(offset), offset);
+ trace_exynos_uart_wo_read(s->channel, exynos4210_uart_regname(offset),
+ offset);
break;
default:
+ trace_exynos_uart_read(s->channel, offset,
+ exynos4210_uart_regname(offset),
+ s->reg[I_(offset)]);
return s->reg[I_(offset)];
}
+ trace_exynos_uart_read(s->channel, offset, exynos4210_uart_regname(offset),
+ 0);
return 0;
}
@@ -555,7 +519,7 @@ static void exynos4210_uart_reset(DeviceState *dev)
fifo_reset(&s->rx);
fifo_reset(&s->tx);
- PRINT_DEBUG("UART%d: Rx FIFO size: %d\n", s->channel, s->rx.size);
+ trace_exynos_uart_rxsize(s->channel, s->rx.size);
}
static const VMStateDescription vmstate_exynos4210_uart_fifo = {
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 2ce7f2f998..ba28b45b53 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -77,3 +77,20 @@ cmsdk_apb_uart_set_params(int speed) "CMSDK APB UART: params set to %d 8N1"
# nrf51_uart.c
nrf51_uart_read(uint64_t addr, uint64_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
nrf51_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
+
+# exynos4210_uart.c
+exynos_uart_irq_raised(uint32_t channel, uint32_t reg) "UART%d: IRQ raised: 0x%08"PRIx32
+exynos_uart_irq_lowered(uint32_t channel) "UART%d: IRQ lowered"
+exynos_uart_update_params(uint32_t channel, int speed, uint8_t parity, int data, int stop) "UART%d: speed: %d, parity: %c, data bits: %d, stop bits: %d"
+exynos_uart_write(uint32_t channel, uint32_t offset, const char *name, uint64_t val) "UART%d: <0x%04x> %s <- 0x%" PRIx64
+exynos_uart_read(uint32_t channel, uint32_t offset, const char *name, uint64_t val) "UART%d: <0x%04x> %s -> 0x%" PRIx64
+exynos_uart_rx_fifo_reset(uint32_t channel) "UART%d: Rx FIFO Reset"
+exynos_uart_tx_fifo_reset(uint32_t channel) "UART%d: Tx FIFO Reset"
+exynos_uart_tx(uint32_t channel, uint8_t ch) "UART%d: Tx 0x%02"PRIx32
+exynos_uart_intclr(uint32_t channel, uint32_t reg) "UART%d: interrupts cleared: 0x%08"PRIx32
+exynos_uart_ro_write(uint32_t channel, const char *name, uint32_t reg) "UART%d: Trying to write into RO register: %s [0x%04"PRIx32"]"
+exynos_uart_rx(uint32_t channel, uint8_t ch) "UART%d: Rx 0x%02"PRIx32
+exynos_uart_rx_error(uint32_t channel) "UART%d: Rx error"
+exynos_uart_wo_read(uint32_t channel, const char *name, uint32_t reg) "UART%d: Trying to read from WO register: %s [0x%04"PRIx32"]"
+exynos_uart_rxsize(uint32_t channel, uint32_t size) "UART%d: Rx FIFO size: %d"
+exynos_uart_channel_error(uint32_t channel) "Wrong UART channel number: %d"
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 5/8] hw/char/exynos4210_uart: Implement post_load function
2020-01-23 5:25 [PATCH v3 0/8] Fix Exynos4210 DMA support Guenter Roeck
` (3 preceding siblings ...)
2020-01-23 5:25 ` [PATCH v3 4/8] hw/char/exynos4210_uart: Convert to support tracing Guenter Roeck
@ 2020-01-23 5:25 ` Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 6/8] hw/char/exynos4210_uart: Implement Rx FIFO level triggers and timeouts Guenter Roeck
` (3 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Guenter Roeck @ 2020-01-23 5:25 UTC (permalink / raw)
To: Peter Maydell; +Cc: Paolo Bonzini, qemu-arm, qemu-devel, Guenter Roeck
After restoring a VM, serial parameters need to be updated to reflect
restored register values. Implement a post_load function to handle this
situation.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
v3: Added Reviewed-by: tag.
v2: Additional patch to implement post-load functionality
in exynos uart driver. Required for next patch in series.
hw/char/exynos4210_uart.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index fb7a3ebd09..5d48701b6d 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -522,10 +522,20 @@ static void exynos4210_uart_reset(DeviceState *dev)
trace_exynos_uart_rxsize(s->channel, s->rx.size);
}
+static int exynos4210_uart_post_load(void *opaque, int version_id)
+{
+ Exynos4210UartState *s = (Exynos4210UartState *)opaque;
+
+ exynos4210_uart_update_parameters(s);
+
+ return 0;
+}
+
static const VMStateDescription vmstate_exynos4210_uart_fifo = {
.name = "exynos4210.uart.fifo",
.version_id = 1,
.minimum_version_id = 1,
+ .post_load = exynos4210_uart_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT32(sp, Exynos4210UartFIFO),
VMSTATE_UINT32(rp, Exynos4210UartFIFO),
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 6/8] hw/char/exynos4210_uart: Implement Rx FIFO level triggers and timeouts
2020-01-23 5:25 [PATCH v3 0/8] Fix Exynos4210 DMA support Guenter Roeck
` (4 preceding siblings ...)
2020-01-23 5:25 ` [PATCH v3 5/8] hw/char/exynos4210_uart: Implement post_load function Guenter Roeck
@ 2020-01-23 5:25 ` Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 7/8] hw/char/exynos4210_uart: Add receive DMA support Guenter Roeck
` (2 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Guenter Roeck @ 2020-01-23 5:25 UTC (permalink / raw)
To: Peter Maydell; +Cc: Paolo Bonzini, qemu-arm, qemu-devel, Guenter Roeck
The driver already implements a receive FIFO, but it does not
handle receive FIFO trigger levels and timeout. Implement the
missing functionality.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
v3: Dropped VMSTATE_TIMER_PTR
Don't call exynos4210_uart_rx_timeout_set() and
exynos4210_uart_update_irq() after writes into the UCON register.
Chip behavior in this situation is not specified and any handling
may be inaccurate, so do nothing.
v2: Call exynos4210_uart_rx_timeout_set() from new post_load function
to set the receive timeout timer.
Add timer to vmstate_exynos4210_uart.
hw/char/exynos4210_uart.c | 117 ++++++++++++++++++++++++++++++--------
hw/char/trace-events | 3 +-
2 files changed, 94 insertions(+), 26 deletions(-)
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 5d48701b6d..8d6b4a071e 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -24,6 +24,7 @@
#include "migration/vmstate.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
+#include "qemu/timer.h"
#include "chardev/char-fe.h"
#include "chardev/char-serial.h"
@@ -118,6 +119,7 @@ static const Exynos4210UartReg exynos4210_uart_regs[] = {
#define ULCON_STOP_BIT_SHIFT 1
/* UART Tx/Rx Status */
+#define UTRSTAT_Rx_TIMEOUT 0x8
#define UTRSTAT_TRANSMITTER_EMPTY 0x4
#define UTRSTAT_Tx_BUFFER_EMPTY 0x2
#define UTRSTAT_Rx_BUFFER_DATA_READY 0x1
@@ -147,6 +149,9 @@ typedef struct Exynos4210UartState {
Exynos4210UartFIFO rx;
Exynos4210UartFIFO tx;
+ QEMUTimer *fifo_timeout_timer;
+ uint64_t wordtime; /* word time in ns */
+
CharBackend chr;
qemu_irq irq;
@@ -209,15 +214,12 @@ static void fifo_reset(Exynos4210UartFIFO *q)
q->rp = 0;
}
-static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(const Exynos4210UartState *s)
+static uint32_t exynos4210_uart_FIFO_trigger_level(uint32_t channel,
+ uint32_t reg)
{
- uint32_t level = 0;
- uint32_t reg;
+ uint32_t level;
- reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
- UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
-
- switch (s->channel) {
+ switch (channel) {
case 0:
level = reg * 32;
break;
@@ -231,12 +233,34 @@ static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(const Exynos4210UartState
break;
default:
level = 0;
- trace_exynos_uart_channel_error(s->channel);
+ trace_exynos_uart_channel_error(channel);
+ break;
}
-
return level;
}
+static uint32_t
+exynos4210_uart_Tx_FIFO_trigger_level(const Exynos4210UartState *s)
+{
+ uint32_t reg;
+
+ reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
+ UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
+
+ return exynos4210_uart_FIFO_trigger_level(s->channel, reg);
+}
+
+static uint32_t
+exynos4210_uart_Rx_FIFO_trigger_level(const Exynos4210UartState *s)
+{
+ uint32_t reg;
+
+ reg = ((s->reg[I_(UFCON)] & UFCON_Rx_FIFO_TRIGGER_LEVEL) >>
+ UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT) + 1;
+
+ return exynos4210_uart_FIFO_trigger_level(s->channel, reg);
+}
+
static void exynos4210_uart_update_irq(Exynos4210UartState *s)
{
/*
@@ -244,13 +268,25 @@ static void exynos4210_uart_update_irq(Exynos4210UartState *s)
* transmit FIFO is smaller than the trigger level.
*/
if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
-
uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >>
UFSTAT_Tx_FIFO_COUNT_SHIFT;
if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) {
s->reg[I_(UINTSP)] |= UINTSP_TXD;
}
+
+ /*
+ * Rx interrupt if trigger level is reached or if rx timeout
+ * interrupt is disabled and there is data in the receive buffer
+ */
+ count = fifo_elements_number(&s->rx);
+ if ((count && !(s->reg[I_(UCON)] & 0x80)) ||
+ count >= exynos4210_uart_Rx_FIFO_trigger_level(s)) {
+ s->reg[I_(UINTSP)] |= UINTSP_RXD;
+ timer_del(s->fifo_timeout_timer);
+ }
+ } else if (s->reg[I_(UTRSTAT)] & UTRSTAT_Rx_BUFFER_DATA_READY) {
+ s->reg[I_(UINTSP)] |= UINTSP_RXD;
}
s->reg[I_(UINTP)] = s->reg[I_(UINTSP)] & ~s->reg[I_(UINTM)];
@@ -264,6 +300,21 @@ static void exynos4210_uart_update_irq(Exynos4210UartState *s)
}
}
+static void exynos4210_uart_timeout_int(void *opaque)
+{
+ Exynos4210UartState *s = opaque;
+
+ trace_exynos_uart_rx_timeout(s->channel, s->reg[I_(UTRSTAT)],
+ s->reg[I_(UINTSP)]);
+
+ if ((s->reg[I_(UTRSTAT)] & UTRSTAT_Rx_BUFFER_DATA_READY) ||
+ (s->reg[I_(UCON)] & (1 << 11))) {
+ s->reg[I_(UINTSP)] |= UINTSP_RXD;
+ s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_TIMEOUT;
+ exynos4210_uart_update_irq(s);
+ }
+}
+
static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
{
int speed, parity, data_bits, stop_bits;
@@ -302,10 +353,24 @@ static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
ssp.data_bits = data_bits;
ssp.stop_bits = stop_bits;
+ s->wordtime = NANOSECONDS_PER_SECOND * (data_bits + stop_bits + 1) / speed;
+
qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
trace_exynos_uart_update_params(
- s->channel, speed, parity, data_bits, stop_bits);
+ s->channel, speed, parity, data_bits, stop_bits, s->wordtime);
+}
+
+static void exynos4210_uart_rx_timeout_set(Exynos4210UartState *s)
+{
+ if (s->reg[I_(UCON)] & 0x80) {
+ uint32_t timeout = ((s->reg[I_(UCON)] >> 12) & 0x0f) * s->wordtime;
+
+ timer_mod(s->fifo_timeout_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + timeout);
+ } else {
+ timer_del(s->fifo_timeout_timer);
+ }
}
static void exynos4210_uart_write(void *opaque, hwaddr offset,
@@ -361,6 +426,10 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
exynos4210_uart_update_irq(s);
break;
case UTRSTAT:
+ if (val & UTRSTAT_Rx_TIMEOUT) {
+ s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_TIMEOUT;
+ }
+ break;
case UERSTAT:
case UFSTAT:
case UMSTAT:
@@ -382,6 +451,7 @@ static void exynos4210_uart_write(void *opaque, hwaddr offset,
break;
}
}
+
static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
unsigned size)
{
@@ -461,7 +531,6 @@ static int exynos4210_uart_can_receive(void *opaque)
return fifo_empty_elements_number(&s->rx);
}
-
static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size)
{
Exynos4210UartState *s = (Exynos4210UartState *)opaque;
@@ -469,24 +538,17 @@ static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size)
if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
if (fifo_empty_elements_number(&s->rx) < size) {
- for (i = 0; i < fifo_empty_elements_number(&s->rx); i++) {
- fifo_store(&s->rx, buf[i]);
- }
+ size = fifo_empty_elements_number(&s->rx);
s->reg[I_(UINTSP)] |= UINTSP_ERROR;
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- } else {
- for (i = 0; i < size; i++) {
- fifo_store(&s->rx, buf[i]);
- }
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
}
- /* XXX: Around here we maybe should check Rx trigger level */
- s->reg[I_(UINTSP)] |= UINTSP_RXD;
+ for (i = 0; i < size; i++) {
+ fifo_store(&s->rx, buf[i]);
+ }
+ exynos4210_uart_rx_timeout_set(s);
} else {
s->reg[I_(URXH)] = buf[0];
- s->reg[I_(UINTSP)] |= UINTSP_RXD;
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
}
+ s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
exynos4210_uart_update_irq(s);
}
@@ -527,6 +589,7 @@ static int exynos4210_uart_post_load(void *opaque, int version_id)
Exynos4210UartState *s = (Exynos4210UartState *)opaque;
exynos4210_uart_update_parameters(s);
+ exynos4210_uart_rx_timeout_set(s);
return 0;
}
@@ -588,6 +651,10 @@ static void exynos4210_uart_init(Object *obj)
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
Exynos4210UartState *s = EXYNOS4210_UART(dev);
+ s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ exynos4210_uart_timeout_int, s);
+ s->wordtime = NANOSECONDS_PER_SECOND * 10 / 9600;
+
/* memory mapping */
memory_region_init_io(&s->iomem, obj, &exynos4210_uart_ops, s,
"exynos4210.uart", EXYNOS4210_UART_REGS_MEM_SIZE);
diff --git a/hw/char/trace-events b/hw/char/trace-events
index ba28b45b53..cb73fee6a9 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -81,7 +81,7 @@ nrf51_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PR
# exynos4210_uart.c
exynos_uart_irq_raised(uint32_t channel, uint32_t reg) "UART%d: IRQ raised: 0x%08"PRIx32
exynos_uart_irq_lowered(uint32_t channel) "UART%d: IRQ lowered"
-exynos_uart_update_params(uint32_t channel, int speed, uint8_t parity, int data, int stop) "UART%d: speed: %d, parity: %c, data bits: %d, stop bits: %d"
+exynos_uart_update_params(uint32_t channel, int speed, uint8_t parity, int data, int stop, uint64_t wordtime) "UART%d: speed: %d, parity: %c, data bits: %d, stop bits: %d wordtime: %"PRId64"ns"
exynos_uart_write(uint32_t channel, uint32_t offset, const char *name, uint64_t val) "UART%d: <0x%04x> %s <- 0x%" PRIx64
exynos_uart_read(uint32_t channel, uint32_t offset, const char *name, uint64_t val) "UART%d: <0x%04x> %s -> 0x%" PRIx64
exynos_uart_rx_fifo_reset(uint32_t channel) "UART%d: Rx FIFO Reset"
@@ -94,3 +94,4 @@ exynos_uart_rx_error(uint32_t channel) "UART%d: Rx error"
exynos_uart_wo_read(uint32_t channel, const char *name, uint32_t reg) "UART%d: Trying to read from WO register: %s [0x%04"PRIx32"]"
exynos_uart_rxsize(uint32_t channel, uint32_t size) "UART%d: Rx FIFO size: %d"
exynos_uart_channel_error(uint32_t channel) "Wrong UART channel number: %d"
+exynos_uart_rx_timeout(uint32_t channel, uint32_t stat, uint32_t intsp) "UART%d: Rx timeout stat=0x%x intsp=0x%x"
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 7/8] hw/char/exynos4210_uart: Add receive DMA support
2020-01-23 5:25 [PATCH v3 0/8] Fix Exynos4210 DMA support Guenter Roeck
` (5 preceding siblings ...)
2020-01-23 5:25 ` [PATCH v3 6/8] hw/char/exynos4210_uart: Implement Rx FIFO level triggers and timeouts Guenter Roeck
@ 2020-01-23 5:25 ` Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 8/8] hw/arm/exynos4210: Connect serial port DMA busy signals with pl330 Guenter Roeck
2020-01-23 15:20 ` [PATCH v3 0/8] Fix Exynos4210 DMA support Peter Maydell
8 siblings, 0 replies; 14+ messages in thread
From: Guenter Roeck @ 2020-01-23 5:25 UTC (permalink / raw)
To: Peter Maydell; +Cc: Paolo Bonzini, qemu-arm, qemu-devel, Guenter Roeck
To support receive DMA, we need to inform the DMA controller if receive data
is available. Otherwise the DMA controller keeps requesting data, causing
receive errors.
Implement this using an interrupt line. The instantiating code then needs
to connect the interrupt with the matching DMA controller GPIO pin.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
v3: No change
v2: Added Reviewed-by: tag
hw/char/exynos4210_uart.c | 24 ++++++++++++++++++++++++
hw/char/trace-events | 2 ++
2 files changed, 26 insertions(+)
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 8d6b4a071e..bf9e586e79 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -154,6 +154,7 @@ typedef struct Exynos4210UartState {
CharBackend chr;
qemu_irq irq;
+ qemu_irq dmairq;
uint32_t channel;
@@ -261,6 +262,24 @@ exynos4210_uart_Rx_FIFO_trigger_level(const Exynos4210UartState *s)
return exynos4210_uart_FIFO_trigger_level(s->channel, reg);
}
+/*
+ * Update Rx DMA busy signal if Rx DMA is enabled. For simplicity,
+ * mark DMA as busy if DMA is enabled and the receive buffer is empty.
+ */
+static void exynos4210_uart_update_dmabusy(Exynos4210UartState *s)
+{
+ bool rx_dma_enabled = (s->reg[I_(UCON)] & 0x03) == 0x02;
+ uint32_t count = fifo_elements_number(&s->rx);
+
+ if (rx_dma_enabled && !count) {
+ qemu_irq_raise(s->dmairq);
+ trace_exynos_uart_dmabusy(s->channel);
+ } else {
+ qemu_irq_lower(s->dmairq);
+ trace_exynos_uart_dmaready(s->channel);
+ }
+}
+
static void exynos4210_uart_update_irq(Exynos4210UartState *s)
{
/*
@@ -282,10 +301,12 @@ static void exynos4210_uart_update_irq(Exynos4210UartState *s)
count = fifo_elements_number(&s->rx);
if ((count && !(s->reg[I_(UCON)] & 0x80)) ||
count >= exynos4210_uart_Rx_FIFO_trigger_level(s)) {
+ exynos4210_uart_update_dmabusy(s);
s->reg[I_(UINTSP)] |= UINTSP_RXD;
timer_del(s->fifo_timeout_timer);
}
} else if (s->reg[I_(UTRSTAT)] & UTRSTAT_Rx_BUFFER_DATA_READY) {
+ exynos4210_uart_update_dmabusy(s);
s->reg[I_(UINTSP)] |= UINTSP_RXD;
}
@@ -311,6 +332,7 @@ static void exynos4210_uart_timeout_int(void *opaque)
(s->reg[I_(UCON)] & (1 << 11))) {
s->reg[I_(UINTSP)] |= UINTSP_RXD;
s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_TIMEOUT;
+ exynos4210_uart_update_dmabusy(s);
exynos4210_uart_update_irq(s);
}
}
@@ -495,6 +517,7 @@ static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
res = s->reg[I_(URXH)];
}
+ exynos4210_uart_update_dmabusy(s);
trace_exynos_uart_read(s->channel, offset,
exynos4210_uart_regname(offset), res);
return res;
@@ -661,6 +684,7 @@ static void exynos4210_uart_init(Object *obj)
sysbus_init_mmio(dev, &s->iomem);
sysbus_init_irq(dev, &s->irq);
+ sysbus_init_irq(dev, &s->dmairq);
}
static void exynos4210_uart_realize(DeviceState *dev, Error **errp)
diff --git a/hw/char/trace-events b/hw/char/trace-events
index cb73fee6a9..6f938301d9 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -79,6 +79,8 @@ nrf51_uart_read(uint64_t addr, uint64_t r, unsigned int size) "addr 0x%" PRIx64
nrf51_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u"
# exynos4210_uart.c
+exynos_uart_dmabusy(uint32_t channel) "UART%d: DMA busy (Rx buffer empty)"
+exynos_uart_dmaready(uint32_t channel) "UART%d: DMA ready"
exynos_uart_irq_raised(uint32_t channel, uint32_t reg) "UART%d: IRQ raised: 0x%08"PRIx32
exynos_uart_irq_lowered(uint32_t channel) "UART%d: IRQ lowered"
exynos_uart_update_params(uint32_t channel, int speed, uint8_t parity, int data, int stop, uint64_t wordtime) "UART%d: speed: %d, parity: %c, data bits: %d, stop bits: %d wordtime: %"PRId64"ns"
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v3 8/8] hw/arm/exynos4210: Connect serial port DMA busy signals with pl330
2020-01-23 5:25 [PATCH v3 0/8] Fix Exynos4210 DMA support Guenter Roeck
` (6 preceding siblings ...)
2020-01-23 5:25 ` [PATCH v3 7/8] hw/char/exynos4210_uart: Add receive DMA support Guenter Roeck
@ 2020-01-23 5:25 ` Guenter Roeck
2020-01-23 15:20 ` [PATCH v3 0/8] Fix Exynos4210 DMA support Peter Maydell
8 siblings, 0 replies; 14+ messages in thread
From: Guenter Roeck @ 2020-01-23 5:25 UTC (permalink / raw)
To: Peter Maydell; +Cc: Paolo Bonzini, qemu-arm, qemu-devel, Guenter Roeck
The Exynos4210 serial driver uses an interrupt line to signal if receive
data is available. Connect that interrupt with the DMA controller's
'peripheral busy' gpio pin to stop the DMA if there is no more receive
data available. Without this patch, receive DMA runs wild and fills the
entire receive DMA buffer with invalid data.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
v3: Added Reviewed-by: tag
Context changes due to increase in number of interrupt lines
v2: Context changes; improved description
This patch has an outstanding review comment, suggesting that
uart and pl330 device states should be kept in Exynos4210State.
I did not address this comment for a number of reasons.
It looks like the problem is hypothetical, the problem may
apply to all devices created in exynos4210_realize(), and I am
not sure I understand what would need to be done to fix
the problem for good (ie for all devices created in the same
function which have the same problem). Overall, I think that
handling this situation would be better left for a separate patch.
hw/arm/exynos4210.c | 42 +++++++++++++++++++++++++++++-------------
1 file changed, 29 insertions(+), 13 deletions(-)
diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c
index 7701a3fa8b..59a27bdd68 100644
--- a/hw/arm/exynos4210.c
+++ b/hw/arm/exynos4210.c
@@ -166,8 +166,8 @@ static uint64_t exynos4210_calc_affinity(int cpu)
return (0x9 << ARM_AFF1_SHIFT) | cpu;
}
-static void pl330_create(uint32_t base, qemu_or_irq *orgate, qemu_irq irq,
- int nreq, int nevents, int width)
+static DeviceState *pl330_create(uint32_t base, qemu_or_irq *orgate,
+ qemu_irq irq, int nreq, int nevents, int width)
{
SysBusDevice *busdev;
DeviceState *dev;
@@ -196,6 +196,7 @@ static void pl330_create(uint32_t base, qemu_or_irq *orgate, qemu_irq irq,
sysbus_connect_irq(busdev, i, qdev_get_gpio_in(DEVICE(orgate), i));
}
qdev_connect_gpio_out(DEVICE(orgate), 0, irq);
+ return dev;
}
static void exynos4210_realize(DeviceState *socdev, Error **errp)
@@ -204,7 +205,7 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
MemoryRegion *system_mem = get_system_memory();
qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
SysBusDevice *busdev;
- DeviceState *dev;
+ DeviceState *dev, *uart[4], *pl330[3];
int i, n;
for (n = 0; n < EXYNOS4210_NCPUS; n++) {
@@ -390,19 +391,19 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
/*** UARTs ***/
- exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
+ uart[0] = exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
EXYNOS4210_UART0_FIFO_SIZE, 0, serial_hd(0),
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]);
- exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
+ uart[1] = exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
EXYNOS4210_UART1_FIFO_SIZE, 1, serial_hd(1),
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]);
- exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
+ uart[2] = exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
EXYNOS4210_UART2_FIFO_SIZE, 2, serial_hd(2),
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]);
- exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
+ uart[3] = exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
EXYNOS4210_UART3_FIFO_SIZE, 3, serial_hd(3),
s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
@@ -450,12 +451,27 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
s->irq_table[exynos4210_get_irq(28, 3)]);
/*** DMA controllers ***/
- pl330_create(EXYNOS4210_PL330_BASE0_ADDR, &s->pl330_irq_orgate[0],
- s->irq_table[exynos4210_get_irq(21, 0)], 32, 32, 32);
- pl330_create(EXYNOS4210_PL330_BASE1_ADDR, &s->pl330_irq_orgate[1],
- s->irq_table[exynos4210_get_irq(21, 1)], 32, 32, 32);
- pl330_create(EXYNOS4210_PL330_BASE2_ADDR, &s->pl330_irq_orgate[2],
- s->irq_table[exynos4210_get_irq(20, 1)], 1, 31, 64);
+ pl330[0] = pl330_create(EXYNOS4210_PL330_BASE0_ADDR,
+ &s->pl330_irq_orgate[0],
+ s->irq_table[exynos4210_get_irq(21, 0)],
+ 32, 32, 32);
+ pl330[1] = pl330_create(EXYNOS4210_PL330_BASE1_ADDR,
+ &s->pl330_irq_orgate[1],
+ s->irq_table[exynos4210_get_irq(21, 1)],
+ 32, 32, 32);
+ pl330[2] = pl330_create(EXYNOS4210_PL330_BASE2_ADDR,
+ &s->pl330_irq_orgate[2],
+ s->irq_table[exynos4210_get_irq(20, 1)],
+ 1, 31, 64);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(uart[0]), 1,
+ qdev_get_gpio_in(pl330[0], 15));
+ sysbus_connect_irq(SYS_BUS_DEVICE(uart[1]), 1,
+ qdev_get_gpio_in(pl330[1], 15));
+ sysbus_connect_irq(SYS_BUS_DEVICE(uart[2]), 1,
+ qdev_get_gpio_in(pl330[0], 17));
+ sysbus_connect_irq(SYS_BUS_DEVICE(uart[3]), 1,
+ qdev_get_gpio_in(pl330[1], 17));
}
static void exynos4210_init(Object *obj)
--
2.17.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v3 0/8] Fix Exynos4210 DMA support
2020-01-23 5:25 [PATCH v3 0/8] Fix Exynos4210 DMA support Guenter Roeck
` (7 preceding siblings ...)
2020-01-23 5:25 ` [PATCH v3 8/8] hw/arm/exynos4210: Connect serial port DMA busy signals with pl330 Guenter Roeck
@ 2020-01-23 15:20 ` Peter Maydell
2020-01-23 15:39 ` Guenter Roeck
8 siblings, 1 reply; 14+ messages in thread
From: Peter Maydell @ 2020-01-23 15:20 UTC (permalink / raw)
To: Guenter Roeck; +Cc: Paolo Bonzini, qemu-arm, QEMU Developers
On Thu, 23 Jan 2020 at 05:25, Guenter Roeck <linux@roeck-us.net> wrote:
>
> Commit 59520dc65e ("hw/arm/exynos4210: Add DMA support for the Exynos4210")
> introduced DMA support for Exynos4210. Unfortunately, it never really
> worked. DMA interrupt line and polarity was wrong, and the serial port
> needs extra code to support DMA. This patch series fixes the problem.
>
> The series also converts pl330 and exynos4210_uart code to support tracing.
> While not strictly necessary, this was very useful for debugging,
> and it seemed too valuable to drop it from the final series. Similar,
> improved support for receive FIFO handling is not strictly necessary
> to fix DMA handling, but I initially thought that it was and added the
> code. Like tracing support it seemed too valuable to drop it.
>
> The series was tested with qemu's smdkc210 and nuri emulations and with
> exynos4210-smdkv310.dtb. Without the series, the emulation does not react
> to serial line input, and serial line output stalls when using DMA. With
> this series in place, serial line input is handled correctly, serial
> output does not stall, and DMA interrupts are observed and handled.
Applied to target-arm.next, thanks.
-- PMM
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 0/8] Fix Exynos4210 DMA support
2020-01-23 15:20 ` [PATCH v3 0/8] Fix Exynos4210 DMA support Peter Maydell
@ 2020-01-23 15:39 ` Guenter Roeck
0 siblings, 0 replies; 14+ messages in thread
From: Guenter Roeck @ 2020-01-23 15:39 UTC (permalink / raw)
To: Peter Maydell; +Cc: Paolo Bonzini, qemu-arm, QEMU Developers
On Thu, Jan 23, 2020 at 03:20:48PM +0000, Peter Maydell wrote:
> On Thu, 23 Jan 2020 at 05:25, Guenter Roeck <linux@roeck-us.net> wrote:
> >
> > Commit 59520dc65e ("hw/arm/exynos4210: Add DMA support for the Exynos4210")
> > introduced DMA support for Exynos4210. Unfortunately, it never really
> > worked. DMA interrupt line and polarity was wrong, and the serial port
> > needs extra code to support DMA. This patch series fixes the problem.
> >
> > The series also converts pl330 and exynos4210_uart code to support tracing.
> > While not strictly necessary, this was very useful for debugging,
> > and it seemed too valuable to drop it from the final series. Similar,
> > improved support for receive FIFO handling is not strictly necessary
> > to fix DMA handling, but I initially thought that it was and added the
> > code. Like tracing support it seemed too valuable to drop it.
> >
> > The series was tested with qemu's smdkc210 and nuri emulations and with
> > exynos4210-smdkv310.dtb. Without the series, the emulation does not react
> > to serial line input, and serial line output stalls when using DMA. With
> > this series in place, serial line input is handled correctly, serial
> > output does not stall, and DMA interrupts are observed and handled.
>
> Applied to target-arm.next, thanks.
>
Thanks a lot for your help!
Guenter
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 1/8] dma/pl330: Convert to support tracing
2020-01-23 5:25 ` [PATCH v3 1/8] dma/pl330: Convert to support tracing Guenter Roeck
@ 2020-01-23 15:51 ` Peter Maydell
2020-01-23 16:23 ` Peter Maydell
0 siblings, 1 reply; 14+ messages in thread
From: Peter Maydell @ 2020-01-23 15:51 UTC (permalink / raw)
To: Guenter Roeck; +Cc: Paolo Bonzini, qemu-arm, QEMU Developers
On Thu, 23 Jan 2020 at 05:25, Guenter Roeck <linux@roeck-us.net> wrote:
>
> Replace debug logging code with tracing.
>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This turns out not to compile on OSX, which is a bit
stricter about format strings:
These two:
> +pl330_dmald(uint32_t chan, uint32_t addr, uint32_t size, uint32_t num, uint32_t ch) "channel:%"PRId8" address:0x%08"PRIx32" size:0x%"PRIx32" num:%"PRId32"%c"
> +pl330_dmast(uint32_t chn, uint32_t addr, uint32_t sz, uint32_t num, uint32_t c) "channel:%"PRId8" address:0x%08"PRIx32" size:0x%"PRIx32" num:%"PRId32" %c"
both provoke
error: format specifies type 'char' but the argument has type
'uint32_t' (aka 'unsigned int') [-Werror,-Wformat]
because of the last argument.
Easy fix would seem to be to change 'uint32_t ch' to 'char ch'
(the argument is always a literal constant 'Y' or 'N').
thanks
-- PMM
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 1/8] dma/pl330: Convert to support tracing
2020-01-23 15:51 ` Peter Maydell
@ 2020-01-23 16:23 ` Peter Maydell
2020-01-23 16:57 ` Guenter Roeck
0 siblings, 1 reply; 14+ messages in thread
From: Peter Maydell @ 2020-01-23 16:23 UTC (permalink / raw)
To: Guenter Roeck; +Cc: Paolo Bonzini, qemu-arm, QEMU Developers
On Thu, 23 Jan 2020 at 15:51, Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Thu, 23 Jan 2020 at 05:25, Guenter Roeck <linux@roeck-us.net> wrote:
> >
> > Replace debug logging code with tracing.
> >
> > Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
> > Signed-off-by: Guenter Roeck <linux@roeck-us.net>
>
> This turns out not to compile on OSX, which is a bit
> stricter about format strings:
>
> These two:
>
> > +pl330_dmald(uint32_t chan, uint32_t addr, uint32_t size, uint32_t num, uint32_t ch) "channel:%"PRId8" address:0x%08"PRIx32" size:0x%"PRIx32" num:%"PRId32"%c"
>
> > +pl330_dmast(uint32_t chn, uint32_t addr, uint32_t sz, uint32_t num, uint32_t c) "channel:%"PRId8" address:0x%08"PRIx32" size:0x%"PRIx32" num:%"PRId32" %c"
>
> both provoke
> error: format specifies type 'char' but the argument has type
> 'uint32_t' (aka 'unsigned int') [-Werror,-Wformat]
>
> because of the last argument.
>
> Easy fix would seem to be to change 'uint32_t ch' to 'char ch'
> (the argument is always a literal constant 'Y' or 'N').
The 'chan'/'chn' argument is wrong too -- should be uint8_t
to match the format string and the type of PL330Chan::tag.
I'll just fix up the pullreq rather than forcing a respin.
-- PMM
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 1/8] dma/pl330: Convert to support tracing
2020-01-23 16:23 ` Peter Maydell
@ 2020-01-23 16:57 ` Guenter Roeck
0 siblings, 0 replies; 14+ messages in thread
From: Guenter Roeck @ 2020-01-23 16:57 UTC (permalink / raw)
To: Peter Maydell; +Cc: Paolo Bonzini, qemu-arm, QEMU Developers
On Thu, Jan 23, 2020 at 04:23:59PM +0000, Peter Maydell wrote:
> On Thu, 23 Jan 2020 at 15:51, Peter Maydell <peter.maydell@linaro.org> wrote:
> >
> > On Thu, 23 Jan 2020 at 05:25, Guenter Roeck <linux@roeck-us.net> wrote:
> > >
> > > Replace debug logging code with tracing.
> > >
> > > Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
> > > Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> >
> > This turns out not to compile on OSX, which is a bit
> > stricter about format strings:
> >
> > These two:
> >
> > > +pl330_dmald(uint32_t chan, uint32_t addr, uint32_t size, uint32_t num, uint32_t ch) "channel:%"PRId8" address:0x%08"PRIx32" size:0x%"PRIx32" num:%"PRId32"%c"
> >
> > > +pl330_dmast(uint32_t chn, uint32_t addr, uint32_t sz, uint32_t num, uint32_t c) "channel:%"PRId8" address:0x%08"PRIx32" size:0x%"PRIx32" num:%"PRId32" %c"
> >
> > both provoke
> > error: format specifies type 'char' but the argument has type
> > 'uint32_t' (aka 'unsigned int') [-Werror,-Wformat]
> >
> > because of the last argument.
> >
> > Easy fix would seem to be to change 'uint32_t ch' to 'char ch'
> > (the argument is always a literal constant 'Y' or 'N').
>
> The 'chan'/'chn' argument is wrong too -- should be uint8_t
> to match the format string and the type of PL330Chan::tag.
> I'll just fix up the pullreq rather than forcing a respin.
Thanks, and sorry for the trouble.
Guenter
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2020-01-23 19:25 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-01-23 5:25 [PATCH v3 0/8] Fix Exynos4210 DMA support Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 1/8] dma/pl330: Convert to support tracing Guenter Roeck
2020-01-23 15:51 ` Peter Maydell
2020-01-23 16:23 ` Peter Maydell
2020-01-23 16:57 ` Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 2/8] hw/core/or-irq: Increase limit of or-lines to 48 Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 3/8] hw/arm/exynos4210: Fix DMA initialization Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 4/8] hw/char/exynos4210_uart: Convert to support tracing Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 5/8] hw/char/exynos4210_uart: Implement post_load function Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 6/8] hw/char/exynos4210_uart: Implement Rx FIFO level triggers and timeouts Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 7/8] hw/char/exynos4210_uart: Add receive DMA support Guenter Roeck
2020-01-23 5:25 ` [PATCH v3 8/8] hw/arm/exynos4210: Connect serial port DMA busy signals with pl330 Guenter Roeck
2020-01-23 15:20 ` [PATCH v3 0/8] Fix Exynos4210 DMA support Peter Maydell
2020-01-23 15:39 ` Guenter Roeck
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).