Hi Alan, thanks for the patch. Yes, it works. Comments below. On Thursday 24 July 2003 20:58, Alan Stern wrote: > On Fri, 18 Jul 2003, Duncan Sands wrote: > > Hi Alan, Johannes, how about this? I tried to make as few changes to the > > existing code as possible. In my opinion it would make more sense to > > have the list of TDs belong to the QH and not the urb_priv, and free them > > when the QH is freed, but that would mean making many more and more > > invasive changes. By the way, does the last > > + uhci_free_pending_tds(uhci); > > make sense? If so, should there be a > > + uhci_remove_pending_qhs(uhci); > > as well? > > Duncan: > > I looked at your suggested patch; it seems like it ought to work.
:) > I'm trying a different approach. It's a little more complicated, but it > doesn't need an extra list header added to each TD. The idea is not to > free the urbp as soon as the URB is given back, but to wait until > uhci_free_pending_qhs() has released the QH as well. My patch also doesn't need to add a list header to each TD: you can just reuse the list entry. I added the new list head to keep things symmetric with QHs. I guess you preferred to keep the TDs as part of the urbp (rather than making them part of the QH) because isochronous transfers have no QH? Fair enough. However, wouldn't a cleaner approach be to do the same for QHs as you do for TDs? I mean: just have a list of urbp's to be removed (rather than a list of QHs), and when the urbp goes down destroy the TDs and any QH? That way you can remove a list_head (remove_list) from the QH as well :) Comments on the patch are below. > Here's the patch. Please try it and let me know if it fixes that > Controller Halted problem. (You will probably have to use a little fuzz > when applying it, because I wrote it on top of a couple of other patches.) > > Alan Stern > > > ===== uhci-hcd.c 1.55 vs edited ===== > --- 1.55/drivers/usb/host/uhci-hcd.c Tue Jul 22 11:19:19 2003 > +++ edited/drivers/usb/host/uhci-hcd.c Wed Jul 23 16:45:35 2003 > @@ -403,7 +403,6 @@ > > /* > * Start removal of QH from schedule; it finishes next frame. > - * TDs should be unlinked before this is called. > */ > static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) > { > @@ -413,8 +412,6 @@ > if (!qh) > return; > > - qh->urbp = NULL; > - > /* > * Only go through the hoops if it's actually linked in > * Queued QHs are removed in uhci_delete_queued_urb, > @@ -666,6 +663,7 @@ > list_add_tail(&urbp->urb_list, &uhci->urb_list); > > urb->hcpriv = urbp; > + atomic_set(&urbp->refcount, 1); > > return urbp; > } > @@ -696,22 +694,20 @@ > } > > /* > - * MUST be called with urb->lock acquired > + * MUST be called with urbp->urb == NULL > */ > -static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb) > +static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb_priv > *urbp) { > struct list_head *head, *tmp; > - struct urb_priv *urbp; > > - urbp = (struct urb_priv *)urb->hcpriv; > if (!urbp) > return; > > if (!list_empty(&urbp->urb_list)) > - warn("uhci_destroy_urb_priv: urb %p still on uhci->urb_list or > uhci->remove_list", urb); + warn("uhci_destroy_urb_priv: urbp %p still on > uhci->urb_list or uhci->remove_list", urbp); > > if (!list_empty(&urbp->complete_list)) > - warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", > urb); > + warn("uhci_destroy_urb_priv: urbp %p still on uhci->complete_list", > urbp); > > head = &urbp->td_list; > tmp = head->next; > @@ -725,7 +721,6 @@ > uhci_free_td(uhci, td); > } > > - urb->hcpriv = NULL; > kmem_cache_free(uhci_up_cachep, urbp); > } > > @@ -891,6 +886,7 @@ > > urbp->qh = qh; > qh->urbp = urbp; > + atomic_inc(&urbp->refcount); Why not define uhci_get_urbp and uhci_put_urbp methods? Especially uhci_put_urbp, which would call uhci_destroy_urb_priv when the urbp goes down. At the moment you do this by hand each time. > uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH); > > @@ -926,6 +922,7 @@ > urbp->short_control_packet = 1; > > /* Create a new QH to avoid pointer overwriting problems */ > + urbp->qh->urbp = NULL; > uhci_remove_qh(uhci, urbp->qh); > > /* Delete all of the TD's except for the status TD at the end */ > @@ -943,6 +940,7 @@ > > urbp->qh = uhci_alloc_qh(uhci, urb->dev); > if (!urbp->qh) { > + atomic_dec(&urbp->refcount); So no destroy_urb_priv here... > err("unable to allocate new QH for control retrigger"); > return -ENOMEM; > } > @@ -1150,6 +1148,7 @@ > > urbp->qh = qh; > qh->urbp = urbp; > + atomic_inc(&urbp->refcount); > > /* Always breadth first */ > uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH); > @@ -1491,7 +1490,9 @@ > > list_del_init(&urbp->urb_list); > spin_unlock_irqrestore(&uhci->urb_list_lock, flags); > - uhci_destroy_urb_priv (uhci, urb); > + urb->hcpriv = NULL; > + urbp->urb = NULL; > + uhci_destroy_urb_priv (uhci, urbp); > > return ret; > } > @@ -1630,9 +1631,8 @@ > > uhci_delete_queued_urb(uhci, urb); > > - /* The interrupt loop will reclaim the QH's */ > + /* The interrupt loop will reclaim the QH's and TD's */ > uhci_remove_qh(uhci, urbp->qh); > - urbp->qh = NULL; > } > > static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) > @@ -1781,19 +1781,24 @@ > > static void uhci_free_pending_qhs(struct uhci_hcd *uhci) > { > - struct list_head *tmp, *head; > + struct list_head *head; > unsigned long flags; > > spin_lock_irqsave(&uhci->qh_remove_list_lock, flags); > head = &uhci->qh_remove_list; > - tmp = head->next; > - while (tmp != head) { > - struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list); > - > - tmp = tmp->next; > + while (!list_empty(head)) { > + struct uhci_qh *qh = list_entry(head->next, > + struct uhci_qh, remove_list); > + struct urb_priv *urbp = qh->urbp; > > list_del_init(&qh->remove_list); > - > + if (urbp && atomic_dec_and_test(&urbp->refcount)) { > + qh->urbp = NULL; > + urbp->qh = NULL; > + spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags); > + uhci_destroy_urb_priv(uhci, urbp); Why release the spinlock before calling this? > + spin_lock_irqsave(&uhci->qh_remove_list_lock, flags); > + } > uhci_free_qh(uhci, qh); > } > spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags); > @@ -1802,10 +1807,14 @@ > static void uhci_finish_urb(struct usb_hcd *hcd, struct urb *urb, struct > pt_regs *regs) { > struct uhci_hcd *uhci = hcd_to_uhci(hcd); > + struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; > unsigned long flags; > > spin_lock_irqsave(&urb->lock, flags); > - uhci_destroy_urb_priv(uhci, urb); > + urbp->urb = NULL; > + urb->hcpriv = NULL; > + if (atomic_dec_and_test(&urbp->refcount)) > + uhci_destroy_urb_priv(uhci, urbp); > spin_unlock_irqrestore(&urb->lock, flags); > > usb_hcd_giveback_urb(hcd, urb, regs); > @@ -1814,24 +1823,21 @@ > static void uhci_finish_completion(struct usb_hcd *hcd, struct pt_regs > *regs) { > struct uhci_hcd *uhci = hcd_to_uhci(hcd); > - struct list_head *tmp, *head; > + struct list_head *head; > unsigned long flags; > > spin_lock_irqsave(&uhci->complete_list_lock, flags); > head = &uhci->complete_list; > - tmp = head->next; > - while (tmp != head) { > - struct urb_priv *urbp = list_entry(tmp, struct urb_priv, > complete_list); > - struct urb *urb = urbp->urb; > + while (!list_empty(head)) { > + struct urb_priv *urbp = list_entry(head->next, > + struct urb_priv, complete_list); > > list_del_init(&urbp->complete_list); > spin_unlock_irqrestore(&uhci->complete_list_lock, flags); > > - uhci_finish_urb(hcd, urb, regs); > + uhci_finish_urb(hcd, urbp->urb, regs); > > spin_lock_irqsave(&uhci->complete_list_lock, flags); > - head = &uhci->complete_list; > - tmp = head->next; > } > spin_unlock_irqrestore(&uhci->complete_list_lock, flags); > } > ===== uhci-hcd.h 1.15 vs edited ===== > --- 1.15/drivers/usb/host/uhci-hcd.h Tue Jul 22 11:26:32 2003 > +++ edited/drivers/usb/host/uhci-hcd.h Wed Jul 23 16:29:16 2003 > @@ -382,6 +382,7 @@ > > unsigned long inserttime; /* In jiffies */ > unsigned long fsbrtime; /* In jiffies */ > + atomic_t refcount; /* 1 for URB, 1 for QH */ > > struct list_head queue_list; /* P: uhci->frame_list_lock */ > struct list_head complete_list; /* P: uhci->complete_list_lock */ By the way, looks like much of the list-handling in uhci-hcd could be done more cleanly using the macros from list.h. Ciao, Duncan. ------------------------------------------------------- This SF.Net email sponsored by: Free pre-built ASP.NET sites including Data Reports, E-commerce, Portals, and Forums are available now. Download today and enter to win an XBOX or Visual Studio .NET. http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01 _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel