Skip to content

Commit d83b405

Browse files
jhovoldgregkh
authored andcommitted
USB: serial: add support for multiple read urbs
Add support for multiple read urbs to generic read implementation. Use a static array of two read urbs for now which is enough to get a 50% throughput increase in one test setup. Signed-off-by: Johan Hovold <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent f5230a5 commit d83b405

File tree

3 files changed

+101
-41
lines changed

3 files changed

+101
-41
lines changed

drivers/usb/serial/generic.c

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* USB Serial Converter Generic functions
33
*
4-
* Copyright (C) 2010 Johan Hovold ([email protected])
4+
* Copyright (C) 2010 - 2011 Johan Hovold ([email protected])
55
* Copyright (C) 1999 - 2002 Greg Kroah-Hartman ([email protected])
66
*
77
* This program is free software; you can redistribute it and/or
@@ -132,7 +132,7 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port
132132

133133
/* if we have a bulk endpoint, start reading from it */
134134
if (port->bulk_in_size)
135-
result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
135+
result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
136136

137137
return result;
138138
}
@@ -157,8 +157,10 @@ static void generic_cleanup(struct usb_serial_port *port)
157157
kfifo_reset_out(&port->write_fifo);
158158
spin_unlock_irqrestore(&port->lock, flags);
159159
}
160-
if (port->bulk_in_size)
161-
usb_kill_urb(port->read_urb);
160+
if (port->bulk_in_size) {
161+
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
162+
usb_kill_urb(port->read_urbs[i]);
163+
}
162164
}
163165
}
164166

@@ -308,19 +310,52 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
308310
return chars;
309311
}
310312

311-
int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
313+
static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
314+
int index, gfp_t mem_flags)
315+
{
316+
int res;
317+
318+
if (!test_and_clear_bit(index, &port->read_urbs_free))
319+
return 0;
320+
321+
dbg("%s - port %d, urb %d\n", __func__, port->number, index);
322+
323+
res = usb_submit_urb(port->read_urbs[index], mem_flags);
324+
if (res) {
325+
if (res != -EPERM) {
326+
dev_err(&port->dev,
327+
"%s - usb_submit_urb failed: %d\n",
328+
__func__, res);
329+
}
330+
set_bit(index, &port->read_urbs_free);
331+
return res;
332+
}
333+
334+
return 0;
335+
}
336+
337+
int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
312338
gfp_t mem_flags)
313339
{
314-
int result;
340+
int res;
341+
int i;
315342

316-
result = usb_submit_urb(port->read_urb, mem_flags);
317-
if (result && result != -EPERM) {
318-
dev_err(&port->dev, "%s - error submitting urb: %d\n",
319-
__func__, result);
343+
dbg("%s - port %d", __func__, port->number);
344+
345+
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
346+
res = usb_serial_generic_submit_read_urb(port, i, mem_flags);
347+
if (res)
348+
goto err;
320349
}
321-
return result;
350+
351+
return 0;
352+
err:
353+
for (; i >= 0; --i)
354+
usb_kill_urb(port->read_urbs[i]);
355+
356+
return res;
322357
}
323-
EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb);
358+
EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs);
324359

325360
void usb_serial_generic_process_read_urb(struct urb *urb)
326361
{
@@ -356,14 +391,19 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
356391
{
357392
struct usb_serial_port *port = urb->context;
358393
unsigned char *data = urb->transfer_buffer;
359-
int status = urb->status;
360394
unsigned long flags;
395+
int i;
361396

362-
dbg("%s - port %d", __func__, port->number);
397+
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
398+
if (urb == port->read_urbs[i])
399+
break;
400+
}
401+
set_bit(i, &port->read_urbs_free);
363402

364-
if (unlikely(status != 0)) {
365-
dbg("%s - nonzero read bulk status received: %d",
366-
__func__, status);
403+
dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i,
404+
urb->actual_length);
405+
if (urb->status) {
406+
dbg("%s - non-zero urb status: %d\n", __func__, urb->status);
367407
return;
368408
}
369409

@@ -376,7 +416,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
376416
port->throttled = port->throttle_req;
377417
if (!port->throttled) {
378418
spin_unlock_irqrestore(&port->lock, flags);
379-
usb_serial_generic_submit_read_urb(port, GFP_ATOMIC);
419+
usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC);
380420
} else
381421
spin_unlock_irqrestore(&port->lock, flags);
382422
}
@@ -443,7 +483,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
443483
spin_unlock_irq(&port->lock);
444484

445485
if (was_throttled)
446-
usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
486+
usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
447487
}
448488
EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle);
449489

@@ -509,8 +549,9 @@ int usb_serial_generic_resume(struct usb_serial *serial)
509549
if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
510550
continue;
511551

