Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 29 May 2014 10:06:18 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r266831 - head/sys/dev/usb/controller
Message-ID:  <201405291006.s4TA6IBj013604@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Thu May 29 10:06:18 2014
New Revision: 266831
URL: http://svnweb.freebsd.org/changeset/base/266831

Log:
  Optimise the ISP/SAF1761 driver:
  - Use an interrupt filter for handling the data path interrupts. This
  increases the throughput significantly.
  - Implement support for USB suspend and resume in USB host mode.
  
  Sponsored by:	DARPA, AFRL

Modified:
  head/sys/dev/usb/controller/saf1761_otg.c
  head/sys/dev/usb/controller/saf1761_otg.h
  head/sys/dev/usb/controller/saf1761_otg_fdt.c

Modified: head/sys/dev/usb/controller/saf1761_otg.c
==============================================================================
--- head/sys/dev/usb/controller/saf1761_otg.c	Thu May 29 07:45:45 2014	(r266830)
+++ head/sys/dev/usb/controller/saf1761_otg.c	Thu May 29 10:06:18 2014	(r266831)
@@ -84,6 +84,13 @@
    ((struct saf1761_otg_softc *)(((uint8_t *)(bus)) - \
     ((uint8_t *)&(((struct saf1761_otg_softc *)0)->sc_bus))))
 
+#define	SAF1761_OTG_PC2UDEV(pc) \
+   (USB_DMATAG_TO_XROOT((pc)->tag_parent)->udev)
+
+#define	SAF1761_DCINTERRUPT_THREAD_IRQ			\
+  (SOTG_DCINTERRUPT_IEVBUS | SOTG_DCINTERRUPT_IEBRST |	\
+  SOTG_DCINTERRUPT_IERESM | SOTG_DCINTERRUPT_IESUSP)
+
 #ifdef USB_DEBUG
 static int saf1761_otg_debug = 0;
 static int saf1761_otg_forcefs = 0;
@@ -201,7 +208,6 @@ saf1761_otg_wakeup_peer(struct saf1761_o
 
 	/* Wait 8ms for remote wakeup to complete. */
 	usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125);
-
 }
 
 static uint8_t
@@ -212,6 +218,10 @@ saf1761_host_channel_alloc(struct saf176
 	if (td->channel < SOTG_HOST_CHANNEL_MAX)
 		return (0);
 
+	/* check if device is suspended */
+	if (SAF1761_OTG_PC2UDEV(td->pc)->flags.self_suspended != 0)
+		return (1);		/* busy - cannot transfer data */
+
 	switch (td->ep_type) {
 	case UE_INTERRUPT:
 		for (x = 0; x != 32; x++) {
@@ -257,19 +267,25 @@ saf1761_host_channel_free(struct saf1761
 		x = td->channel - 32;
 		td->channel = SOTG_HOST_CHANNEL_MAX;
 		sc->sc_host_intr_map &= ~(1 << x);
-		SAF1761_WRITE_LE_4(sc, SOTG_INT_PTD_SKIP_PTD, ~sc->sc_host_intr_map);
+		sc->sc_host_intr_suspend_map &= ~(1 << x);
+		SAF1761_WRITE_LE_4(sc, SOTG_INT_PTD_SKIP_PTD,
+		    (~sc->sc_host_intr_map) | sc->sc_host_intr_suspend_map);
 		break;
 	case UE_ISOCHRONOUS:
 		x = td->channel;
 		td->channel = SOTG_HOST_CHANNEL_MAX;
 		sc->sc_host_isoc_map &= ~(1 << x);
-		SAF1761_WRITE_LE_4(sc, SOTG_ISO_PTD_SKIP_PTD, ~sc->sc_host_isoc_map);
+		sc->sc_host_isoc_suspend_map &= ~(1 << x);
+		SAF1761_WRITE_LE_4(sc, SOTG_ISO_PTD_SKIP_PTD,
+		    (~sc->sc_host_isoc_map) | sc->sc_host_isoc_suspend_map);
 		break;
 	default:
 		x = td->channel - 64;
 		td->channel = SOTG_HOST_CHANNEL_MAX;
 		sc->sc_host_async_map &= ~(1 << x);
-		SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD, ~sc->sc_host_async_map);
+		sc->sc_host_async_suspend_map &= ~(1 << x);
+		SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD,
+		    (~sc->sc_host_async_map) | sc->sc_host_async_suspend_map);
 		break;
 	}
 }
