And I really should have slept before posting patches last week-end :(

Anyway, here's one without the obvious bug I had in hcd_unlink_urb().
That's what happens when you do too many things at the same time :(

This time, it's tested on a dual CPU machine with USB kbd and mouse
and these work fine.

diff -urN linux-2.5/drivers/usb/core/hcd-pci.c 
linuxppc-2.5-benh/drivers/usb/core/hcd-pci.c
--- linux-2.5/drivers/usb/core/hcd-pci.c        2003-08-24 22:34:26.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/core/hcd-pci.c        2003-08-24 22:34:09.000000000 
+0200
@@ -32,6 +32,15 @@
 #include <linux/usb.h>
 #include "hcd.h"
 
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/pci-bridge.h>
+#include <asm/prom.h>
+#ifndef CONFIG_PM
+#      define CONFIG_PM
+#endif
+#endif
 
 /* PCI-based HCs are normal, but custom bus glue should be ok */
 
@@ -284,14 +293,27 @@
                /* remote wakeup needs hub->suspend() cooperation */
                // pci_enable_wake (dev, 3, 1);
 
+               hcd->state = USB_STATE_QUIESCING;
+
                pci_save_state (dev, hcd->pci_state);
 
                /* driver may want to disable DMA etc */
                retval = hcd->driver->suspend (hcd, state);
-               hcd->state = USB_STATE_SUSPENDED;
-       }
 
-       pci_set_power_state (dev, state);
+#ifdef CONFIG_PMAC_PBOOK
+               {
+                       struct device_node      *of_node;
+ 
+                       /* Disable USB PAD & cell clock */
+                       of_node = pci_device_to_OF_node (dev);
+                       if (of_node)
+                               pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
+               }
+#endif
+
+
+               pci_set_power_state (dev, state);
+       }
        return retval;
 }
 EXPORT_SYMBOL (usb_hcd_pci_suspend);
@@ -308,12 +330,25 @@
        int                     retval;
 
        hcd = pci_get_drvdata(dev);
+
+               dev_dbg (hcd->controller, "usb_hcd_pci_resume\n");
+
        if (hcd->state != USB_STATE_SUSPENDED) {
                dev_dbg (hcd->controller, "can't resume, not suspended!\n");
                return -EL3HLT;
        }
        hcd->state = USB_STATE_RESUMING;
 
+#ifdef CONFIG_PMAC_PBOOK
+       {
+               struct device_node *of_node;
+
+               /* Re-enable USB PAD & cell clock */
+               of_node = pci_device_to_OF_node (dev);
+               if (of_node)
+                       pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
+       }
+#endif
        pci_set_power_state (dev, 0);
        pci_restore_state (dev, hcd->pci_state);
 
diff -urN linux-2.5/drivers/usb/core/hcd.c linuxppc-2.5-benh/drivers/usb/core/hcd.c
--- linux-2.5/drivers/usb/core/hcd.c    2003-08-24 22:34:26.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/core/hcd.c    2003-08-25 18:49:17.000000000 +0200
@@ -483,7 +483,7 @@
 {
        struct urb      *urb;
        struct usb_hcd  *hcd;
-       int             length;
+       int             length = 0;
        unsigned long   flags;
 
        urb = (struct urb *) ptr;
@@ -499,7 +499,8 @@
                return;
        }
 
-       length = hcd->driver->hub_status_data (hcd, urb->transfer_buffer);
+       if (!HCD_IS_SUSPENDED (hcd->state))
+               length = hcd->driver->hub_status_data (hcd, urb->transfer_buffer);
 
        /* complete the status urb, or retrigger the timer */
        spin_lock (&hcd_data_lock);
@@ -1192,6 +1193,10 @@
                retval = -ENODEV;
                goto done;
        }
+       if (HCD_IS_SUSPENDED (hcd->state)) {
+               retval = -ESHUTDOWN;
+               goto done;
+       }
 
        if (!urb->hcpriv) {
                retval = -EINVAL;
@@ -1484,8 +1489,10 @@
                return IRQ_NONE;
 
        hcd->driver->irq (hcd, r);
-       if (hcd->state != start && hcd->state == USB_STATE_HALT)
+       if (hcd->state != start && hcd->state == USB_STATE_HALT) {
+               printk("hcd died\n");
                usb_hc_died (hcd);
+       }
        return IRQ_HANDLED;
 }
 EXPORT_SYMBOL (usb_hcd_irq);
diff -urN linux-2.5/drivers/usb/host/ohci-hcd.c 
linuxppc-2.5-benh/drivers/usb/host/ohci-hcd.c
--- linux-2.5/drivers/usb/host/ohci-hcd.c       2003-08-24 22:34:29.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/host/ohci-hcd.c       2003-08-24 22:34:13.000000000 
+0200
@@ -222,10 +222,12 @@
        spin_lock_irqsave (&ohci->lock, flags);
 
        /* don't submit to a dead HC */
