Hi J.C.,

wow, thanks for all the work and explanation!


On Sun, 7 Mar 2010 16:56:26 -0800 J.C. Roberts wrote:

> On Sun, 7 Mar 2010 22:31:18 +0100 Christopher Zimmermann
> <madro...@zakweb.de> wrote:
> 
> > ok, you misunderstood me. My BIOS needs 'legacy' to be turned on to 
> > use the USB-keyboard. 
> 
> Yep, you weren't clear on "legacy" as meaning "Legacy USB Support" but
> I was able to dig up a possibly similar/correct manual. According to
> Asus, "K8S-MV" as seen in your dmesg, doesn't exist. The closest I
> found was "K8S-MX"

Yes, it says K8S-MV on the board, but it looks like the K8S-MX.
The bios menu is not the same, but similar.

> http://dlsvr.asus.com/pub/ASUS/mb/sock754/k8s-mx/e1884_k8s-mx.pdf
> 
> Page 56 (2-20) of the above looks kind of like what you've described.
> 
> Does your BIOS have the very strange option of:
> 
>       "Stop EHCI HC in OHCI handover" [Disabled] [Enabled]
> 
> as shown in the (possibly wrong) manual I found?

Yes, I have this option, but it makes no difference to what value I 
set it.

> Additionally, one of the possible reasons why your keyboard and 
> mouse
> will not work without "Legacy USB Support" and/or "OnBoard SiS USB 1.1
> DEVICE" enabled is because they are plugged into the wrong port. In
> other words you've shut off the Host Controller ("SiS 5597/5598") for
> the port (s) where your mouse and keyboard are plugged in.

As I understand it, the 'legacy' option just means the bios should 
talk to USB devices (like my keyboard). Turning it off means the BIOS 
won't touch my host controler nor my keyboard.

When I turn off the 'legacy' option everything works fine. The code in 
OpenBSD which is "waiting for BIOS to give up control" will then not 
even be executed (see dev/pci/ehci_pci.c). The relevant register bits 
are even called "EHCI_LEGSUP_BIOSOWNED" and "EHCI_LEGSUP_OSOWNED".
You see, "LEG" like in "LEGacy".

> > > Is the kernel locked up? --Possibly No. The kernel may be 
> > > ignoring
> > > the USB mouse/keyboard that you specifically told the bios to
> > > ignore by turning on "Legacy Mode." When the BIOS tells the kernel
> > > that it has no mouse or keyboard installed, then the kernel
> > > thinks, "Ah, we're running headless," and adjusts accordingly.
> > 
> > the kernel stops while booting. Read my orignal post again. I found 
> > the very line of code causing this problem, but still don't know 
> > exactly how to fix it.
> 
> The (possibly wrong) manual I found has that very weird BIOS option
> for OHCI to EHCI handover. If your system has something similar, then
> this *might* be the root of your problem. If OHCI refuses to
> "handover" to EHCI, then it could explain why EHCI is waiting around
> for the BIOS to give up control.

As said above, this option does not change the behavior. Now I tried 
to port the way, linux protects this section where the driver tries to 
"take port ownership". Still it did not fix the lockup. The patch is 
attached, if you are interested.


christopher




Index: dev/usb/ehci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehci.c,v
retrieving revision 1.106
diff -u -p -r1.106 ehci.c
--- dev/usb/ehci.c      26 Nov 2009 12:27:48 -0000      1.106
+++ dev/usb/ehci.c      8 Mar 2010 08:44:51 -0000
@@ -81,7 +81,7 @@ struct cfdriver ehci_cd = {
 #ifdef EHCI_DEBUG
 #define DPRINTF(x)     do { if (ehcidebug) printf x; } while(0)
 #define DPRINTFN(n,x)  do { if (ehcidebug>(n)) printf x; } while (0)
-int ehcidebug = 0;
+int ehcidebug = 0x19;
 #define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f))
 #else
 #define DPRINTF(x)
@@ -502,22 +502,49 @@ ehci_init(ehci_softc_t *sc)
            EHCI_CMD_PSE |
            EHCI_CMD_RS);
 
