[PATCH] hw/char: disable ibex uart receive if the buffer is full

Alexander Wagner posted 1 patch 3 years, 3 months ago
Test checkpatch passed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20210215231528.2718086-1-alexander.wagner@ulal.de
Maintainers: Alistair Francis <Alistair.Francis@wdc.com>, Paolo Bonzini <pbonzini@redhat.com>, "Marc-André Lureau" <marcandre.lureau@redhat.com>
There is a newer version of this series
hw/char/ibex_uart.c         | 20 +++++++++++++++-----
include/hw/char/ibex_uart.h |  4 ++++
2 files changed, 19 insertions(+), 5 deletions(-)
[PATCH] hw/char: disable ibex uart receive if the buffer is full
Posted by Alexander Wagner 3 years, 3 months ago
Not disabling the UART leads to QEMU overwriting the UART receive buffer with
the newest received byte. The rx_level variable is added to allow the use of
the existing OpenTitan driver libraries.

Signed-off-by: Alexander Wagner <alexander.wagner@ulal.de>
---
 hw/char/ibex_uart.c         | 20 +++++++++++++++-----
 include/hw/char/ibex_uart.h |  4 ++++
 2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
index 89f1182c9b..dac09d53d6 100644
--- a/hw/char/ibex_uart.c
+++ b/hw/char/ibex_uart.c
@@ -66,7 +66,8 @@ static int ibex_uart_can_receive(void *opaque)
 {
     IbexUartState *s = opaque;
 
-    if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
+    if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK)
+           && !(s->uart_status & R_STATUS_RXFULL_MASK)) {
         return 1;
     }
 
@@ -83,6 +84,8 @@ static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
 
     s->uart_status &= ~R_STATUS_RXIDLE_MASK;
     s->uart_status &= ~R_STATUS_RXEMPTY_MASK;
+    s->uart_status |= R_STATUS_RXFULL_MASK;
+    s->rx_level += 1;
 
     if (size > rx_fifo_level) {
         s->uart_intr_state |= R_INTR_STATE_RX_WATERMARK_MASK;
@@ -199,6 +202,7 @@ static void ibex_uart_reset(DeviceState *dev)
     s->uart_timeout_ctrl = 0x00000000;
 
     s->tx_level = 0;
+    s->rx_level = 0;
 
     s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
 
@@ -243,11 +247,15 @@ static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
 
     case R_RDATA:
         retvalue = s->uart_rdata;
-        if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
+        if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) && (s->rx_level > 0)) {
             qemu_chr_fe_accept_input(&s->chr);
 
-            s->uart_status |= R_STATUS_RXIDLE_MASK;
-            s->uart_status |= R_STATUS_RXEMPTY_MASK;
+            s->rx_level -= 1;
+            s->uart_status &= ~R_STATUS_RXFULL_MASK;
+            if (s->rx_level == 0) {
+                s->uart_status |= R_STATUS_RXIDLE_MASK;
+                s->uart_status |= R_STATUS_RXEMPTY_MASK;
+            }
         }
         break;
     case R_WDATA:
@@ -261,7 +269,8 @@ static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
     case R_FIFO_STATUS:
         retvalue = s->uart_fifo_status;
 
-        retvalue |= s->tx_level & 0x1F;
+        retvalue |= (s->rx_level & 0x1F) << R_FIFO_STATUS_RXLVL_SHIFT;
+        retvalue |= (s->tx_level & 0x1F) << R_FIFO_STATUS_TXLVL_SHIFT;
 
         qemu_log_mask(LOG_UNIMP,
                       "%s: RX fifos are not supported\n", __func__);
