Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 11 Jan 2015 12:01:47 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r276967 - stable/8/sys/dev/usb/controller
Message-ID:  <201501111201.t0BC1lP9081206@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Sun Jan 11 12:01:46 2015
New Revision: 276967
URL: https://svnweb.freebsd.org/changeset/base/276967

Log:
  MFC r251499, r271156, r276321, r276404, r276407, r276799 and r273376:
  Various XHCI fixes and improvements:
  - Add IDs for Intel Patsburg USB 2.0 controller (dependancy).
  - Add support for polling the XHCI interrupt handler when
    the regular interrupt handler is not working properly or
    in case of MSI interrupts which are not yet supported.
    Remove interrupt setup code for FreeBSD versions older
    than 700031.
  - Improve and fix MSI interrupt allocation, setup and release.
  - Add missed flushing of data which can happen when "xhci_configure_mask()"
    is called from "xhci_configure_reset_endpoint()". Ensure the 3-strikes
    error feature is always enabled except for ISOCHRONOUS transfers.
  - Allow systems having a page size greater than 4K to use fewer
    scatter-gather XHCI TRB entries for its payload data. The XHCI
    controller can handle at least 65536 bytes per scatter-gather list
    entry.
  - Add the Intel BayTrail USB device which needs port routing for USB 3.0.
  
  PR:	179342

Modified:
  stable/8/sys/dev/usb/controller/ehci_pci.c
  stable/8/sys/dev/usb/controller/xhci.c
  stable/8/sys/dev/usb/controller/xhci.h
  stable/8/sys/dev/usb/controller/xhci_pci.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/dev/   (props changed)
  stable/8/sys/dev/usb/   (props changed)

Modified: stable/8/sys/dev/usb/controller/ehci_pci.c
==============================================================================
--- stable/8/sys/dev/usb/controller/ehci_pci.c	Sun Jan 11 11:53:12 2015	(r276966)
+++ stable/8/sys/dev/usb/controller/ehci_pci.c	Sun Jan 11 12:01:46 2015	(r276967)
@@ -120,6 +120,12 @@ ehci_pci_match(device_t self)
 	case 0x43961002:
 		return ("AMD SB7x0/SB8x0/SB9x0 USB 2.0 controller");
 
+	case 0x0f348086:
+		return ("Intel BayTrail USB 2.0 controller");
+	case 0x1d268086:
+		return ("Intel Patsburg USB 2.0 controller");
+	case 0x1d2d8086:
+		return ("Intel Patsburg USB 2.0 controller");
 	case 0x1e268086:
 		return ("Intel Panther Point USB 2.0 controller");
 	case 0x1e2d8086:

Modified: stable/8/sys/dev/usb/controller/xhci.c
==============================================================================
--- stable/8/sys/dev/usb/controller/xhci.c	Sun Jan 11 11:53:12 2015	(r276966)
+++ stable/8/sys/dev/usb/controller/xhci.c	Sun Jan 11 12:01:46 2015	(r276967)
@@ -86,6 +86,7 @@ __FBSDID("$FreeBSD$");
 #ifdef USB_DEBUG
 static int xhcidebug;
 static int xhciroute;
