Skip to content

Commit

Permalink
mxser: fix timeout calculation for low rates
Browse files Browse the repository at this point in the history
Paul reported, that low rates like B300 make the driver to hang in
mxser_wait_until_sent. His debugging tackled the issue down to the
info->timeout computation in mxser_set_baud. Obviously, ints are used
there and they easily overflow with these low rates: B300 makes
info->timeout to be -373.

So switch all these types to unsigned as it ought to be. And use the u64
domain to perform the computation as in the worst case, we need 35 bits
to store the computed value (before division).

And use do_div not to break 32 bit kernels.

[v2] make it actually build

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: Paul <Paul@abelian.netcom.co.uk>
Tested-by: <Paul@abelian.netcom.co.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Jiri Slaby authored and Greg Kroah-Hartman committed Sep 18, 2017
1 parent 432219f commit 104583b
Showing 1 changed file with 11 additions and 5 deletions.
16 changes: 11 additions & 5 deletions drivers/tty/mxser.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,11 @@ struct mxser_port {
unsigned char err_shadow;

struct async_icount icount; /* kernel counters for 4 input interrupts */
int timeout;
unsigned int timeout;

int read_status_mask;
int ignore_status_mask;
int xmit_fifo_size;
unsigned int xmit_fifo_size;
int xmit_head;
int xmit_tail;
int xmit_cnt;
Expand Down Expand Up @@ -572,8 +572,9 @@ static void mxser_dtr_rts(struct tty_port *port, int on)
static int mxser_set_baud(struct tty_struct *tty, long newspd)
{
struct mxser_port *info = tty->driver_data;
int quot = 0, baud;
unsigned int quot = 0, baud;
unsigned char cval;
u64 timeout;

if (!info->ioaddr)
return -1;
Expand All @@ -594,8 +595,13 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd)
quot = 0;
}

info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
info->timeout += HZ / 50; /* Add .02 seconds of slop */
/*
* worst case (128 * 1000 * 10 * 18432) needs 35 bits, so divide in the
* u64 domain
*/
timeout = (u64)info->xmit_fifo_size * HZ * 10 * quot;
do_div(timeout, info->baud_base);
info->timeout = timeout + HZ / 50; /* Add .02 seconds of slop */

if (quot) {
info->MCR |= UART_MCR_DTR;
Expand Down

0 comments on commit 104583b

Please sign in to comment.