USB: serial: keyspan_pda: fix data loss on receive throttling
Subsystems (3)
Johan Hovold
maintainerPATCH 1/1 USB: serial: keyspan_pda: fix data loss on receive throttling
Killing the interrupt-in urb when the line disciple requests throttling may lead to data loss if an ongoing transfer is cancelled.
Instead set a flag to prevent the completion handler from resubmitting the urb until the port is unthrottled.
Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by Johan Hovold <[email protected]>
--- drivers/usb/serial/keyspan_pda.c | 44 +++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 9 deletions(-)
drivers/usb/serial/keyspan_pda.c +35 -9
@@ -33,6 +33,8 @@ struct keyspan_pda_private {struct work_struct unthrottle_work;struct usb_serial *serial;struct usb_serial_port *port; +bool throttled; +bool throttle_req; };static int keyspan_pda_write_start (struct usb_serial_port *port);
@@ -148,6 +150,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)int retval;int status = urb->status;struct keyspan_pda_private *priv; +bool throttled = false;unsigned long flags; priv =usb_get_serial_port_data (port);
@@ -209,16 +212,24 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) } exit: - retval =usb_submit_urb (urb,GFP_ATOMIC ); -if (retval) -dev_err (&port->dev, -"%s - usb_submit_urb failed with result %d\n" , - __func__, retval); +spin_lock_irqsave (&port->lock, flags); +if (priv->throttle_req) { + priv->throttled = true; + throttled = true; + } +spin_unlock_irqrestore (&port->lock, flags); + +if (!throttled) { + retval =usb_submit_urb (urb,GFP_ATOMIC ); +if (retval) +dev_err (&port->dev,"failed to resubmit in urb: %d\n" , retval); + } }static void keyspan_pda_rx_throttle (struct tty_struct *tty) {struct usb_serial_port *port = tty->driver_data; +struct keyspan_pda_private *priv =usb_get_serial_port_data (port);/* * Stop receiving characters. We just turn off the URB request, and
@@ -228,16 +239,29 @@ static void keyspan_pda_rx_throttle(struct tty_struct *tty)* send an XOFF, although it might make sense to foist that off upon * the device too. */ -usb_kill_urb (port->interrupt_in_urb); +spin_lock_irq (&port->lock); + priv->throttle_req = true; +spin_unlock_irq (&port->lock); }static void keyspan_pda_rx_unthrottle (struct tty_struct *tty) {struct usb_serial_port *port = tty->driver_data; +struct keyspan_pda_private *priv =usb_get_serial_port_data (port); +bool throttled; +int ret; -/* just restart the receive interrupt URB */ -if (usb_submit_urb (port->interrupt_in_urb,GFP_KERNEL )) -dev_dbg (&port->dev,"usb_submit_urb(read urb) failed\n" ); +spin_lock_irq (&port->lock); + throttled = priv->throttled; + priv->throttled = false; + priv->throttle_req = false; +spin_unlock_irq (&port->lock); + +if (throttled) { + ret =usb_submit_urb (port->interrupt_in_urb,GFP_KERNEL ); +if (ret) +dev_err (&port->dev,"failed to submit in urb: %d\n" , ret); + } }static speed_t keyspan_pda_setbaud (struct usb_serial *serial,speed_t baud)
@@ -577,6 +601,8 @@ static int keyspan_pda_open(struct tty_struct *tty,spin_lock_irq (&port->lock); priv->tx_room = rc; + priv->throttled = false; + priv->throttle_req = false;spin_unlock_irq (&port->lock); rc =usb_submit_urb (port->interrupt_in_urb,GFP_KERNEL );
Signature · 1 line
2.54.0