Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: serial: cyberjack: use irqsave() in USB's complete callback

The USB completion callback does not disable interrupts while acquiring
the lock. We want to remove the local_irq_disable() invocation from
__usb_hcd_giveback_urb() and therefore it is required for the callback
handler to disable the interrupts while acquiring the lock.
The callback may be invoked either in IRQ or BH context depending on the
USB host controller.
Use the _irqsave() variant of the locking primitives.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Johan Hovold <johan@kernel.org>

authored by

John Ogness and committed by
Johan Hovold
c75d18cc 3391ca1d

+10 -7
+10 -7
drivers/usb/serial/cyberjack.c
··· 255 255 struct device *dev = &port->dev; 256 256 unsigned char *data = urb->transfer_buffer; 257 257 int status = urb->status; 258 + unsigned long flags; 258 259 int result; 259 260 260 261 /* the urb might have been killed. */ ··· 271 270 /* This is a announcement of coming bulk_ins. */ 272 271 unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3; 273 272 274 - spin_lock(&priv->lock); 273 + spin_lock_irqsave(&priv->lock, flags); 275 274 276 275 old_rdtodo = priv->rdtodo; 277 276 278 277 if (old_rdtodo > SHRT_MAX - size) { 279 278 dev_dbg(dev, "To many bulk_in urbs to do.\n"); 280 - spin_unlock(&priv->lock); 279 + spin_unlock_irqrestore(&priv->lock, flags); 281 280 goto resubmit; 282 281 } 283 282 ··· 286 285 287 286 dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo); 288 287 289 - spin_unlock(&priv->lock); 288 + spin_unlock_irqrestore(&priv->lock, flags); 290 289 291 290 if (!old_rdtodo) { 292 291 result = usb_submit_urb(port->read_urb, GFP_ATOMIC); ··· 310 309 struct cyberjack_private *priv = usb_get_serial_port_data(port); 311 310 struct device *dev = &port->dev; 312 311 unsigned char *data = urb->transfer_buffer; 312 + unsigned long flags; 313 313 short todo; 314 314 int result; 315 315 int status = urb->status; ··· 327 325 tty_flip_buffer_push(&port->port); 328 326 } 329 327 330 - spin_lock(&priv->lock); 328 + spin_lock_irqsave(&priv->lock, flags); 331 329 332 330 /* Reduce urbs to do by one. */ 333 331 priv->rdtodo -= urb->actual_length; ··· 336 334 priv->rdtodo = 0; 337 335 todo = priv->rdtodo; 338 336 339 - spin_unlock(&priv->lock); 337 + spin_unlock_irqrestore(&priv->lock, flags); 340 338 341 339 dev_dbg(dev, "%s - rdtodo: %d\n", __func__, todo); 342 340 ··· 356 354 struct cyberjack_private *priv = usb_get_serial_port_data(port); 357 355 struct device *dev = &port->dev; 358 356 int status = urb->status; 357 + unsigned long flags; 359 358 360 359 set_bit(0, &port->write_urbs_free); 361 360 if (status) { ··· 365 362 return; 366 363 } 367 364 368 - spin_lock(&priv->lock); 365 + spin_lock_irqsave(&priv->lock, flags); 369 366 370 367 /* only do something if we have more data to send */ 371 368 if (priv->wrfilled) { ··· 409 406 } 410 407 411 408 exit: 412 - spin_unlock(&priv->lock); 409 + spin_unlock_irqrestore(&priv->lock, flags); 413 410 usb_serial_port_softint(port); 414 411 } 415 412