@@ -447,7 +463,8 @@ saf1761_host_setup_tx(struct saf1761_otg
 	SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp);
 
 	/* activate PTD */
-	SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD, ~sc->sc_host_async_map);
+	SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD,
+	    (~sc->sc_host_async_map) | sc->sc_host_async_suspend_map);
 
 	td->toggle = 1;
 busy:
@@ -553,7 +570,8 @@ saf1761_host_bulk_data_rx(struct saf1761
 	SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp);
 
 	/* activate PTD */
-	SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD, ~sc->sc_host_async_map);
+	SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD,
+	    (~sc->sc_host_async_map) | sc->sc_host_async_suspend_map);
 busy:
 	return (1);	/* busy */
 complete:
@@ -639,7 +657,8 @@ saf1761_host_bulk_data_tx(struct saf1761
 	SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp);
 
 	/* activate PTD */
-	SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD, ~sc->sc_host_async_map);
+	SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD,
+	    (~sc->sc_host_async_map) | sc->sc_host_async_suspend_map);
 
 	td->toggle ^= 1;
 busy:
@@ -748,7 +767,8 @@ saf1761_host_intr_data_rx(struct saf1761
 	SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp);
 
 	/* activate PTD */
-	SAF1761_WRITE_LE_4(sc, SOTG_INT_PTD_SKIP_PTD, ~sc->sc_host_intr_map);
+	SAF1761_WRITE_LE_4(sc, SOTG_INT_PTD_SKIP_PTD,
+	    (~sc->sc_host_intr_map) | sc->sc_host_intr_suspend_map);
 busy:
 	return (1);	/* busy */
 complete:
