Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 8 Dec 2003 21:37:45 -0500
From:      Anish Mistry <mistry.7@osu.edu>
To:        freebsd-current@freebsd.org
Subject:   USB OHCI suspend and resume
Message-ID:  <200312082138.00259.mistry.7@osu.edu>

next in thread | raw e-mail | index | archive | help

--Boundary-00=_5VT1/msm8vnNWQM
Content-Type: multipart/signed;
  charset="us-ascii";
  protocol="application/pgp-signature";
  micalg=pgp-sha1;
  boundary="Boundary-02=_IWT1/UUuys9G9pl";
  name=" "
Content-Transfer-Encoding: 7bit

--Boundary-02=_IWT1/UUuys9G9pl
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
Content-Description: signed data
Content-Disposition: inline

I've attached a patch that along with the 20031203 acpica import, allows=20
usb(ohci) suspend and resume to work without panicing my system.  There is=
=20
a very good chance it may cause/fix problems with usb(ohci) on your=20
system.  Please report back any error or panic backtraces.  style fixes to=
=20
the patch coming near the end of the week.

Thanks,

=2D-=20
Anish Mistry

--Boundary-02=_IWT1/UUuys9G9pl
Content-Type: application/pgp-signature
Content-Description: signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (FreeBSD)

iD8DBQA/1TWIxqA5ziudZT0RArYqAJ9cekAEC5FMd8rFM/E9X8fP7j6OqQCgznes
2sfP3AX7Rq5cQKacJhuQcgM=
=rzh/
-----END PGP SIGNATURE-----

--Boundary-02=_IWT1/UUuys9G9pl--

--Boundary-00=_5VT1/msm8vnNWQM
Content-Type: text/x-diff;
  charset="us-ascii";
  name="ohci-sr-20031208.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="ohci-sr-20031208.patch"

diff -u sys/dev/usb.orig/ohci.c sys/dev/usb/ohci.c
--- sys/dev/usb.orig/ohci.c	Mon Dec  8 21:23:51 2003
+++ sys/dev/usb/ohci.c	Mon Dec  8 21:25:58 2003
@@ -1010,7 +1010,7 @@
 	DPRINTF(("ohci_shutdown: stopping the HC\n"));
 	OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
 }
-
+#endif
 /*
  * Handle suspend/resume.
  *
@@ -1018,6 +1018,134 @@
  * called from an intterupt context.  This is all right since we
  * are almost suspended anyway.
  */