512-
if (port->read_urb) {
513-
r = usb_submit_urb(port->read_urb, GFP_NOIO);
552+
if (port->bulk_in_size) {
553+
r = usb_serial_generic_submit_read_urbs(port,
554+
GFP_NOIO);
514555
if (r < 0)
515556
c++;
516557
}

drivers/usb/serial/usb-serial.c

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,8 @@ static void kill_traffic(struct usb_serial_port *port)
562562
{
563563
int i;
564564

565-
usb_kill_urb(port->read_urb);
565+
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
566+
usb_kill_urb(port->read_urbs[i]);
566567
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
567568
usb_kill_urb(port->write_urbs[i]);
568569
/*
@@ -594,15 +595,17 @@ static void port_release(struct device *dev)
594595
kill_traffic(port);
595596
cancel_work_sync(&port->work);
596597

597-
usb_free_urb(port->read_urb);
598598
usb_free_urb(port->interrupt_in_urb);
599599
usb_free_urb(port->interrupt_out_urb);
600+
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
601+
usb_free_urb(port->read_urbs[i]);
602+
kfree(port->bulk_in_buffers[i]);
603+
}
600604
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {
601605
usb_free_urb(port->write_urbs[i]);
602606
kfree(port->bulk_out_buffers[i]);
603607
}
604608
kfifo_free(&port->write_fifo);
605-
kfree(port->bulk_in_buffer);
606609
kfree(port->interrupt_in_buffer);
607610
kfree(port->interrupt_out_buffer);
608611
kfree(port);
@@ -721,6 +724,7 @@ int usb_serial_probe(struct usb_interface *interface,
721724
unsigned int minor;
722725
int buffer_size;
723726
int i;
727+
int j;
724728
int num_interrupt_in = 0;
725729
int num_interrupt_out = 0;
726730
int num_bulk_in = 0;
@@ -903,31 +907,39 @@ int usb_serial_probe(struct usb_interface *interface,
903907
for (i = 0; i < num_bulk_in; ++i) {
904908
endpoint = bulk_in_endpoint[i];
905909
port = serial->port[i];
906-
port->read_urb = usb_alloc_urb(0, GFP_KERNEL);
907-
if (!port->read_urb) {
908-
dev_err(&interface->dev, "No free urbs available\n");
909-
goto probe_error;
910-
}
911910
buffer_size = max_t(int, serial->type->bulk_in_size,
912911
usb_endpoint_maxp(endpoint));
913912
port->bulk_in_size = buffer_size;
914913
port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
915-
port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
916-
if (!port->bulk_in_buffer) {
917-
dev_err(&interface->dev,
914+
915+
for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) {
916+
set_bit(j, &port->read_urbs_free);
917+
port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
918+
if (!port->read_urbs[j]) {
919+
dev_err(&interface->dev,
920+
"No free urbs available\n");
921+
goto probe_error;
922+
}
923+
port->bulk_in_buffers[j] = kmalloc(buffer_size,
924+
GFP_KERNEL);
925+
if (!port->bulk_in_buffers[j]) {
926+
dev_err(&interface->dev,
918927
"Couldn't allocate bulk_in_buffer\n");
919-
goto probe_error;
920-
}
921-
usb_fill_bulk_urb(port->read_urb, dev,
922-
usb_rcvbulkpipe(dev,
928+
goto probe_error;
929+
}
930+
usb_fill_bulk_urb(port->read_urbs[j], dev,
931+
usb_rcvbulkpipe(dev,
923932
endpoint->bEndpointAddress),
924-
port->bulk_in_buffer, buffer_size,
925-
serial->type->read_bulk_callback, port);
933+
port->bulk_in_buffers[j], buffer_size,
934+
serial->type->read_bulk_callback,
935+
port);
936+
}
937+
938+
port->read_urb = port->read_urbs[0];
939+
port->bulk_in_buffer = port->bulk_in_buffers[0];
926940
}
927941

928942
for (i = 0; i < num_bulk_out; ++i) {
929-
int j;
930-
931943
endpoint = bulk_out_endpoint[i];
932944
port = serial->port[i];
933945
if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))

include/linux/usb/serial.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ enum port_dev_state {
5858
* @read_urb: pointer to the bulk in struct urb for this port.
5959
* @bulk_in_endpointAddress: endpoint address for the bulk in pipe for this
6060
* port.
61+
* @bulk_in_buffers: pointers to the bulk in buffers for this port
62+
* @read_urbs: pointers to the bulk in urbs for this port
63+
* @read_urbs_free: status bitmap the for bulk in urbs
6164
* @bulk_out_buffer: pointer to the bulk out buffer for this port.
6265
* @bulk_out_size: the size of the bulk_out_buffer, in bytes.
6366
* @write_urb: pointer to the bulk out struct urb for this port.
@@ -98,6 +101,10 @@ struct usb_serial_port {
98101
struct urb *read_urb;
99102
__u8 bulk_in_endpointAddress;
100103

104+
unsigned char *bulk_in_buffers[2];
105+
struct urb *read_urbs[2];
106+
unsigned long read_urbs_free;
107+
101108
unsigned char *bulk_out_buffer;
102109
int bulk_out_size;
103110
struct urb *write_urb;
@@ -338,7 +345,7 @@ extern void usb_serial_generic_disconnect(struct usb_serial *serial);
338345
extern void usb_serial_generic_release(struct usb_serial *serial);
339346
extern int usb_serial_generic_register(int debug);
340347
extern void usb_serial_generic_deregister(void);
341-
extern int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
348+
extern int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
342349
gfp_t mem_flags);
343350
extern void usb_serial_generic_process_read_urb(struct urb *urb);
344351
extern int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port,

0 commit comments

Comments
 (0)