@@ -838,7 +858,8 @@ saf1761_host_intr_data_tx(struct saf1761
 	SAF1761_WRITE_LE_4(sc, pdt_addr + SOTG_PTD_DW0, temp);
 
 	/* activate PTD */
-	SAF1761_WRITE_LE_4(sc, SOTG_INT_PTD_SKIP_PTD, ~sc->sc_host_intr_map);
+	SAF1761_WRITE_LE_4(sc, SOTG_INT_PTD_SKIP_PTD,
+	    (~sc->sc_host_intr_map) | sc->sc_host_intr_suspend_map);
 
 	td->toggle ^= 1;
 busy:
@@ -852,7 +873,8 @@ static uint8_t
 saf1761_host_isoc_data_rx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
 {
 	/* activate PTD */
-	SAF1761_WRITE_LE_4(sc, SOTG_ISO_PTD_SKIP_PTD, ~sc->sc_host_isoc_map);
+	SAF1761_WRITE_LE_4(sc, SOTG_ISO_PTD_SKIP_PTD,
+	    (~sc->sc_host_isoc_map) | sc->sc_host_isoc_suspend_map);
 
 	return (1);	/* busy */
 }
@@ -861,7 +883,8 @@ static uint8_t
 saf1761_host_isoc_data_tx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
 {
 	/* activate PTD */
-	SAF1761_WRITE_LE_4(sc, SOTG_ISO_PTD_SKIP_PTD, ~sc->sc_host_isoc_map);
+	SAF1761_WRITE_LE_4(sc, SOTG_ISO_PTD_SKIP_PTD,
+	    (~sc->sc_host_isoc_map) | sc->sc_host_isoc_suspend_map);
 
 	return (1);	/* busy */
 }
@@ -1222,7 +1245,7 @@ saf1761_device_data_tx_sync(struct saf17
 	return (0);			/* complete */
 }
 
-static uint8_t
+static void
 saf1761_otg_xfer_do_fifo(struct saf1761_otg_softc *sc, struct usb_xfer *xfer)
 {
 	struct saf1761_otg_td *td;
@@ -1231,6 +1254,9 @@ saf1761_otg_xfer_do_fifo(struct saf1761_
 	DPRINTFN(9, "\n");
 
 	td = xfer->td_transfer_cache;
+	if (td == NULL)
+		return;
+
 	while (1) {
 		if ((td->func) (sc, td)) {
 			/* operation in progress */
@@ -1258,28 +1284,37 @@ saf1761_otg_xfer_do_fifo(struct saf1761_
 		td->toggle = toggle;
 		xfer->td_transfer_cache = td;
 	}
-	return (1);			/* not complete */
+	return;
 
 done:
 	/* compute all actual lengths */
+	xfer->td_transfer_cache = NULL;
+	sc->sc_xfer_complete = 1;
+}
+
+static uint8_t
+saf1761_otg_xfer_do_complete(struct saf1761_otg_softc *sc, struct usb_xfer *xfer)
+{
+	struct saf1761_otg_td *td;
 
-	saf1761_otg_standard_done(xfer);
+	DPRINTFN(9, "\n");
 
-	return (0);			/* complete */
+	td = xfer->td_transfer_cache;
+	if (td == NULL) {
+		/* compute all actual lengths */
+		saf1761_otg_standard_done(xfer);
+		return (1);
+	}
+	return (0);
 }
 
 static void
-saf1761_otg_interrupt_poll(struct saf1761_otg_softc *sc)
+saf1761_otg_interrupt_poll_locked(struct saf1761_otg_softc *sc)
 {
 	struct usb_xfer *xfer;
 
-repeat:
-	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
-		if (!saf1761_otg_xfer_do_fifo(sc, xfer)) {
-			/* queue has been modified */
-			goto repeat;
-		}
-	}
+	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry)
+		saf1761_otg_xfer_do_fifo(sc, xfer);
 }
 
 static void
@@ -1329,13 +1364,27 @@ saf1761_otg_update_vbus(struct saf1761_o
 	}
 }
 
-void
-saf1761_otg_interrupt(struct saf1761_otg_softc *sc)
+static void
+saf1761_otg_interrupt_complete_locked(struct saf1761_otg_softc *sc)
 {
-	uint32_t status;
+	struct usb_xfer *xfer;
+repeat:
+	/* scan for completion events */
+	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+		if (saf1761_otg_xfer_do_complete(sc, xfer))
+			goto repeat;
+	}
+}
+
+int
+saf1761_otg_filter_interrupt(void *arg)
+{
+	struct saf1761_otg_softc *sc = arg;
+	int retval = FILTER_HANDLED;
 	uint32_t hcstat;
+	uint32_t status;
 
-	USB_BUS_LOCK(&sc->sc_bus);
+	USB_BUS_SPIN_LOCK(&sc->sc_bus);
 
 	hcstat = SAF1761_READ_LE_4(sc, SOTG_HCINTERRUPT);
 	/* acknowledge all host controller interrupts */
@@ -1343,17 +1392,47 @@ saf1761_otg_interrupt(struct saf1761_otg
 
 	status = SAF1761_READ_LE_4(sc, SOTG_DCINTERRUPT);
 	/* acknowledge all device controller interrupts */
-	SAF1761_WRITE_LE_4(sc, SOTG_DCINTERRUPT, status);
-
-	DPRINTF("DCINTERRUPT=0x%08x HCINTERRUPT=0x%08x SOF=0x%08x "
-	    "FRINDEX=0x%08x\n", status, hcstat,
-	    SAF1761_READ_LE_4(sc, SOTG_FRAME_NUM),
-	    SAF1761_READ_LE_4(sc, SOTG_FRINDEX));
+	SAF1761_WRITE_LE_4(sc, SOTG_DCINTERRUPT,
+	    status & ~SAF1761_DCINTERRUPT_THREAD_IRQ);
 
 	(void) SAF1761_READ_LE_4(sc, SOTG_ATL_PTD_DONE_PTD);
 	(void) SAF1761_READ_LE_4(sc, SOTG_INT_PTD_DONE_PTD);
 	(void) SAF1761_READ_LE_4(sc, SOTG_ISO_PTD_DONE_PTD);
 
+	if (status & SAF1761_DCINTERRUPT_THREAD_IRQ)
+		retval = FILTER_SCHEDULE_THREAD;
+
+	/* poll FIFOs, if any */
+	saf1761_otg_interrupt_poll_locked(sc);
+
+	if (sc->sc_xfer_complete != 0)
+		retval = FILTER_SCHEDULE_THREAD;
+
+	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
+
+	return (retval);
+}
+
+void
+saf1761_otg_interrupt(void *arg)
+{
+	struct saf1761_otg_softc *sc = arg;
+	uint32_t status;
+
+	USB_BUS_LOCK(&sc->sc_bus);
+	USB_BUS_SPIN_LOCK(&sc->sc_bus);
+
+	status = SAF1761_READ_LE_4(sc, SOTG_DCINTERRUPT) & 
+	    SAF1761_DCINTERRUPT_THREAD_IRQ;
+
+	/* acknowledge all device controller interrupts */
+	SAF1761_WRITE_LE_4(sc, SOTG_DCINTERRUPT, status);
+
+	DPRINTF("DCINTERRUPT=0x%08x SOF=0x%08x "
+	    "FRINDEX=0x%08x\n", status,
+	    SAF1761_READ_LE_4(sc, SOTG_FRAME_NUM),
+	    SAF1761_READ_LE_4(sc, SOTG_FRINDEX));
+
 	/* update VBUS and ID bits, if any */
 	if (status & SOTG_DCINTERRUPT_IEVBUS)
 		saf1761_otg_update_vbus(sc);
@@ -1405,9 +1484,14 @@ saf1761_otg_interrupt(struct saf1761_otg
 			saf1761_otg_root_intr(sc);
 		}
 	}
-	/* poll all active transfers */
-	saf1761_otg_interrupt_poll(sc);
 
+	if (sc->sc_xfer_complete != 0) {
+		sc->sc_xfer_complete = 0;
+
+		/* complete FIFOs, if any */
+		saf1761_otg_interrupt_complete_locked(sc);
+	}
+	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
 	USB_BUS_UNLOCK(&sc->sc_bus);
 }
 