@@ -364,6 +373,7 @@ static void ibex_uart_write(void *opaque, hwaddr addr,
         s->uart_fifo_ctrl = value;
 
         if (value & R_FIFO_CTRL_RXRST_MASK) {
+            s->rx_level = 0;
             qemu_log_mask(LOG_UNIMP,
                           "%s: RX fifos are not supported\n", __func__);
         }
diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h
index 03d19e3f6f..546f958eb8 100644
--- a/include/hw/char/ibex_uart.h
+++ b/include/hw/char/ibex_uart.h
@@ -62,6 +62,8 @@ REG32(FIFO_CTRL, 0x1c)
     FIELD(FIFO_CTRL, RXILVL, 2, 3)
     FIELD(FIFO_CTRL, TXILVL, 5, 2)
 REG32(FIFO_STATUS, 0x20)
+    FIELD(FIFO_STATUS, TXLVL, 0, 5)
+    FIELD(FIFO_STATUS, RXLVL, 16, 5)
 REG32(OVRD, 0x24)
 REG32(VAL, 0x28)
 REG32(TIMEOUT_CTRL, 0x2c)
@@ -82,6 +84,8 @@ struct IbexUartState {
     uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
     uint32_t tx_level;
 
+    uint32_t rx_level;
+
     QEMUTimer *fifo_trigger_handle;
     uint64_t char_tx_time;
 
-- 
2.25.1


Re: [PATCH] hw/char: disable ibex uart receive if the buffer is full
Posted by Alexander Wagner 3 years, 2 months ago
ping

https://patchew.org/QEMU/20210215231528.2718086-1-alexander.wagner@ulal.de/

On 16.02.21 00:15, Alexander Wagner wrote:
> Not disabling the UART leads to QEMU overwriting the UART receive buffer with
> the newest received byte. The rx_level variable is added to allow the use of
> the existing OpenTitan driver libraries.
>
> Signed-off-by: Alexander Wagner <alexander.wagner@ulal.de>
> ---
>   hw/char/ibex_uart.c         | 20 +++++++++++++++-----
>   include/hw/char/ibex_uart.h |  4 ++++
>   2 files changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
> index 89f1182c9b..dac09d53d6 100644
> --- a/hw/char/ibex_uart.c
> +++ b/hw/char/ibex_uart.c
> @@ -66,7 +66,8 @@ static int ibex_uart_can_receive(void *opaque)
>   {
>       IbexUartState *s = opaque;
>   
> -    if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
> +    if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK)
> +           && !(s->uart_status & R_STATUS_RXFULL_MASK)) {
>           return 1;
>       }
>   
> @@ -83,6 +84,8 @@ static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
>   
>       s->uart_status &= ~R_STATUS_RXIDLE_MASK;
>       s->uart_status &= ~R_STATUS_RXEMPTY_MASK;
> +    s->uart_status |= R_STATUS_RXFULL_MASK;
> +    s->rx_level += 1;
>   
>       if (size > rx_fifo_level) {
>           s->uart_intr_state |= R_INTR_STATE_RX_WATERMARK_MASK;
> @@ -199,6 +202,7 @@ static void ibex_uart_reset(DeviceState *dev)
>       s->uart_timeout_ctrl = 0x00000000;
>   
>       s->tx_level = 0;
> +    s->rx_level = 0;
>   
>       s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
>   
> @@ -243,11 +247,15 @@ static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
>   
>       case R_RDATA:
>           retvalue = s->uart_rdata;
> -        if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
> +        if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) && (s->rx_level > 0)) {
>               qemu_chr_fe_accept_input(&s->chr);
>   
> -            s->uart_status |= R_STATUS_RXIDLE_MASK;
> -            s->uart_status |= R_STATUS_RXEMPTY_MASK;
> +            s->rx_level -= 1;
> +            s->uart_status &= ~R_STATUS_RXFULL_MASK;
> +            if (s->rx_level == 0) {
> +                s->uart_status |= R_STATUS_RXIDLE_MASK;
> +                s->uart_status |= R_STATUS_RXEMPTY_MASK;
> +            }
>           }
>           break;
>       case R_WDATA:
> @@ -261,7 +269,8 @@ static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
>       case R_FIFO_STATUS:
>           retvalue = s->uart_fifo_status;
>   
> -        retvalue |= s->tx_level & 0x1F;
> +        retvalue |= (s->rx_level & 0x1F) << R_FIFO_STATUS_RXLVL_SHIFT;
> +        retvalue |= (s->tx_level & 0x1F) << R_FIFO_STATUS_TXLVL_SHIFT;
>   
>           qemu_log_mask(LOG_UNIMP,
>                         "%s: RX fifos are not supported\n", __func__);
> @@ -364,6 +373,7 @@ static void ibex_uart_write(void *opaque, hwaddr addr,
>           s->uart_fifo_ctrl = value;
>   
>           if (value & R_FIFO_CTRL_RXRST_MASK) {
> +            s->rx_level = 0;
>               qemu_log_mask(LOG_UNIMP,
>                             "%s: RX fifos are not supported\n", __func__);
>           }
> diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h
> index 03d19e3f6f..546f958eb8 100644
> --- a/include/hw/char/ibex_uart.h
> +++ b/include/hw/char/ibex_uart.h
> @@ -62,6 +62,8 @@ REG32(FIFO_CTRL, 0x1c)
>       FIELD(FIFO_CTRL, RXILVL, 2, 3)
>       FIELD(FIFO_CTRL, TXILVL, 5, 2)
>   REG32(FIFO_STATUS, 0x20)
> +    FIELD(FIFO_STATUS, TXLVL, 0, 5)
> +    FIELD(FIFO_STATUS, RXLVL, 16, 5)
>   REG32(OVRD, 0x24)
>   REG32(VAL, 0x28)
>   REG32(TIMEOUT_CTRL, 0x2c)
> @@ -82,6 +84,8 @@ struct IbexUartState {
>       uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
>       uint32_t tx_level;
>   
> +    uint32_t rx_level;
> +
>       QEMUTimer *fifo_trigger_handle;
>       uint64_t char_tx_time;
>   

Re: [PATCH] hw/char: disable ibex uart receive if the buffer is full
Posted by Alistair Francis 3 years, 2 months ago
On Mon, Feb 15, 2021 at 9:06 PM Alexander Wagner
<alexander.wagner@ulal.de> wrote:
>
> Not disabling the UART leads to QEMU overwriting the UART receive buffer with
> the newest received byte. The rx_level variable is added to allow the use of
> the existing OpenTitan driver libraries.
>
> Signed-off-by: Alexander Wagner <alexander.wagner@ulal.de>

Thanks for the patch!

I'm glad to see others using OT on QEMU.

> ---
>  hw/char/ibex_uart.c         | 20 +++++++++++++++-----
>  include/hw/char/ibex_uart.h |  4 ++++
>  2 files changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
> index 89f1182c9b..dac09d53d6 100644
> --- a/hw/char/ibex_uart.c
> +++ b/hw/char/ibex_uart.c
> @@ -66,7 +66,8 @@ static int ibex_uart_can_receive(void *opaque)
>  {
>      IbexUartState *s = opaque;
>
> -    if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
> +    if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK)
> +           && !(s->uart_status & R_STATUS_RXFULL_MASK)) {
>          return 1;
>      }
>
> @@ -83,6 +84,8 @@ static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
>
>      s->uart_status &= ~R_STATUS_RXIDLE_MASK;
>      s->uart_status &= ~R_STATUS_RXEMPTY_MASK;
> +    s->uart_status |= R_STATUS_RXFULL_MASK;

Doesn't this mean we set RXFULL on every receive? Shouldn't this check
the rx_level first?

Alistair

> +    s->rx_level += 1;
>
>      if (size > rx_fifo_level) {
>          s->uart_intr_state |= R_INTR_STATE_RX_WATERMARK_MASK;
> @@ -199,6 +202,7 @@ static void ibex_uart_reset(DeviceState *dev)
>      s->uart_timeout_ctrl = 0x00000000;
>
>      s->tx_level = 0;
> +    s->rx_level = 0;
>
>      s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
>
> @@ -243,11 +247,15 @@ static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
>
>      case R_RDATA:
>          retvalue = s->uart_rdata;
> -        if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
> +        if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) && (s->rx_level > 0)) {
>              qemu_chr_fe_accept_input(&s->chr);
>
> -            s->uart_status |= R_STATUS_RXIDLE_MASK;
> -            s->uart_status |= R_STATUS_RXEMPTY_MASK;
> +            s->rx_level -= 1;
> +            s->uart_status &= ~R_STATUS_RXFULL_MASK;
> +            if (s->rx_level == 0) {
> +                s->uart_status |= R_STATUS_RXIDLE_MASK;
> +                s->uart_status |= R_STATUS_RXEMPTY_MASK;
> +            }
>          }
>          break;
>      case R_WDATA:
> @@ -261,7 +269,8 @@ static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
>      case R_FIFO_STATUS:
>          retvalue = s->uart_fifo_status;
>
> -        retvalue |= s->tx_level & 0x1F;
> +        retvalue |= (s->rx_level & 0x1F) << R_FIFO_STATUS_RXLVL_SHIFT;
> +        retvalue |= (s->tx_level & 0x1F) << R_FIFO_STATUS_TXLVL_SHIFT;
>
>          qemu_log_mask(LOG_UNIMP,
>                        "%s: RX fifos are not supported\n", __func__);
> @@ -364,6 +373,7 @@ static void ibex_uart_write(void *opaque, hwaddr addr,
>          s->uart_fifo_ctrl = value;
>
>          if (value & R_FIFO_CTRL_RXRST_MASK) {
> +            s->rx_level = 0;
>              qemu_log_mask(LOG_UNIMP,
>                            "%s: RX fifos are not supported\n", __func__);
>          }
> diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h
> index 03d19e3f6f..546f958eb8 100644
> --- a/include/hw/char/ibex_uart.h
> +++ b/include/hw/char/ibex_uart.h
> @@ -62,6 +62,8 @@ REG32(FIFO_CTRL, 0x1c)
>      FIELD(FIFO_CTRL, RXILVL, 2, 3)
>      FIELD(FIFO_CTRL, TXILVL, 5, 2)
>  REG32(FIFO_STATUS, 0x20)
> +    FIELD(FIFO_STATUS, TXLVL, 0, 5)
> +    FIELD(FIFO_STATUS, RXLVL, 16, 5)
>  REG32(OVRD, 0x24)
>  REG32(VAL, 0x28)
>  REG32(TIMEOUT_CTRL, 0x2c)
> @@ -82,6 +84,8 @@ struct IbexUartState {
>      uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
>      uint32_t tx_level;
>
> +    uint32_t rx_level;
> +
>      QEMUTimer *fifo_trigger_handle;
>      uint64_t char_tx_time;
>
> --
> 2.25.1
>
>

Re: [PATCH] hw/char: disable ibex uart receive if the buffer is full
Posted by Alexander Wagner 3 years, 2 months ago
On 08.03.21 14:47, Alistair Francis wrote:
>>   hw/char/ibex_uart.c         | 20 +++++++++++++++-----
>>   include/hw/char/ibex_uart.h |  4 ++++
>>   2 files changed, 19 insertions(+), 5 deletions(-)
>>
>> diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
>> index 89f1182c9b..dac09d53d6 100644
>> --- a/hw/char/ibex_uart.c
>> +++ b/hw/char/ibex_uart.c
>> @@ -66,7 +66,8 @@ static int ibex_uart_can_receive(void *opaque)
>>   {
>>       IbexUartState *s = opaque;
>>
>> -    if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
>> +    if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK)
>> +           && !(s->uart_status & R_STATUS_RXFULL_MASK)) {
>>           return 1;
>>       }
>>
>> @@ -83,6 +84,8 @@ static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
>>
>>       s->uart_status &= ~R_STATUS_RXIDLE_MASK;
>>       s->uart_status &= ~R_STATUS_RXEMPTY_MASK;
>> +    s->uart_status |= R_STATUS_RXFULL_MASK;
> Doesn't this mean we set RXFULL on every receive? Shouldn't this check
> the rx_level first?
>
> Alistair

Thank you for having a look! :)

