From 62a3f63182a7cda98bdc168ed841507befca014f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 13 Sep 2021 16:07:21 +0100 Subject: hw/char: cadence_uart: Disable transmit when input clock is disabled At present when input clock is disabled, any character transmitted to tx fifo can still show on the serial line, which is wrong. Fixes: b636db306e06 ("hw/char/cadence_uart: add clock support") Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Message-id: 20210901124521.30599-3-bmeng.cn@gmail.com Signed-off-by: Peter Maydell --- hw/char/cadence_uart.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'hw/char/cadence_uart.c') diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index b4b5e8a3ee..154be34992 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -327,6 +327,11 @@ static gboolean cadence_uart_xmit(void *do_not_use, GIOCondition cond, static void uart_write_tx_fifo(CadenceUARTState *s, const uint8_t *buf, int size) { + /* ignore characters when unclocked or in reset */ + if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) { + return; + } + if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) { return; } -- cgit 1.4.1 From 983f4adf364628bf1e75f99d85a47a803d2e2dce Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 13 Sep 2021 16:07:21 +0100 Subject: hw/char: cadence_uart: Move clock/reset check to uart_can_receive() Currently the clock/reset check is done in uart_receive(), but we can move the check to uart_can_receive() which is earlier. Signed-off-by: Bin Meng Reviewed-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Message-id: 20210901124521.30599-4-bmeng.cn@gmail.com Signed-off-by: Peter Maydell --- hw/char/cadence_uart.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'hw/char/cadence_uart.c') diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index 154be34992..fff8be3619 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -235,8 +235,16 @@ static void uart_parameters_setup(CadenceUARTState *s) static int uart_can_receive(void *opaque) { CadenceUARTState *s = opaque; - int ret = MAX(CADENCE_UART_RX_FIFO_SIZE, CADENCE_UART_TX_FIFO_SIZE); - uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE; + int ret; + uint32_t ch_mode; + + /* ignore characters when unclocked or in reset */ + if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) { + return 0; + } + + ret = MAX(CADENCE_UART_RX_FIFO_SIZE, CADENCE_UART_TX_FIFO_SIZE); + ch_mode = s->r[R_MR] & UART_MR_CHMODE; if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) { ret = MIN(ret, CADENCE_UART_RX_FIFO_SIZE - s->rx_count); @@ -358,11 +366,6 @@ static void uart_receive(void *opaque, const uint8_t *buf, int size) CadenceUARTState *s = opaque; uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE; - /* ignore characters when unclocked or in reset */ - if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) { - return; - } - if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) { uart_write_rx_fifo(opaque, buf, size); } -- cgit 1.4.1 From 7956a8f5dd702adf351575b2aee9dbd99001b61f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 13 Sep 2021 16:07:21 +0100 Subject: hw/char: cadence_uart: Convert to memop_with_attrs() ops This converts uart_read() and uart_write() to memop_with_attrs() ops. Signed-off-by: Bin Meng Reviewed-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Message-id: 20210901124521.30599-5-bmeng.cn@gmail.com Signed-off-by: Peter Maydell --- hw/char/cadence_uart.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'hw/char/cadence_uart.c') diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index fff8be3619..8bcf2b718a 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -411,15 +411,15 @@ static void uart_read_rx_fifo(CadenceUARTState *s, uint32_t *c) uart_update_status(s); } -static void uart_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) +static MemTxResult uart_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size, MemTxAttrs attrs) { CadenceUARTState *s = opaque; DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value); offset >>= 2; if (offset >= CADENCE_UART_R_MAX) { - return; + return MEMTX_DECODE_ERROR; } switch (offset) { case R_IER: /* ier (wts imr) */ @@ -466,30 +466,34 @@ static void uart_write(void *opaque, hwaddr offset, break; } uart_update_status(s); + + return MEMTX_OK; } -static uint64_t uart_read(void *opaque, hwaddr offset, - unsigned size) +static MemTxResult uart_read(void *opaque, hwaddr offset, + uint64_t *value, unsigned size, MemTxAttrs attrs) { CadenceUARTState *s = opaque; uint32_t c = 0; offset >>= 2; if (offset >= CADENCE_UART_R_MAX) { - c = 0; - } else if (offset == R_TX_RX) { + return MEMTX_DECODE_ERROR; + } + if (offset == R_TX_RX) { uart_read_rx_fifo(s, &c); } else { - c = s->r[offset]; + c = s->r[offset]; } DB_PRINT(" offset:%x data:%08x\n", (unsigned)(offset << 2), (unsigned)c); - return c; + *value = c; + return MEMTX_OK; } static const MemoryRegionOps uart_ops = { - .read = uart_read, - .write = uart_write, + .read_with_attrs = uart_read, + .write_with_attrs = uart_write, .endianness = DEVICE_NATIVE_ENDIAN, }; -- cgit 1.4.1 From 9834ecaaea8dfe1def47431f096a2b77de3583a1 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 13 Sep 2021 16:07:21 +0100 Subject: hw/char: cadence_uart: Ignore access when unclocked or in reset for uart_{read, write}() Read or write to uart registers when unclocked or in reset should be ignored. Add the check there, and as a result of this, the check in uart_write_tx_fifo() is now unnecessary. Signed-off-by: Bin Meng Reviewed-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Message-id: 20210901124521.30599-6-bmeng.cn@gmail.com Signed-off-by: Peter Maydell --- hw/char/cadence_uart.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'hw/char/cadence_uart.c') diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index 8bcf2b718a..5f5a4645ac 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -335,11 +335,6 @@ static gboolean cadence_uart_xmit(void *do_not_use, GIOCondition cond, static void uart_write_tx_fifo(CadenceUARTState *s, const uint8_t *buf, int size) { - /* ignore characters when unclocked or in reset */ - if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) { - return; - } - if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) { return; } @@ -416,6 +411,11 @@ static MemTxResult uart_write(void *opaque, hwaddr offset, { CadenceUARTState *s = opaque; + /* ignore access when unclocked or in reset */ + if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) { + return MEMTX_ERROR; + } + DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value); offset >>= 2; if (offset >= CADENCE_UART_R_MAX) { @@ -476,6 +476,11 @@ static MemTxResult uart_read(void *opaque, hwaddr offset, CadenceUARTState *s = opaque; uint32_t c = 0; + /* ignore access when unclocked or in reset */ + if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) { + return MEMTX_ERROR; + } + offset >>= 2; if (offset >= CADENCE_UART_R_MAX) { return MEMTX_DECODE_ERROR; -- cgit 1.4.1 From 47c305f6f2761c5be9b5a69721cd586aaae0d43e Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Mon, 13 Sep 2021 16:07:21 +0100 Subject: hw/char: cadence_uart: Log a guest error when device is unclocked or in reset We've got SW that expects FSBL (Bootlooader) to setup clocks and resets. It's quite common that users run that SW on QEMU without FSBL (FSBL typically requires the Xilinx tools installed). That's fine, since users can stil use -device loader to enable clocks etc. To help folks understand what's going, a log (guest-error) message would be helpful here. In particular with the serial port since things will go very quiet if they get things wrong. Suggested-by: Edgar E. Iglesias Signed-off-by: Bin Meng Reviewed-by: Edgar E. Iglesias Reviewed-by: Alistair Francis Message-id: 20210901124521.30599-7-bmeng.cn@gmail.com Signed-off-by: Peter Maydell --- hw/char/cadence_uart.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'hw/char/cadence_uart.c') diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index 5f5a4645ac..c069a30842 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -240,6 +240,8 @@ static int uart_can_receive(void *opaque) /* ignore characters when unclocked or in reset */ if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: uart is unclocked or in reset\n", + __func__); return 0; } @@ -376,6 +378,8 @@ static void uart_event(void *opaque, QEMUChrEvent event) /* ignore characters when unclocked or in reset */ if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: uart is unclocked or in reset\n", + __func__); return; } @@ -413,6 +417,8 @@ static MemTxResult uart_write(void *opaque, hwaddr offset, /* ignore access when unclocked or in reset */ if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: uart is unclocked or in reset\n", + __func__); return MEMTX_ERROR; } @@ -478,6 +484,8 @@ static MemTxResult uart_read(void *opaque, hwaddr offset, /* ignore access when unclocked or in reset */ if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: uart is unclocked or in reset\n", + __func__); return MEMTX_ERROR; } -- cgit 1.4.1