Commit 934da463 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

usb: cdc-acm: stop dropping tx buffers

The "increase cdc-acm write throughput" patch left in place two
now-obsolete mechanisms, either of which can make the cdc-acm
driver drop TX data (nasty!).  This patch removes them:

  - The write_ready flag ... if an URB and buffer were found,
    they can (and should!) always be used.

  - TX path acm_wb_is_used() ... used when the buffer was just
    allocated, so that check is pointless.

Also fix a won't-yet-matter leak of a write buffer on a disconnect path.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Cc:  David Engraf <david.engraf@netcom.eu>
Acked-by: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 672c4e18
...@@ -144,11 +144,6 @@ static int acm_wb_is_avail(struct acm *acm) ...@@ -144,11 +144,6 @@ static int acm_wb_is_avail(struct acm *acm)
return n; return n;
} }
static inline int acm_wb_is_used(struct acm *acm, int wbn)
{
return acm->wb[wbn].use;
}
/* /*
* Finish write. * Finish write.
*/ */
...@@ -157,7 +152,6 @@ static void acm_write_done(struct acm *acm, struct acm_wb *wb) ...@@ -157,7 +152,6 @@ static void acm_write_done(struct acm *acm, struct acm_wb *wb)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&acm->write_lock, flags); spin_lock_irqsave(&acm->write_lock, flags);
acm->write_ready = 1;
wb->use = 0; wb->use = 0;
acm->transmitting--; acm->transmitting--;
spin_unlock_irqrestore(&acm->write_lock, flags); spin_unlock_irqrestore(&acm->write_lock, flags);
...@@ -190,40 +184,25 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb) ...@@ -190,40 +184,25 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
static int acm_write_start(struct acm *acm, int wbn) static int acm_write_start(struct acm *acm, int wbn)
{ {
unsigned long flags; unsigned long flags;
struct acm_wb *wb; struct acm_wb *wb = &acm->wb[wbn];
int rc; int rc;
spin_lock_irqsave(&acm->write_lock, flags); spin_lock_irqsave(&acm->write_lock, flags);
if (!acm->dev) { if (!acm->dev) {
wb->use = 0;
spin_unlock_irqrestore(&acm->write_lock, flags); spin_unlock_irqrestore(&acm->write_lock, flags);
return -ENODEV; return -ENODEV;
} }
if (!acm->write_ready) {
spin_unlock_irqrestore(&acm->write_lock, flags);
return 0; /* A white lie */
}
wb = &acm->wb[wbn];
if(acm_wb_is_avail(acm) <= 1)
acm->write_ready = 0;
dbg("%s susp_count: %d", __func__, acm->susp_count); dbg("%s susp_count: %d", __func__, acm->susp_count);
if (acm->susp_count) { if (acm->susp_count) {
acm->old_ready = acm->write_ready;
acm->delayed_wb = wb; acm->delayed_wb = wb;
acm->write_ready = 0;
schedule_work(&acm->waker); schedule_work(&acm->waker);
spin_unlock_irqrestore(&acm->write_lock, flags); spin_unlock_irqrestore(&acm->write_lock, flags);
return 0; /* A white lie */ return 0; /* A white lie */
} }
usb_mark_last_busy(acm->dev); usb_mark_last_busy(acm->dev);
if (!acm_wb_is_used(acm, wbn)) {
spin_unlock_irqrestore(&acm->write_lock, flags);
return 0;
}
rc = acm_start_wb(acm, wb); rc = acm_start_wb(acm, wb);
spin_unlock_irqrestore(&acm->write_lock, flags); spin_unlock_irqrestore(&acm->write_lock, flags);
...@@ -512,7 +491,6 @@ static void acm_softint(struct work_struct *work) ...@@ -512,7 +491,6 @@ static void acm_softint(struct work_struct *work)
static void acm_waker(struct work_struct *waker) static void acm_waker(struct work_struct *waker)
{ {
struct acm *acm = container_of(waker, struct acm, waker); struct acm *acm = container_of(waker, struct acm, waker);
unsigned long flags;
int rv; int rv;
rv = usb_autopm_get_interface(acm->control); rv = usb_autopm_get_interface(acm->control);
...@@ -524,9 +502,6 @@ static void acm_waker(struct work_struct *waker) ...@@ -524,9 +502,6 @@ static void acm_waker(struct work_struct *waker)
acm_start_wb(acm, acm->delayed_wb); acm_start_wb(acm, acm->delayed_wb);
acm->delayed_wb = NULL; acm->delayed_wb = NULL;
} }
spin_lock_irqsave(&acm->write_lock, flags);
acm->write_ready = acm->old_ready;
spin_unlock_irqrestore(&acm->write_lock, flags);
usb_autopm_put_interface(acm->control); usb_autopm_put_interface(acm->control);
} }
...@@ -697,7 +672,7 @@ static int acm_tty_write_room(struct tty_struct *tty) ...@@ -697,7 +672,7 @@ static int acm_tty_write_room(struct tty_struct *tty)
* Do not let the line discipline to know that we have a reserve, * Do not let the line discipline to know that we have a reserve,
* or it might get too enthusiastic. * or it might get too enthusiastic.
*/ */
return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0; return acm_wb_is_avail(acm) ? acm->writesize : 0;
} }
static int acm_tty_chars_in_buffer(struct tty_struct *tty) static int acm_tty_chars_in_buffer(struct tty_struct *tty)
...@@ -1076,7 +1051,6 @@ skip_normal_probe: ...@@ -1076,7 +1051,6 @@ skip_normal_probe:
spin_lock_init(&acm->write_lock); spin_lock_init(&acm->write_lock);
spin_lock_init(&acm->read_lock); spin_lock_init(&acm->read_lock);
mutex_init(&acm->mutex); mutex_init(&acm->mutex);
acm->write_ready = 1;
acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
......
...@@ -106,8 +106,6 @@ struct acm { ...@@ -106,8 +106,6 @@ struct acm {
struct list_head spare_read_bufs; struct list_head spare_read_bufs;
struct list_head filled_read_bufs; struct list_head filled_read_bufs;
int write_used; /* number of non-empty write buffers */ int write_used; /* number of non-empty write buffers */
int write_ready; /* write urb is not running */
int old_ready;
int processing; int processing;
int transmitting; int transmitting;
spinlock_t write_lock; spinlock_t write_lock;
......
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