Re: CDC-ACM driver: data duplication due to throttling

Joris van Rantwijk <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
One more thing to bother you with ;-)

Since acm->throttle_lock is only used to protect the simple flag byte
acm->throttle, it is somewhat more efficient and convenient to use
an atomic_t instead of a spinlock.

The included patch makes these changes. It applies on top of the most
recent version of the throttle fix. Feel free, of course, to drop this
one if you don't like to fix stuff when it ain't broken.

Signed-off-by: Joris van Rantwijk <[email protected]>


diff -urp -U5 linux-2.6.19.2-x/drivers/usb/class/cdc-acm.c linux-2.6.19.2/drivers/usb/class/cdc-acm.c
--- linux-2.6.19.2-x/drivers/usb/class/cdc-acm.c	2007-02-05 11:19:08.000000000 +0100
+++ linux-2.6.19.2/drivers/usb/class/cdc-acm.c	2007-02-05 11:04:35.000000000 +0100
@@ -65,10 +65,11 @@
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 #include <linux/list.h>
+#include <asm/atomic.h>
 
 #include "cdc-acm.h"
 
 /*
  * Version Information
@@ -324,20 +325,14 @@ static void acm_rx_tasklet(unsigned long
 	struct acm *acm = (void *)_acm;
 	struct acm_rb *buf;
 	struct tty_struct *tty = acm->tty;
 	struct acm_ru *rcv;
 	unsigned long flags;
-	unsigned char throttled;
+	int throttled;
 	dbg("Entering acm_rx_tasklet");
 
-	if (!ACM_READY(acm))
-		return;
-
-	spin_lock(&acm->throttle_lock);
-	throttled = acm->throttle;
-	spin_unlock(&acm->throttle_lock);
-	if (throttled)
+	if (!ACM_READY(acm) || atomic_read(&acm->throttle))
 		return;
 
 next_buffer:
 	spin_lock_irqsave(&acm->read_lock, flags);
 	if (list_empty(&acm->filled_read_bufs)) {
@@ -350,13 +345,11 @@ next_buffer:
 	spin_unlock_irqrestore(&acm->read_lock, flags);
 
 	dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
 
 	tty_buffer_request_room(tty, buf->size);
-	spin_lock(&acm->throttle_lock);
-	throttled = acm->throttle;
-	spin_unlock(&acm->throttle_lock);
+	throttled = atomic_read(&acm->throttle);
 	if (!throttled)
 		tty_insert_flip_string(tty, buf->base, buf->size);
 	tty_flip_buffer_push(tty);
 
 	if (throttled) {
@@ -483,11 +476,11 @@ static int acm_tty_open(struct tty_struc
 	}
 	for (i = 0; i < acm->rx_buflimit; i++) {
 		list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
 	}
 
-	acm->throttle = 0;
+	atomic_set(&acm->throttle, 0);
 
 	tasklet_schedule(&acm->urb_task);
 
 done:
 err_out:
@@ -600,23 +593,19 @@ static int acm_tty_chars_in_buffer(struc
 static void acm_tty_throttle(struct tty_struct *tty)
 {
 	struct acm *acm = tty->driver_data;
 	if (!ACM_READY(acm))
 		return;
-	spin_lock_bh(&acm->throttle_lock);
-	acm->throttle = 1;
-	spin_unlock_bh(&acm->throttle_lock);
+	atomic_set(&acm->throttle, 1);
 }
 
 static void acm_tty_unthrottle(struct tty_struct *tty)
 {
 	struct acm *acm = tty->driver_data;
 	if (!ACM_READY(acm))
 		return;
-	spin_lock_bh(&acm->throttle_lock);
-	acm->throttle = 0;
-	spin_unlock_bh(&acm->throttle_lock);
+	atomic_set(&acm->throttle, 0);
 	tasklet_schedule(&acm->urb_task);
 }
 
 static void acm_tty_break_ctl(struct tty_struct *tty, int state)
 {
@@ -933,11 +922,11 @@ skip_normal_probe:
 	acm->readsize = readsize;
 	acm->rx_buflimit = num_rx_buf;
 	acm->urb_task.func = acm_rx_tasklet;
 	acm->urb_task.data = (unsigned long) acm;
 	INIT_WORK(&acm->work, acm_softint, acm);
-	spin_lock_init(&acm->throttle_lock);
+	atomic_set(&acm->throttle, 0);
 	spin_lock_init(&acm->write_lock);
 	spin_lock_init(&acm->read_lock);
 	acm->write_ready = 1;
 	acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
 
diff -urp -U5 linux-2.6.19.2-x/drivers/usb/class/cdc-acm.h linux-2.6.19.2/drivers/usb/class/cdc-acm.h
--- linux-2.6.19.2-x/drivers/usb/class/cdc-acm.h	2007-02-05 11:18:41.000000000 +0100
+++ linux-2.6.19.2/drivers/usb/class/cdc-acm.h	2007-02-05 10:56:12.000000000 +0100
@@ -108,18 +108,17 @@ struct acm {
 	int write_ready;				/* write urb is not running */
 	spinlock_t write_lock;
 	struct usb_cdc_line_coding line;		/* bits, stop, parity */
 	struct work_struct work;			/* work queue entry for line discipline waking up */
 	struct tasklet_struct urb_task;                 /* rx processing */
-	spinlock_t throttle_lock;			/* synchronize throtteling and read callback */
 	unsigned int ctrlin;				/* input control lines (DCD, DSR, RI, break, overruns) */
 	unsigned int ctrlout;				/* output control lines (DTR, RTS) */
 	unsigned int writesize;				/* max packet size for the output bulk endpoint */
 	unsigned int readsize,ctrlsize;			/* buffer sizes for freeing */
 	unsigned int used;				/* someone has this acm's device open */
 	unsigned int minor;				/* acm minor number */
-	unsigned char throttle;				/* throttled by tty layer */
+	atomic_t throttle;				/* throttled by tty layer */
 	unsigned char clocal;				/* termios CLOCAL */
 	unsigned int ctrl_caps;				/* control capabilities from the class specific header */
 };
 
 #define CDC_DATA_INTERFACE_TYPE	0x0a

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier.
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.