+usbd_status
+ohci_resume(struct ohci_softc *sc)
+{
+	int s;
+	u_int32_t ctl, ival, fm, per, rev;
+		
+#if defined(__OpenBSD__)
+	printf(",");
+#else
+	printf("%s:", USBDEVNAME(sc->sc_bus.bdev));
+#endif
+	rev = OREAD4(sc, OHCI_REVISION);
+	printf(" OHCI version %d.%d%s\n", OHCI_REV_HI(rev), OHCI_REV_LO(rev),
+	       OHCI_REV_LEGACY(rev) ? ", legacy support" : "");
+	printf("ohci_resume: controller state: ");
+	switch(OREAD4(sc, OHCI_CONTROL) & OHCI_HCFS_MASK) {
+		case OHCI_HCFS_SUSPEND:
+			printf("SUSPEND");
+			break;
+		case OHCI_HCFS_RESUME:
+                        printf("RESUME");
+                        break;
+		case OHCI_HCFS_RESET:
+                        printf("RESET");
+                        break;
+		case OHCI_HCFS_OPERATIONAL:
+                        printf("OPERATIONAL");
+                        break;
+	}
+	printf("\n");
+	s = splhardusb();
+	/* The controller only responds to resume or reset writes at this point, so lets resume */
+	/* We are only supposed to enter resume state from a suspend state.  Should we check? */
+	OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESUME);
+	usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);	
+	/* check if the controller has resumed */
+        ctl = OREAD4(sc, OHCI_CONTROL);
+        if((ctl & OHCI_HCFS_RESUME) == OHCI_HCFS_RESUME) {
+                printf("ohci_resume: controller state: RESUME\n");
+        } else {
+                /* panic or abort? */
+                printf("ohci_resume: ??? controller did not resume!\n");
+                printf("ohci_resume: OHCI_CONTROL: 0x%x\n",ctl);
+        }
+
+#ifdef USB_DEBUG
+        ohci_dumpregs(sc);
+#endif
+
+	/* reset or controller may not start */
+	OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
+	usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY);
+
+        /* spec says save frame interrupt value, reset, then restore */
+        ival = OHCI_GET_IVAL(OREAD4(sc, OHCI_FM_INTERVAL));
+        OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */
+        usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY);
+
+ 	/* Some broken BIOSes do not recover these values */
+	OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0));
+	OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr);
+	OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr);
+	/* disable all interrupts and then switch on all desired interrupts */
+	OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
+	OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_intre | OHCI_MIE );
+
+	fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT;
+	fm |= OHCI_FSMPS(ival) | ival;
+	OWRITE4(sc, OHCI_FM_INTERVAL, fm);
+	per = OHCI_PERIODIC(ival);
+	OWRITE4(sc, OHCI_PERIODIC_START, per);
+
+	/* start controller */
+        ctl = sc->sc_control;
+        OWRITE4(sc, OHCI_CONTROL, ctl);
+        usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
+
+	/* power up ports */
+	OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC);
+	usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY);
+	splx(s);
+#ifdef USB_DEBUG
+        ohci_dumpregs(sc);
+#endif
+	
+	return (USBD_NORMAL_COMPLETION);
+}
+
+usbd_status
+ohci_suspend(struct ohci_softc *sc)
+{
+	u_int32_t ctl;
+	int s;
+
+#ifdef USB_DEBUG
+        ohci_dumpregs(sc);
+#endif
+
+	/*
+         * Preserve register values, in case that APM BIOS
+         * does not recover them.
+         */
+        sc->sc_control = OREAD4(sc, OHCI_CONTROL);
+        sc->sc_intre = OREAD4(sc, OHCI_INTERRUPT_ENABLE);
+	s = splhardusb();
+	/* disable interrupts */
+	OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
+	splx(s);
+	/* Reset to stop processing frames or the controller might not suspend */
+	OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
+	usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY);
+	/* now suspend */
+	ctl = OHCI_HCFS_SUSPEND;
+	OWRITE4(sc, OHCI_CONTROL, ctl);
+	usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
+	/* check if the controller is suspended */
+	ctl = OREAD4(sc, OHCI_CONTROL);
+	if((ctl & OHCI_HCFS_SUSPEND) == OHCI_HCFS_SUSPEND) {
+		printf("ohci_suspend: controller state: SUSPEND.\n");
+	} else {
+		/* panic or abort? */
+		printf("ohci_suspend: ??? controller did no suspend!\n");
+		printf("ohci_suspend: OHCI_CONTROL: 0x%x\n",ctl);
+	}
+	return (USBD_NORMAL_COMPLETION);
+}
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
 void
 ohci_power(int why, void *v)
 {
diff -u sys/dev/usb.orig/ohci_pci.c sys/dev/usb/ohci_pci.c
--- sys/dev/usb.orig/ohci_pci.c	Mon Dec  8 21:23:54 2003
+++ sys/dev/usb/ohci_pci.c	Mon Dec  8 21:24:21 2003
@@ -304,11 +304,39 @@
 	return 0;
 }
 
+/* implement suspend and resume */
+static int
+ohci_pci_suspend(device_t self)
+{
+	int err;
+	ohci_softc_t *sc = device_get_softc(self);
+	err = bus_generic_suspend(self);
+	if (err)
+		return err;
+	ohci_suspend(sc);
+	return 0;
+}
+
+static int
+ohci_pci_resume(device_t self)
+{
+	ohci_softc_t *sc = device_get_softc(self);
+	pci_set_powerstate(self, PCI_POWERSTATE_D0);
+	if(ohci_resume(sc) != USBD_NORMAL_COMPLETION) {
+		return ENXIO;
+	}
+	bus_generic_resume(self);
+	return 0;
+}
+
 static device_method_t ohci_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe, ohci_pci_probe),
 	DEVMETHOD(device_attach, ohci_pci_attach),
-	DEVMETHOD(device_shutdown, bus_generic_shutdown),
+	DEVMETHOD(device_detach, bus_generic_detach),
+	DEVMETHOD(device_suspend, ohci_pci_suspend),
+	DEVMETHOD(device_resume, ohci_pci_resume),
+ 	DEVMETHOD(device_shutdown, bus_generic_shutdown),
 
 	/* Bus interface */
 	DEVMETHOD(bus_print_child, bus_generic_print_child),
diff -u sys/dev/usb.orig/ohcivar.h sys/dev/usb/ohcivar.h
--- sys/dev/usb.orig/ohcivar.h	Mon Dec  8 21:23:51 2003
+++ sys/dev/usb/ohcivar.h	Mon Dec  8 21:24:21 2003
@@ -158,6 +158,8 @@
 #define OXFER(xfer) ((struct ohci_xfer *)(xfer))
 
 usbd_status	ohci_init(ohci_softc_t *);
+usbd_status	ohci_suspend(ohci_softc_t *);
+usbd_status	ohci_resume(ohci_softc_t *);
 int		ohci_intr(void *);
 #if defined(__NetBSD__) || defined(__OpenBSD__)
 int		ohci_detach(ohci_softc_t *, int);

--Boundary-00=_5VT1/msm8vnNWQM--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200312082138.00259.mistry.7>