[PATCH 5/5] usb_debug: EXPERIMENTAL - poll hcd device to force writes

From: Jason Wessel
Date: Tue May 05 2009 - 22:02:24 EST


The problem that this patch tries to solve is that data is lost
because there are too many outstanding transmit urb's.

The question is what is the right way to force the controller to catch
up, and ideally let the kernel do some other things in the mean time?

This patch takes the route of forcibly polling the hcd device to drain
the urb queue and initiate the bulk write call backs.

NOTE this patch is not signed off, it is a question of what is the
right way to do this?
---
drivers/usb/core/hcd.c | 1 +
drivers/usb/serial/usb_debug.c | 23 +++++++++++++++++++++++
2 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 42b93da..57c09c2 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1760,6 +1760,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
local_irq_restore(flags);
return rc;
}
+EXPORT_SYMBOL_GPL(usb_hcd_irq);

/*-------------------------------------------------------------------------*/

diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index 58feab9..8838418 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#include "../core/hcd.h"

#define URB_UPPER_LIMIT 42
#define USB_DEBUG_MAX_PACKET_SIZE 8
@@ -91,6 +92,23 @@ static int usb_debug_port_probe(struct usb_serial_port *port)
return 0;
}

+/* If the driver is close to running of tx urb's try to free some up
+ * by asking the hcd device to do some processing. XXX This needs
+ * review as to if this is a reasonable way to implement forcing the
+ * HCD device to run.
+ */
+static void poll_hcd_irq(struct urb *urb)
+{
+ struct usb_hcd *hcd;
+
+ if (!urb)
+ return;
+
+ hcd = bus_to_hcd(urb->dev->bus);
+ if (hcd)
+ usb_hcd_irq(0, hcd);
+}
+
static int usb_debug_write_room(struct tty_struct *tty)
{
unsigned long flags;
@@ -156,10 +174,15 @@ static int usb_debug_write(struct tty_struct *tty,
dbg("%s - write request of 0 bytes", __func__);

while (count > 0) {
+ int loops = 1000;
+try_again:
spin_lock_irqsave(&priv->tx_lock, flags);
if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) {
spin_unlock_irqrestore(&priv->tx_lock, flags);
dbg("%s - write limit hit\n", __func__);
+ poll_hcd_irq(port->read_urb);
+ if (loops-- > 0)
+ goto try_again;
return bwrite;
}

--
1.6.3.rc0.1.gf800

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/