Yes, this is correct. The RXFULL is currently set on every receive. The 
RXFULL is used to indicate to QEMU that the device cannot receive any 
further bytes.

As the FIFO buffers are currently not yet implemented I thought it would 
make sense to behave like the OT UART could only receive one byte at a time.

Alex


Re: [PATCH] hw/char: disable ibex uart receive if the buffer is full
Posted by Alistair Francis 3 years, 2 months ago
On Tue, Mar 9, 2021 at 2:27 AM Alexander Wagner
<alexander.wagner@ulal.de> wrote:
>
>
> On 08.03.21 14:47, Alistair Francis wrote:
> >>   hw/char/ibex_uart.c         | 20 +++++++++++++++-----
> >>   include/hw/char/ibex_uart.h |  4 ++++
> >>   2 files changed, 19 insertions(+), 5 deletions(-)
> >>
> >> diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
> >> index 89f1182c9b..dac09d53d6 100644
> >> --- a/hw/char/ibex_uart.c
> >> +++ b/hw/char/ibex_uart.c
> >> @@ -66,7 +66,8 @@ static int ibex_uart_can_receive(void *opaque)
> >>   {
> >>       IbexUartState *s = opaque;
> >>
> >> -    if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
> >> +    if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK)
> >> +           && !(s->uart_status & R_STATUS_RXFULL_MASK)) {
> >>           return 1;
> >>       }
> >>
> >> @@ -83,6 +84,8 @@ static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
> >>
> >>       s->uart_status &= ~R_STATUS_RXIDLE_MASK;
> >>       s->uart_status &= ~R_STATUS_RXEMPTY_MASK;
> >> +    s->uart_status |= R_STATUS_RXFULL_MASK;
> > Doesn't this mean we set RXFULL on every receive? Shouldn't this check
> > the rx_level first?
> >
> > Alistair
>
> Thank you for having a look! :)
>
> Yes, this is correct. The RXFULL is currently set on every receive. The
> RXFULL is used to indicate to QEMU that the device cannot receive any
> further bytes.
>
> As the FIFO buffers are currently not yet implemented I thought it would
> make sense to behave like the OT UART could only receive one byte at a time.

