Hi,

Pete Zaitcev:
> > From: "Matthias Urlichs" <[EMAIL PROTECTED]>
> 
> The patch looks ok, but what about this:
> 
> > Please apply on top of my last patch.
> 
> I need that one too.
> 
Here it is again. (NB, this has been hand-edited; I hope it still
applies reasonably cleanly.)

_

This patch fixes the following problem:
When the OHCI controller vanishes (it's on PCMCIA and got pulled), it
won't trigger any more interrupts which could cleanup the data
structures.

Therefore, we need to free the TDs ourself.

Signed-off-by: Matthias Urlichs <[EMAIL PROTECTED]>
_

diff -rub ./drivers/usb/host/usb-ohci.c 
../linux-2.4.27/drivers/usb/host/usb-ohci.c
--- ./drivers/usb/host/usb-ohci.c       2004-09-13 09:33:34.000000000 +0000
+++ ../linux-2.4.27/drivers/usb/host/usb-ohci.c 2004-09-13 11:31:40.000000000 
+0000
@@ -131,6 +131,7 @@
  * URB support functions 
  *-------------------------------------------------------------------------*/ 
 
+static void dl_del_list (ohci_t  * ohci, unsigned int frame);
 static void ohci_complete_add(struct ohci *ohci, struct urb *urb)
 {
 
@@ -933,14 +937,12 @@
                if (cnt > 0) {
 
                        if (ohci->disabled) {
-                               /* FIXME: Something like this should kick in,
-                                * though it's currently an exotic case ...
-                                * the controller won't ever be touching
-                                * these lists again!!
-                               dl_del_list (ohci,
-                                       le16_to_cpu (ohci->hcca->frame_no) & 1);
+                               /* The controller won't ever be touching
+                                * these lists again, so drop the EDs
                                 */
                                warn ("TD leak, %d", cnt);
+                               dl_del_list (ohci, 0);
+                               dl_del_list (ohci, 1);
 
                        } else if (!in_interrupt ()) {
                                DECLARE_WAIT_QUEUE_HEAD (freedev_wakeup); 
@@ -955,9 +957,20 @@
                                        timeout = schedule_timeout (timeout);
                                set_current_state(TASK_RUNNING);
                                remove_wait_queue (&freedev_wakeup, &wait);
+
                                if (dev->ed_cnt) {
+#if 0
                                        err ("free device %d timeout", 
usb_dev->devnum);
                                        return -ETIMEDOUT;
+#else
+                                       /* The SF interrupt handler may not be 
called any more.
+                                          Example: if the PC-Card with the 
OHCI controller has been pulled ... */
+                                       /* XXX this is a band-aid fix!  -- M.U 
*/
+
+                                       ohci->disabled=1;
+                                       dl_del_list (ohci, 0);
+                                       dl_del_list (ohci, 1);
+#endif
                                }
                        } else {
                                /* likely some interface's driver has a 
refcount bug */
diff -rub ./drivers/usb/host/usb-ohci.h 
../linux-2.4.27/drivers/usb/host/usb-ohci.h
--- ./drivers/usb/host/usb-ohci.h       2004-09-13 09:33:34.000000000 +0000
+++ ../linux-2.4.27/drivers/usb/host/usb-ohci.h 2004-09-13 10:56:28.000000000 
+0000
@@ -575,9 +575,24 @@
        return 0;
 }
 
+static inline void
+td_free (struct ohci *hc, struct td *td)
+{
+       hash_free_td (hc, td);
+       pci_pool_free (hc->td_cache, td, td->td_dma);
+}
+
+
 static void ohci_mem_cleanup (struct ohci *ohci)
 {
+       int i;
        if (ohci->td_cache) {
+               struct hash_list_t *tdh;
+               for(i=0, tdh=&ohci->td_hash[0]; i < TD_HASH_SIZE; i++, tdh++) {
+                       while(tdh->head)
+                               td_free (ohci, tdh->head->virt);
+               }
+
                pci_pool_destroy (ohci->td_cache);
                ohci->td_cache = 0;
        }
@@ -607,14 +624,6 @@
        return td;
 }
 
-static inline void
-td_free (struct ohci *hc, struct td *td)
-{
-       hash_free_td (hc, td);
-       pci_pool_free (hc->td_cache, td, td->td_dma);
-}
-
-
 /* DEV + EDs ... only the EDs need to be consistent */
 static inline struct ohci_device *
 dev_alloc (struct ohci *hc, int mem_flags)

-- 
Matthias Urlichs   |   {M:U} IT Design @ m-u-it.de   |  [EMAIL PROTECTED]

Attachment: signature.asc
Description: Digital signature

Reply via email to