diff mbox series

lib: utils/serial: Round UART8250 baud rate divisor to nearest integer

Message ID 20220121150614.18877-1-jakub.luzny@codasip.com
State Accepted
Headers show
Series lib: utils/serial: Round UART8250 baud rate divisor to nearest integer | expand

Commit Message

Jakub Lužný Jan. 21, 2022, 3:06 p.m. UTC
Previously, it was rounded down and that gives suboptimal results when
non-standard clock sources or baud rates are used.

Signed-off-by: Jakub Luzny <jakub.luzny@codasip.com>
---
 lib/utils/serial/uart8250.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Jessica Clarke Jan. 21, 2022, 3:21 p.m. UTC | #1
On 21 Jan 2022, at 15:06, Jakub Luzny <jakub.luzny@codasip.com> wrote:
> 
> Previously, it was rounded down and that gives suboptimal results when
> non-standard clock sources or baud rates are used.
> 
> Signed-off-by: Jakub Luzny <jakub.luzny@codasip.com>
> ---
> lib/utils/serial/uart8250.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/lib/utils/serial/uart8250.c b/lib/utils/serial/uart8250.c
> index 1cf6624..ccc7aa0 100644
> --- a/lib/utils/serial/uart8250.c
> +++ b/lib/utils/serial/uart8250.c
> @@ -101,7 +101,7 @@ int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
> 	uart8250_in_freq   = in_freq;
> 	uart8250_baudrate  = baudrate;
> 
> -	bdiv = uart8250_in_freq / (16 * uart8250_baudrate);
> +	bdiv = (uart8250_in_freq + 8 * uart8250_baudrate) / (16 * uart8250_baudrate);

This could do weird things if the numbers are sufficiently large to
overflow (unlikely but maybe possible). You can instead use the simpler:

  (uart8250_in_freq / (8 * uart8250_baudrate) + 1) / 2

which is approximately what FreeBSD does (it shifts rather than
multiplies and divides).

Jess
Jakub Lužný Jan. 24, 2022, 3:04 p.m. UTC | #2
Yes, this could happen if the UART peripheral would run at clocks
around 4GHz, which is really unlikely. My solution is basically what
the Linux kernel does (through the DIV_ROUND_CLOSEST macro). I
consider it more readable than the FreeBSD-like solution you propose.
But if you disagree, I can send a patch following your proposal.

Jakub

On Fri, Jan 21, 2022 at 4:21 PM Jessica Clarke <jrtc27@jrtc27.com> wrote:
>
> On 21 Jan 2022, at 15:06, Jakub Luzny <jakub.luzny@codasip.com> wrote:
> >
> > Previously, it was rounded down and that gives suboptimal results when
> > non-standard clock sources or baud rates are used.
> >
> > Signed-off-by: Jakub Luzny <jakub.luzny@codasip.com>
> > ---
> > lib/utils/serial/uart8250.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/lib/utils/serial/uart8250.c b/lib/utils/serial/uart8250.c
> > index 1cf6624..ccc7aa0 100644
> > --- a/lib/utils/serial/uart8250.c
> > +++ b/lib/utils/serial/uart8250.c
> > @@ -101,7 +101,7 @@ int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
> >       uart8250_in_freq   = in_freq;
> >       uart8250_baudrate  = baudrate;
> >
> > -     bdiv = uart8250_in_freq / (16 * uart8250_baudrate);
> > +     bdiv = (uart8250_in_freq + 8 * uart8250_baudrate) / (16 * uart8250_baudrate);
>
> This could do weird things if the numbers are sufficiently large to
> overflow (unlikely but maybe possible). You can instead use the simpler:
>
>   (uart8250_in_freq / (8 * uart8250_baudrate) + 1) / 2
>
> which is approximately what FreeBSD does (it shifts rather than
> multiplies and divides).
>
> Jess
>
Anup Patel Feb. 4, 2022, 5:48 a.m. UTC | #3
On Fri, Jan 21, 2022 at 8:36 PM Jakub Luzny <jakub.luzny@codasip.com> wrote:
>
> Previously, it was rounded down and that gives suboptimal results when
> non-standard clock sources or baud rates are used.
>
> Signed-off-by: Jakub Luzny <jakub.luzny@codasip.com>

Looks good to me.

Reviewed-by: Anup Patel <anup@brainfault.org>

Applied this patch to the riscv/opensbi repo.

Thanks,
Anup

> ---
>  lib/utils/serial/uart8250.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/lib/utils/serial/uart8250.c b/lib/utils/serial/uart8250.c
> index 1cf6624..ccc7aa0 100644
> --- a/lib/utils/serial/uart8250.c
> +++ b/lib/utils/serial/uart8250.c
> @@ -101,7 +101,7 @@ int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
>         uart8250_in_freq   = in_freq;
>         uart8250_baudrate  = baudrate;
>
> -       bdiv = uart8250_in_freq / (16 * uart8250_baudrate);
> +       bdiv = (uart8250_in_freq + 8 * uart8250_baudrate) / (16 * uart8250_baudrate);
>
>         /* Disable all interrupts */
>         set_reg(UART_IER_OFFSET, 0x00);
> --
> 2.20.1
>
>
> --
> opensbi mailing list
> opensbi@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi
diff mbox series

Patch

diff --git a/lib/utils/serial/uart8250.c b/lib/utils/serial/uart8250.c
index 1cf6624..ccc7aa0 100644
--- a/lib/utils/serial/uart8250.c
+++ b/lib/utils/serial/uart8250.c
@@ -101,7 +101,7 @@  int uart8250_init(unsigned long base, u32 in_freq, u32 baudrate, u32 reg_shift,
 	uart8250_in_freq   = in_freq;
 	uart8250_baudrate  = baudrate;
 
-	bdiv = uart8250_in_freq / (16 * uart8250_baudrate);
+	bdiv = (uart8250_in_freq + 8 * uart8250_baudrate) / (16 * uart8250_baudrate);
 
 	/* Disable all interrupts */
 	set_reg(UART_IER_OFFSET, 0x00);