On Wed, May 19, 2004 at 11:02:52PM +1000, herbert wrote:
> On Thu, May 13, 2004 at 10:26:25PM -0400, Alan Stern wrote:
> > 
> > Nothing guarantees it!  That's one of the other things that needs to be
> > fixed.  The way I eventually want it to work is that there will be a list
> > of urbp's that have been removed from the schedule and are waiting for the
> > hardware to let them go (like we have now) together with a record of the
> > frame number at the time they were removed.  There will also be another
> 
> OK, how about this patch?

Let's fix QHs/TDs too.  Plus I forgot to set the age when the current
pending list is removed...
-- 
Visit Openswan at http://www.openswan.org/
Email:  Herbert Xu ~{PmV>HI~} <[EMAIL PROTECTED]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
===== drivers/usb/host/uhci-hcd.c 1.77 vs edited =====
--- 1.77/drivers/usb/host/uhci-hcd.c    Wed Apr 14 20:19:54 2004
+++ edited/drivers/usb/host/uhci-hcd.c  Wed May 19 23:41:50 2004
@@ -95,6 +95,10 @@
 static int uhci_get_current_frame_number(struct uhci_hcd *uhci);
 static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
 static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
+static void uhci_remove_pending_urbps(struct uhci_hcd *uhci);
+static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs *regs);
+static void uhci_free_pending_qhs(struct uhci_hcd *uhci);
+static void uhci_free_pending_tds(struct uhci_hcd *uhci);
 
 static void hc_state_transitions(struct uhci_hcd *uhci);
 
@@ -373,6 +377,7 @@
 {
        struct uhci_qh *pqh;
        u32 newlink;
+       unsigned int age;
 
        if (!qh)
                return;
@@ -425,6 +430,12 @@
        list_del_init(&qh->urbp->queue_list);
        qh->urbp = NULL;
 
+       age = uhci_get_current_frame_number(uhci);
+       if (age != uhci->qh_remove_age) {
+               uhci_free_pending_qhs(uhci);
+               uhci->qh_remove_age = age;
+       }
+
        /* Check to see if the remove list is empty. Set the IOC bit */
        /* to force an interrupt so we can remove the QH */
        if (list_empty(&uhci->qh_remove_list))
@@ -628,6 +639,7 @@
 {
        struct list_head *head, *tmp;
        struct urb_priv *urbp;
+       unsigned int age;
 
        urbp = (struct urb_priv *)urb->hcpriv;
        if (!urbp)
@@ -637,6 +649,12 @@
                dev_warn(uhci_dev(uhci), "urb %p still on uhci->urb_list "
                                "or uhci->remove_list!\n", urb);
 
+       age = uhci_get_current_frame_number(uhci);
+       if (age != uhci->td_remove_age) {
+               uhci_free_pending_tds(uhci);
+               uhci->td_remove_age = age;
+       }
+
        /* Check to see if the remove list is empty. Set the IOC bit */
        /* to force an interrupt so we can remove the TD's*/
        if (list_empty(&uhci->td_remove_list))
@@ -1512,6 +1530,7 @@
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        unsigned long flags;
        struct urb_priv *urbp;
+       unsigned int age;
 
        spin_lock_irqsave(&uhci->schedule_lock, flags);
        urbp = urb->hcpriv;
@@ -1521,6 +1540,12 @@
 
        uhci_unlink_generic(uhci, urb);
 
+       age = uhci_get_current_frame_number(uhci);
+       if (age != uhci->urb_remove_age) {
+               uhci_remove_pending_urbps(uhci);
+               uhci->urb_remove_age = age;
+       }
+
        /* If we're the first, set the next interrupt bit */
        if (list_empty(&uhci->urb_remove_list))
                uhci_set_next_interrupt(uhci);
@@ -1590,6 +1615,12 @@
        INIT_LIST_HEAD(&list);
 
        spin_lock_irqsave(&uhci->schedule_lock, flags);
+       if (!list_empty(&uhci->urb_remove_list) &&
+           uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) {
+               uhci_remove_pending_urbps(uhci);
+               uhci_finish_completion(hcd, NULL);
+       }
+
        head = &uhci->urb_list;
        tmp = head->next;
        while (tmp != head) {
@@ -1728,6 +1759,7 @@
        unsigned int io_addr = uhci->io_addr;
        unsigned short status;
        struct list_head *tmp, *head;
+       unsigned int age;
 
        /*
         * Read the interrupt status, and write it back to clear the
@@ -1758,11 +1790,20 @@
 
        spin_lock(&uhci->schedule_lock);
 
-       uhci_free_pending_qhs(uhci);
-       uhci_free_pending_tds(uhci);
-       uhci_remove_pending_urbps(uhci);
-
-       uhci_clear_next_interrupt(uhci);
+       age = uhci_get_current_frame_number(uhci);
+       if (age != uhci->qh_remove_age)
+               uhci_free_pending_qhs(uhci);
+       if (age != uhci->td_remove_age)
+               uhci_free_pending_tds(uhci);
+       if (age != uhci->urb_remove_age)
+               uhci_remove_pending_urbps(uhci);
+
+       if (list_empty(&uhci->urb_remove_list) &&
+           list_empty(&uhci->td_remove_list) &&
+           list_empty(&uhci->qh_remove_list))
+               uhci_clear_next_interrupt(uhci);
+       else
+               uhci_set_next_interrupt(uhci);
 
        /* Walk the list of pending URB's to see which ones completed */
        head = &uhci->urb_list;
===== drivers/usb/host/uhci-hcd.h 1.23 vs edited =====
--- 1.23/drivers/usb/host/uhci-hcd.h    Mon Apr 19 21:05:56 2004
+++ edited/drivers/usb/host/uhci-hcd.h  Wed May 19 23:25:26 2004
@@ -357,12 +357,15 @@
 
        /* List of QH's that are done, but waiting to be unlinked (race) */
        struct list_head qh_remove_list;        /* P: uhci->schedule_lock */
+       unsigned int qh_remove_age;             /* Age in frames */
 
        /* List of TD's that are done, but waiting to be freed (race) */
        struct list_head td_remove_list;        /* P: uhci->schedule_lock */
+       unsigned int td_remove_age;             /* Age in frames */
 
        /* List of asynchronously unlinked URB's */
        struct list_head urb_remove_list;       /* P: uhci->schedule_lock */
+       unsigned int urb_remove_age;            /* Age in frames */
 
        /* List of URB's awaiting completion callback */
        struct list_head complete_list;         /* P: uhci->schedule_lock */

Reply via email to