diff mbox series

lib: utils/serial: Modify uart_getc to a blocking function

Message ID 20211113070622.90364-1-wxjstz@126.com
State Rejected
Headers show
Series lib: utils/serial: Modify uart_getc to a blocking function | expand

Commit Message

Xiang W Nov. 13, 2021, 7:06 a.m. UTC
If uart_getc is non-blocking, if the sending end is faster than the
receiving end, the data received by some functions(sbi_gets) is
incomplete

Signed-off-by: Xiang W <wxjstz@126.com>
---
 lib/utils/serial/gaisler-uart.c |  5 ++---
 lib/utils/serial/shakti-uart.c  |  7 +++----
 lib/utils/serial/sifive-uart.c  |  9 +++++----
 lib/utils/serial/uart8250.c     |  6 +++---
 lib/utils/sys/htif.c            | 11 +++++------
 5 files changed, 18 insertions(+), 20 deletions(-)

Comments

Jessica Clarke Nov. 13, 2021, 10:11 p.m. UTC | #1
On 13 Nov 2021, at 07:06, Xiang W <wxjstz@126.com> wrote:
> 
> If uart_getc is non-blocking, if the sending end is faster than the
> receiving end, the data received by some functions(sbi_gets) is
> incomplete

Without hardware flow control this is always going to be true. Making
getc blocking does not change that. Moreover, making it blocking means
there is no longer a way to poll, whereas having it be non-blocking
means you can poll, and if you want to make it blocking you can always
put a loop in the caller (which also avoids putting it in every single
driver).

Also, this breaks the SBI getchar call; it’s supposed to be
non-blocking, but this makes it blocking, so it is impossible for an OS
to poll the SBI console.

Thus, NACK of the entire concept.

Jess

