aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/generic.c')
-rw-r--r--drivers/usb/serial/generic.c76
1 files changed, 41 insertions, 35 deletions
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 2274d9625f63..1be8bea372a2 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -106,12 +106,8 @@ void usb_serial_generic_deregister(void)
106int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port) 106int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port)
107{ 107{
108 int result = 0; 108 int result = 0;
109 unsigned long flags;
110 109
111 spin_lock_irqsave(&port->lock, flags); 110 clear_bit(USB_SERIAL_THROTTLED, &port->flags);
112 port->throttled = 0;
113 port->throttle_req = 0;
114 spin_unlock_irqrestore(&port->lock, flags);
115 111
116 if (port->bulk_in_size) 112 if (port->bulk_in_size)
117 result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); 113 result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
@@ -375,7 +371,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
375{ 371{
376 struct usb_serial_port *port = urb->context; 372 struct usb_serial_port *port = urb->context;
377 unsigned char *data = urb->transfer_buffer; 373 unsigned char *data = urb->transfer_buffer;
378 unsigned long flags; 374 bool stopped = false;
379 int status = urb->status; 375 int status = urb->status;
380 int i; 376 int i;
381 377
@@ -383,42 +379,55 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
383 if (urb == port->read_urbs[i]) 379 if (urb == port->read_urbs[i])
384 break; 380 break;
385 } 381 }
386 set_bit(i, &port->read_urbs_free);
387 382
388 dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i, 383 dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i,
389 urb->actual_length); 384 urb->actual_length);
390 switch (status) { 385 switch (status) {
391 case 0: 386 case 0:
387 usb_serial_debug_data(&port->dev, __func__, urb->actual_length,
388 data);
389 port->serial->type->process_read_urb(urb);
392 break; 390 break;
393 case -ENOENT: 391 case -ENOENT:
394 case -ECONNRESET: 392 case -ECONNRESET:
395 case -ESHUTDOWN: 393 case -ESHUTDOWN:
396 dev_dbg(&port->dev, "%s - urb stopped: %d\n", 394 dev_dbg(&port->dev, "%s - urb stopped: %d\n",
397 __func__, status); 395 __func__, status);
398 return; 396 stopped = true;
397 break;
399 case -EPIPE: 398 case -EPIPE:
400 dev_err(&port->dev, "%s - urb stopped: %d\n", 399 dev_err(&port->dev, "%s - urb stopped: %d\n",
401 __func__, status); 400 __func__, status);
402 return; 401 stopped = true;
402 break;
403 default: 403 default:
404 dev_dbg(&port->dev, "%s - nonzero urb status: %d\n", 404 dev_dbg(&port->dev, "%s - nonzero urb status: %d\n",
405 __func__, status); 405 __func__, status);
406 goto resubmit; 406 break;
407 } 407 }
408 408
409 usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); 409 /*
410 port->serial->type->process_read_urb(urb); 410 * Make sure URB processing is done before marking as free to avoid
411 * racing with unthrottle() on another CPU. Matches the barriers
412 * implied by the test_and_clear_bit() in
413 * usb_serial_generic_submit_read_urb().
414 */
415 smp_mb__before_atomic();
416 set_bit(i, &port->read_urbs_free);
417 /*
418 * Make sure URB is marked as free before checking the throttled flag
419 * to avoid racing with unthrottle() on another CPU. Matches the
420 * smp_mb() in unthrottle().
421 */
422 smp_mb__after_atomic();
411 423
412resubmit: 424 if (stopped)
413 /* Throttle the device if requested by tty */ 425 return;
414 spin_lock_irqsave(&port->lock, flags); 426
415 port->throttled = port->throttle_req; 427 if (test_bit(USB_SERIAL_THROTTLED, &port->flags))
416 if (!port->throttled) { 428 return;
417 spin_unlock_irqrestore(&port->lock, flags); 429
418 usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC); 430 usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC);
419 } else {
420 spin_unlock_irqrestore(&port->lock, flags);
421 }
422} 431}
423EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); 432EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
424 433
@@ -454,10 +463,9 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
454 default: 463 default:
455 dev_err_console(port, "%s - nonzero urb status: %d\n", 464 dev_err_console(port, "%s - nonzero urb status: %d\n",
456 __func__, status); 465 __func__, status);
457 goto resubmit; 466 break;
458 } 467 }
459 468
460resubmit:
461 usb_serial_generic_write_start(port, GFP_ATOMIC); 469 usb_serial_generic_write_start(port, GFP_ATOMIC);
462 usb_serial_port_softint(port); 470 usb_serial_port_softint(port);
463} 471}
@@ -466,26 +474,24 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback);
466void usb_serial_generic_throttle(struct tty_struct *tty) 474void usb_serial_generic_throttle(struct tty_struct *tty)
467{ 475{
468 struct usb_serial_port *port = tty->driver_data; 476 struct usb_serial_port *port = tty->driver_data;
469 unsigned long flags;
470 477
471 spin_lock_irqsave(&port->lock, flags); 478 set_bit(USB_SERIAL_THROTTLED, &port->flags);
472 port->throttle_req = 1;
473 spin_unlock_irqrestore(&port->lock, flags);
474} 479}
475EXPORT_SYMBOL_GPL(usb_serial_generic_throttle); 480EXPORT_SYMBOL_GPL(usb_serial_generic_throttle);
476 481
477void usb_serial_generic_unthrottle(struct tty_struct *tty) 482void usb_serial_generic_unthrottle(struct tty_struct *tty)
478{ 483{
479 struct usb_serial_port *port = tty->driver_data; 484 struct usb_serial_port *port = tty->driver_data;
480 int was_throttled;
481 485
482 spin_lock_irq(&port->lock); 486 clear_bit(USB_SERIAL_THROTTLED, &port->flags);
483 was_throttled = port->throttled; 487
484 port->throttled = port->throttle_req = 0; 488 /*
485 spin_unlock_irq(&port->lock); 489 * Matches the smp_mb__after_atomic() in
490 * usb_serial_generic_read_bulk_callback().
491 */
492 smp_mb();
486 493
487 if (was_throttled) 494 usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
488 usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
489} 495}
490EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); 496EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle);
491 497