Re: [PATCH v3] serial: 8250_dw: preserve BUSY-safe fractional divisor programming
From: Andy Shevchenko
Date: Mon Oct 26 2026 - 15:16:54 EST
On Mon, Oct 26, 2026 at 09:59:10AM -0600, James Hilliard wrote:
> dw8250_probe() installs a divisor setter that makes the UART idle and
> checks DLAB before writing DLL and DLH. When dw8250_setup_port() detects
> fractional-divisor support, it replaces that setter with the library's
> callback. The replacement writes DLF and uses serial8250_do_set_divisor(),
> bypassing the divisor setter's idle sequence and DLAB readback.
>
> If the LCR update fails to set DLAB, the subsequent divisor writes can
> reach TX and IER instead of DLL and DLH.
>
> Expose the library's fractional-divisor calculation and DLF write as
> shared helpers. Install the BUSY-safe setter after hardware discovery and
> use the shared DLF helper to program the fractional field only after DLAB
> has been confirmed, alongside DLL and DLH. Select the shared calculator
> when fractional divisors are supported, preserving the core calculation
> for integer-only ports. Keep the check for fractional-divisor support in
> the shared DLF setter so callers can use it for either kind of port.
...
> + /* Use the BUSY-safe sequence for both integer and fractional divisors. */
> + if (data->data.dlf_size)
> + p->get_divisor = dw8250_get_divisor_dlf;
Yeah, this will be the similar issue with layering violation that Ilpo pointed
out elsewhere. So, perhaps easiest way for now is to let it be as is here, id
est not assigning .get_divisor() at all. Otherwise we would need the same check
in there and the branch on what to do if it's not a DLF case.
> + p->set_divisor = dw8250_set_divisor;
...
> if (reg) {
> pd->dlf_size = fls(reg);
> - p->get_divisor = dw8250_get_divisor;
> + p->get_divisor = dw8250_get_divisor_dlf;
Just add a static function wrapper that simply calls this, so we won't
change it here at all.
static unsigned int dw8250_get_divisor(struct uart_port *p, unsigned int baud,
unsigned int *frac)
{
return dw8250_get_divisor_dlf(p, baud, frac);
}
> p->set_divisor = dw8250_set_divisor;
> }
--
With Best Regards,
Andy Shevchenko