Commit e4cf3aa8f9cd6ee4d583b5d445b5c152acefcde4

Authored by David Engraf
Committed by Greg Kroah-Hartman
1 parent 28d1dfadd3

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;