-       if (ohci->disabled || ohci->sleeping) {
+       if (ohci->disabled) {
                retval = -ENODEV;
                goto fail;
        }
+       /* Debug, shouldn't happen */
+       WARN_ON(HCD_IS_SUSPENDED(hcd->state));
 
        /* schedule the ed if needed */
        if (ed->state == ED_IDLE) {
@@ -467,7 +469,6 @@
 
        spin_lock_init (&ohci->lock);
        ohci->disabled = 1;
-       ohci->sleeping = 0;
 
        /* Tell the controller where the control and bulk lists are
         * The lists are empty now. */
@@ -572,9 +573,8 @@
                return;
 
        /* interrupt for some other device? */
-       } else if ((ints &= readl (&regs->intrenable)) == 0) {
+       } else if ((ints &= readl (&regs->intrenable)) == 0)
                return;
-       } 
 
        if (ints & OHCI_INTR_UE) {
                disable (ohci);
@@ -582,16 +582,21 @@
                // e.g. due to PCI Master/Target Abort
 
                ohci_dump (ohci, 1);
-               hc_reset (ohci);
+               if (!HCD_IS_SUSPENDED(hcd->state))
+                       hc_reset (ohci);
        }
   
        if (ints & OHCI_INTR_WDH) {
-               writel (OHCI_INTR_WDH, &regs->intrdisable);     
+               if (!HCD_IS_SUSPENDED(hcd->state))
+                       writel (OHCI_INTR_WDH, &regs->intrdisable);     
                dl_done_list (ohci, dl_reverse_done_list (ohci), ptregs);
-               writel (OHCI_INTR_WDH, &regs->intrenable); 
+               if (!HCD_IS_SUSPENDED(hcd->state))
+                       writel (OHCI_INTR_WDH, &regs->intrenable); 
        }
   
        /* could track INTR_SO to reduce available PCI/... bandwidth */
+       if (!HCD_IS_RUNNING(hcd->state))
+               return;
 
        /* handle any pending URB/ED unlinks, leaving INTR_SF enabled
         * when there's still unlinking to be done (next frame).
@@ -650,7 +655,6 @@
        int i;
 
        ohci->disabled = 1;
-       ohci->sleeping = 0;
        if (hcd_to_bus (&ohci->hcd)->root_hub)
                usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub);
        
diff -urN linux-2.5/drivers/usb/host/ohci-hub.c 
linuxppc-2.5-benh/drivers/usb/host/ohci-hub.c
--- linux-2.5/drivers/usb/host/ohci-hub.c       2003-08-24 22:34:29.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/host/ohci-hub.c       2003-08-24 22:34:13.000000000 
+0200
@@ -71,6 +71,11 @@
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
        int             ports, i, changed = 0, length = 1;
 
+       if (HCD_IS_SUSPENDED(hcd->state)) {
+               printk("ohci_hub_status_data() : sleeping\n");
+               return 0;
+       }
+
        ports = roothub_a (ohci) & RH_A_NDP; 
        if (ports > MAX_ROOT_PORTS) {
                if (ohci->disabled)
@@ -161,6 +166,11 @@
        u32             temp;
        int             retval = 0;
 
+       if (HCD_IS_SUSPENDED(hcd->state)) {
+               printk("ohci_hub_control() : sleeping\n");
+               return -ENODEV;
+       }
+
        switch (typeReq) {
        case ClearHubFeature:
                switch (wValue) {
diff -urN linux-2.5/drivers/usb/host/ohci-pci.c 
linuxppc-2.5-benh/drivers/usb/host/ohci-pci.c
--- linux-2.5/drivers/usb/host/ohci-pci.c       2003-08-24 22:34:29.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/host/ohci-pci.c       2003-08-24 22:34:13.000000000 
+0200
@@ -126,8 +126,7 @@
 
        /* act as if usb suspend can always be used */
        ohci_dbg (ohci, "suspend to %d\n", state);
-       ohci->sleeping = 1;
-
+       
        /* First stop processing */
        spin_lock_irqsave (&ohci->lock, flags);
        ohci->hc_control &=
@@ -142,22 +141,21 @@
        if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
                mdelay (1);
                
-#ifdef CONFIG_PMAC_PBOOK
-       if (_machine == _MACH_Pmac)
-               disable_irq (hcd->pdev->irq);
-       /* else, 2.4 assumes shared irqs -- don't disable */
-#endif
-
        /* Enable remote wakeup */
        writel (readl (&ohci->regs->intrenable) | OHCI_INTR_RD,
                &ohci->regs->intrenable);
 
        /* Suspend chip and let things settle down a bit */
-       ohci->hc_control = OHCI_USB_SUSPEND;
+       spin_lock_irqsave(&ohci->lock, flags);
+       hcd->state = USB_STATE_SUSPENDED;
+       ohci->hc_control = OHCI_USB_SUSPEND;
        writel (ohci->hc_control, &ohci->regs->control);
        (void) readl (&ohci->regs->control);
