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 > --