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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html