ChangeSet 1.1843.4.14, 2004/08/24 11:55:24-07:00, [EMAIL PROTECTED]

[PATCH] USB OTG: ohci reset updates (2/5)

Generic OTG and reset support for OTG.

 - Declare and use a start_hnp() board-specific procedure.  The OMAP
   implementation will come separately, it can't yet be configured.

 - When OTG is configured, implement the usb_bus_start_enum() hook;
   that just starts a root port reset.

 - When some task (usually khubd) resets a root port, make sure it takes
   the full 50 msec.  The OHCI reset timer is in hardware, and the host
   may need to issue multiple resets to guard against concurrent resume.

 - For backward compatibility, don't kick in the new 50 msec logic unless
   it could be needed:  without CONFIG_USB_SUSPEND, nothing will suspend
   so nothing could resume.  Which is good, at least until we start to
   measure how long a reset takes ... it seems chip-specific.

Signed-off-by: David Brownell <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>


 drivers/usb/host/ohci-hub.c  |   94 +++++++++++++++++++++++++++++++++++++++++--
 drivers/usb/host/ohci-omap.c |    1 
 drivers/usb/host/ohci-pci.c  |    3 -
 drivers/usb/host/ohci-q.c    |    3 -
 4 files changed, 93 insertions(+), 8 deletions(-)


diff -Nru a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
--- a/drivers/usb/host/ohci-hub.c       2004-08-26 16:42:31 -07:00
+++ b/drivers/usb/host/ohci-hub.c       2004-08-26 16:42:31 -07:00
@@ -435,6 +435,89 @@
 
 /*-------------------------------------------------------------------------*/
 
+#ifdef CONFIG_USB_OTG
+
+static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       u32                     status;
+
+       if (!port)
+               return -EINVAL;
+       port--;
+
+       /* start port reset before HNP protocol times out */
+       status = ohci_readl(&ohci->regs->roothub.portstatus [port]);
+       if (!(status & RH_PS_CCS))
+               return -ENODEV;
+
+       /* khubd will finish the reset later */
+       writel(RH_PS_PRS, &ohci->regs->roothub.portstatus [port]);
+       return 0;
+}
+
+static void start_hnp(struct ohci_hcd *ohci);
+
+#else
+
+#define        ohci_start_port_reset           NULL
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+
+/* See usb 7.1.7.5:  root hubs must issue at least 50 msec reset signaling,
+ * not necessarily continuous ... to guard against resume signaling.
+ * The short timeout is safe for non-root hubs, and is backward-compatible
+ * with earlier Linux hosts.
+ */
+#ifdef CONFIG_USB_SUSPEND
+#define        PORT_RESET_MSEC         50
+#else
+#define        PORT_RESET_MSEC         10
+#endif
+
+/* this timer value might be vendor-specific ... */
+#define        PORT_RESET_HW_MSEC      10
+
+/* wrap-aware logic stolen from <linux/jiffies.h> */
+#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0)
+
+/* called from some task, normally khubd */
+static inline void root_port_reset (struct ohci_hcd *ohci, unsigned port)
+{
+       u32     *portstat = &ohci->regs->roothub.portstatus [port];
+       u32     temp;
+       u16     now = readl(&ohci->regs->fmnumber);
+       u16     reset_done = now + PORT_RESET_MSEC;
+
+       /* build a "continuous enough" reset signal, with up to
+        * 3msec gap between pulses.  scheduler HZ==100 must work;
+        * this might need to be deadline-scheduled.
+        */
+       do {
+               /* spin until any current reset finishes */
+               for (;;) {
+                       temp = ohci_readl (portstat);
+                       if (!(temp & RH_PS_PRS))
+                               break;
+                       udelay (500);
+               } 
+
+               if (!(temp & RH_PS_CCS))
+                       break;
+               if (temp & RH_PS_PRSC)
+                       writel (RH_PS_PRSC, portstat);
+
+               /* start the next reset, sleep till it's probably done */
+               writel (RH_PS_PRS, portstat);
+               msleep(PORT_RESET_HW_MSEC);
+               now = readl(&ohci->regs->fmnumber);
+       } while (tick_before(now, reset_done));
+       /* caller synchronizes using PRSC */
+}
+
 static int ohci_hub_control (
        struct usb_hcd  *hcd,
        u16             typeReq,
@@ -533,6 +616,12 @@
                wIndex--;
                switch (wValue) {
                case USB_PORT_FEAT_SUSPEND:
+#ifdef CONFIG_USB_OTG
+                       if (ohci->hcd.self.otg_port == (wIndex + 1)
+                                       && ohci->hcd.self.b_hnp_enable)
+                               start_hnp(ohci);
+                       else
+#endif
                        writel (RH_PS_PSS,
                                &ohci->regs->roothub.portstatus [wIndex]);
                        break;
@@ -541,10 +630,7 @@
                                &ohci->regs->roothub.portstatus [wIndex]);
                        break;
                case USB_PORT_FEAT_RESET:
-                       temp = ohci_readl (&ohci->regs->roothub.portstatus [wIndex]);
-                       if (temp & RH_PS_CCS)
-                               writel (RH_PS_PRS,
-                                   &ohci->regs->roothub.portstatus [wIndex]);
+                       root_port_reset (ohci, wIndex);
                        break;
                default:
                        goto error;
diff -Nru a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
--- a/drivers/usb/host/ohci-omap.c      2004-08-26 16:42:31 -07:00
+++ b/drivers/usb/host/ohci-omap.c      2004-08-26 16:42:31 -07:00
@@ -566,6 +566,7 @@
        .hub_suspend =          ohci_hub_suspend,
        .hub_resume =           ohci_hub_resume,
 #endif
+       .start_port_reset =     ohci_start_port_reset,
 };
 
 /*-------------------------------------------------------------------------*/
diff -Nru a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
--- a/drivers/usb/host/ohci-pci.c       2004-08-26 16:42:31 -07:00
+++ b/drivers/usb/host/ohci-pci.c       2004-08-26 16:42:31 -07:00
@@ -242,6 +242,7 @@
        .hub_suspend =          ohci_hub_suspend,
        .hub_resume =           ohci_hub_resume,
 #endif
+       .start_port_reset =     ohci_start_port_reset,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -276,7 +277,7 @@
        if (usb_disabled())
                return -ENODEV;
 
-       printk (KERN_DEBUG "%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+       pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
                sizeof (struct ed), sizeof (struct td));
        return pci_module_init (&ohci_pci_driver);
 }
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c 2004-08-26 16:42:31 -07:00
+++ b/drivers/usb/host/ohci-q.c 2004-08-26 16:42:31 -07:00
@@ -900,9 +900,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* wrap-aware logic stolen from <linux/jiffies.h> */
-#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0)
-
 /* there are some urbs/eds to unlink; called in_irq(), with HCD locked */
 static void
 finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)



-------------------------------------------------------
SF.Net email is sponsored by Shop4tech.com-Lowest price on Blank Media
100pk Sonic DVD-R 4x for only $29 -100pk Sonic DVD+R for only $33
Save 50% off Retail on Ink & Toner - Free Shipping and Free Gift.
http://www.shop4tech.com/z/Inkjet_Cartridges/9_108_r285
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to