-       /* Take over port ownership */
+       /* Take over port ownership
+         *      
+         * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
+         * are explicitly handed to companion controller(s), so no TT is
+         * involved with the root hub.  (Except where one is integrated,
+         * and there's no companion controller unless maybe for USB OTG.)
+         *              
+         * Turning on the CF flag will transfer ownership of all ports
+         * from the companions to the EHCI controller.  If any of the
+         * companions are in the middle of a port reset at the time, it
+         * could cause trouble.  Write-locking ehci_cf_port_reset_rwsem
+         * guarantees that no resets are in progress.  After we set CF,
+         * a short delay lets the hardware catch up; new resets shouldn't
+         * be started before the port switching actions could complete.
+        * 
+        * This explanation is taken from the Linux kernel 2.6.33
+        * drivers/usb/host/ehci-hcd.c by David Brownell
+         */   
+       rw_enter_write(&ehci_cf_port_reset_rwlock);
+       DPRINTFN(2, ("ehci: after lock\n"));
+       delay(500000);
+       DPRINTFN(2, ("ehci: after delay1\n"));
        EOWRITE4(sc, EHCI_CONFIGFLAG, EHCI_CONF_CF);
 
+       delay(500000);
+       DPRINTFN(2, ("ehci: after delay2\n"));
+       DPRINTFN(2, ("ehci: before loop\n"));
        for (i = 0; i < 100; i++) {
                usb_delay_ms(&sc->sc_bus, 1);
+               DPRINTFN(2, ("ehci: after sleep %d\n", i));
                hcr = EOREAD4(sc, EHCI_USBSTS) & EHCI_STS_HCH;
+               DPRINTFN(2, ("ehci: after EOREAD\n"));
                if (!hcr)
                        break;
        }
+       DPRINTFN(2, ("ehci: after loop\n"));
+       rw_exit_write(&ehci_cf_port_reset_rwlock);
        if (hcr) {
                printf("%s: run timeout\n", sc->sc_bus.bdev.dv_xname);
                return (USBD_IOERROR);
        }
 
        /* Enable interrupts */
-       DPRINTFN(1,("ehci_init: enabling\n"));
        EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
 
        return (USBD_NORMAL_COMPLETION);
