Commit 63832515 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

USB: serial: fix assumption that throttle/unthrottle cannot sleep

many serial subdrivers are clearly written as if throttle/unthrottle
cannot sleep. This leads to unneeded atomic submissions. This
patch converts affected drivers in a way to makes very clear that
throttle/unthrottle can sleep. Thus future misdesigns can be avoided
and efficiency and reliability improved.

This removes any such assumption using GFP_KERNEL and spin_lock_irq()
Signed-off-by: default avatarOliver Neukum <oliver@neukum.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent b2a5cf1b
...@@ -554,13 +554,12 @@ static void aircable_throttle(struct tty_struct *tty) ...@@ -554,13 +554,12 @@ static void aircable_throttle(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct aircable_private *priv = usb_get_serial_port_data(port); struct aircable_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->rx_lock, flags); spin_lock_irq(&priv->rx_lock);
priv->rx_flags |= THROTTLED; priv->rx_flags |= THROTTLED;
spin_unlock_irqrestore(&priv->rx_lock, flags); spin_unlock_irq(&priv->rx_lock);
} }
/* Based on ftdi_sio.c unthrottle */ /* Based on ftdi_sio.c unthrottle */
...@@ -569,14 +568,13 @@ static void aircable_unthrottle(struct tty_struct *tty) ...@@ -569,14 +568,13 @@ static void aircable_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct aircable_private *priv = usb_get_serial_port_data(port); struct aircable_private *priv = usb_get_serial_port_data(port);
int actually_throttled; int actually_throttled;
unsigned long flags;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->rx_lock, flags); spin_lock_irq(&priv->rx_lock);
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
spin_unlock_irqrestore(&priv->rx_lock, flags); spin_unlock_irq(&priv->rx_lock);
if (actually_throttled) if (actually_throttled)
schedule_work(&priv->rx_work); schedule_work(&priv->rx_work);
......
...@@ -1155,13 +1155,12 @@ static void cypress_throttle(struct tty_struct *tty) ...@@ -1155,13 +1155,12 @@ static void cypress_throttle(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct cypress_private *priv = usb_get_serial_port_data(port); struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags); spin_lock_irq(&priv->lock);
priv->rx_flags = THROTTLED; priv->rx_flags = THROTTLED;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irq(&priv->lock);
} }
...@@ -1170,14 +1169,13 @@ static void cypress_unthrottle(struct tty_struct *tty) ...@@ -1170,14 +1169,13 @@ static void cypress_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct cypress_private *priv = usb_get_serial_port_data(port); struct cypress_private *priv = usb_get_serial_port_data(port);
int actually_throttled, result; int actually_throttled, result;
unsigned long flags;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags); spin_lock_irq(&priv->lock);
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
priv->rx_flags = 0; priv->rx_flags = 0;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irq(&priv->lock);
if (!priv->comm_is_ok) if (!priv->comm_is_ok)
return; return;
...@@ -1185,7 +1183,7 @@ static void cypress_unthrottle(struct tty_struct *tty) ...@@ -1185,7 +1183,7 @@ static void cypress_unthrottle(struct tty_struct *tty)
if (actually_throttled) { if (actually_throttled) {
port->interrupt_in_urb->dev = port->serial->dev; port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) { if (result) {
dev_err(&port->dev, "%s - failed submitting read urb, " dev_err(&port->dev, "%s - failed submitting read urb, "
"error %d\n", __func__, result); "error %d\n", __func__, result);
......
...@@ -391,7 +391,7 @@ static void empeg_unthrottle(struct tty_struct *tty) ...@@ -391,7 +391,7 @@ static void empeg_unthrottle(struct tty_struct *tty)
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
port->read_urb->dev = port->serial->dev; port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC); result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) if (result)
dev_err(&port->dev, dev_err(&port->dev,
"%s - failed submitting read urb, error %d\n", "%s - failed submitting read urb, error %d\n",
......
...@@ -1390,14 +1390,13 @@ static void garmin_throttle(struct tty_struct *tty) ...@@ -1390,14 +1390,13 @@ static void garmin_throttle(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
unsigned long flags;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
/* set flag, data received will be put into a queue /* set flag, data received will be put into a queue
for later processing */ for later processing */
spin_lock_irqsave(&garmin_data_p->lock, flags); spin_lock_irq(&garmin_data_p->lock);
garmin_data_p->flags |= FLAGS_QUEUING|FLAGS_THROTTLED; garmin_data_p->flags |= FLAGS_QUEUING|FLAGS_THROTTLED;
spin_unlock_irqrestore(&garmin_data_p->lock, flags); spin_unlock_irq(&garmin_data_p->lock);
} }
...@@ -1405,13 +1404,12 @@ static void garmin_unthrottle(struct tty_struct *tty) ...@@ -1405,13 +1404,12 @@ static void garmin_unthrottle(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
unsigned long flags;
int status; int status;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&garmin_data_p->lock, flags); spin_lock_irq(&garmin_data_p->lock);
garmin_data_p->flags &= ~FLAGS_THROTTLED; garmin_data_p->flags &= ~FLAGS_THROTTLED;
spin_unlock_irqrestore(&garmin_data_p->lock, flags); spin_unlock_irq(&garmin_data_p->lock);
/* in native mode send queued data to tty, in /* in native mode send queued data to tty, in
serial mode nothing needs to be done here */ serial mode nothing needs to be done here */
...@@ -1419,7 +1417,7 @@ static void garmin_unthrottle(struct tty_struct *tty) ...@@ -1419,7 +1417,7 @@ static void garmin_unthrottle(struct tty_struct *tty)
garmin_flush_queue(garmin_data_p); garmin_flush_queue(garmin_data_p);
if (0 != (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) { if (0 != (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
status = usb_submit_urb(port->read_urb, GFP_ATOMIC); status = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (status) if (status)
dev_err(&port->dev, dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n", "%s - failed resubmitting read urb, error %d\n",
......
...@@ -290,7 +290,7 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty) ...@@ -290,7 +290,7 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)
/* just restart the receive interrupt URB */ /* just restart the receive interrupt URB */
dbg("keyspan_pda_rx_unthrottle port %d", port->number); dbg("keyspan_pda_rx_unthrottle port %d", port->number);
port->interrupt_in_urb->dev = port->serial->dev; port->interrupt_in_urb->dev = port->serial->dev;
if (usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC)) if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
dbg(" usb_submit_urb(read urb) failed"); dbg(" usb_submit_urb(read urb) failed");
return; return;
} }
......
...@@ -951,7 +951,7 @@ static void klsi_105_unthrottle(struct tty_struct *tty) ...@@ -951,7 +951,7 @@ static void klsi_105_unthrottle(struct tty_struct *tty)
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
port->read_urb->dev = port->serial->dev; port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC); result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) if (result)
dev_err(&port->dev, dev_err(&port->dev,
"%s - failed submitting read urb, error %d\n", "%s - failed submitting read urb, error %d\n",
......
...@@ -777,20 +777,19 @@ static void mct_u232_throttle(struct tty_struct *tty) ...@@ -777,20 +777,19 @@ static void mct_u232_throttle(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct mct_u232_private *priv = usb_get_serial_port_data(port); struct mct_u232_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int control_state; unsigned int control_state;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags); spin_lock_irq(&priv->lock);
priv->rx_flags |= THROTTLED; priv->rx_flags |= THROTTLED;
if (C_CRTSCTS(tty)) { if (C_CRTSCTS(tty)) {
priv->control_state &= ~TIOCM_RTS; priv->control_state &= ~TIOCM_RTS;
control_state = priv->control_state; control_state = priv->control_state;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irq(&priv->lock);
(void) mct_u232_set_modem_ctrl(port->serial, control_state); (void) mct_u232_set_modem_ctrl(port->serial, control_state);
} else { } else {
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irq(&priv->lock);
} }
} }
...@@ -799,20 +798,19 @@ static void mct_u232_unthrottle(struct tty_struct *tty) ...@@ -799,20 +798,19 @@ static void mct_u232_unthrottle(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct mct_u232_private *priv = usb_get_serial_port_data(port); struct mct_u232_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int control_state; unsigned int control_state;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags); spin_lock_irq(&priv->lock);
if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) { if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
priv->rx_flags &= ~THROTTLED; priv->rx_flags &= ~THROTTLED;
priv->control_state |= TIOCM_RTS; priv->control_state |= TIOCM_RTS;
control_state = priv->control_state; control_state = priv->control_state;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irq(&priv->lock);
(void) mct_u232_set_modem_ctrl(port->serial, control_state); (void) mct_u232_set_modem_ctrl(port->serial, control_state);
} else { } else {
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irq(&priv->lock);
} }
} }
......
...@@ -165,33 +165,31 @@ static void symbol_throttle(struct tty_struct *tty) ...@@ -165,33 +165,31 @@ static void symbol_throttle(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct symbol_private *priv = usb_get_serial_data(port->serial); struct symbol_private *priv = usb_get_serial_data(port->serial);
unsigned long flags;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags); spin_lock_irq(&priv->lock);
priv->throttled = true; priv->throttled = true;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irq(&priv->lock);
} }
static void symbol_unthrottle(struct tty_struct *tty) static void symbol_unthrottle(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct symbol_private *priv = usb_get_serial_data(port->serial); struct symbol_private *priv = usb_get_serial_data(port->serial);
unsigned long flags;
int result; int result;
bool was_throttled; bool was_throttled;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags); spin_lock_irq(&priv->lock);
priv->throttled = false; priv->throttled = false;
was_throttled = priv->actually_throttled; was_throttled = priv->actually_throttled;
priv->actually_throttled = false; priv->actually_throttled = false;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irq(&priv->lock);
priv->int_urb->dev = port->serial->dev; priv->int_urb->dev = port->serial->dev;
if (was_throttled) { if (was_throttled) {
result = usb_submit_urb(priv->int_urb, GFP_ATOMIC); result = usb_submit_urb(priv->int_urb, GFP_KERNEL);
if (result) if (result)
dev_err(&port->dev, dev_err(&port->dev,
"%s - failed submitting read urb, error %d\n", "%s - failed submitting read urb, error %d\n",
......
...@@ -583,12 +583,11 @@ static void visor_throttle(struct tty_struct *tty) ...@@ -583,12 +583,11 @@ static void visor_throttle(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct visor_private *priv = usb_get_serial_port_data(port); struct visor_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags); spin_lock_irq(&priv->lock);
priv->throttled = 1; priv->throttled = 1;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irq(&priv->lock);
} }
...@@ -596,17 +595,16 @@ static void visor_unthrottle(struct tty_struct *tty) ...@@ -596,17 +595,16 @@ static void visor_unthrottle(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct visor_private *priv = usb_get_serial_port_data(port); struct visor_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
int result; int result;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags); spin_lock_irq(&priv->lock);
priv->throttled = 0; priv->throttled = 0;
priv->actually_throttled = 0; priv->actually_throttled = 0;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irq(&priv->lock);
port->read_urb->dev = port->serial->dev; port->read_urb->dev = port->serial->dev;
result = usb_submit_urb(port->read_urb, GFP_ATOMIC); result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) if (result)
dev_err(&port->dev, dev_err(&port->dev,
"%s - failed submitting read urb, error %d\n", "%s - failed submitting read urb, error %d\n",
......
...@@ -949,13 +949,12 @@ static void whiteheat_throttle(struct tty_struct *tty) ...@@ -949,13 +949,12 @@ static void whiteheat_throttle(struct tty_struct *tty)
{ {
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct whiteheat_private *info = usb_get_serial_port_data(port); struct whiteheat_private *info = usb_get_serial_port_data(port);
unsigned long flags;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&info->lock, flags); spin_lock_irq(&info->lock);
info->flags |= THROTTLED; info->flags |= THROTTLED;
spin_unlock_irqrestore(&info->lock, flags); spin_unlock_irq(&info->lock);
return; return;
} }
...@@ -966,14 +965,13 @@ static void whiteheat_unthrottle(struct tty_struct *tty) ...@@ -966,14 +965,13 @@ static void whiteheat_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data; struct usb_serial_port *port = tty->driver_data;
struct whiteheat_private *info = usb_get_serial_port_data(port); struct whiteheat_private *info = usb_get_serial_port_data(port);
int actually_throttled; int actually_throttled;
unsigned long flags;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&info->lock, flags); spin_lock_irq(&info->lock);
actually_throttled = info->flags & ACTUALLY_THROTTLED; actually_throttled = info->flags & ACTUALLY_THROTTLED;
info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED); info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
spin_unlock_irqrestore(&info->lock, flags); spin_unlock_irq(&info->lock);
if (actually_throttled) if (actually_throttled)
rx_data_softint(&info->rx_work); rx_data_softint(&info->rx_work);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment