Thread (10 messages) 10 messages, 3 authors, 2008-02-01

Re: [patch v6 3/4] USB: add Cypress c67x00 OTG controller HCD driver

From: Alan Stern <stern@rowland.harvard.edu>
Date: 2008-01-29 15:27:49

On Tue, 29 Jan 2008, Peter Korsgaard wrote:
This patch adds HCD support for the Cypress c67x00 family of devices.
quoted hunk ↗ jump to hunk
--- /dev/null
+++ linux-2.6/drivers/usb/c67x00/c67x00-hcd.c
+int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&c67x00->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
+	c67x00_release_urb(c67x00, urb);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+	spin_unlock_irqrestore(&c67x00->lock, flags);
+
+	usb_hcd_giveback_urb(hcd, urb, status);
This is wrong.  usb_hcd_giveback_urb() must be called with local
interrupts disabled.
+/*
+ * pre: urb != NULL and c67x00 locked, urb unlocked
+ */
+static inline void
+c67x00_giveback_urb(struct c67x00_hcd *c67x00, struct urb *urb, int status)
+{
+	struct c67x00_urb_priv *urbp;
+
+	if (!urb)
+		return;
Since you have the documented precondition that urb != NULL, and since
this routine is never called in a context where urb could be NULL,
there's no need for this test.  Also, I doubt that this routine really
needs to be inline (and besides, the compiler is better at making such
decisions than we are).
+static void c67x00_sched_done(unsigned long __c67x00)
+{
+	struct c67x00_hcd *c67x00 = (struct c67x00_hcd *)__c67x00;
+	struct c67x00_urb_priv *urbp, *tmp;
+	struct urb *urb;
+
+	spin_lock(&c67x00->lock);
+
+	/* Loop over the done list and give back all the urbs */
+	list_for_each_entry_safe(urbp, tmp, &c67x00->done_list, hep_node) {
+		urb = urbp->urb;
+		c67x00_release_urb(c67x00, urb);
+		if (!usb_hcd_check_unlink_urb(c67x00_hcd_to_hcd(c67x00),
+					      urb, urbp->status)) {
The function call above is completely wrong.  It is meant to be used only
from within the dequeue method.
+			usb_hcd_unlink_urb_from_ep(c67x00_hcd_to_hcd(c67x00),
+						   urb);
+			spin_unlock(&c67x00->lock);
+			usb_hcd_giveback_urb(c67x00_hcd_to_hcd(c67x00), urb,
+					     urbp->status);
+			spin_lock(&c67x00->lock);
+		}
+	}
+	spin_unlock(&c67x00->lock);
+}
Is there some reason this routine needs to run in a tasklet?  Why not
just call it directly?

Also, the fact that it is in a tasklet means that it runs with
interrupts enabled.  Hence your spin_lock() and spin_unlock() calls
will not do the right thing.

Alan Stern
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help