aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/class/cdc-acm.c
diff options
context:
space:
mode:
authorDavid Engraf <david.engraf@netcom.eu>2008-03-20 05:01:34 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-04-25 00:16:44 -0400
commite4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4 (patch)
tree1e1a442763c227bbe0c72952f8e5e599ecd30a97 /drivers/usb/class/cdc-acm.c
parent28d1dfadd3ca07e7ec1c3de4f82ac2b8ece4be91 (diff)
USB: increase cdc-acm write throughput
the following patch uses 16 write urbs and a writsize of wMaxPacketSize * 20. With this patch I get the maximum througput from my linux system with 20MB/sec read and 15 MB/sec write (full speed 1 MB/sec both) I also deleted the flag URB_NO_FSBR for the writeurbs, because this makes my full speed devices significant slower. Signed-off-by: David Engraf <david.engraf@netcom.eu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/class/cdc-acm.c')
-rw-r--r--drivers/usb/class/cdc-acm.c81
1 files changed, 41 insertions, 40 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 1ded83b66af0..d9b408113921 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -31,6 +31,7 @@
31 * v0.23 - use softirq for rx processing, as needed by tty layer 31 * v0.23 - use softirq for rx processing, as needed by tty layer
32 * v0.24 - change probe method to evaluate CDC union descriptor 32 * v0.24 - change probe method to evaluate CDC union descriptor
33 * v0.25 - downstream tasks paralelized to maximize throughput 33 * v0.25 - downstream tasks paralelized to maximize throughput
34 * v0.26 - multiple write urbs, writesize increased
34 */ 35 */
35 36
36/* 37/*
@@ -72,7 +73,7 @@
72/* 73/*
73 * Version Information 74 * Version Information
74 */ 75 */
75#define DRIVER_VERSION "v0.25" 76#define DRIVER_VERSION "v0.26"
76#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek" 77#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
77#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" 78#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
78 79
@@ -118,7 +119,7 @@ static int acm_wb_alloc(struct acm *acm)
118 int i, wbn; 119 int i, wbn;
119 struct acm_wb *wb; 120 struct acm_wb *wb;
120 121
121 wbn = acm->write_current; 122 wbn = 0;
122 i = 0; 123 i = 0;
123 for (;;) { 124 for (;;) {
124 wb = &acm->wb[wbn]; 125 wb = &acm->wb[wbn];
@@ -132,11 +133,6 @@ static int acm_wb_alloc(struct acm *acm)
132 } 133 }
133} 134}
134 135
135static void acm_wb_free(struct acm *acm, int wbn)
136{
137 acm->wb[wbn].use = 0;
138}
139
140static int acm_wb_is_avail(struct acm *acm) 136static int acm_wb_is_avail(struct acm *acm)
141{ 137{
142 int i, n; 138 int i, n;
@@ -156,26 +152,22 @@ static inline int acm_wb_is_used(struct acm *acm, int wbn)
156/* 152/*
157 * Finish write. 153 * Finish write.
158 */ 154 */
159static void acm_write_done(struct acm *acm) 155static void acm_write_done(struct acm *acm, struct acm_wb *wb)
160{ 156{
161 unsigned long flags; 157 unsigned long flags;
162 int wbn;
163 158
164 spin_lock_irqsave(&acm->write_lock, flags); 159 spin_lock_irqsave(&acm->write_lock, flags);
165 acm->write_ready = 1; 160 acm->write_ready = 1;
166 wbn = acm->write_current; 161 wb->use = 0;
167 acm_wb_free(acm, wbn);
168 acm->write_current = (wbn + 1) % ACM_NW;
169 spin_unlock_irqrestore(&acm->write_lock, flags); 162 spin_unlock_irqrestore(&acm->write_lock, flags);
170} 163}
171 164
172/* 165/*
173 * Poke write. 166 * Poke write.
174 */ 167 */
175static int acm_write_start(struct acm *acm) 168static int acm_write_start(struct acm *acm, int wbn)
176{ 169{
177 unsigned long flags; 170 unsigned long flags;
178 int wbn;
179 struct acm_wb *wb; 171 struct acm_wb *wb;
180 int rc; 172 int rc;
181 173
@@ -190,24 +182,24 @@ static int acm_write_start(struct acm *acm)
190 return 0; /* A white lie */ 182 return 0; /* A white lie */
191 } 183 }
192 184
193 wbn = acm->write_current;
194 if (!acm_wb_is_used(acm, wbn)) { 185 if (!acm_wb_is_used(acm, wbn)) {
195 spin_unlock_irqrestore(&acm->write_lock, flags); 186 spin_unlock_irqrestore(&acm->write_lock, flags);
196 return 0; 187 return 0;
197 } 188 }
198 wb = &acm->wb[wbn]; 189 wb = &acm->wb[wbn];
199 190
200 acm->write_ready = 0; 191 if(acm_wb_is_avail(acm) <= 1)
192 acm->write_ready = 0;
201 spin_unlock_irqrestore(&acm->write_lock, flags); 193 spin_unlock_irqrestore(&acm->write_lock, flags);
202 194
203 acm->writeurb->transfer_buffer = wb->buf; 195 wb->urb->transfer_buffer = wb->buf;
204 acm->writeurb->transfer_dma = wb->dmah; 196 wb->urb->transfer_dma = wb->dmah;
205 acm->writeurb->transfer_buffer_length = wb->len; 197 wb->urb->transfer_buffer_length = wb->len;
206 acm->writeurb->dev = acm->dev; 198 wb->urb->dev = acm->dev;
207 199
208 if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) { 200 if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) {
209 dbg("usb_submit_urb(write bulk) failed: %d", rc); 201 dbg("usb_submit_urb(write bulk) failed: %d", rc);
210 acm_write_done(acm); 202 acm_write_done(acm, wb);
211 } 203 }
212 return rc; 204 return rc;
213} 205}
@@ -450,12 +442,13 @@ urbs:
450/* data interface wrote those outgoing bytes */ 442/* data interface wrote those outgoing bytes */
451static void acm_write_bulk(struct urb *urb) 443static void acm_write_bulk(struct urb *urb)
452{ 444{
453 struct acm *acm = (struct acm *)urb->context; 445 struct acm *acm;
446 struct acm_wb *wb = (struct acm_wb *)urb->context;
454 447
455 dbg("Entering acm_write_bulk with status %d", urb->status); 448 dbg("Entering acm_write_bulk with status %d", urb->status);
456 449
457 acm_write_done(acm); 450 acm = wb->instance;
458 acm_write_start(acm); 451 acm_write_done(acm, wb);
459 if (ACM_READY(acm)) 452 if (ACM_READY(acm))
460 schedule_work(&acm->work); 453 schedule_work(&acm->work);
461} 454}
@@ -557,7 +550,8 @@ static void acm_tty_unregister(struct acm *acm)
557 usb_put_intf(acm->control); 550 usb_put_intf(acm->control);
558 acm_table[acm->minor] = NULL; 551 acm_table[acm->minor] = NULL;
559 usb_free_urb(acm->ctrlurb); 552 usb_free_urb(acm->ctrlurb);
560 usb_free_urb(acm->writeurb); 553 for (i = 0; i < ACM_NW; i++)
554 usb_free_urb(acm->wb[i].urb);
561 for (i = 0; i < nr; i++) 555 for (i = 0; i < nr; i++)
562 usb_free_urb(acm->ru[i].urb); 556 usb_free_urb(acm->ru[i].urb);
563 kfree(acm->country_codes); 557 kfree(acm->country_codes);
@@ -578,7 +572,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
578 if (acm->dev) { 572 if (acm->dev) {
579 acm_set_control(acm, acm->ctrlout = 0); 573 acm_set_control(acm, acm->ctrlout = 0);
580 usb_kill_urb(acm->ctrlurb); 574 usb_kill_urb(acm->ctrlurb);
581 usb_kill_urb(acm->writeurb); 575 for (i = 0; i < ACM_NW; i++)
576 usb_kill_urb(acm->wb[i].urb);
582 for (i = 0; i < nr; i++) 577 for (i = 0; i < nr; i++)
583 usb_kill_urb(acm->ru[i].urb); 578 usb_kill_urb(acm->ru[i].urb);
584 usb_autopm_put_interface(acm->control); 579 usb_autopm_put_interface(acm->control);
@@ -606,7 +601,6 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
606 spin_lock_irqsave(&acm->write_lock, flags); 601 spin_lock_irqsave(&acm->write_lock, flags);
607 if ((wbn = acm_wb_alloc(acm)) < 0) { 602 if ((wbn = acm_wb_alloc(acm)) < 0) {
608 spin_unlock_irqrestore(&acm->write_lock, flags); 603 spin_unlock_irqrestore(&acm->write_lock, flags);
609 acm_write_start(acm);
610 return 0; 604 return 0;
611 } 605 }
612 wb = &acm->wb[wbn]; 606 wb = &acm->wb[wbn];
@@ -617,7 +611,7 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
617 wb->len = count; 611 wb->len = count;
618 spin_unlock_irqrestore(&acm->write_lock, flags); 612 spin_unlock_irqrestore(&acm->write_lock, flags);
619 613
620 if ((stat = acm_write_start(acm)) < 0) 614 if ((stat = acm_write_start(acm, wbn)) < 0)
621 return stat; 615 return stat;
622 return count; 616 return count;
623} 617}
@@ -977,7 +971,7 @@ skip_normal_probe:
977 971
978 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); 972 ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
979 readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2); 973 readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
980 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize); 974 acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
981 acm->control = control_interface; 975 acm->control = control_interface;
982 acm->data = data_interface; 976 acm->data = data_interface;
983 acm->minor = minor; 977 acm->minor = minor;
@@ -1032,10 +1026,19 @@ skip_normal_probe:
1032 goto alloc_fail7; 1026 goto alloc_fail7;
1033 } 1027 }
1034 } 1028 }
1035 acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); 1029 for(i = 0; i < ACM_NW; i++)
1036 if (!acm->writeurb) { 1030 {
1037 dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n"); 1031 struct acm_wb *snd = &(acm->wb[i]);
1038 goto alloc_fail7; 1032
1033 if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
1034 dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)");
1035 goto alloc_fail7;
1036 }
1037
1038 usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1039 NULL, acm->writesize, acm_write_bulk, snd);
1040 snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1041 snd->instance = acm;
1039 } 1042 }
1040 1043
1041 usb_set_intfdata (intf, acm); 1044 usb_set_intfdata (intf, acm);
@@ -1071,10 +1074,6 @@ skip_countries:
1071 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 1074 acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1072 acm->ctrlurb->transfer_dma = acm->ctrl_dma; 1075 acm->ctrlurb->transfer_dma = acm->ctrl_dma;
1073 1076
1074 usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
1075 NULL, acm->writesize, acm_write_bulk, acm);
1076 acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
1077
1078 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); 1077 dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
1079 1078
1080 acm_set_control(acm, acm->ctrlout); 1079 acm_set_control(acm, acm->ctrlout);
@@ -1092,7 +1091,8 @@ skip_countries:
1092 1091
1093 return 0; 1092 return 0;
1094alloc_fail8: 1093alloc_fail8:
1095 usb_free_urb(acm->writeurb); 1094 for (i = 0; i < ACM_NW; i++)
1095 usb_free_urb(acm->wb[i].urb);
1096alloc_fail7: 1096alloc_fail7:
1097 for (i = 0; i < num_rx_buf; i++) 1097 for (i = 0; i < num_rx_buf; i++)
1098 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); 1098 usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
@@ -1116,7 +1116,8 @@ static void stop_data_traffic(struct acm *acm)
1116 tasklet_disable(&acm->urb_task); 1116 tasklet_disable(&acm->urb_task);
1117 1117
1118 usb_kill_urb(acm->ctrlurb); 1118 usb_kill_urb(acm->ctrlurb);
1119 usb_kill_urb(acm->writeurb); 1119 for(i = 0; i < ACM_NW; i++)
1120 usb_kill_urb(acm->wb[i].urb);
1120 for (i = 0; i < acm->rx_buflimit; i++) 1121 for (i = 0; i < acm->rx_buflimit; i++)
1121 usb_kill_urb(acm->ru[i].urb); 1122 usb_kill_urb(acm->ru[i].urb);
1122 1123