-       mdelay (500); /* No schedule here ! */
-
+       spin_unlock_irqrestore(&ohci->lock, flags);
+       
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout((500 * HZ) / 1000);
+       
        tmp = readl (&ohci->regs->control) | OHCI_CTRL_HCFS;
        switch (tmp) {
                case OHCI_USB_RESET:
@@ -177,16 +175,7 @@
        pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd);
        cmd &= ~PCI_COMMAND_MASTER;
        pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd);
-#ifdef CONFIG_PMAC_PBOOK
-       {
-               struct device_node      *of_node;
- 
-               /* Disable USB PAD & cell clock */
-               of_node = pci_device_to_OF_node (hcd->pdev);
-               if (of_node)
-                       pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
-       }
-#endif
+
        return 0;
 }
 
@@ -198,16 +187,6 @@
        int                     retval = 0;
        unsigned long           flags;
 
-#ifdef CONFIG_PMAC_PBOOK
-       {
-               struct device_node *of_node;
-
-               /* Re-enable USB PAD & cell clock */
-               of_node = pci_device_to_OF_node (hcd->pdev);
-               if (of_node)
-                       pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
-       }
-#endif
        /* did we suspend, or were we powered off? */
        ohci->hc_control = readl (&ohci->regs->control);
        temp = ohci->hc_control & OHCI_CTRL_HCFS;
@@ -235,7 +214,7 @@
                ohci->hc_control = OHCI_USB_RESUME;
                writel (ohci->hc_control, &ohci->regs->control);
                (void) readl (&ohci->regs->control);
-               mdelay (20); /* no schedule here ! */
+               mdelay (20); /* could schedule here ... */
                /* Some controllers (lucent) need a longer delay here */
                mdelay (15);
 
@@ -256,7 +235,6 @@
                /* Then re-enable operations */
                spin_lock_irqsave (&ohci->lock, flags);
                ohci->disabled = 0;
-               ohci->sleeping = 0;
                ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
                if (!ohci->ed_rm_list) {
                        if (ohci->ed_controltail)
@@ -276,10 +254,6 @@
                (void) readl (&ohci->regs->intrdisable);
                spin_unlock_irqrestore (&ohci->lock, flags);
 
-#ifdef CONFIG_PMAC_PBOOK
-               if (_machine == _MACH_Pmac)
-                       enable_irq (hcd->pdev->irq);
-#endif
                if (ohci->hcca->done_head)
                        dl_done_list (ohci, dl_reverse_done_list (ohci), NULL);
                writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
@@ -287,9 +261,8 @@
                /* assume there are TDs on the bulk and control lists */
                writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
 
-// ohci_dump_status (ohci);
-ohci_dbg (ohci, "sleeping = %d, disabled = %d\n",
-               ohci->sleeping, ohci->disabled);
+               // ohci_dump_status (ohci);
+               ohci_dbg (ohci, "disabled = %d\n", ohci->disabled);
                break;
 
        default:
diff -urN linux-2.5/drivers/usb/host/ohci-q.c 
linuxppc-2.5-benh/drivers/usb/host/ohci-q.c
--- linux-2.5/drivers/usb/host/ohci-q.c 2003-08-24 22:34:29.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/host/ohci-q.c 2003-08-24 22:34:13.000000000 +0200
@@ -449,12 +449,10 @@
        ohci->ed_rm_list = ed;
 
        /* enable SOF interrupt */
-       if (!ohci->sleeping) {
-               writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
-               writel (OHCI_INTR_SF, &ohci->regs->intrenable);
-               // flush those pci writes
-               (void) readl (&ohci->regs->control);
-       }
+               writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+               writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+       // flush those pci writes
+               (void) readl (&ohci->regs->control);
 }
 
 /*-------------------------------------------------------------------------*
@@ -938,7 +936,7 @@
 
                /* but if there's work queued, reschedule */
                if (!list_empty (&ed->td_list)) {
-                       if (!ohci->disabled && !ohci->sleeping)
+                       if (!ohci->disabled && !HCD_IS_SUSPENDED(ohci->hcd.state))
                                ed_schedule (ohci, ed);
                }
 
diff -urN linux-2.5/drivers/usb/host/ohci.h linuxppc-2.5-benh/drivers/usb/host/ohci.h
--- linux-2.5/drivers/usb/host/ohci.h   2003-08-24 22:34:29.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/host/ohci.h   2003-08-24 22:34:13.000000000 +0200
@@ -366,7 +366,6 @@
         * driver state
         */
        int                     disabled;       /* e.g. got a UE, we're hung */
-       int                     sleeping;
        int                     load [NUM_INTS];
        u32                     hc_control;     /* copy of hc control reg */
 




-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to