Michael:
In the absence of any suggestions, we might as well try to verify my
idea about what's going wrong. The patch below adds a little more
debugging information; please try repeating the last test with this
patch in place of the previous one.
Alan Stern
Index: usb-4.3/drivers/usb/core/devio.c
===================================================================
--- usb-4.3.orig/drivers/usb/core/devio.c
+++ usb-4.3/drivers/usb/core/devio.c
@@ -100,6 +100,11 @@ static bool usbfs_snoop;
module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
+static unsigned usbfs_snoop_max = 65536;
+module_param(usbfs_snoop_max, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(usbfs_snoop_max,
+ "maximum number of bytes to print while snooping");
+
#define snoop(dev, format, arg...) \
do { \
if (usbfs_snoop) \
@@ -392,6 +397,7 @@ static void snoop_urb(struct usb_device
ep, t, d, length, timeout_or_status);
}
+ data_len = min(data_len, usbfs_snoop_max);
if (data && data_len > 0) {
print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
data, data_len, 1);
@@ -402,7 +408,8 @@ static void snoop_urb_data(struct urb *u
{
int i, size;
- if (!usbfs_snoop)
+ len = min(len, usbfs_snoop_max);
+ if (!usbfs_snoop || len == 0)
return;
if (urb->num_sgs == 0) {
@@ -510,7 +517,9 @@ static void async_completed(struct urb *
cred = get_cred(as->cred);
secid = as->secid;
}
- snoop(&urb->dev->dev, "urb complete\n");
+ if (urb->actual_length == 0 && urb->transfer_buffer_length == 16384)
+ urb->actual_length = 16;
+ snoop(&urb->dev->dev, "urb complete %p\n", as->urb);
snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
as->status, COMPLETE, NULL, 0);
if ((urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN)
@@ -1372,9 +1381,9 @@ static int proc_do_submiturb(struct usb_
uurb->type = USBDEVFS_URB_TYPE_INTERRUPT;
goto interrupt_urb;
}
- num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE);
- if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize)
- num_sgs = 0;
+// num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE);
+// if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize)
+// num_sgs = 0;
if (ep->streams)
stream_id = uurb->stream_id;
break;
@@ -1490,14 +1499,15 @@ static int proc_do_submiturb(struct usb_
ret = -EFAULT;
goto error;
}
- } else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
+// } else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
+ } else {
/*
* Isochronous input data may end up being
* discontiguous if some of the packets are short.
* Clear the buffer so that the gaps don't leak
* kernel data to userspace.
*/
- memset(as->urb->transfer_buffer, 0,
+ memset(as->urb->transfer_buffer, 0x55,
uurb->buffer_length);
}
}
@@ -1554,6 +1564,7 @@ static int proc_do_submiturb(struct usb_
as->pid = get_pid(task_pid(current));
as->cred = get_current_cred();
security_task_getsecid(current, &as->secid);
+ snoop(&ps->dev->dev, "urb submit %p\n", as->urb);
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
as->urb->transfer_buffer_length, 0, SUBMIT,
NULL, 0);
@@ -1709,8 +1720,12 @@ static struct async *reap_as(struct usb_
static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
{
struct async *as = reap_as(ps);
+
if (as) {
- int retval = processcompl(as, (void __user * __user *)arg);
+ int retval;
+
+ snoop(&ps->dev->dev, "%s: REAP %p\n", __func__, as->userurb);
+ retval = processcompl(as, (void __user * __user *)arg);
free_async(as);
return retval;
}
@@ -1726,6 +1741,7 @@ static int proc_reapurbnonblock(struct u
as = async_getcompleted(ps);
if (as) {
+ snoop(&ps->dev->dev, "%s: REAP %p\n", __func__, as->userurb);
retval = processcompl(as, (void __user * __user *)arg);
free_async(as);
} else {
@@ -1852,8 +1868,12 @@ static int processcompl_compat(struct as
static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
{
struct async *as = reap_as(ps);
+
if (as) {
- int retval = processcompl_compat(as, (void __user * __user
*)arg);
+ int retval;
+
+ snoop(&ps->dev->dev, "%s: REAP %p\n", __func__, as->userurb);
+ retval = processcompl_compat(as, (void __user * __user *)arg);
free_async(as);
return retval;
}
@@ -1869,6 +1889,7 @@ static int proc_reapurbnonblock_compat(s
as = async_getcompleted(ps);
if (as) {
+ snoop(&ps->dev->dev, "%s: REAP %p\n", __func__, as->userurb);
retval = processcompl_compat(as, (void __user * __user *)arg);
free_async(as);
} else {
@@ -2273,7 +2294,7 @@ static long usbdev_do_ioctl(struct file
#endif
case USBDEVFS_DISCARDURB:
- snoop(&dev->dev, "%s: DISCARDURB\n", __func__);
+ snoop(&dev->dev, "%s: DISCARDURB %p\n", __func__, p);
ret = proc_unlinkurb(ps, p);
break;
Index: usb-4.3/drivers/usb/host/ehci-dbg.c
===================================================================
--- usb-4.3.orig/drivers/usb/host/ehci-dbg.c
+++ usb-4.3/drivers/usb/host/ehci-dbg.c
@@ -436,7 +436,8 @@ static void qh_lines (
scratch = hc32_to_cpup(ehci, &hw->hw_info1);
hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &hw->hw_current) : 0;
temp = scnprintf (next, size,
- "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
+ "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)"
+ " [cur %08x next %08x buf %08x]",
qh, scratch & 0x007f,
speed_char (scratch),
(scratch >> 8) & 0x000f,
@@ -444,7 +445,10 @@ static void qh_lines (
hc32_to_cpup(ehci, &hw->hw_token), mark,
(cpu_to_hc32(ehci, QTD_TOGGLE) & hw->hw_token)
? "data1" : "data0",
- (hc32_to_cpup(ehci, &hw->hw_alt_next) >> 1) & 0x0f);
+ (hc32_to_cpup(ehci, &hw->hw_alt_next) >> 1) & 0x0f,
+ hc32_to_cpup(ehci, &hw->hw_current),
+ hc32_to_cpup(ehci, &hw->hw_qtd_next),
+ hc32_to_cpup(ehci, &hw->hw_buf[0]));
size -= temp;
next += temp;
@@ -464,7 +468,8 @@ static void qh_lines (
mark = '/';
}
temp = snprintf (next, size,
- "\n\t%p%c%s len=%d %08x urb %p",
+ "\n\t%p%c%s len=%d %08x urb %p"
+ " [td %08x buf %08x]",
td, mark, ({ char *tmp;
switch ((scratch>>8)&0x03) {
case 0: tmp = "out"; break;
@@ -474,7 +479,9 @@ static void qh_lines (
} tmp;}),
(scratch >> 16) & 0x7fff,
scratch,
- td->urb);
+ td->urb,
+ (u32) td->qtd_dma,
+ hc32_to_cpup(ehci, &td->hw_buf[0]));
if (size < temp)
temp = size;
size -= temp;
Index: usb-4.3/drivers/usb/host/ehci-q.c
===================================================================
--- usb-4.3.orig/drivers/usb/host/ehci-q.c
+++ usb-4.3/drivers/usb/host/ehci-q.c
@@ -132,10 +132,14 @@ qh_refresh (struct ehci_hcd *ehci, struc
* qtd is updated in qh_completions(). Update the QH
* overlay here.
*/
- if (qh->hw->hw_token & ACTIVE_BIT(ehci))
+ if (qh->hw->hw_token & ACTIVE_BIT(ehci)) {
qh->hw->hw_qtd_next = qtd->hw_next;
+ if (qh->should_be_inactive)
+ ehci_info(ehci, "qh %p should be inactive!\n", qh);
+ }
else
qh_update(ehci, qh, qtd);
+ qh->should_be_inactive = 0;
}
/*-------------------------------------------------------------------------*/
@@ -438,6 +442,7 @@ qh_completions (struct ehci_hcd *ehci, s
(hw->hw_token & ACTIVE_BIT(ehci))) {
token = hc32_to_cpu(ehci, hw->hw_token);
hw->hw_token &= ~ACTIVE_BIT(ehci);
+ qh->should_be_inactive = 1;
/* An unlink may leave an incomplete
* async transaction in the TT buffer.
Index: usb-4.3/drivers/usb/host/ehci.h
===================================================================
--- usb-4.3.orig/drivers/usb/host/ehci.h
+++ usb-4.3/drivers/usb/host/ehci.h
@@ -439,6 +439,7 @@ struct ehci_qh {
unsigned dequeue_during_giveback:1;
unsigned exception:1; /* got a fault, or an unlink
was requested */
+ unsigned should_be_inactive:1;
};
/*-------------------------------------------------------------------------*/
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html