Commit e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4
Committed by
Greg Kroah-Hartman
1 parent
28d1dfadd3
Exists in
master
and in
7 other branches
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>
Showing 2 changed files with 45 additions and 43 deletions Side-by-side Diff
drivers/usb/class/cdc-acm.c
... | ... | @@ -31,6 +31,7 @@ |
31 | 31 | * v0.23 - use softirq for rx processing, as needed by tty layer |
32 | 32 | * v0.24 - change probe method to evaluate CDC union descriptor |
33 | 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 | 74 | * Version Information |
74 | 75 | */ |
75 | -#define DRIVER_VERSION "v0.25" | |
76 | +#define DRIVER_VERSION "v0.26" | |
76 | 77 | #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek" |
77 | 78 | #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" |
78 | 79 | |
... | ... | @@ -118,7 +119,7 @@ |
118 | 119 | int i, wbn; |
119 | 120 | struct acm_wb *wb; |
120 | 121 | |
121 | - wbn = acm->write_current; | |
122 | + wbn = 0; | |
122 | 123 | i = 0; |
123 | 124 | for (;;) { |
124 | 125 | wb = &acm->wb[wbn]; |
... | ... | @@ -132,11 +133,6 @@ |
132 | 133 | } |
133 | 134 | } |
134 | 135 | |
135 | -static void acm_wb_free(struct acm *acm, int wbn) | |
136 | -{ | |
137 | - acm->wb[wbn].use = 0; | |
138 | -} | |
139 | - | |
140 | 136 | static int acm_wb_is_avail(struct acm *acm) |
141 | 137 | { |
142 | 138 | int i, n; |
143 | 139 | |
144 | 140 | |
145 | 141 | |
146 | 142 | |
... | ... | @@ -156,26 +152,22 @@ |
156 | 152 | /* |
157 | 153 | * Finish write. |
158 | 154 | */ |
159 | -static void acm_write_done(struct acm *acm) | |
155 | +static void acm_write_done(struct acm *acm, struct acm_wb *wb) | |
160 | 156 | { |
161 | 157 | unsigned long flags; |
162 | - int wbn; | |
163 | 158 | |
164 | 159 | spin_lock_irqsave(&acm->write_lock, flags); |
165 | 160 | acm->write_ready = 1; |
166 | - wbn = acm->write_current; | |
167 | - acm_wb_free(acm, wbn); | |
168 | - acm->write_current = (wbn + 1) % ACM_NW; | |
161 | + wb->use = 0; | |
169 | 162 | spin_unlock_irqrestore(&acm->write_lock, flags); |
170 | 163 | } |
171 | 164 | |
172 | 165 | /* |
173 | 166 | * Poke write. |
174 | 167 | */ |
175 | -static int acm_write_start(struct acm *acm) | |
168 | +static int acm_write_start(struct acm *acm, int wbn) | |
176 | 169 | { |
177 | 170 | unsigned long flags; |
178 | - int wbn; | |
179 | 171 | struct acm_wb *wb; |
180 | 172 | int rc; |
181 | 173 | |
182 | 174 | |
183 | 175 | |
184 | 176 | |
185 | 177 | |
... | ... | @@ -190,24 +182,24 @@ |
190 | 182 | return 0; /* A white lie */ |
191 | 183 | } |
192 | 184 | |
193 | - wbn = acm->write_current; | |
194 | 185 | if (!acm_wb_is_used(acm, wbn)) { |
195 | 186 | spin_unlock_irqrestore(&acm->write_lock, flags); |
196 | 187 | return 0; |
197 | 188 | } |
198 | 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 | 193 | spin_unlock_irqrestore(&acm->write_lock, flags); |
202 | 194 | |
203 | - acm->writeurb->transfer_buffer = wb->buf; | |
204 | - acm->writeurb->transfer_dma = wb->dmah; | |
205 | - acm->writeurb->transfer_buffer_length = wb->len; | |
206 | - acm->writeurb->dev = acm->dev; | |
195 | + wb->urb->transfer_buffer = wb->buf; | |
196 | + wb->urb->transfer_dma = wb->dmah; | |
197 | + wb->urb->transfer_buffer_length = wb->len; | |
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 | 201 | dbg("usb_submit_urb(write bulk) failed: %d", rc); |
210 | - acm_write_done(acm); | |
202 | + acm_write_done(acm, wb); | |
211 | 203 | } |
212 | 204 | return rc; |
213 | 205 | } |
214 | 206 | |
... | ... | @@ -450,12 +442,13 @@ |
450 | 442 | /* data interface wrote those outgoing bytes */ |
451 | 443 | static 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 | 448 | dbg("Entering acm_write_bulk with status %d", urb->status); |
456 | 449 | |
457 | - acm_write_done(acm); | |
458 | - acm_write_start(acm); | |
450 | + acm = wb->instance; | |
451 | + acm_write_done(acm, wb); | |
459 | 452 | if (ACM_READY(acm)) |
460 | 453 | schedule_work(&acm->work); |
461 | 454 | } |
... | ... | @@ -557,7 +550,8 @@ |
557 | 550 | usb_put_intf(acm->control); |
558 | 551 | acm_table[acm->minor] = NULL; |
559 | 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 | 555 | for (i = 0; i < nr; i++) |
562 | 556 | usb_free_urb(acm->ru[i].urb); |
563 | 557 | kfree(acm->country_codes); |
... | ... | @@ -578,7 +572,8 @@ |
578 | 572 | if (acm->dev) { |
579 | 573 | acm_set_control(acm, acm->ctrlout = 0); |
580 | 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 | 577 | for (i = 0; i < nr; i++) |
583 | 578 | usb_kill_urb(acm->ru[i].urb); |
584 | 579 | usb_autopm_put_interface(acm->control); |
... | ... | @@ -606,7 +601,6 @@ |
606 | 601 | spin_lock_irqsave(&acm->write_lock, flags); |
607 | 602 | if ((wbn = acm_wb_alloc(acm)) < 0) { |
608 | 603 | spin_unlock_irqrestore(&acm->write_lock, flags); |
609 | - acm_write_start(acm); | |
610 | 604 | return 0; |
611 | 605 | } |
612 | 606 | wb = &acm->wb[wbn]; |
... | ... | @@ -617,7 +611,7 @@ |
617 | 611 | wb->len = count; |
618 | 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 | 615 | return stat; |
622 | 616 | return count; |
623 | 617 | } |
... | ... | @@ -977,7 +971,7 @@ |
977 | 971 | |
978 | 972 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); |
979 | 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 | 975 | acm->control = control_interface; |
982 | 976 | acm->data = data_interface; |
983 | 977 | acm->minor = minor; |
... | ... | @@ -1032,10 +1026,19 @@ |
1032 | 1026 | goto alloc_fail7; |
1033 | 1027 | } |
1034 | 1028 | } |
1035 | - acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); | |
1036 | - if (!acm->writeurb) { | |
1037 | - dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n"); | |
1038 | - goto alloc_fail7; | |
1029 | + for(i = 0; i < ACM_NW; i++) | |
1030 | + { | |
1031 | + struct acm_wb *snd = &(acm->wb[i]); | |
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 | 1044 | usb_set_intfdata (intf, acm); |
... | ... | @@ -1071,10 +1074,6 @@ |
1071 | 1074 | acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
1072 | 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 | 1077 | dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); |
1079 | 1078 | |
1080 | 1079 | acm_set_control(acm, acm->ctrlout); |
... | ... | @@ -1092,7 +1091,8 @@ |
1092 | 1091 | |
1093 | 1092 | return 0; |
1094 | 1093 | alloc_fail8: |
1095 | - usb_free_urb(acm->writeurb); | |
1094 | + for (i = 0; i < ACM_NW; i++) | |
1095 | + usb_free_urb(acm->wb[i].urb); | |
1096 | 1096 | alloc_fail7: |
1097 | 1097 | for (i = 0; i < num_rx_buf; i++) |
1098 | 1098 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); |
... | ... | @@ -1116,7 +1116,8 @@ |
1116 | 1116 | tasklet_disable(&acm->urb_task); |
1117 | 1117 | |
1118 | 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 | 1121 | for (i = 0; i < acm->rx_buflimit; i++) |
1121 | 1122 | usb_kill_urb(acm->ru[i].urb); |
1122 | 1123 |
drivers/usb/class/cdc-acm.h
... | ... | @@ -59,7 +59,7 @@ |
59 | 59 | * when processing onlcr, so we only need 2 buffers. These values must be |
60 | 60 | * powers of 2. |
61 | 61 | */ |
62 | -#define ACM_NW 2 | |
62 | +#define ACM_NW 16 | |
63 | 63 | #define ACM_NR 16 |
64 | 64 | |
65 | 65 | struct acm_wb { |
... | ... | @@ -67,6 +67,8 @@ |
67 | 67 | dma_addr_t dmah; |
68 | 68 | int len; |
69 | 69 | int use; |
70 | + struct urb *urb; | |
71 | + struct acm *instance; | |
70 | 72 | }; |
71 | 73 | |
72 | 74 | struct acm_rb { |
... | ... | @@ -88,7 +90,7 @@ |
88 | 90 | struct usb_interface *control; /* control interface */ |
89 | 91 | struct usb_interface *data; /* data interface */ |
90 | 92 | struct tty_struct *tty; /* the corresponding tty */ |
91 | - struct urb *ctrlurb, *writeurb; /* urbs */ | |
93 | + struct urb *ctrlurb; /* urbs */ | |
92 | 94 | u8 *ctrl_buffer; /* buffers of urbs */ |
93 | 95 | dma_addr_t ctrl_dma; /* dma handles of buffers */ |
94 | 96 | u8 *country_codes; /* country codes from device */ |
... | ... | @@ -103,7 +105,6 @@ |
103 | 105 | struct list_head spare_read_urbs; |
104 | 106 | struct list_head spare_read_bufs; |
105 | 107 | struct list_head filled_read_bufs; |
106 | - int write_current; /* current write buffer */ | |
107 | 108 | int write_used; /* number of non-empty write buffers */ |
108 | 109 | int write_ready; /* write urb is not running */ |
109 | 110 | spinlock_t write_lock; |