+static int xhcipolling;
 
 SYSCTL_NODE(_hw_usb, OID_AUTO, xhci, CTLFLAG_RW, 0, "USB XHCI");
 SYSCTL_INT(_hw_usb_xhci, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN,
@@ -94,6 +95,9 @@ TUNABLE_INT("hw.usb.xhci.debug", &xhcide
 SYSCTL_INT(_hw_usb_xhci, OID_AUTO, xhci_port_route, CTLFLAG_RW | CTLFLAG_TUN,
     &xhciroute, 0, "Routing bitmap for switching EHCI ports to XHCI controller");
 TUNABLE_INT("hw.usb.xhci.xhci_port_route", &xhciroute);
+SYSCTL_INT(_hw_usb_xhci, OID_AUTO, use_polling, CTLFLAG_RW | CTLFLAG_TUN,
+    &xhcipolling, 0, "Set to enable software interrupt polling for XHCI controller");
+TUNABLE_INT("hw.usb.xhci.use_polling", &xhcipolling);
 #else
 #define	xhciroute 0
 #endif
@@ -181,6 +185,16 @@ xhci_dump_device(struct xhci_softc *sc, 
 }
 #endif
 
+uint8_t
+xhci_use_polling(void)
+{
+#ifdef USB_DEBUG
+	return (xhcipolling != 0);
+#else
+	return (0);
+#endif
+}
+
 static void
 xhci_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb)
 {
@@ -2252,6 +2266,7 @@ xhci_configure_mask(struct usb_device *u
 		temp |= XHCI_SCTX_0_CTX_NUM_SET(x + 1);
 		xhci_ctx_set_le32(sc, &pinp->ctx_slot.dwSctx0, temp);
 	}
+	usb_pc_cpu_flush(&sc->sc_hw.devs[index].input_pc);
 	return (0);
 }
 
@@ -2339,10 +2354,14 @@ xhci_configure_endpoint(struct usb_devic
 	    XHCI_EPCTX_1_MAXB_SET(max_packet_count) |
 	    XHCI_EPCTX_1_MAXP_SIZE_SET(max_packet_size);
 
-	if ((udev->parent_hs_hub != NULL) || (udev->address != 0)) {
-		if (type != UE_ISOCHRONOUS)
-			temp |= XHCI_EPCTX_1_CERR_SET(3);
-	}
+	/*
+	 * Always enable the "three strikes and you are gone" feature
+	 * except for ISOCHRONOUS endpoints. This is suggested by
+	 * section 4.3.3 in the XHCI specification about device slot
+	 * initialisation.
+	 */
+	if (type != UE_ISOCHRONOUS)
+		temp |= XHCI_EPCTX_1_CERR_SET(3);
 
 	switch (type) {
 	case UE_CONTROL:

Modified: stable/8/sys/dev/usb/controller/xhci.h
==============================================================================
--- stable/8/sys/dev/usb/controller/xhci.h	Sun Jan 11 11:53:12 2015	(r276966)
+++ stable/8/sys/dev/usb/controller/xhci.h	Sun Jan 11 12:01:46 2015	(r276967)
@@ -311,11 +311,23 @@ struct xhci_dev_endpoint_trbs {
 	struct xhci_trb		trb[XHCI_MAX_ENDPOINTS][XHCI_MAX_TRANSFERS];
 };
 
-#define	XHCI_TD_PAGE_NBUF	17	/* units, room enough for 64Kbytes */
-#define	XHCI_TD_PAGE_SIZE	4096	/* bytes */
-#define	XHCI_TD_PAYLOAD_MAX	(XHCI_TD_PAGE_SIZE * (XHCI_TD_PAGE_NBUF - 1))
+#if (USB_PAGE_SIZE < 4096)
+#error "The XHCI driver needs a pagesize above or equal to 4K"
+#endif
+
+/* Define the maximum payload which we will handle in a single TRB */
+#define	XHCI_TD_PAYLOAD_MAX	65536	/* bytes */
+
+/* Define the maximum payload of a single scatter-gather list element */
+#define	XHCI_TD_PAGE_SIZE \
+  ((USB_PAGE_SIZE < XHCI_TD_PAYLOAD_MAX) ? USB_PAGE_SIZE : XHCI_TD_PAYLOAD_MAX)
+
+/* Define the maximum length of the scatter-gather list */
+#define	XHCI_TD_PAGE_NBUF \
+  (((XHCI_TD_PAYLOAD_MAX + XHCI_TD_PAGE_SIZE - 1) / XHCI_TD_PAGE_SIZE) + 1)
 
 struct xhci_td {
+	/* one LINK TRB has been added to the TRB array */
 	struct xhci_trb		td_trb[XHCI_TD_PAGE_NBUF + 1];
 
 /*
@@ -432,6 +444,8 @@ struct xhci_softc {
 	struct usb_process	sc_config_proc;
 	struct usb_bus_msg	sc_config_msg[2];
 
+	struct usb_callout	sc_callout;
+
 	xhci_port_route_t	*sc_port_route;
 
 	union xhci_hub_desc	sc_hub_desc;
@@ -441,7 +455,6 @@ struct xhci_softc {
 
 	struct usb_device	*sc_devices[XHCI_MAX_DEVICES];
 	struct resource		*sc_io_res;
-	int			sc_irq_rid;
 	struct resource		*sc_irq_res;
 
 	void			*sc_intr_hdl;
@@ -498,6 +511,7 @@ struct xhci_softc {
 
 /* prototypes */
 
+uint8_t 	xhci_use_polling(void);
 usb_error_t xhci_halt_controller(struct xhci_softc *);
 usb_error_t xhci_init(struct xhci_softc *, device_t);
 usb_error_t xhci_start_controller(struct xhci_softc *);

Modified: stable/8/sys/dev/usb/controller/xhci_pci.c
==============================================================================
--- stable/8/sys/dev/usb/controller/xhci_pci.c	Sun Jan 11 11:53:12 2015	(r276966)
+++ stable/8/sys/dev/usb/controller/xhci_pci.c	Sun Jan 11 12:01:46 2015	(r276967)
@@ -102,6 +102,8 @@ xhci_pci_match(device_t self)
 	case 0x10421b21:
 		return ("ASMedia ASM1042 USB 3.0 controller");
 
+	case 0x0f358086:
+		return ("Intel Intel BayTrail USB 3.0 controller");
 	case 0x9c318086:
 	case 0x1e318086:
 		return ("Intel Panther Point USB 3.0 controller");
@@ -136,6 +138,16 @@ xhci_pci_probe(device_t self)
 static int xhci_use_msi = 1;
 TUNABLE_INT("hw.usb.xhci.msi", &xhci_use_msi);
 
+static void
+xhci_interrupt_poll(void *_sc)
+{
+	struct xhci_softc *sc = _sc;
+	USB_BUS_UNLOCK(&sc->sc_bus);
+	xhci_interrupt(sc);
+	USB_BUS_LOCK(&sc->sc_bus);
+	usb_callout_reset(&sc->sc_callout, 1, (void *)&xhci_interrupt_poll, sc);
+}
+
 static int
 xhci_pci_port_route(device_t self, uint32_t set, uint32_t clear)
 {
@@ -187,23 +199,22 @@ xhci_pci_attach(device_t self)
 	sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
 	sc->sc_io_size = rman_get_size(sc->sc_io_res);
 
-	sc->sc_irq_rid = 0;
+	usb_callout_init_mtx(&sc->sc_callout, &sc->sc_bus.bus_mtx, 0);
+
+	rid = 0;
 	if (xhci_use_msi) {
-		count = pci_msi_count(self);
-		if (count >= 1) {
-			count = 1;
-			if (pci_alloc_msi(self, &count) == 0) {
-				if (bootverbose)
-					device_printf(self, "MSI enabled\n");
-				sc->sc_irq_rid = 1;
-			}
+		count = 1;
+		if (pci_alloc_msi(self, &count) == 0) {
+			if (bootverbose)
+				device_printf(self, "MSI enabled\n");
+			rid = 1;
 		}
 	}
-	sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ,
-	    &sc->sc_irq_rid, RF_SHAREABLE | RF_ACTIVE);
+	sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE | (rid != 0 ? 0 : RF_SHAREABLE));
 	if (sc->sc_irq_res == NULL) {
+		pci_release_msi(self);
 		device_printf(self, "Could not allocate IRQ\n");
-		goto error;
 	}
 	sc->sc_bus.bdev = device_add_child(self, "usbus", -1);
 	if (sc->sc_bus.bdev == NULL) {
@@ -214,20 +225,31 @@ xhci_pci_attach(device_t self)
 
 	sprintf(sc->sc_vendor, "0x%04x", pci_get_vendor(self));
 
-#if (__FreeBSD_version >= 700031)
-	err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-	    NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl);
-#else
-	err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
-	    (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl);
-#endif
-	if (err) {
-		device_printf(self, "Could not setup IRQ, err=%d\n", err);
-		sc->sc_intr_hdl = NULL;
-		goto error;
+	if (sc->sc_irq_res != NULL) {
+		err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
+		    NULL, (driver_intr_t *)xhci_interrupt, sc, &sc->sc_intr_hdl);
+		if (err != 0) {
+			bus_release_resource(self, SYS_RES_IRQ,
+			    rman_get_rid(sc->sc_irq_res), sc->sc_irq_res);
+			sc->sc_irq_res = NULL;
+			pci_release_msi(self);
+			device_printf(self, "Could not setup IRQ, err=%d\n", err);
+			sc->sc_intr_hdl = NULL;
+		}
+	}
+	if (sc->sc_irq_res == NULL || sc->sc_intr_hdl == NULL) {
+		if (xhci_use_polling() != 0) {
+			device_printf(self, "Interrupt polling at %dHz\n", hz);
+			USB_BUS_LOCK(&sc->sc_bus);
+			xhci_interrupt_poll(sc);
+			USB_BUS_UNLOCK(&sc->sc_bus);
+		} else
+			goto error;
 	}
+
 	/* On Intel chipsets reroute ports from EHCI to XHCI controller. */
 	switch (pci_get_devid(self)) {
+	case 0x0f358086:	/* BayTrail */
 	case 0x9c318086:	/* Panther Point */
 	case 0x1e318086:	/* Panther Point */
 	case 0x8c318086:	/* Lynx Point */
@@ -239,6 +261,14 @@ xhci_pci_attach(device_t self)
 		break;
 	}
 
+	if (sc->sc_irq_res == NULL || sc->sc_intr_hdl == NULL ||
+	    xhci_use_polling() != 0) {
+		device_printf(self, "Interrupt polling at %dHz\n", hz);
+		USB_BUS_LOCK(&sc->sc_bus);
+		xhci_interrupt_poll(sc);
+		USB_BUS_UNLOCK(&sc->sc_bus);
+	}
+
 	xhci_pci_take_controller(self);
 
 	err = xhci_halt_controller(sc);
@@ -274,21 +304,22 @@ xhci_pci_detach(device_t self)
 	/* during module unload there are lots of children leftover */
 	device_delete_all_children(self);
 
+	if (sc->sc_io_res) {
+		usb_callout_drain(&sc->sc_callout);
+		xhci_halt_controller(sc);
+	}
+
 	pci_disable_busmaster(self);
 
 	if (sc->sc_irq_res && sc->sc_intr_hdl) {
-
-		xhci_halt_controller(sc);
-
 		bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl);
 		sc->sc_intr_hdl = NULL;
 	}
 	if (sc->sc_irq_res) {
-		if (sc->sc_irq_rid == 1)
-			pci_release_msi(self);
-		bus_release_resource(self, SYS_RES_IRQ, sc->sc_irq_rid,
-		    sc->sc_irq_res);
+		bus_release_resource(self, SYS_RES_IRQ,
+		    rman_get_rid(sc->sc_irq_res), sc->sc_irq_res);
 		sc->sc_irq_res = NULL;
+		pci_release_msi(self);
 	}
 	if (sc->sc_io_res) {
 		bus_release_resource(self, SYS_RES_MEMORY, PCI_XHCI_CBMEM,



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