@@ -2368,7 +2395,7 @@ ehci_alloc_sqh(ehci_softc_t *sc)
        usb_dma_t dma;
 
        if (sc->sc_freeqhs == NULL) {
-               DPRINTFN(2, ("ehci_alloc_sqh: allocating chunk\n"));
+               DPRINTFN(20, ("ehci_alloc_sqh: allocating chunk\n"));
                err = usb_allocmem(&sc->sc_bus, EHCI_SQH_SIZE * EHCI_SQH_CHUNK,
                    EHCI_PAGE_SIZE, &dma);
 #ifdef EHCI_DEBUG
@@ -2410,7 +2437,7 @@ ehci_alloc_sqtd(ehci_softc_t *sc)
        int s;
 
        if (sc->sc_freeqtds == NULL) {
-               DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n"));
+               DPRINTFN(20, ("ehci_alloc_sqtd: allocating chunk\n"));
                err = usb_allocmem(&sc->sc_bus, EHCI_SQTD_SIZE*EHCI_SQTD_CHUNK,
                    EHCI_PAGE_SIZE, &dma);
 #ifdef EHCI_DEBUG
Index: dev/usb/usb.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb.c,v
retrieving revision 1.62
diff -u -p -r1.62 usb.c
--- dev/usb/usb.c       9 Nov 2009 17:53:39 -0000       1.62
+++ dev/usb/usb.c       8 Mar 2010 08:44:52 -0000
@@ -69,7 +69,7 @@
 #ifdef USB_DEBUG
 #define DPRINTF(x)     do { if (usbdebug) printf x; } while (0)
 #define DPRINTFN(n,x)  do { if (usbdebug>(n)) printf x; } while (0)
-int    usbdebug = 0;
+int    usbdebug = 20;
 #if defined(UHCI_DEBUG) && NUHCI > 0
 extern int     uhcidebug;
 #endif
Index: dev/usb/usb.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb.h,v
retrieving revision 1.35
diff -u -p -r1.35 usb.h
--- dev/usb/usb.h       1 Mar 2010 23:35:56 -0000       1.35
+++ dev/usb/usb.h       8 Mar 2010 08:44:53 -0000
@@ -51,6 +51,8 @@
 
 #define USB_FRAMES_PER_SECOND 1000
 
+#define EHCI_DEBUG
+#define USB_DEBUG
 /*
  * The USB records contain some unaligned little-endian word
  * components.  The U[SG]ETW macros take care of both the alignment
@@ -688,3 +690,6 @@ struct usb_event {
 #define USB_SET_CM_OVER_DATA   _IOW ('U', 131, int)
 
 #endif /* _USB_H_ */
+
+/* see ehci.c, usb_subr.h and usbdi.c */
+extern struct rwlock ehci_cf_port_reset_rwlock;
Index: dev/usb/usb_subr.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb_subr.c,v
retrieving revision 1.73
diff -u -p -r1.73 usb_subr.c
--- dev/usb/usb_subr.c  14 Jan 2009 21:02:57 -0000      1.73
+++ dev/usb/usb_subr.c  8 Mar 2010 08:44:55 -0000
@@ -338,10 +338,14 @@ void
 usb_delay_ms(usbd_bus_handle bus, u_int ms)
 {
        /* Wait at least two clock ticks so we know the time has passed. */
-       if (bus->use_polling || cold)
+       if (bus->use_polling || cold) {
+               DPRINTF(("usb_delay_ms: delaying for %u ms\n", ms));
                delay((ms+1) * 1000);
-       else
+       }
+       else {
+               DPRINTF(("usb_delay_ms: tsleeping for %u ms\n", ms));
                tsleep(&ms, PRIBIO, "usbdly", (ms*hz+999)/1000 + 1);
+       }
 }
 
 /* Delay given a device handle. */
@@ -399,11 +403,14 @@ usbd_reset_port(usbd_device_handle dev, 
        USETW(req.wValue, UHF_PORT_RESET);
        USETW(req.wIndex, port);
        USETW(req.wLength, 0);
+       DPRINTFN(1,("usbd_reset_port: before lock"));
+       rw_enter_write(&ehci_cf_port_reset_rwlock);
+       DPRINTFN(1,("usbd_reset_port: after lock"));
        err = usbd_do_request(dev, &req, 0);
        DPRINTFN(1,("usbd_reset_port: port %d reset done, error=%s\n",
                    port, usbd_errstr(err)));
        if (err)
-               return (err);
+               goto done;
        n = 10;
        do {
                /* Wait for device to recover from reset. */
@@ -412,14 +419,18 @@ usbd_reset_port(usbd_device_handle dev, 
                if (err) {
                        DPRINTF(("usbd_reset_port: get status failed %d\n",
                                 err));
-                       return (err);
+                       goto done;
                }
                /* If the device disappeared, just give up. */
-               if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS))
-                       return (USBD_NORMAL_COMPLETION);
+               if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) {
+                       err = USBD_NORMAL_COMPLETION;
+                       goto done;
+               }
        } while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);
-       if (n == 0)
-               return (USBD_TIMEOUT);
+       if (n == 0) {
+               err = USBD_TIMEOUT;
+               goto done;
+       }
        err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
 #ifdef USB_DEBUG
        if (err)
@@ -429,6 +440,9 @@ usbd_reset_port(usbd_device_handle dev, 
 
        /* Wait for the device to recover from reset. */
        usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY);
+
+done:
+       rw_exit_write(&ehci_cf_port_reset_rwlock);
        return (err);
 }
 
Index: dev/usb/usbdi.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdi.c,v
retrieving revision 1.38
diff -u -p -r1.38 usbdi.c
--- dev/usb/usbdi.c     5 Mar 2010 17:28:54 -0000       1.38
+++ dev/usb/usbdi.c     8 Mar 2010 08:44:56 -0000
@@ -67,12 +67,16 @@ usbd_status usbd_open_pipe_ival(usbd_int
 int usbd_nbuses = 0;
 
 struct rwlock usbpalock;
+struct rwlock ehci_cf_port_reset_rwlock;
 
 void
 usbd_init(void)
 {
-       if (usbd_nbuses == 0)
+       if (usbd_nbuses == 0) {
                rw_init(&usbpalock, "usbpalock");
+               rw_init(&ehci_cf_port_reset_rwlock,
+                       "ehci_cf_port_reset_rwlock");
+       }
        usbd_nbuses++;
 }

Reply via email to