aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/class/cdc-acm.c
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.com>2018-09-05 11:56:46 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-09-10 14:40:29 -0400
commitdf3aa13c7bbb307e172c37f193f9a7aa058d4739 (patch)
treea06040ae7f90e44fb7603723a81554dde0aeb66d /drivers/usb/class/cdc-acm.c
parentfa827966090e2a6fc07b437d0d2ffae748ec6e28 (diff)
Revert "cdc-acm: implement put_char() and flush_chars()"
This reverts commit a81cf9799ad7299b03a4dff020d9685f9ac5f3e0. The patch causes a regression, which I cannot find the reason for. So let's revert for now, as a revert hurts only performance. Original report: I was trying to resolve the problem with Oliver but we don't get any conclusion for 5 months, so I am now sending this to mail list and cdc_acm authors. I am using simple request-response protocol to obtain the boiller parameters in constant intervals. A simple one transaction is: 1. opening the /dev/ttyACM0 2. sending the following 10-bytes request to the device: unsigned char req[] = {0x02, 0xfe, 0x01, 0x05, 0x08, 0x02, 0x01, 0x69, 0xab, 0x03}; 3. reading response (frame of 74 bytes length). 4. closing the descriptor I am doing this transaction with 5 seconds intervals. Before the bad commit everything was working correctly: I've got a requests and a responses in a timely manner. After the bad commit more time I am using the kernel module, more problems I have. The graph [2] is showing the problem. As you can see after module load all seems fine but after about 30 minutes I've got a plenty of EAGAINs when doing read()'s and trying to read back the data. When I rmmod and insmod the cdc_acm module again, then the situation is starting over again: running ok shortly after load, and more time it is running, more EAGAINs I have when calling read(). As a bonus I can see the problem on the device itself: The device is configured as you can see here on this screen [3]. It has two transmision LEDs: TX and RX. Blink duration is set for 100ms. This is a recording before the bad commit when all is working fine: [4] And this is with the bad commit: [5] As you can see the TX led is blinking wrongly long (indicating transmission?) and I have problems doing read() calls (EAGAIN). Reported-by: Mariusz Bialonczyk <manio@skyboo.net> Signed-off-by: Oliver Neukum <oneukum@suse.com> Fixes: a81cf9799ad7 ("cdc-acm: implement put_char() and flush_chars()") Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r--drivers/usb/class/cdc-acm.c73
1 files changed, 0 insertions, 73 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 27346d69f393..f9b40a9dc4d3 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -780,20 +780,9 @@ static int acm_tty_write(struct tty_struct *tty,
780 } 780 }
781 781
782 if (acm->susp_count) { 782 if (acm->susp_count) {
783 if (acm->putbuffer) {
784 /* now to preserve order */
785 usb_anchor_urb(acm->putbuffer->urb, &acm->delayed);
786 acm->putbuffer = NULL;
787 }
788 usb_anchor_urb(wb->urb, &acm->delayed); 783 usb_anchor_urb(wb->urb, &acm->delayed);
789 spin_unlock_irqrestore(&acm->write_lock, flags); 784 spin_unlock_irqrestore(&acm->write_lock, flags);
790 return count; 785 return count;
791 } else {
792 if (acm->putbuffer) {
793 /* at this point there is no good way to handle errors */
794 acm_start_wb(acm, acm->putbuffer);
795 acm->putbuffer = NULL;
796 }
797 } 786 }
798 787
799 stat = acm_start_wb(acm, wb); 788 stat = acm_start_wb(acm, wb);
@@ -804,66 +793,6 @@ static int acm_tty_write(struct tty_struct *tty,
804 return count; 793 return count;
805} 794}
806 795
807static void acm_tty_flush_chars(struct tty_struct *tty)
808{
809 struct acm *acm = tty->driver_data;
810 struct acm_wb *cur;
811 int err;
812 unsigned long flags;
813
814 spin_lock_irqsave(&acm->write_lock, flags);
815
816 cur = acm->putbuffer;
817 if (!cur) /* nothing to do */
818 goto out;
819
820 acm->putbuffer = NULL;
821 err = usb_autopm_get_interface_async(acm->control);
822 if (err < 0) {
823 cur->use = 0;
824 acm->putbuffer = cur;
825 goto out;
826 }
827
828 if (acm->susp_count)
829 usb_anchor_urb(cur->urb, &acm->delayed);
830 else
831 acm_start_wb(acm, cur);
832out:
833 spin_unlock_irqrestore(&acm->write_lock, flags);
834 return;
835}
836
837static int acm_tty_put_char(struct tty_struct *tty, unsigned char ch)
838{
839 struct acm *acm = tty->driver_data;
840 struct acm_wb *cur;
841 int wbn;
842 unsigned long flags;
843
844overflow:
845 cur = acm->putbuffer;
846 if (!cur) {
847 spin_lock_irqsave(&acm->write_lock, flags);
848 wbn = acm_wb_alloc(acm);
849 if (wbn >= 0) {
850 cur = &acm->wb[wbn];
851 acm->putbuffer = cur;
852 }
853 spin_unlock_irqrestore(&acm->write_lock, flags);
854 if (!cur)
855 return 0;
856 }
857
858 if (cur->len == acm->writesize) {
859 acm_tty_flush_chars(tty);
860 goto overflow;
861 }
862
863 cur->buf[cur->len++] = ch;
864 return 1;
865}
866
867static int acm_tty_write_room(struct tty_struct *tty) 796static int acm_tty_write_room(struct tty_struct *tty)
868{ 797{
869 struct acm *acm = tty->driver_data; 798 struct acm *acm = tty->driver_data;
@@ -1987,8 +1916,6 @@ static const struct tty_operations acm_ops = {
1987 .cleanup = acm_tty_cleanup, 1916 .cleanup = acm_tty_cleanup,
1988 .hangup = acm_tty_hangup, 1917 .hangup = acm_tty_hangup,
1989 .write = acm_tty_write, 1918 .write = acm_tty_write,
1990 .put_char = acm_tty_put_char,
1991 .flush_chars = acm_tty_flush_chars,
1992 .write_room = acm_tty_write_room, 1919 .write_room = acm_tty_write_room,
1993 .ioctl = acm_tty_ioctl, 1920 .ioctl = acm_tty_ioctl,
1994 .throttle = acm_tty_throttle, 1921 .throttle = acm_tty_throttle,