On 22:08 Wed 19 Feb     , Philippe Mathieu-Daudé wrote:
> In the IOCanReadHandler sh_serial_can_receive(), if the Serial
> Control Register 'Receive Enable' bit is set (bit 4), then we
> returns a size of (1 << 4) which happens to be equal to 16,
return

> so effectively SH_RX_FIFO_LENGTH.
> 
> The IOReadHandler, sh_serial_receive1() takes care to receive
> multiple chars, but if the FIFO is partly filled, we only process
> the number of free slots in the FIFO, discarding the other chars!
> 
> Fix by returning how many elements the FIFO can queue in the
> IOCanReadHandler, so we don't have to process more than that in
> the IOReadHandler, thus not discarding anything.
> 
> Remove the now unnecessary check on 's->rx_cnt < SH_RX_FIFO_LENGTH'
> in IOReadHandler, reducing the block indentation.
> 
> Fixes: 63242a007a1 ("SH4: Serial controller improvement")
> Signed-off-by: Philippe Mathieu-Daudé <phi...@linaro.org>

nice one :)
Reviewed-by: Luc Michel <luc.mic...@amd.com>

> ---
>  hw/char/sh_serial.c | 30 ++++++++++++++----------------
>  1 file changed, 14 insertions(+), 16 deletions(-)
> 
> diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
> index 247aeb071ac..41c8175a638 100644
> --- a/hw/char/sh_serial.c
> +++ b/hw/char/sh_serial.c
> @@ -320,7 +320,7 @@ static uint64_t sh_serial_read(void *opaque, hwaddr offs,
> 
>  static int sh_serial_can_receive(SHSerialState *s)
>  {
> -    return s->scr & (1 << 4);
> +    return s->scr & (1 << 4) ? SH_RX_FIFO_LENGTH - s->rx_head : 0;
>  }
> 
>  static void sh_serial_receive_break(SHSerialState *s)
> @@ -353,22 +353,20 @@ static void sh_serial_receive1(void *opaque, const 
> uint8_t *buf, int size)
>      if (s->feat & SH_SERIAL_FEAT_SCIF) {
>          int i;
>          for (i = 0; i < size; i++) {
> -            if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
> -                s->rx_fifo[s->rx_head++] = buf[i];
> -                if (s->rx_head == SH_RX_FIFO_LENGTH) {
> -                    s->rx_head = 0;
> -                }
> -                s->rx_cnt++;
> -                if (s->rx_cnt >= s->rtrg) {
> -                    s->flags |= SH_SERIAL_FLAG_RDF;
> -                    if (s->scr & (1 << 6) && s->rxi) {
> -                        timer_del(&s->fifo_timeout_timer);
> -                        qemu_set_irq(s->rxi, 1);
> -                    }
> -                } else {
> -                    timer_mod(&s->fifo_timeout_timer,
> -                        qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
> +            s->rx_fifo[s->rx_head++] = buf[i];
> +            if (s->rx_head == SH_RX_FIFO_LENGTH) {
> +                s->rx_head = 0;
> +            }
> +            s->rx_cnt++;
> +            if (s->rx_cnt >= s->rtrg) {
> +                s->flags |= SH_SERIAL_FLAG_RDF;
> +                if (s->scr & (1 << 6) && s->rxi) {
> +                    timer_del(&s->fifo_timeout_timer);
> +                    qemu_set_irq(s->rxi, 1);
>                  }
> +            } else {
> +                timer_mod(&s->fifo_timeout_timer,
> +                    qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
>              }
>          }
>      } else {
> --
> 2.47.1
> 

-- 

Reply via email to