Ah, good point.

Can you add a comment where it is set describing that then?

Alistair

>
> Alex
>

Re: [PATCH] hw/char: disable ibex uart receive if the buffer is full
Posted by Alexander Wagner 3 years, 2 months ago
On 09.03.21 15:29, Alistair Francis wrote:
> On Tue, Mar 9, 2021 at 2:27 AM Alexander Wagner
> <alexander.wagner@ulal.de> wrote:
>>
>> On 08.03.21 14:47, Alistair Francis wrote:
>>>>    hw/char/ibex_uart.c         | 20 +++++++++++++++-----
>>>>    include/hw/char/ibex_uart.h |  4 ++++
>>>>    2 files changed, 19 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
>>>> index 89f1182c9b..dac09d53d6 100644
>>>> --- a/hw/char/ibex_uart.c
>>>> +++ b/hw/char/ibex_uart.c
>>>> @@ -66,7 +66,8 @@ static int ibex_uart_can_receive(void *opaque)
>>>>    {
>>>>        IbexUartState *s = opaque;
>>>>
>>>> -    if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
>>>> +    if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK)
>>>> +           && !(s->uart_status & R_STATUS_RXFULL_MASK)) {
>>>>            return 1;
>>>>        }
>>>>
>>>> @@ -83,6 +84,8 @@ static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
>>>>
>>>>        s->uart_status &= ~R_STATUS_RXIDLE_MASK;
>>>>        s->uart_status &= ~R_STATUS_RXEMPTY_MASK;
>>>> +    s->uart_status |= R_STATUS_RXFULL_MASK;
>>> Doesn't this mean we set RXFULL on every receive? Shouldn't this check
>>> the rx_level first?
>>>
>>> Alistair
>> Thank you for having a look! :)
>>
>> Yes, this is correct. The RXFULL is currently set on every receive. The
>> RXFULL is used to indicate to QEMU that the device cannot receive any
>> further bytes.
>>
>> As the FIFO buffers are currently not yet implemented I thought it would
>> make sense to behave like the OT UART could only receive one byte at a time.
> Ah, good point.
>
> Can you add a comment where it is set describing that then?
>
> Alistair
>
Sure, I just added a comment and emailed this as patch v2.

Alex