Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+3 −29
Original line number Diff line number Diff line
@@ -144,11 +144,6 @@ static int acm_wb_is_avail(struct acm *acm)
	return n;
}

static inline int acm_wb_is_used(struct acm *acm, int wbn)
{
	return acm->wb[wbn].use;
}

/*
 * Finish write.
 */
@@ -157,7 +152,6 @@ static void acm_write_done(struct acm *acm, struct acm_wb *wb)
	unsigned long flags;

	spin_lock_irqsave(&acm->write_lock, flags);
	acm->write_ready = 1;
	wb->use = 0;
	acm->transmitting--;
	spin_unlock_irqrestore(&acm->write_lock, flags);
@@ -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)
{
	unsigned long flags;
	struct acm_wb *wb;
	struct acm_wb *wb = &acm->wb[wbn];
	int rc;

	spin_lock_irqsave(&acm->write_lock, flags);
	if (!acm->dev) {
		wb->use = 0;
		spin_unlock_irqrestore(&acm->write_lock, flags);
		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);
	if (acm->susp_count) {
		acm->old_ready = acm->write_ready;
		acm->delayed_wb = wb;
		acm->write_ready = 0;
		schedule_work(&acm->waker);
		spin_unlock_irqrestore(&acm->write_lock, flags);
		return 0;	/* A white lie */
	}
	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);
	spin_unlock_irqrestore(&acm->write_lock, flags);

@@ -512,7 +491,6 @@ static void acm_softint(struct work_struct *work)
static void acm_waker(struct work_struct *waker)
{
	struct acm *acm = container_of(waker, struct acm, waker);
	unsigned long flags;
	int rv;

	rv = usb_autopm_get_interface(acm->control);
@@ -524,9 +502,6 @@ static void acm_waker(struct work_struct *waker)
		acm_start_wb(acm, acm->delayed_wb);
		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);
}

@@ -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,
	 * 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)
@@ -1076,7 +1051,6 @@ skip_normal_probe:
	spin_lock_init(&acm->write_lock);
	spin_lock_init(&acm->read_lock);
	mutex_init(&acm->mutex);
	acm->write_ready = 1;
	acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);

	buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
+0 −2
Original line number Diff line number Diff line
@@ -106,8 +106,6 @@ struct acm {
	struct list_head spare_read_bufs;
	struct list_head filled_read_bufs;
	int write_used;					/* number of non-empty write buffers */
	int write_ready;				/* write urb is not running */
	int old_ready;
	int processing;
	int transmitting;
	spinlock_t write_lock;