Re: [PATCH] USB: serial: Fix read regression in 2.6.31

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 2009-09-21 at 17:07 -0700, Johan Hovold wrote:
> 
> Use ASYNCB_INITIALIZED to determine when to stop reading.
> 
> Port count can no longer be used to determine when to stop reading from
> the device as it can be zero when the first read callbacks are made (see
> tty_port_block_til_read where port count is temporarily decremented
> during serial_open).
> 
> Signed-off-by: Johan Hovold <jhovold@xxxxxxxxx>
> ---
> 
> Hi,
> 
> Here's a patch which fixes the port count issue for all drivers. I only
> have access to an ftdi device at the moment so that's the only driver
> I've been able to test (against latest git with latest patches from
> Greg's tree).
> 
> Regards,
> Johan
> 
> 
>  drivers/usb/serial/aircable.c        |    5 +++--
>  drivers/usb/serial/cypress_m8.c      |    3 ++-
>  drivers/usb/serial/digi_acceleport.c |    8 +++++---
>  drivers/usb/serial/ftdi_sio.c        |    8 ++++----
>  drivers/usb/serial/generic.c         |    3 ++-
>  drivers/usb/serial/ir-usb.c          |    3 ++-
>  drivers/usb/serial/keyspan.c         |   24 ++++++++++++++----------
>  drivers/usb/serial/opticon.c         |    2 +-
>  drivers/usb/serial/option.c          |    4 +++-
>  drivers/usb/serial/oti6858.c         |    4 ++--
>  drivers/usb/serial/pl2303.c          |    4 ++--
>  drivers/usb/serial/sierra.c          |    7 +++++--
>  drivers/usb/serial/spcp8x5.c         |    5 +++--
>  13 files changed, 48 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
> index 2cbfab3..edba62f 100644
> --- a/drivers/usb/serial/aircable.c
> +++ b/drivers/usb/serial/aircable.c
> @@ -42,6 +42,7 @@
>   *
>   */
> 
> +#include <linux/serial.h>
>  #include <linux/tty.h>
>  #include <linux/tty_flip.h>
>  #include <linux/circ_buf.h>
> @@ -468,7 +469,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
> 
>         if (status) {
>                 dbg("%s - urb status = %d", __func__, status);
> -               if (!port->port.count) {
> +               if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                         dbg("%s - port is closed, exiting.", __func__);
>                         return;
>                 }
> @@ -531,7 +532,7 @@ static void aircable_read_bulk_callback(struct urb *urb)
>         tty_kref_put(tty);
> 
>         /* Schedule the next read _if_ we are still open */
> -       if (port->port.count) {
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                 usb_fill_bulk_urb(port->read_urb, port->serial->dev,
>                                   usb_rcvbulkpipe(port->serial->dev,
>                                           port->bulk_in_endpointAddress),
> diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
> index e0a8b71..c683a10 100644
> --- a/drivers/usb/serial/cypress_m8.c
> +++ b/drivers/usb/serial/cypress_m8.c
> @@ -1329,7 +1329,8 @@ continue_read:
> 
>         /* Continue trying to always read... unless the port has closed. */
> 
> -       if (port->port.count > 0 && priv->comm_is_ok) {
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags) &&
> +                       priv->comm_is_ok) {
>                 usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
>                                 usb_rcvintpipe(port->serial->dev,
>                                         port->interrupt_in_endpointAddress),
> diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
> index ab3dd99..9259d38 100644
> --- a/drivers/usb/serial/digi_acceleport.c
> +++ b/drivers/usb/serial/digi_acceleport.c
> @@ -244,6 +244,7 @@
>  #include <linux/uaccess.h>
>  #include <linux/usb.h>
>  #include <linux/wait.h>
> +#include <linux/serial.h>
>  #include <linux/usb/serial.h>
> 
>  /* Defines */
> @@ -1265,7 +1266,8 @@ static void digi_write_bulk_callback(struct urb *urb)
>         /* try to send any buffered data on this port, if it is open */
>         spin_lock(&priv->dp_port_lock);
>         priv->dp_write_urb_in_use = 0;
> -       if (port->port.count && priv->dp_out_buf_len > 0) {
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags) &&
> +                       priv->dp_out_buf_len > 0) {
>                 *((unsigned char *)(port->write_urb->transfer_buffer))
>                         = (unsigned char)DIGI_CMD_SEND_DATA;
>                 *((unsigned char *)(port->write_urb->transfer_buffer) + 1)
> @@ -1663,7 +1665,7 @@ static int digi_read_inb_callback(struct urb *urb)
> 
>         /* do not process callbacks on closed ports */
>         /* but do continue the read chain */
> -       if (port->port.count == 0)
> +       if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
>                 return 0;
> 
>         /* short/multiple packet check */
> @@ -1776,7 +1778,7 @@ static int digi_read_oob_callback(struct urb *urb)
> 
>                 tty = tty_port_tty_get(&port->port);
>                 rts = 0;
> -               if (port->port.count)
> +               if (test_bit(ASYNCB_INITIALIZED, &port->port.flags))
>                         rts = tty->termios->c_cflag & CRTSCTS;
> 
>                 if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
> diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
> index 4f883b1..7eaea14 100644
> --- a/drivers/usb/serial/ftdi_sio.c
> +++ b/drivers/usb/serial/ftdi_sio.c
> @@ -2033,7 +2033,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
> 
>         dbg("%s - port %d", __func__, port->number);
> 
> -       if (port->port.count <= 0)
> +       if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
>                 return;
> 
>         tty = tty_port_tty_get(&port->port);
> @@ -2089,7 +2089,7 @@ static void ftdi_process_read(struct work_struct *work)
> 
>         dbg("%s - port %d", __func__, port->number);
> 
> -       if (port->port.count <= 0)
> +       if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
>                 return;
> 
>         tty = tty_port_tty_get(&port->port);
> @@ -2247,7 +2247,7 @@ static void ftdi_process_read(struct work_struct *work)
>                 }
>                 spin_unlock_irqrestore(&priv->rx_lock, flags);
>                 /* if the port is closed stop trying to read */
> -               if (port->port.count > 0)
> +               if (test_bit(ASYNCB_INITIALIZED, &port->port.flags))
>                         /* delay processing of remainder */
>                         schedule_delayed_work(&priv->rx_work, 1);
>                 else
> @@ -2259,7 +2259,7 @@ static void ftdi_process_read(struct work_struct *work)
>         priv->rx_processed = 0;
> 
>         /* if the port is closed stop trying to read */
> -       if (port->port.count > 0) {
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                 /* Continue trying to always read  */
>                 usb_fill_bulk_urb(port->read_urb, port->serial->dev,
>                         usb_rcvbulkpipe(port->serial->dev,
> diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
> index deba08c..4aa2eb4 100644
> --- a/drivers/usb/serial/generic.c
> +++ b/drivers/usb/serial/generic.c
> @@ -17,6 +17,7 @@
>  #include <linux/module.h>
>  #include <linux/moduleparam.h>
>  #include <linux/usb.h>
> +#include <linux/serial.h>
>  #include <linux/usb/serial.h>
>  #include <linux/uaccess.h>
>  #include <linux/kfifo.h>
> @@ -583,7 +584,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)
> 
>         for (i = 0; i < serial->num_ports; i++) {
>                 port = serial->port[i];
> -               if (!port->port.count)
> +               if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
>                         continue;
> 
>                 if (port->read_urb) {
> diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
> index 95d8d26..694fe31 100644
> --- a/drivers/usb/serial/ir-usb.c
> +++ b/drivers/usb/serial/ir-usb.c
> @@ -65,6 +65,7 @@
>  #include <linux/module.h>
>  #include <linux/spinlock.h>
>  #include <linux/uaccess.h>
> +#include <linux/serial.h>
>  #include <linux/usb.h>
>  #include <linux/usb/serial.h>
>  #include <linux/usb/irda.h>
> @@ -445,7 +446,7 @@ static void ir_read_bulk_callback(struct urb *urb)
> 
>         dbg("%s - port %d", __func__, port->number);
> 
> -       if (!port->port.count) {
> +       if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                 dbg("%s - port closed.", __func__);
>                 return;
>         }
> diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
> index f8c4b07..3193f3e 100644
> --- a/drivers/usb/serial/keyspan.c
> +++ b/drivers/usb/serial/keyspan.c
> @@ -108,6 +108,7 @@
>  #include <linux/firmware.h>
>  #include <linux/ihex.h>
>  #include <linux/uaccess.h>
> +#include <linux/serial.h>
>  #include <linux/usb.h>
>  #include <linux/usb/serial.h>
>  #include "keyspan.h"
> @@ -464,7 +465,7 @@ static void usa26_indat_callback(struct urb *urb)
> 
>         /* Resubmit urb so we continue receiving */
>         urb->dev = port->serial->dev;
> -       if (port->port.count) {
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                 err = usb_submit_urb(urb, GFP_ATOMIC);
>                 if (err != 0)
>                         dbg("%s - resubmit read urb failed. (%d)",
> @@ -483,7 +484,7 @@ static void usa2x_outdat_callback(struct urb *urb)
>         p_priv = usb_get_serial_port_data(port);
>         dbg("%s - urb %d", __func__, urb == p_priv->out_urbs[1]);
> 
> -       if (port->port.count)
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags))
>                 usb_serial_port_softint(port);
>  }
> 
> @@ -615,7 +616,7 @@ static void usa28_indat_callback(struct urb *urb)
> 
>                 /* Resubmit urb so we continue receiving */
>                 urb->dev = port->serial->dev;
> -               if (port->port.count) {
> +               if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                         err = usb_submit_urb(urb, GFP_ATOMIC);
>                         if (err != 0)
>                                 dbg("%s - resubmit read urb failed. (%d)",
> @@ -856,7 +857,7 @@ static void usa49_indat_callback(struct urb *urb)
> 
>         /* Resubmit urb so we continue receiving */
>         urb->dev = port->serial->dev;
> -       if (port->port.count) {
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                 err = usb_submit_urb(urb, GFP_ATOMIC);
>                 if (err != 0)
>                         dbg("%s - resubmit read urb failed. (%d)",
> @@ -904,10 +905,11 @@ static void usa49wg_indat_callback(struct urb *urb)
>                                 /* no error on any byte */
>                                 i++;
>                                 for (x = 1; x < len ; ++x)
> -                                       if (port->port.count)
> +                                       if (test_bit(ASYNCB_INITIALIZED,
> +                                                       &port->port.flags)) {
>                                                 tty_insert_flip_char(tty,
>                                                                 data[i++], 0);
> -                                       else
> +                                       } else
>                                                 i++;
>                         } else {
>                                 /*
> @@ -922,13 +924,15 @@ static void usa49wg_indat_callback(struct urb *urb)
>                                         if (stat & RXERROR_PARITY)
>                                                 flag |= TTY_PARITY;
>                                         /* XXX should handle break (0x10) */
> -                                       if (port->port.count)
> +                                       if (test_bit(ASYNCB_INITIALIZED,
> +                                                       &port->port.flags)) {
>                                                 tty_insert_flip_char(tty,
>                                                         data[i+1], flag);
> +                                       }
>                                         i += 2;
>                                 }
>                         }
> -                       if (port->port.count)
> +                       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags))
>                                 tty_flip_buffer_push(tty);
>                         tty_kref_put(tty);
>                 }
> @@ -1013,7 +1017,7 @@ static void usa90_indat_callback(struct urb *urb)
> 
>         /* Resubmit urb so we continue receiving */
>         urb->dev = port->serial->dev;
> -       if (port->port.count) {
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                 err = usb_submit_urb(urb, GFP_ATOMIC);
>                 if (err != 0)
>                         dbg("%s - resubmit read urb failed. (%d)",
> @@ -2418,7 +2422,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
>                 msg.portEnabled = 0;
>         /* Sending intermediate configs */
>         else {
> -               if (port->port.count)
> +               if (test_bit(ASYNCB_INITIALIZED, &port->port.flags))
>                         msg.portEnabled = 1;
>                 msg.txBreak = (p_priv->break_on);
>         }
> diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
> index 1085a57..1aa6593 100644
> --- a/drivers/usb/serial/opticon.c
> +++ b/drivers/usb/serial/opticon.c
> @@ -499,7 +499,7 @@ static int opticon_resume(struct usb_interface *intf)
>         int result;
> 
>         mutex_lock(&port->mutex);
> -       if (port->port.count)
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags))
>                 result = usb_submit_urb(priv->bulk_read_urb, GFP_NOIO);
>         else
>                 result = 0;
> diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
> index f66e398..63c3c7e 100644
> --- a/drivers/usb/serial/option.c
> +++ b/drivers/usb/serial/option.c
> @@ -39,6 +39,7 @@
>  #include <linux/tty_flip.h>
>  #include <linux/module.h>
>  #include <linux/bitops.h>
> +#include <linux/serial.h>
>  #include <linux/usb.h>
>  #include <linux/usb/serial.h>
> 
> @@ -868,7 +869,8 @@ static void option_indat_callback(struct urb *urb)
>                 tty_kref_put(tty);
> 
>                 /* Resubmit urb so we continue receiving */
> -               if (port->port.count && status != -ESHUTDOWN) {
> +               if (test_bit(ASYNCB_INITIALIZED, &port->port.flags) &&
> +                               status != -ESHUTDOWN) {
>                         err = usb_submit_urb(urb, GFP_ATOMIC);
>                         if (err)
>                                 printk(KERN_ERR "%s: resubmit read urb failed. "
> diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
> index 0f4a70c..d21d4cc 100644
> --- a/drivers/usb/serial/oti6858.c
> +++ b/drivers/usb/serial/oti6858.c
> @@ -927,7 +927,7 @@ static void oti6858_read_bulk_callback(struct urb *urb)
>         spin_unlock_irqrestore(&priv->lock, flags);
> 
>         if (status != 0) {
> -               if (!port->port.count) {
> +               if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                         dbg("%s(): port is closed, exiting", __func__);
>                         return;
>                 }
> @@ -955,7 +955,7 @@ static void oti6858_read_bulk_callback(struct urb *urb)
>         tty_kref_put(tty);
> 
>         /* schedule the interrupt urb if we are still open */
> -       if (port->port.count != 0) {
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                 port->interrupt_in_urb->dev = port->serial->dev;
>                 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
>                 if (result != 0) {
> diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
> index 1128e01..2c3fc74 100644
> --- a/drivers/usb/serial/pl2303.c
> +++ b/drivers/usb/serial/pl2303.c
> @@ -1070,7 +1070,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
> 
>         if (status) {
>                 dbg("%s - urb status = %d", __func__, status);
> -               if (!port->port.count) {
> +               if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                         dbg("%s - port is closed, exiting.", __func__);
>                         return;
>                 }
> @@ -1106,7 +1106,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
>         }
>         tty_kref_put(tty);
>         /* Schedule the next read _if_ we are still open */
> -       if (port->port.count) {
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                 urb->dev = port->serial->dev;
>                 result = usb_submit_urb(urb, GFP_ATOMIC);
>                 if (result)
> diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
> index 68fa0e4..9f4b43a 100644
> --- a/drivers/usb/serial/sierra.c
> +++ b/drivers/usb/serial/sierra.c
> @@ -27,6 +27,7 @@
>  #include <linux/tty.h>
>  #include <linux/tty_flip.h>
>  #include <linux/module.h>
> +#include <linux/serial.h>
>  #include <linux/usb.h>
>  #include <linux/usb/serial.h>
> 
> @@ -578,7 +579,8 @@ static void sierra_indat_callback(struct urb *urb)
>         }
> 
>         /* Resubmit urb so we continue receiving */
> -       if (port->port.count && status != -ESHUTDOWN && status != -EPERM) {
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags) &&
> +                       status != -ESHUTDOWN && status != -EPERM) {
>                 usb_mark_last_busy(port->serial->dev);
>                 err = usb_submit_urb(urb, GFP_ATOMIC);
>                 if (err)
> @@ -640,7 +642,8 @@ static void sierra_instat_callback(struct urb *urb)
>                 dev_dbg(&port->dev, "%s: error %d\n", __func__, status);
> 
>         /* Resubmit urb so we continue receiving IRQ data */
> -       if (port->port.count && status != -ESHUTDOWN && status != -ENOENT) {
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags) &&
> +                       status != -ESHUTDOWN && status != -ENOENT) {
>                 usb_mark_last_busy(serial->dev);
>                 urb->dev = serial->dev;
>                 err = usb_submit_urb(urb, GFP_ATOMIC);
> diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
> index 61e7c40..43d54d1 100644
> --- a/drivers/usb/serial/spcp8x5.c
> +++ b/drivers/usb/serial/spcp8x5.c
> @@ -23,6 +23,7 @@
>  #include <linux/tty_driver.h>
>  #include <linux/tty_flip.h>
>  #include <linux/module.h>
> +#include <linux/serial.h>
>  #include <linux/spinlock.h>
>  #include <linux/usb.h>
>  #include <linux/usb/serial.h>
> @@ -687,7 +688,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
> 
>         /* check the urb status */
>         if (result) {
> -               if (!port->port.count)
> +               if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
>                         return;
>                 if (result == -EPROTO) {
>                         /* spcp8x5 mysteriously fails with -EPROTO */
> @@ -737,7 +738,7 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
>         tty_kref_put(tty);
> 
>         /* Schedule the next read _if_ we are still open */
> -       if (port->port.count) {
> +       if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
>                 urb->dev = port->serial->dev;
>                 result = usb_submit_urb(urb , GFP_ATOMIC);
>                 if (result)
> --
> 1.6.4.2
> 
> --
> 
> 
> 
> 
> 
Hi Johan,
There seems to be a problem with this patch for sierra.c driver as
Matthew Safar pointed out.
The patch changes the use of port.count in sierra_indat_callback for a
test_bit(ASYNCB_INITIALIZED). The problem is that the bit is set by
usb_serial only _after_ the sierra_open is called.

Often when modem has something to say its data  sits in a queue in the modem
and once an RX urb is available the data is sent to the host. Often that
happens while we are still in open - submitting more RX urbs. Because of
the bit being set later we wouldn't re-cycle the first n rx urbs and
performance would suffer or the host-bound transfer could stall all
together.
Could it be the rest of the drivers have similar problem? (we have  not
check that).
In sierra driver case we have "opened flag" - could it be used to achieve the same?


Regards,
Elina


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux