Re: [PATCH v1] USB: EHCI: disable IAA_WATCHDOG and START_UNLINK_INTR if they needn't to be handled

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

 



On Tue, 27 Aug 2013, Ming Lei wrote:

> > I don't understand your argument.  The uhci-hcd _does_ support
> > interrupt URBs being submitted from tasklets, workqueues, kernel
> > threads, or whatever.  The guarantee is that the interrupt URB will be
> > scheduled right away if the endpoint queue has not emptied out.
> 
> Considered it is common for interrupt queue that only one URB is
> submitted, there is no the guarantee if drivers submit URB in
> tasklet scheduled from complete(), so the URB isn't submitted
> right away always for the driver.

Yes.  I'm not sure what is the best way to explain this...

Think about it this way: Why did you write the "USB: EHCI: improve
interrupt qh unlink" patch in the first place?  Essentially the same
reason applies to uhci-hcd and ohci-hcd, and they will need similar
patches.

> > The problem is that the HCDs currently _do_ guarantee the isochronous
> > URBs submitted by the completion handler will be scheduled immediately
> > following the preceding URB (to the best of their ability -- not all
> > the HCDs can do this).  Maintaining this guarantee while giving back
> > URBs in a tasklet is difficult.  See the 3/3 patch in the RFC series I
> > just posted to get an idea of the required changes.
> 
> There are already several drivers which submits URB from tasklet
> scheduled in complete(), which doesn't submit URB directly. Is there
> any difference with what does in giveback in tasklet patch from view
> of HCD?

No.  There is a difference only when the completion submits an 
isochronous URB directly.

> >> > Suppose an URB is submitted while the endpoint queue is non-empty, so
> >> > it is scheduled to start in the next slot after the end of the last URB
> >> > in the queue.  Does that next slot occur after the frame stored in
> >> > ehci->last_iso_frame?
> >>
> >> I think it is yes, actually the new slot is always after current uframe
> >> during iso_stream_schedule from tasklet, and it is behind
> >> ehci->last_iso_frame which is updated in ehci_irq path.
> >
> > Wrong.  Here are a couple of examples.  Assume first that the
> > endpoint's interval is 8 frames (it's a full-speed device):
> >
> >         The last packet of the last URB on the queue is scheduled
> >         for frame 100.  Because of an SMI, IRQs are delayed until
> >         the controller reaches frame 105.
> >
> >         When the interrupt occurs, ehci-hcd will scan the siTDs
> >         for the endpoint and give them all back.  At the end,
> >         last_iso_frame will be set to 104 (it lags one behind the
> >         current frame number).
> >
> >         Let's say the tasklet takes 1 ms to start up, so the
> >         completion handler runs during frame 106.  It submits an
> >         URB.  This URB is scheduled for the next unused slot, which
> >         is 108 (i.e., 8 frames after the last packet of the last
> >         URB).  Since 108 is larger than both 104 and 106, the next
> >         slot does indeed come after both ehci->last_iso_frame and
> >         the current frame number.
> 
> Yes, but the TDs(URB) can't be missed, suppose there are 8
> packets, so the last packet of the new URB will be completed in
> 164, when IRQ comes at 165, ehci_irq() will scan from 104 to
> 165, so the URB can be completed successfully, then update
> last_iso_frame as 164.
> 
> Then what is wrong?

Nothing is wrong, either with my example or with yours.

> > Now assume the endpoint's interval is 1 frame:
> >
> >         The last packet of the last URB on the queue is scheduled
> >         for frame 200.  Because of an SMI, IRQs are delayed until
> >         the controller reaches frame 205.
> >
> >         When the interrupt occurs, ehci-hcd will scan the siTDs
> >         for the endpoint and give them all back.  At the end,
> >         last_iso_frame will be set to 204.
> >
> >         The tasklet takes 1 ms to start up, so the completion handler
> >         runs during frame 206.  It submits an URB.  This URB is
> >         scheduled for the next unused slot, which is 201 (i.e., 1 frame
> >         after the last packet of the last URB).  Since 201 is smaller
> >         than both 204 and 206, the next slot does indeed come before
> >         both ehci->last_iso_frame and the current frame number.
> 
> iso_stream_schedule() will figure out that the next slot(201) is behind
> the scheduling threshold(case of 'start < next'), then update the next
> slot as one new slot which is larger 206 if URB_ISO_ASAP, so looks
> the TDs(USB) can't be missed too.
> 
> Without URB_ISO_ASAP, there might be problem since 201 won't
> be scanned next time in scan_isoc, so is it what your RFC3 is fixing?

Yes, it is.  Now you understand my point.

> If I understand the above problem correctly, the same problem exists
> on drivers which submit URB in tasklet scheduled from complete() too
> before the moving, doesn't it?

That's right.  Probably those drivers always use URB_ISO_ASAP, so the 
problem doesn't arise.  If they don't use URB_ISO_ASAP ... well, then 
they will get inconsistent results when an underrun occurs.

Below is an updated version of the last 1/3 RFC patch (still without
percpu variables).  What do you think of it?

Alan Stern



Index: usb-3.11/include/linux/usb/hcd.h
===================================================================
--- usb-3.11.orig/include/linux/usb/hcd.h
+++ usb-3.11/include/linux/usb/hcd.h
@@ -73,6 +73,7 @@ struct giveback_urb_bh {
 	spinlock_t lock;
 	struct list_head  head;
 	struct tasklet_struct bh;
+	struct usb_host_endpoint *giveback_ep;
 };
 
 struct usb_hcd {
@@ -378,6 +379,12 @@ static inline int hcd_giveback_urb_in_bh
 	return hcd->driver->flags & HCD_BH;
 }
 
+static inline bool hcd_periodic_giveback_in_progress(struct usb_hcd *hcd,
+		struct usb_host_endpoint *ep)
+{
+	return hcd->high_prio_bh.giveback_ep == ep;
+}
+
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
 extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
 		int status);
Index: usb-3.11/drivers/usb/core/hcd.c
===================================================================
--- usb-3.11.orig/drivers/usb/core/hcd.c
+++ usb-3.11/drivers/usb/core/hcd.c
@@ -1690,7 +1690,9 @@ static void usb_giveback_urb_bh(unsigned
 
 		urb = list_entry(local_list.next, struct urb, urb_list);
 		list_del_init(&urb->urb_list);
+		bh->giveback_ep = urb->ep;
 		__usb_hcd_giveback_urb(urb);
+		bh->giveback_ep = NULL;
 	}
 
 	/* check if there are new URBs to giveback */

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