@@ -1694,9 +1778,12 @@ saf1761_otg_start_standard_chain(struct 
 
 	DPRINTFN(9, "\n");
 
+	USB_BUS_SPIN_LOCK(&sc->sc_bus);
+
 	/* poll one time */
-	if (saf1761_otg_xfer_do_fifo(sc, xfer)) {
+	saf1761_otg_xfer_do_fifo(sc, xfer);
 
+	if (xfer->td_transfer_cache != NULL) {
 		/*
 		 * Only enable the endpoint interrupt when we are
 		 * actually waiting for data, hence we are dealing
@@ -1712,7 +1799,11 @@ saf1761_otg_start_standard_chain(struct 
 			usbd_transfer_timeout_ms(xfer,
 			    &saf1761_otg_timeout, xfer->timeout);
 		}
+	} else {
+		/* catch completion, if any */
+		saf1761_otg_interrupt_complete_locked(sc);
 	}
+	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
 }
 
 static void
@@ -1856,6 +1947,8 @@ saf1761_otg_device_done(struct usb_xfer 
 	DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n",
 	    xfer, xfer->endpoint, error);
 
+	USB_BUS_SPIN_LOCK(&sc->sc_bus);
+
 	if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
 		saf1761_otg_intr_set(xfer, 0);
 	} else {
@@ -1869,6 +1962,8 @@ saf1761_otg_device_done(struct usb_xfer 
 
 	/* dequeue transfer and start next transfer */
 	usbd_transfer_done(xfer, error);
+
+	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
 }
 
 static void
@@ -1896,8 +1991,9 @@ saf1761_otg_set_stall(struct usb_device 
 
 	DPRINTFN(5, "endpoint=%p\n", ep);
 
-	/* set FORCESTALL */
+	/* set STALL bit */
 	sc = SAF1761_OTG_BUS2SC(udev->bus);
+
 	ep_no = (ep->edesc->bEndpointAddress & UE_ADDR);
 	ep_dir = (ep->edesc->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT));
 	ep_type = (ep->edesc->bmAttributes & UE_XFERTYPE);
@@ -1906,6 +2002,8 @@ saf1761_otg_set_stall(struct usb_device 
 		/* should not happen */
 		return;
 	}
+	USB_BUS_SPIN_LOCK(&sc->sc_bus);
+
 	/* select the correct endpoint */
 	SAF1761_WRITE_LE_4(sc, SOTG_EP_INDEX,
 	    (ep_no << SOTG_EP_INDEX_ENDP_INDEX_SHIFT) |
@@ -1914,10 +2012,12 @@ saf1761_otg_set_stall(struct usb_device 
 
 	/* set stall */
 	SAF1761_WRITE_LE_4(sc, SOTG_CTRL_FUNC, SOTG_CTRL_FUNC_STALL);
+
+	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
 }
 
 static void
-saf1761_otg_clear_stall_sub(struct saf1761_otg_softc *sc,
+saf1761_otg_clear_stall_sub_locked(struct saf1761_otg_softc *sc,
     uint8_t ep_no, uint8_t ep_type, uint8_t ep_dir)
 {
 	if (ep_type == UE_CONTROL) {
@@ -1959,14 +2059,18 @@ saf1761_otg_clear_stall(struct usb_devic
 	/* get softc */
 	sc = SAF1761_OTG_BUS2SC(udev->bus);
 
+	USB_BUS_SPIN_LOCK(&sc->sc_bus);
+
 	/* get endpoint descriptor */
 	ed = ep->edesc;
 
 	/* reset endpoint */
-	saf1761_otg_clear_stall_sub(sc,
+	saf1761_otg_clear_stall_sub_locked(sc,
 	    (ed->bEndpointAddress & UE_ADDR),
 	    (ed->bmAttributes & UE_XFERTYPE),
 	    (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT)));
+
+	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
 }
 
 usb_error_t
@@ -2218,7 +2322,10 @@ saf1761_otg_do_poll(struct usb_bus *bus)
 	struct saf1761_otg_softc *sc = SAF1761_OTG_BUS2SC(bus);
 
 	USB_BUS_LOCK(&sc->sc_bus);
-	saf1761_otg_interrupt_poll(sc);
+	USB_BUS_SPIN_LOCK(&sc->sc_bus);
+	saf1761_otg_interrupt_poll_locked(sc);
+	saf1761_otg_interrupt_complete_locked(sc);
+	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
 	USB_BUS_UNLOCK(&sc->sc_bus);
 }
 
@@ -3150,6 +3257,115 @@ saf1761_otg_set_hw_power_sleep(struct us
 	}
 }
 
+static void
+saf1761_otg_device_resume(struct usb_device *udev)
+{
+	struct saf1761_otg_softc *sc;
+	struct saf1761_otg_td *td;
+	struct usb_xfer *xfer;
+	uint8_t x;
+
+	DPRINTF("\n");
+
+	if (udev->flags.usb_mode != USB_MODE_HOST)
+		return;
+
+	sc = SAF1761_OTG_BUS2SC(udev->bus);
+
+	USB_BUS_LOCK(&sc->sc_bus);
+	USB_BUS_SPIN_LOCK(&sc->sc_bus);
+
+	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+		if (xfer->xroot->udev != udev)
+			continue;
+
+		td = xfer->td_transfer_cache;
+		if (td == NULL || td->channel >= SOTG_HOST_CHANNEL_MAX)
+			continue;
+
+		switch (td->ep_type) {
+		case UE_INTERRUPT:
+			x = td->channel - 32;
+			sc->sc_host_intr_suspend_map &= ~(1 << x);
+			SAF1761_WRITE_LE_4(sc, SOTG_INT_PTD_SKIP_PTD,
+			    (~sc->sc_host_intr_map) | sc->sc_host_intr_suspend_map);
+			break;
+		case UE_ISOCHRONOUS:
+			x = td->channel;
+			sc->sc_host_isoc_suspend_map &= ~(1 << x);
+			SAF1761_WRITE_LE_4(sc, SOTG_ISO_PTD_SKIP_PTD,
+			    (~sc->sc_host_isoc_map) | sc->sc_host_isoc_suspend_map);
+			break;
+		default:
+			x = td->channel - 64;
+			sc->sc_host_async_suspend_map &= ~(1 << x);
+			SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD,
+			    (~sc->sc_host_async_map) | sc->sc_host_async_suspend_map);
+			break;
+		}
+	}
+
+	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
+	USB_BUS_UNLOCK(&sc->sc_bus);
+
+	/* poll all transfers again to restart resumed ones */
+	saf1761_otg_do_poll(&sc->sc_bus);
+}
+
+static void
+saf1761_otg_device_suspend(struct usb_device *udev)
+{
+	struct saf1761_otg_softc *sc;
+	struct saf1761_otg_td *td;
+	struct usb_xfer *xfer;
+	uint8_t x;
+
+	DPRINTF("\n");
+
+	if (udev->flags.usb_mode != USB_MODE_HOST)
+		return;
+
+	sc = SAF1761_OTG_BUS2SC(udev->bus);
+
+	USB_BUS_LOCK(&sc->sc_bus);
+	USB_BUS_SPIN_LOCK(&sc->sc_bus);
+
+	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+
+		if (xfer->xroot->udev != udev)
+			continue;
+
+		td = xfer->td_transfer_cache;
+		if (td == NULL || td->channel >= SOTG_HOST_CHANNEL_MAX)
+			continue;
+
+		switch (td->ep_type) {
+		case UE_INTERRUPT:
+			x = td->channel - 32;
+			sc->sc_host_intr_suspend_map |= (1 << x);
+			SAF1761_WRITE_LE_4(sc, SOTG_INT_PTD_SKIP_PTD,
+			    (~sc->sc_host_intr_map) | sc->sc_host_intr_suspend_map);
+			break;
+		case UE_ISOCHRONOUS:
+			x = td->channel;
+			sc->sc_host_isoc_suspend_map |= (1 << x);
+			SAF1761_WRITE_LE_4(sc, SOTG_ISO_PTD_SKIP_PTD,
+			    (~sc->sc_host_isoc_map) | sc->sc_host_isoc_suspend_map);
+			break;
+		default:
+			x = td->channel - 64;
+			sc->sc_host_async_suspend_map |= (1 << x);
+			SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD,
+			    (~sc->sc_host_async_map) | sc->sc_host_async_suspend_map);
+			break;
+		}
+	}
+
+	USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
+	USB_BUS_UNLOCK(&sc->sc_bus);
+}
+
 static const struct usb_bus_methods saf1761_otg_bus_methods =
 {
 	.endpoint_init = &saf1761_otg_ep_init,
@@ -3162,4 +3378,6 @@ static const struct usb_bus_methods saf1
 	.roothub_exec = &saf1761_otg_roothub_exec,
 	.xfer_poll = &saf1761_otg_do_poll,
 	.set_hw_power_sleep = saf1761_otg_set_hw_power_sleep,
+	.device_resume = &saf1761_otg_device_resume,
+	.device_suspend = &saf1761_otg_device_suspend,
 };

