RE: [PATCH 05/48] USB: EHCI: update toggle state for linked QHs

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

 



I just want to say the ehci_qh spliting patch needs to be refreshed after this patch is in 2.6.31-rc3, since it makes changes to ehci_q.c and uses qh->hw* stuff.

Thanks,
Alek
>-----Original Message-----
>From: linux-usb-owner@xxxxxxxxxxxxxxx
>[mailto:linux-usb-owner@xxxxxxxxxxxxxxx] On Behalf Of Greg Kroah-Hartman
>Sent: 2009年7月13日 6:41
>To: linux-usb@xxxxxxxxxxxxxxx
>Cc: Alan Stern; David Brownell; Greg Kroah-Hartman
>Subject: [PATCH 05/48] USB: EHCI: update toggle state for linked QHs
>
>From: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
>
>This is an update to the "usb-ehci-update-toggle-state-for-linked-qhs"
>patch.  Since an HCD's endpoint_reset method can be called in
>interrupt context, it mustn't assume that interrupts are enabled or
>that it can sleep.
>
>So we revert to the original way of refreshing QHs' toggle bits.  Now
>the endpoint_reset method merely clears the toggle flag in the device
>structure (as was done before) and starts an async QH unlink.  When the
>QH is linked again, after the unlink finishes and an URB is queued,
>the qh_refresh() routine will update the QH's toggle bit.
>
>Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
>Tested-by: David <david@xxxxxxxxxxxxxxx>
>CC: David Brownell <david-b@xxxxxxxxxxx>
>Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxx>
>---
> drivers/usb/host/ehci-hcd.c |   35 ++++++++++++++++-------------------
> drivers/usb/host/ehci-q.c   |   19 ++++++++++++++++++-
> 2 files changed, 34 insertions(+), 20 deletions(-)
>
>diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
>index 2b72473..99c7560 100644
>--- a/drivers/usb/host/ehci-hcd.c
>+++ b/drivers/usb/host/ehci-hcd.c
>@@ -1030,12 +1030,14 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct
>usb_host_endpoint *ep)
> 	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
>@@ -1044,29 +1046,24 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct
>usb_host_endpoint *ep)
> 	 * 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)
>diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
>index 3192f68..1976b1b 100644
>--- a/drivers/usb/host/ehci-q.c
>+++ b/drivers/usb/host/ehci-q.c
>@@ -93,6 +93,22 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct
>ehci_qtd *qtd)
> 	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);
>@@ -834,6 +850,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;
> }
>@@ -864,7 +881,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct
>ehci_qh *qh)
> 		}
> 	}
>
>-	/* 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);
>
>--
>1.6.3.2
>
>--
>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
?韬{.n?????%??檩??w?{.n???{炳???骅w*jg????????G??⒏⒎?:+v????????????"??????

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

  Powered by Linux