> Signed-off-by: Xiang W <wxjstz@126.com>
> ---
> lib/utils/serial/gaisler-uart.c |  5 ++---
> lib/utils/serial/shakti-uart.c  |  7 +++----
> lib/utils/serial/sifive-uart.c  |  9 +++++----
> lib/utils/serial/uart8250.c     |  6 +++---
> lib/utils/sys/htif.c            | 11 +++++------
> 5 files changed, 18 insertions(+), 20 deletions(-)
> 
> diff --git a/lib/utils/serial/gaisler-uart.c b/lib/utils/serial/gaisler-uart.c
> index 49298e9..1dc5ae0 100644
> --- a/lib/utils/serial/gaisler-uart.c
> +++ b/lib/utils/serial/gaisler-uart.c
> @@ -51,9 +51,8 @@ static void gaisler_uart_putc(char ch)
> 
> static int gaisler_uart_getc(void)
> {
> -	u32 ret = get_reg(UART_REG_STATUS);
> -	if (!(ret & UART_STATUS_DATAREADY))
> -		return -1;
> +	while (!(get_reg(UART_REG_STATUS) & UART_STATUS_DATAREADY))
> +		;
> 	return get_reg(UART_REG_DATA) & UART_DATA_DATA;
> }
> 
> diff --git a/lib/utils/serial/shakti-uart.c b/lib/utils/serial/shakti-uart.c
> index e77a985..a5b72aa 100644
> --- a/lib/utils/serial/shakti-uart.c
> +++ b/lib/utils/serial/shakti-uart.c
> @@ -32,10 +32,9 @@ static void shakti_uart_putc(char ch)
> 
> static int shakti_uart_getc(void)
> {
> -	u16 status = readw(uart_base + REG_STATUS);
> -	if (status & UART_RX_FULL)
> -		return readb(uart_base + REG_RX);
> -	return -1;
> +	while (!(readw(uart_base + REG_STATUS) & UART_RX_FULL))
> +		;
> +	return readb(uart_base + REG_RX);
> }
> 
> static struct sbi_console_device shakti_console = {
> diff --git a/lib/utils/serial/sifive-uart.c b/lib/utils/serial/sifive-uart.c
> index 57d80fa..68a9ca7 100644
> --- a/lib/utils/serial/sifive-uart.c
> +++ b/lib/utils/serial/sifive-uart.c
> @@ -76,10 +76,11 @@ static void sifive_uart_putc(char ch)
> 
> static int sifive_uart_getc(void)
> {
> -	u32 ret = get_reg(UART_REG_RXFIFO);
> -	if (!(ret & UART_RXFIFO_EMPTY))
> -		return ret & UART_RXFIFO_DATA;
> -	return -1;
> +	u32 ret;
> +	do
> +		ret = get_reg(UART_REG_RXFIFO);
> +	while (ret & UART_RXFIFO_EMPTY);
> +	return ret & UART_RXFIFO_DATA;
> }
> 
> static struct sbi_console_device sifive_console = {
> diff --git a/lib/utils/serial/uart8250.c b/lib/utils/serial/uart8250.c
> index 1cf6624..bab8111 100644
> --- a/lib/utils/serial/uart8250.c
> +++ b/lib/utils/serial/uart8250.c
> @@ -79,9 +79,9 @@ static void uart8250_putc(char ch)
> 
> static int uart8250_getc(void)
> {
> -	if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
> -		return get_reg(UART_RBR_OFFSET);
> -	return -1;
> +	while (!(get_reg(UART_LSR_OFFSET) & UART_LSR_DR))
> +		;
> +	return get_reg(UART_RBR_OFFSET);
> }
> 
> static struct sbi_console_device uart8250_console = {
> diff --git a/lib/utils/sys/htif.c b/lib/utils/sys/htif.c
> index 7c69c7f..dfda30a 100644
> --- a/lib/utils/sys/htif.c
> +++ b/lib/utils/sys/htif.c
> @@ -47,7 +47,7 @@
> 
> volatile uint64_t tohost __attribute__((section(".htif")));
> volatile uint64_t fromhost __attribute__((section(".htif")));
> -static int htif_console_buf;
> +static int htif_console_buf = -1;
> static spinlock_t htif_lock = SPIN_LOCK_INITIALIZER;
> 
> static void __check_fromhost()
> @@ -130,12 +130,11 @@ static int htif_getc(void)
> 
> 	spin_lock(&htif_lock);
> 
> -	__check_fromhost();
> +	while (htif_console_buf < 0)
> +		__check_fromhost();
> 	ch = htif_console_buf;
> -	if (ch >= 0) {
> -		htif_console_buf = -1;
> -		__set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
> -	}
> +	htif_console_buf = -1;
> +	__set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
> 
> 	spin_unlock(&htif_lock);
> 
> -- 
> 2.30.2
> 
> 
> -- 
> opensbi mailing list
> opensbi@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi
Xiang W Nov. 14, 2021, 12:16 a.m. UTC | #2
在 2021-11-13星期六的 22:11 +0000,Jessica Clarke写道:
> On 13 Nov 2021, at 07:06, Xiang W <wxjstz@126.com> wrote:
> > 
> > If uart_getc is non-blocking, if the sending end is faster than the
> > receiving end, the data received by some functions(sbi_gets) is
> > incomplete
> 
> Without hardware flow control this is always going to be true. Making
> getc blocking does not change that. Moreover, making it blocking
> means
> there is no longer a way to poll, whereas having it be non-blocking
> means you can poll, and if you want to make it blocking you can
> always
> put a loop in the caller (which also avoids putting it in every
> single
> driver).
> 
> Also, this breaks the SBI getchar call; it’s supposed to be
> non-blocking, but this makes it blocking, so it is impossible for an
> OS
> to poll the SBI console.
Linux also needs blocking sbi_getc, the following is the source code in
linux

static int hvc_sbi_tty_get(uint32_t vtermno, char *buf, int count)
{
	int i, c;

	for (i = 0; i < count; i++) {
		c = sbi_console_getchar();
		if (c < 0)
			break;
		buf[i] = c;
	}

	return i;
}

static const struct hv_ops hvc_sbi_ops = {
	.get_chars = hvc_sbi_tty_get,
	.put_chars = hvc_sbi_tty_put,
};

Regards,
Xiang W
> 
> Thus, NACK of the entire concept.
> 
> Jess
> 
> > Signed-off-by: Xiang W <wxjstz@126.com>
> > ---
> > lib/utils/serial/gaisler-uart.c |  5 ++---
> > lib/utils/serial/shakti-uart.c  |  7 +++----
> > lib/utils/serial/sifive-uart.c  |  9 +++++----
> > lib/utils/serial/uart8250.c     |  6 +++---
> > lib/utils/sys/htif.c            | 11 +++++------
> > 5 files changed, 18 insertions(+), 20 deletions(-)
> > 
> > diff --git a/lib/utils/serial/gaisler-uart.c
> > b/lib/utils/serial/gaisler-uart.c
> > index 49298e9..1dc5ae0 100644
> > --- a/lib/utils/serial/gaisler-uart.c
> > +++ b/lib/utils/serial/gaisler-uart.c
> > @@ -51,9 +51,8 @@ static void gaisler_uart_putc(char ch)
> > 
> > static int gaisler_uart_getc(void)
> > {
> > -       u32 ret = get_reg(UART_REG_STATUS);
> > -       if (!(ret & UART_STATUS_DATAREADY))
> > -               return -1;
> > +       while (!(get_reg(UART_REG_STATUS) & UART_STATUS_DATAREADY))
> > +               ;
> >         return get_reg(UART_REG_DATA) & UART_DATA_DATA;
> > }
> > 
> > diff --git a/lib/utils/serial/shakti-uart.c
> > b/lib/utils/serial/shakti-uart.c
> > index e77a985..a5b72aa 100644
> > --- a/lib/utils/serial/shakti-uart.c
> > +++ b/lib/utils/serial/shakti-uart.c
> > @@ -32,10 +32,9 @@ static void shakti_uart_putc(char ch)
> > 
> > static int shakti_uart_getc(void)
> > {
> > -       u16 status = readw(uart_base + REG_STATUS);
> > -       if (status & UART_RX_FULL)
> > -               return readb(uart_base + REG_RX);
> > -       return -1;
> > +       while (!(readw(uart_base + REG_STATUS) & UART_RX_FULL))
> > +               ;
> > +       return readb(uart_base + REG_RX);
> > }
> > 
> > static struct sbi_console_device shakti_console = {
> > diff --git a/lib/utils/serial/sifive-uart.c
> > b/lib/utils/serial/sifive-uart.c
> > index 57d80fa..68a9ca7 100644
> > --- a/lib/utils/serial/sifive-uart.c
> > +++ b/lib/utils/serial/sifive-uart.c
> > @@ -76,10 +76,11 @@ static void sifive_uart_putc(char ch)
> > 
> > static int sifive_uart_getc(void)
> > {
> > -       u32 ret = get_reg(UART_REG_RXFIFO);
> > -       if (!(ret & UART_RXFIFO_EMPTY))
> > -               return ret & UART_RXFIFO_DATA;
> > -       return -1;
> > +       u32 ret;
> > +       do
> > +               ret = get_reg(UART_REG_RXFIFO);
> > +       while (ret & UART_RXFIFO_EMPTY);
> > +       return ret & UART_RXFIFO_DATA;
> > }
> > 
> > static struct sbi_console_device sifive_console = {
> > diff --git a/lib/utils/serial/uart8250.c
> > b/lib/utils/serial/uart8250.c
> > index 1cf6624..bab8111 100644
> > --- a/lib/utils/serial/uart8250.c
> > +++ b/lib/utils/serial/uart8250.c
> > @@ -79,9 +79,9 @@ static void uart8250_putc(char ch)
> > 
> > static int uart8250_getc(void)
> > {
> > -       if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
> > -               return get_reg(UART_RBR_OFFSET);
> > -       return -1;
> > +       while (!(get_reg(UART_LSR_OFFSET) & UART_LSR_DR))
> > +               ;
> > +       return get_reg(UART_RBR_OFFSET);
> > }
> > 
> > static struct sbi_console_device uart8250_console = {
> > diff --git a/lib/utils/sys/htif.c b/lib/utils/sys/htif.c
> > index 7c69c7f..dfda30a 100644
> > --- a/lib/utils/sys/htif.c
> > +++ b/lib/utils/sys/htif.c
> > @@ -47,7 +47,7 @@
> > 
> > volatile uint64_t tohost __attribute__((section(".htif")));
> > volatile uint64_t fromhost __attribute__((section(".htif")));
> > -static int htif_console_buf;
> > +static int htif_console_buf = -1;
> > static spinlock_t htif_lock = SPIN_LOCK_INITIALIZER;
> > 
> > static void __check_fromhost()
> > @@ -130,12 +130,11 @@ static int htif_getc(void)
> > 
> >         spin_lock(&htif_lock);
> > 
> > -       __check_fromhost();
> > +       while (htif_console_buf < 0)
> > +               __check_fromhost();
> >         ch = htif_console_buf;
> > -       if (ch >= 0) {
> > -               htif_console_buf = -1;
> > -               __set_tohost(HTIF_DEV_CONSOLE,
> > HTIF_CONSOLE_CMD_GETC, 0);
> > -       }
> > +       htif_console_buf = -1;
> > +       __set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
> > 
> >         spin_unlock(&htif_lock);
> > 
> > -- 
> > 2.30.2
> > 
> > 
> > -- 
> > opensbi mailing list
> > opensbi@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/opensbi
Jessica Clarke Nov. 14, 2021, 12:18 a.m. UTC | #3
On 14 Nov 2021, at 00:16, Xiang W <wxjstz@126.com> wrote:
> 
> 在 2021-11-13星期六的 22:11 +0000,Jessica Clarke写道:
>> On 13 Nov 2021, at 07:06, Xiang W <wxjstz@126.com> wrote:
>>> 
>>> If uart_getc is non-blocking, if the sending end is faster than the
>>> receiving end, the data received by some functions(sbi_gets) is
>>> incomplete
>> 
>> Without hardware flow control this is always going to be true. Making
>> getc blocking does not change that. Moreover, making it blocking
>> means
>> there is no longer a way to poll, whereas having it be non-blocking
>> means you can poll, and if you want to make it blocking you can
>> always
>> put a loop in the caller (which also avoids putting it in every
>> single
>> driver).
>> 
>> Also, this breaks the SBI getchar call; it’s supposed to be
>> non-blocking, but this makes it blocking, so it is impossible for an
>> OS
>> to poll the SBI console.
> Linux also needs blocking sbi_getc, the following is the source code in
> linux
> 
> static int hvc_sbi_tty_get(uint32_t vtermno, char *buf, int count)
> {
> 	int i, c;
> 
> 	for (i = 0; i < count; i++) {
> 		c = sbi_console_getchar();
> 		if (c < 0)
> 			break;
> 		buf[i] = c;
> 	}
> 
> 	return i;
> }
> 
> static const struct hv_ops hvc_sbi_ops = {
> 	.get_chars = hvc_sbi_tty_get,
> 	.put_chars = hvc_sbi_tty_put,
> };

That is non-blocking. It stops as soon as it gets -1.

Also, Linux is not the only OS in existence. Even if Linux did want a
blocking interface, that doesn’t mean that’s what the SBI should
provide.

Don’t change the semantics of existing SBI calls, otherwise what’s the
point of freezing specs.

Jess
Xiang W Nov. 14, 2021, 12:23 a.m. UTC | #4
在 2021-11-13星期六的 22:11 +0000,Jessica Clarke写道:
> On 13 Nov 2021, at 07:06, Xiang W <wxjstz@126.com> wrote:
> > 
> > If uart_getc is non-blocking, if the sending end is faster than the
> > receiving end, the data received by some functions(sbi_gets) is
> > incomplete
> 
> Without hardware flow control this is always going to be true. Making
> getc blocking does not change that. Moreover, making it blocking
> means
> there is no longer a way to poll, whereas having it be non-blocking
> means you can poll, and if you want to make it blocking you can
> always
> put a loop in the caller (which also avoids putting it in every
> single
> driver).
> 
> Also, this breaks the SBI getchar call; it’s supposed to be
> non-blocking, but this makes it blocking, so it is impossible for an
> OS
> to poll the SBI console.

uart get does not support and returns the same value without receiving
data. So polling will also cause problems

int sbi_getc(void)
{
	if (console_dev && console_dev->console_getc)
		// Return -1 without valid data
		return console_dev->console_getc();
	return -1;
}

Regards,
Xiang W
> 
> Thus, NACK of the entire concept.
> 
> Jess
> 
> > Signed-off-by: Xiang W <wxjstz@126.com>
> > ---
> > lib/utils/serial/gaisler-uart.c |  5 ++---
> > lib/utils/serial/shakti-uart.c  |  7 +++----
> > lib/utils/serial/sifive-uart.c  |  9 +++++----
> > lib/utils/serial/uart8250.c     |  6 +++---
> > lib/utils/sys/htif.c            | 11 +++++------
> > 5 files changed, 18 insertions(+), 20 deletions(-)
> > 
> > diff --git a/lib/utils/serial/gaisler-uart.c
> > b/lib/utils/serial/gaisler-uart.c
> > index 49298e9..1dc5ae0 100644
> > --- a/lib/utils/serial/gaisler-uart.c
> > +++ b/lib/utils/serial/gaisler-uart.c
> > @@ -51,9 +51,8 @@ static void gaisler_uart_putc(char ch)
> > 
> > static int gaisler_uart_getc(void)
> > {
> > -       u32 ret = get_reg(UART_REG_STATUS);
> > -       if (!(ret & UART_STATUS_DATAREADY))
> > -               return -1;
> > +       while (!(get_reg(UART_REG_STATUS) & UART_STATUS_DATAREADY))
> > +               ;
> >         return get_reg(UART_REG_DATA) & UART_DATA_DATA;
> > }
> > 
> > diff --git a/lib/utils/serial/shakti-uart.c
> > b/lib/utils/serial/shakti-uart.c
> > index e77a985..a5b72aa 100644
> > --- a/lib/utils/serial/shakti-uart.c
> > +++ b/lib/utils/serial/shakti-uart.c
> > @@ -32,10 +32,9 @@ static void shakti_uart_putc(char ch)
> > 
> > static int shakti_uart_getc(void)
> > {
> > -       u16 status = readw(uart_base + REG_STATUS);
> > -       if (status & UART_RX_FULL)
> > -               return readb(uart_base + REG_RX);
> > -       return -1;
> > +       while (!(readw(uart_base + REG_STATUS) & UART_RX_FULL))
> > +               ;
> > +       return readb(uart_base + REG_RX);
> > }
> > 
> > static struct sbi_console_device shakti_console = {
> > diff --git a/lib/utils/serial/sifive-uart.c
> > b/lib/utils/serial/sifive-uart.c
> > index 57d80fa..68a9ca7 100644
> > --- a/lib/utils/serial/sifive-uart.c
> > +++ b/lib/utils/serial/sifive-uart.c
> > @@ -76,10 +76,11 @@ static void sifive_uart_putc(char ch)
> > 
> > static int sifive_uart_getc(void)
> > {
> > -       u32 ret = get_reg(UART_REG_RXFIFO);
> > -       if (!(ret & UART_RXFIFO_EMPTY))
> > -               return ret & UART_RXFIFO_DATA;
> > -       return -1;
> > +       u32 ret;
> > +       do
> > +               ret = get_reg(UART_REG_RXFIFO);
> > +       while (ret & UART_RXFIFO_EMPTY);
> > +       return ret & UART_RXFIFO_DATA;
> > }
> > 
> > static struct sbi_console_device sifive_console = {
> > diff --git a/lib/utils/serial/uart8250.c
> > b/lib/utils/serial/uart8250.c
> > index 1cf6624..bab8111 100644
> > --- a/lib/utils/serial/uart8250.c
> > +++ b/lib/utils/serial/uart8250.c
> > @@ -79,9 +79,9 @@ static void uart8250_putc(char ch)
> > 
> > static int uart8250_getc(void)
> > {
> > -       if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
> > -               return get_reg(UART_RBR_OFFSET);
> > -       return -1;
> > +       while (!(get_reg(UART_LSR_OFFSET) & UART_LSR_DR))
> > +               ;
> > +       return get_reg(UART_RBR_OFFSET);
> > }
> > 
> > static struct sbi_console_device uart8250_console = {
> > diff --git a/lib/utils/sys/htif.c b/lib/utils/sys/htif.c
> > index 7c69c7f..dfda30a 100644
> > --- a/lib/utils/sys/htif.c
> > +++ b/lib/utils/sys/htif.c
> > @@ -47,7 +47,7 @@
> > 
> > volatile uint64_t tohost __attribute__((section(".htif")));
> > volatile uint64_t fromhost __attribute__((section(".htif")));
> > -static int htif_console_buf;
> > +static int htif_console_buf = -1;
> > static spinlock_t htif_lock = SPIN_LOCK_INITIALIZER;
> > 
> > static void __check_fromhost()
> > @@ -130,12 +130,11 @@ static int htif_getc(void)
> > 
> >         spin_lock(&htif_lock);
> > 
> > -       __check_fromhost();
> > +       while (htif_console_buf < 0)
> > +               __check_fromhost();
> >         ch = htif_console_buf;
> > -       if (ch >= 0) {
> > -               htif_console_buf = -1;
> > -               __set_tohost(HTIF_DEV_CONSOLE,
> > HTIF_CONSOLE_CMD_GETC, 0);
> > -       }
> > +       htif_console_buf = -1;
> > +       __set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
> > 
> >         spin_unlock(&htif_lock);
> > 
> > -- 
> > 2.30.2
> > 
> > 
> > -- 
> > opensbi mailing list
> > opensbi@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/opensbi
> 
>
Jessica Clarke Nov. 14, 2021, 12:31 a.m. UTC | #5
On 14 Nov 2021, at 00:23, Xiang W <wxjstz@126.com> wrote:
> 在 2021-11-13星期六的 22:11 +0000,Jessica Clarke写道:
>> On 13 Nov 2021, at 07:06, Xiang W <wxjstz@126.com> wrote:
>>> 
>>> If uart_getc is non-blocking, if the sending end is faster than the
>>> receiving end, the data received by some functions(sbi_gets) is
>>> incomplete
>> 
>> Without hardware flow control this is always going to be true. Making
>> getc blocking does not change that. Moreover, making it blocking
>> means
>> there is no longer a way to poll, whereas having it be non-blocking
>> means you can poll, and if you want to make it blocking you can
>> always
>> put a loop in the caller (which also avoids putting it in every
>> single
>> driver).
>> 
>> Also, this breaks the SBI getchar call; it’s supposed to be
>> non-blocking, but this makes it blocking, so it is impossible for an
>> OS
>> to poll the SBI console.
> 
> uart get does not support and returns the same value without receiving
> data. So polling will also cause problems
> 
> int sbi_getc(void)
> {
> 	if (console_dev && console_dev->console_getc)
> 		// Return -1 without valid data
> 		return console_dev->console_getc();
> 	return -1;
> }

I do not understand what you are saying. There is no problem here. If
there is no character available, either because there is no UART or
because the UART’s receive buffer has been drained, the OS is told
there is no character. What’s wrong with that?

The only problem I can see is that BBL returns 0 when there is no UART
and -1 when there’s a UART but no character available, so this is not a
correct implementation of the legacy SBI, but probably a more sensible
interface given 0 is a valid character.

Jess
Xiang W Nov. 14, 2021, 1:27 a.m. UTC | #6
在 2021-11-14星期日的 00:31 +0000,Jessica Clarke写道:
> On 14 Nov 2021, at 00:23, Xiang W <wxjstz@126.com> wrote:
> > 在 2021-11-13星期六的 22:11 +0000,Jessica Clarke写道:
> > > On 13 Nov 2021, at 07:06, Xiang W <wxjstz@126.com> wrote:
> > > > 
> > > > If uart_getc is non-blocking, if the sending end is faster than
> > > > the
> > > > receiving end, the data received by some functions(sbi_gets) is
> > > > incomplete
> > > 
> > > Without hardware flow control this is always going to be true.
> > > Making
> > > getc blocking does not change that. Moreover, making it blocking
> > > means
> > > there is no longer a way to poll, whereas having it be non-
> > > blocking
> > > means you can poll, and if you want to make it blocking you can
> > > always
> > > put a loop in the caller (which also avoids putting it in every
> > > single
> > > driver).
> > > 
> > > Also, this breaks the SBI getchar call; it’s supposed to be
> > > non-blocking, but this makes it blocking, so it is impossible for
> > > an
> > > OS
> > > to poll the SBI console.
> > 
> > uart get does not support and returns the same value without
> > receiving
> > data. So polling will also cause problems
> > 
> > int sbi_getc(void)
> > {
> >         if (console_dev && console_dev->console_getc)
> >                 // Return -1 without valid data
> >                 return console_dev->console_getc();
> >         return -1;
> > }
> 
> I do not understand what you are saying. There is no problem here. If
> there is no character available, either because there is no UART or
> because the UART’s receive buffer has been drained, the OS is told
> there is no character. What’s wrong with that?
What I mean is that the program that executes the sbi call cannot
confirm whether it has not implemented console_dev->getc or has not
received data

Found the linux polling code, linux opened a kernel thread for polling.
Therefore, no implemented  is the same as unreceived data.

Thk
Xiang W
> 
> The only problem I can see is that BBL returns 0 when there is no
> UART
> and -1 when there’s a UART but no character available, so this is not
> a
> correct implementation of the legacy SBI, but probably a more
> sensible
> interface given 0 is a valid character.
> 
> Jess
Xiang W Nov. 14, 2021, 1:30 a.m. UTC | #7
在 2021-11-13星期六的 15:06 +0800,Xiang W写道:
> If uart_getc is non-blocking, if the sending end is faster than the
> receiving end, the data received by some functions(sbi_gets) is
> incomplete
> 
Revoke this patch

Regards,
Xiang W
> Signed-off-by: Xiang W <wxjstz@126.com>
> ---
>  lib/utils/serial/gaisler-uart.c |  5 ++---
>  lib/utils/serial/shakti-uart.c  |  7 +++----
>  lib/utils/serial/sifive-uart.c  |  9 +++++----
>  lib/utils/serial/uart8250.c     |  6 +++---
>  lib/utils/sys/htif.c            | 11 +++++------
>  5 files changed, 18 insertions(+), 20 deletions(-)
> 
> diff --git a/lib/utils/serial/gaisler-uart.c
> b/lib/utils/serial/gaisler-uart.c
> index 49298e9..1dc5ae0 100644
> --- a/lib/utils/serial/gaisler-uart.c
> +++ b/lib/utils/serial/gaisler-uart.c
> @@ -51,9 +51,8 @@ static void gaisler_uart_putc(char ch)
>  
>  static int gaisler_uart_getc(void)
>  {
> -       u32 ret = get_reg(UART_REG_STATUS);
> -       if (!(ret & UART_STATUS_DATAREADY))
> -               return -1;
> +       while (!(get_reg(UART_REG_STATUS) & UART_STATUS_DATAREADY))
> +               ;
>         return get_reg(UART_REG_DATA) & UART_DATA_DATA;
>  }
>  
> diff --git a/lib/utils/serial/shakti-uart.c
> b/lib/utils/serial/shakti-uart.c
> index e77a985..a5b72aa 100644
> --- a/lib/utils/serial/shakti-uart.c
> +++ b/lib/utils/serial/shakti-uart.c
> @@ -32,10 +32,9 @@ static void shakti_uart_putc(char ch)
>  
>  static int shakti_uart_getc(void)
>  {
> -       u16 status = readw(uart_base + REG_STATUS);
> -       if (status & UART_RX_FULL)
> -               return readb(uart_base + REG_RX);
> -       return -1;
> +       while (!(readw(uart_base + REG_STATUS) & UART_RX_FULL))
> +               ;
> +       return readb(uart_base + REG_RX);
>  }
>  
>  static struct sbi_console_device shakti_console = {
> diff --git a/lib/utils/serial/sifive-uart.c
> b/lib/utils/serial/sifive-uart.c
> index 57d80fa..68a9ca7 100644
> --- a/lib/utils/serial/sifive-uart.c
> +++ b/lib/utils/serial/sifive-uart.c
> @@ -76,10 +76,11 @@ static void sifive_uart_putc(char ch)
>  
>  static int sifive_uart_getc(void)
>  {
> -       u32 ret = get_reg(UART_REG_RXFIFO);
> -       if (!(ret & UART_RXFIFO_EMPTY))
> -               return ret & UART_RXFIFO_DATA;
> -       return -1;
> +       u32 ret;
> +       do
> +               ret = get_reg(UART_REG_RXFIFO);
> +       while (ret & UART_RXFIFO_EMPTY);
> +       return ret & UART_RXFIFO_DATA;
>  }
>  
>  static struct sbi_console_device sifive_console = {
> diff --git a/lib/utils/serial/uart8250.c
> b/lib/utils/serial/uart8250.c
> index 1cf6624..bab8111 100644
> --- a/lib/utils/serial/uart8250.c
> +++ b/lib/utils/serial/uart8250.c
> @@ -79,9 +79,9 @@ static void uart8250_putc(char ch)
>  
>  static int uart8250_getc(void)
>  {
> -       if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
> -               return get_reg(UART_RBR_OFFSET);
> -       return -1;
> +       while (!(get_reg(UART_LSR_OFFSET) & UART_LSR_DR))
> +               ;
> +       return get_reg(UART_RBR_OFFSET);
>  }
>  
>  static struct sbi_console_device uart8250_console = {
> diff --git a/lib/utils/sys/htif.c b/lib/utils/sys/htif.c
> index 7c69c7f..dfda30a 100644
> --- a/lib/utils/sys/htif.c
> +++ b/lib/utils/sys/htif.c
> @@ -47,7 +47,7 @@
>  
>  volatile uint64_t tohost __attribute__((section(".htif")));
>  volatile uint64_t fromhost __attribute__((section(".htif")));
> -static int htif_console_buf;
> +static int htif_console_buf = -1;
>  static spinlock_t htif_lock = SPIN_LOCK_INITIALIZER;
>  
>  static void __check_fromhost()
> @@ -130,12 +130,11 @@ static int htif_getc(void)
>  
>         spin_lock(&htif_lock);
>  
> -       __check_fromhost();
> +       while (htif_console_buf < 0)
> +               __check_fromhost();
>         ch = htif_console_buf;
> -       if (ch >= 0) {
> -               htif_console_buf = -1;
> -               __set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC,
> 0);
> -       }
> +       htif_console_buf = -1;
> +       __set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
>  
>         spin_unlock(&htif_lock);
>
Xiang W Nov. 14, 2021, 1:49 a.m. UTC | #8
在 2021-11-14星期日的 00:31 +0000,Jessica Clarke写道:
> On 14 Nov 2021, at 00:23, Xiang W <wxjstz@126.com> wrote:
> > 在 2021-11-13星期六的 22:11 +0000,Jessica Clarke写道:
> > > On 13 Nov 2021, at 07:06, Xiang W <wxjstz@126.com> wrote:
> > > > 
> > > > If uart_getc is non-blocking, if the sending end is faster than
> > > > the
> > > > receiving end, the data received by some functions(sbi_gets) is
> > > > incomplete
> > > 
> > > Without hardware flow control this is always going to be true.
> > > Making
> > > getc blocking does not change that. Moreover, making it blocking
> > > means
> > > there is no longer a way to poll, whereas having it be non-
> > > blocking
> > > means you can poll, and if you want to make it blocking you can
> > > always
> > > put a loop in the caller (which also avoids putting it in every
> > > single
> > > driver).
> > > 
> > > Also, this breaks the SBI getchar call; it’s supposed to be
> > > non-blocking, but this makes it blocking, so it is impossible for
> > > an
> > > OS
> > > to poll the SBI console.
> > 
> > uart get does not support and returns the same value without
> > receiving
> > data. So polling will also cause problems
> > 
> > int sbi_getc(void)
> > {
> >         if (console_dev && console_dev->console_getc)
> >                 // Return -1 without valid data
> >                 return console_dev->console_getc();
> >         return -1;
Hi, Jess

Can we return SBI_ENOTSUPP(-2) here to identify that
console_dev->console_getc is not implemented.
> > }
> 
> I do not understand what you are saying. There is no problem here. If
> there is no character available, either because there is no UART or
> because the UART’s receive buffer has been drained, the OS is told
> there is no character. What’s wrong with that?
> 
> The only problem I can see is that BBL returns 0 when there is no
> UART
> and -1 when there’s a UART but no character available, so this is not
> a
> correct implementation of the legacy SBI, but probably a more
> sensible
> interface given 0 is a valid character.
I think 0 is not a good idea. The value obtained by getc is 0-255,
which includes 0.

Regards,
Xiang W
> Jess
> 
>
diff mbox series

Patch

diff --git a/lib/utils/serial/gaisler-uart.c b/lib/utils/serial/gaisler-uart.c
index 49298e9..1dc5ae0 100644
--- a/lib/utils/serial/gaisler-uart.c
+++ b/lib/utils/serial/gaisler-uart.c
@@ -51,9 +51,8 @@  static void gaisler_uart_putc(char ch)
 
 static int gaisler_uart_getc(void)
 {
-	u32 ret = get_reg(UART_REG_STATUS);
-	if (!(ret & UART_STATUS_DATAREADY))
-		return -1;
+	while (!(get_reg(UART_REG_STATUS) & UART_STATUS_DATAREADY))
+		;
 	return get_reg(UART_REG_DATA) & UART_DATA_DATA;
 }
 
diff --git a/lib/utils/serial/shakti-uart.c b/lib/utils/serial/shakti-uart.c
index e77a985..a5b72aa 100644
--- a/lib/utils/serial/shakti-uart.c
+++ b/lib/utils/serial/shakti-uart.c
@@ -32,10 +32,9 @@  static void shakti_uart_putc(char ch)
 
 static int shakti_uart_getc(void)
 {
-	u16 status = readw(uart_base + REG_STATUS);
-	if (status & UART_RX_FULL)
-		return readb(uart_base + REG_RX);
-	return -1;
+	while (!(readw(uart_base + REG_STATUS) & UART_RX_FULL))
+		;
+	return readb(uart_base + REG_RX);
 }
 
 static struct sbi_console_device shakti_console = {
diff --git a/lib/utils/serial/sifive-uart.c b/lib/utils/serial/sifive-uart.c
index 57d80fa..68a9ca7 100644
--- a/lib/utils/serial/sifive-uart.c
+++ b/lib/utils/serial/sifive-uart.c
@@ -76,10 +76,11 @@  static void sifive_uart_putc(char ch)
 
 static int sifive_uart_getc(void)
 {
-	u32 ret = get_reg(UART_REG_RXFIFO);
-	if (!(ret & UART_RXFIFO_EMPTY))
-		return ret & UART_RXFIFO_DATA;
-	return -1;
+	u32 ret;
+	do
+		ret = get_reg(UART_REG_RXFIFO);
+	while (ret & UART_RXFIFO_EMPTY);
+	return ret & UART_RXFIFO_DATA;
 }
 
 static struct sbi_console_device sifive_console = {
diff --git a/lib/utils/serial/uart8250.c b/lib/utils/serial/uart8250.c
index 1cf6624..bab8111 100644
--- a/lib/utils/serial/uart8250.c
+++ b/lib/utils/serial/uart8250.c
@@ -79,9 +79,9 @@  static void uart8250_putc(char ch)
 
 static int uart8250_getc(void)
 {
-	if (get_reg(UART_LSR_OFFSET) & UART_LSR_DR)
-		return get_reg(UART_RBR_OFFSET);
-	return -1;
+	while (!(get_reg(UART_LSR_OFFSET) & UART_LSR_DR))
+		;
+	return get_reg(UART_RBR_OFFSET);
 }
 
 static struct sbi_console_device uart8250_console = {
diff --git a/lib/utils/sys/htif.c b/lib/utils/sys/htif.c
index 7c69c7f..dfda30a 100644
--- a/lib/utils/sys/htif.c
+++ b/lib/utils/sys/htif.c
@@ -47,7 +47,7 @@ 
 
 volatile uint64_t tohost __attribute__((section(".htif")));
 volatile uint64_t fromhost __attribute__((section(".htif")));
-static int htif_console_buf;
+static int htif_console_buf = -1;
 static spinlock_t htif_lock = SPIN_LOCK_INITIALIZER;
 
 static void __check_fromhost()
@@ -130,12 +130,11 @@  static int htif_getc(void)
 
 	spin_lock(&htif_lock);
 
-	__check_fromhost();
+	while (htif_console_buf < 0)
+		__check_fromhost();
 	ch = htif_console_buf;
-	if (ch >= 0) {
-		htif_console_buf = -1;
-		__set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
-	}
+	htif_console_buf = -1;
+	__set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
 
 	spin_unlock(&htif_lock);