Modified: head/sys/dev/usb/controller/saf1761_otg.h
==============================================================================
--- head/sys/dev/usb/controller/saf1761_otg.h	Thu May 29 07:45:45 2014	(r266830)
+++ head/sys/dev/usb/controller/saf1761_otg.h	Thu May 29 10:06:18 2014	(r266831)
@@ -140,11 +140,15 @@ struct saf1761_otg_softc {
 	bus_space_handle_t sc_io_hdl;
 
 	uint32_t sc_host_async_map;
+	uint32_t sc_host_async_suspend_map;
 	uint32_t sc_host_intr_map;
+	uint32_t sc_host_intr_suspend_map;
 	uint32_t sc_host_isoc_map;
+	uint32_t sc_host_isoc_suspend_map;
 	uint32_t sc_intr_enable;	/* enabled interrupts */
 	uint32_t sc_hw_mode;		/* hardware mode */
 	uint32_t sc_interrupt_cfg;	/* interrupt configuration */
+	uint32_t sc_xfer_complete;
 
 	uint32_t sc_bounce_buffer[1024 / 4];
 
@@ -162,6 +166,7 @@ struct saf1761_otg_softc {
 
 usb_error_t saf1761_otg_init(struct saf1761_otg_softc *sc);
 void	saf1761_otg_uninit(struct saf1761_otg_softc *sc);
-void	saf1761_otg_interrupt(struct saf1761_otg_softc *sc);
+driver_filter_t saf1761_otg_filter_interrupt;
+driver_intr_t saf1761_otg_interrupt;
 
 #endif					/* _SAF1761_OTG_H_ */

Modified: head/sys/dev/usb/controller/saf1761_otg_fdt.c
==============================================================================
--- head/sys/dev/usb/controller/saf1761_otg_fdt.c	Thu May 29 07:45:45 2014	(r266830)
+++ head/sys/dev/usb/controller/saf1761_otg_fdt.c	Thu May 29 10:06:18 2014	(r266831)
@@ -210,8 +210,8 @@ saf1761_otg_fdt_attach(device_t dev)
 
 	device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
 
-	err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-	    NULL, (driver_intr_t *)saf1761_otg_interrupt, sc, &sc->sc_intr_hdl);
+	err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_TTY | INTR_MPSAFE,
+	    &saf1761_otg_filter_interrupt, &saf1761_otg_interrupt, sc, &sc->sc_intr_hdl);
 	if (err) {
 		sc->sc_intr_hdl = NULL;
 		goto error;



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