Re: USB/DVB - Old Technotrend TT-connect S-2400 regression tracked down

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, 27 May 2009, David wrote:

> > If it works okay for you, I'll submit it.
> >
> >   
> Still looks good to me.

It turns out that the patch can't be used as is.  It assumes the
endpoint_reset method is always called in process context, but this
isn't true.

Below is a partial reversion combined with an update.  Dave, could you 
test it to make sure it still fixes the problem?  No need to send any 
usbmon data if it does, a "Tested-by:" will be good enough.

Greg, assuming this works out, I'll submit this patch to be folded into
"usb-ehci-update-toggle-state-for-linked-qhs", already in your tree.  
Will that be okay?

Alan Stern



Index: usb-2.6/drivers/usb/host/ehci-hcd.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/ehci-hcd.c
+++ usb-2.6/drivers/usb/host/ehci-hcd.c
@@ -1032,12 +1032,14 @@ ehci_endpoint_reset(struct usb_hcd *hcd,
 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
 	struct ehci_qh		*qh;
 	int			eptype = usb_endpoint_type(&ep->desc);
+	int			epnum = usb_endpoint_num(&ep->desc);
+	int			is_out = usb_endpoint_dir_out(&ep->desc);
+	unsigned long		flags;
 
 	if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
 		return;
 
- rescan:
-	spin_lock_irq(&ehci->lock);
+	spin_lock_irqsave(&ehci->lock, flags);
 	qh = ep->hcpriv;
 
 	/* For Bulk and Interrupt endpoints we maintain the toggle state
@@ -1046,29 +1048,24 @@ ehci_endpoint_reset(struct usb_hcd *hcd,
 	 * the toggle bit in the QH.
 	 */
 	if (qh) {
+		usb_settoggle(qh->dev, epnum, is_out, 0);
 		if (!list_empty(&qh->qtd_list)) {
 			WARN_ONCE(1, "clear_halt for a busy endpoint\n");
-		} else if (qh->qh_state == QH_STATE_IDLE) {
-			qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
-		} else {
-			/* It's not safe to write into the overlay area
-			 * while the QH is active.  Unlink it first and
-			 * wait for the unlink to complete.
+		} else if (qh->qh_state == QH_STATE_LINKED) {
+
+			/* The toggle value in the QH can't be updated
+			 * while the QH is active.  Unlink it now;
+			 * re-linking will call qh_refresh().
 			 */
-			if (qh->qh_state == QH_STATE_LINKED) {
-				if (eptype == USB_ENDPOINT_XFER_BULK) {
-					unlink_async(ehci, qh);
-				} else {
-					intr_deschedule(ehci, qh);
-					(void) qh_schedule(ehci, qh);
-				}
+			if (eptype == USB_ENDPOINT_XFER_BULK) {
+				unlink_async(ehci, qh);
+			} else {
+				intr_deschedule(ehci, qh);
+				(void) qh_schedule(ehci, qh);
 			}
-			spin_unlock_irq(&ehci->lock);
-			schedule_timeout_uninterruptible(1);
-			goto rescan;
 		}
 	}
-	spin_unlock_irq(&ehci->lock);
+	spin_unlock_irqrestore(&ehci->lock, flags);
 }
 
 static int ehci_get_frame (struct usb_hcd *hcd)
Index: usb-2.6/drivers/usb/host/ehci-q.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/ehci-q.c
+++ usb-2.6/drivers/usb/host/ehci-q.c
@@ -93,6 +93,22 @@ qh_update (struct ehci_hcd *ehci, struct
 	qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
 	qh->hw_alt_next = EHCI_LIST_END(ehci);
 
+	/* Except for control endpoints, we make hardware maintain data
+	 * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
+	 * and set the pseudo-toggle in udev. Only usb_clear_halt() will
+	 * ever clear it.
+	 */
+	if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
+		unsigned	is_out, epnum;
+
+		is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
+		epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f;
+		if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
+			qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
+			usb_settoggle (qh->dev, epnum, is_out, 1);
+		}
+	}
+
 	/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
 	wmb ();
 	qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
@@ -877,6 +893,7 @@ done:
 	qh->qh_state = QH_STATE_IDLE;
 	qh->hw_info1 = cpu_to_hc32(ehci, info1);
 	qh->hw_info2 = cpu_to_hc32(ehci, info2);
+	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
 	qh_refresh (ehci, qh);
 	return qh;
 }
@@ -911,7 +928,7 @@ static void qh_link_async (struct ehci_h
 		}
 	}
 
-	/* clear halt and maybe recover from silicon quirk */
+	/* clear halt and/or toggle; and maybe recover from silicon quirk */
 	if (qh->qh_state == QH_STATE_IDLE)
 		qh_refresh (ehci, qh);
 

--
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

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux