Hi,

I thought I'd poke at the "sparse" lock checking stuff too,
and as I half expected, it didn't like the way all the HCDs
temporarily yield their spinlocks while calling out to URB
completion handlers.  But a fix to remove the warnings is
simple, just use a construct something like this to annotate
those functions that call usb_hcd_giveback_urb():

        #ifdef __CHECKER__
        #define __yields(x)     __attribute__((context(1,1)))
        #else
        #define __yields(x)
        #endif

Sample patch attached.  Should I repackage it so that the
new annotation goes into <linux/compiler.h> with the other
lock annotations?  In this case, the reason to watch out
for this lock idiom is that HCDs need to understand that
schedule data structures may have changed.  Normally it's
just a case of a USB driver resubmitting that URB, for a
periodic transfer to/from an endpoint; but not always.

Another option of course being to change how all the HCDs
work.  But that gets messy ... giveback() could put URBs
into queues so a BH calls the completions, at the cost of
forcing some sort of schedule re-scan in each of the HCDs,
to detect later what's now evident right when giveback()
returns:  that particular endpoint queue is empty, so
it's eligible for descheduling.  Such a change adds more
complexity to the way the HCDs' DMA queues are managed;
which I'd rather avoid, that being twitchey code.  It'd
also mean periodic transfers (including isochronous ones)
would see increased completion latencies...

Other options of course include having such an annotation
just within USB, or ignoring the warnings for now.

Comments?

- Dave
--- 1.64/drivers/usb/host/ehci-q.c	2004-11-04 18:38:12 -08:00
+++ edited/drivers/usb/host/ehci-q.c	2004-11-20 07:48:03 -08:00
@@ -173,8 +173,15 @@
 	}
 }
 
+#ifdef __CHECKER__
+#define	__yields(x)	__attribute__((context(1,1)))
+#else
+#define	__yields(x)	
+#endif
+
 static void
 ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
+__yields(ehci->lock)
 {
 	if (likely (urb->hcpriv != 0)) {
 		struct ehci_qh	*qh = (struct ehci_qh *) urb->hcpriv;
--- 1.71/drivers/usb/host/ohci-q.c	2004-11-04 18:38:13 -08:00
+++ edited/drivers/usb/host/ohci-q.c	2004-11-20 07:48:03 -08:00
@@ -28,6 +28,12 @@
 
 /*-------------------------------------------------------------------------*/
 
+#ifdef __CHECKER__
+#define	__yields(x)	__attribute__((context(1,1)))
+#else
+#define	__yields(x)	
+#endif
+
 /*
  * URB goes back to driver, and isn't reissued.
  * It's completely gone from HC data structures.
@@ -35,6 +41,7 @@
  */
 static void
 finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs)
+__yields(ohci->lock)
 {
 	// ASSERT (urb->hcpriv != 0);
 
--- 1.68/drivers/usb/host/uhci-hcd.c	2004-11-04 18:38:13 -08:00
+++ edited/drivers/usb/host/uhci-hcd.c	2004-11-20 07:48:03 -08:00
@@ -1602,7 +1602,15 @@
 	}
 }
 
-static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
+#ifdef __CHECKER__
+#define	__yields(x)	__attribute__((context(1,1)))
+#else
+#define	__yields(x)	
+#endif
+
+static void
+uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
+__yields(uhci->schedule_lock)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 

Reply via email to