OK, here we go. Enclosed is my current patch that changes some of the
PowerMac specific stuff in a more logical way and get rid of
ohci->sleeping (I didn't get rid of ohci->disabled yet).
So far, suspend & resume with no device plugged works, BUT, once
resumed, I get an irq storm of about 200000 irqs/sec on each of
my 2 OHCIs, which slows down the machine dramatically until I
rmmod & insmod the driver. I haven't yet investigated what interrupt
the HCI is trying to send yet nor did I try with USB devices plugged.
Ben.
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 11:34:57.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/core/hcd-pci.c 2003-08-24 11:16:56.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 11:34:57.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/core/hcd.c 2003-08-24 11:16:56.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,8 @@
retval = -ENODEV;
goto done;
}
+ if (!HCD_IS_SUSPENDED (hcd->state))
+ return -ESHUTDOWN;
if (!urb->hcpriv) {
retval = -EINVAL;
@@ -1480,12 +1483,14 @@
struct usb_hcd *hcd = __hcd;
int start = hcd->state;
- if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
+ // if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
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 11:35:00.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/host/ohci-hcd.c 2003-08-24 11:16:59.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 (®s->intrenable)) == 0) {
+ } else if ((ints &= readl (®s->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, ®s->intrdisable);
+ if (!HCD_IS_SUSPENDED(hcd->state))
+ writel (OHCI_INTR_WDH, ®s->intrdisable);
dl_done_list (ohci, dl_reverse_done_list (ohci), ptregs);
- writel (OHCI_INTR_WDH, ®s->intrenable);
+ if (!HCD_IS_SUSPENDED(hcd->state))
+ writel (OHCI_INTR_WDH, ®s->intrenable);
}
/* could track INTR_SO to reduce available PCI/... bandwidth */
+ if (HCD_IS_SUSPENDED(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 11:35:00.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/host/ohci-hub.c 2003-08-24 11:16:59.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 11:35:00.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/host/ohci-pci.c 2003-08-24 11:25:08.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 11:35:00.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/host/ohci-q.c 2003-08-24 11:16:59.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 11:35:00.000000000 +0200
+++ linuxppc-2.5-benh/drivers/usb/host/ohci.h 2003-08-24 11:16:59.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: VM Ware
With VMware you can run multiple operating systems on a single machine.
WITHOUT REBOOTING! Mix Linux / Windows / Novell virtual machines
at the same time. Free trial click here:http://www.vmware.com/wl/offer/358/0
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel