tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

xhci patch for nick-nhusb branch



Hello,

Here are some xhci patches for nick-nhusb branch.


nh-xhci-cos.diff
	+ Add comments. Some cosmetic changes.
nh-xhci-clearhalt.diff
	+ Don't abuse pipe->up_async_task for
	  xhci_clear_endpoint_stall_async_task.
	  Add member struct usb_task xp_async_task to struct xhci_pipe.
nh-xhci-slot.diff
	+ Fix slot leak when address_device fails.
	+ Eliminate device_xname().
nh-xhci-chkxfer.diff
	+ Add some sanity checks for xfer.
nh-xhci-trberr.diff
	+ Rewrite if-else-if chains with switch-case.
nh-xhci-ss.diff
	+ Eliminate confusing UPS_SUPER_SPEED flag and introduce
	  UPS_OTHER_SPEED flag that indicates ud_speed of device is
	  super speed (or more).
	  uhub shall set this flag if ud_speed is super speed (or more).
	+ Add the macro that checks ud_speed is super speed.
	  The codes shall use this macro to check ud_speed is super speed.
	+ Add speed type conversion functions.
	+ Include port link status in port_status if port is super speed.
nh-xhci-quirks.diff
	+ Add patch for intel chips quirk from ryoon@ in
	  https://mail-index.netbsd.org/netbsd-bugs/2014/08/31/msg038109.html
	  slightly modified to set quirks before calling xhci_init.
	+ Set special IMOD value and route ports to xhci for intel chips.


--
t-hash

--- src/sys/dev/usb/xhci.c.orig	2015-04-07 17:55:43.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2015-05-25 20:33:49.000000000 +0900
@@ -26,6 +26,15 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/*
+ * USB rev 3.1 specification
+ *  http://www.usb.org/developers/docs/usb_31_040315.zip
+ * USB rev 2.0 specification
+ *  http://www.usb.org/developers/docs/usb20_docs/usb_20_031815.zip
+ * xHCI rev 1.1 specification
+ *  http://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf
+ */
+
 #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.20 2015/04/07 06:52:03 skrll Exp $");
 
@@ -1374,7 +1383,7 @@ xhci_stop_endpoint(struct usbd_pipe *pip
 /*
  * Set TR Dequeue Pointer.
  * xCHI 1.1  4.6.10  6.4.3.9
- * Purge all of transfer requests in ring.
+ * Purge all of transfer requests on ring.
  * EPSTATE of endpoint must be ERROR or STOPPED, or CONTEXT_STATE error.
  */
 static usbd_status
@@ -1578,7 +1587,13 @@ xhci_abort_xfer(struct usbd_xfer *xfer, 
 }
 
 #if 1 /* XXX experimental */
-/* issue reset_ep and set_dequeue in thread context */
+/*
+ * Recover STALLed endpoint.
+ * xHCI 1.1 sect 4.10.2.1
+ * Issue RESET_EP to recover halt condition and SET_TR_DEQUEUE to remove
+ * all transfers on transfer ring.
+ * These are done in thread context asynchronously.
+ */
 static void
 xhci_clear_endpoint_stall_async_task(void *cookie)
 {
@@ -1624,7 +1639,6 @@ xhci_clear_endpoint_stall_async(struct u
 }
 
 #endif /* XXX experimental */
-
 /*
  * Notify roothub port status/change to uhub_intr.
  */
@@ -2765,8 +2779,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 		break;
 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
 		break;
-	case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
-	{
+	case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): {
 		int optval = (index >> 8) & 0xff;
 		index &= 0xff;
 		if (index < 1 || index > sc->sc_maxports) {




--- src/sys/dev/usb/xhci.c.orig	2015-05-25 20:33:49.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2015-05-25 20:48:51.000000000 +0900
@@ -116,6 +116,7 @@ fail:
 
 struct xhci_pipe {
 	struct usbd_pipe xp_pipe;
+	struct usb_task xp_async_task;
 };
 
 #define XHCI_COMMAND_RING_TRBS 256
@@ -1620,6 +1621,7 @@ static usbd_status
 xhci_clear_endpoint_stall_async(struct usbd_xfer *xfer)
 {
 	struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+	struct xhci_pipe * const xp = (struct xhci_pipe *)xfer->ux_pipe;
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 	DPRINTFN(4, "xfer %p", xfer, 0, 0, 0);
@@ -1628,11 +1630,9 @@ xhci_clear_endpoint_stall_async(struct u
 		return USBD_IOERROR;
 	}
 
-	/* XXX never use up_async_task for incompatible type of function */
-	usb_init_task(&xfer->ux_pipe->up_async_task,
+	usb_init_task(&xp->xp_async_task,
 	    xhci_clear_endpoint_stall_async_task, xfer, USB_TASKQ_MPSAFE);
-	usb_add_task(xfer->ux_pipe->up_dev, &xfer->ux_pipe->up_async_task,
-	    USB_TASKQ_HC);
+	usb_add_task(xfer->ux_pipe->up_dev, &xp->xp_async_task, USB_TASKQ_HC);
 	DPRINTFN(4, "ends", 0, 0, 0, 0);
 
 	return USBD_NORMAL_COMPLETION;




--- src/sys/dev/usb/xhci.c.orig	2015-05-25 20:48:51.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2015-05-25 21:00:05.000000000 +0900
@@ -2064,6 +2064,14 @@ xhci_new_device(device_t parent, struct 
 		err = xhci_init_slot(dev, slot, route, rhport);
 		if (err) {
 			dev->ud_hcpriv = NULL;
+			/*
+			 * We have to disable_slot here because
+			 * xs->xs_idx == 0 when xhci_init_slot fails,
+			 * in that case usbd_remove_dev won't work.
+			 */
+			mutex_enter(&sc->sc_lock);
+			xhci_disable_slot(sc, slot);
+			mutex_exit(&sc->sc_lock);
 			goto bad;
 		}
 
@@ -2087,9 +2095,9 @@ xhci_new_device(device_t parent, struct 
 		/* 4.8.2.1 */
 		if (speed == USB_SPEED_SUPER) {
 			if (dd->bMaxPacketSize != 9) {
-				printf("%s: invalid mps 2^%u for SS ep0,"
+				printf("xhci%d: invalid mps 2^%u for SS ep0,"
 				    " using 512\n",
-				    device_xname(sc->sc_dev),
+				    device_unit(sc->sc_dev),
 				    dd->bMaxPacketSize);
 				dd->bMaxPacketSize = 9;
 			}




--- src/sys/dev/usb/xhci.c.orig	2015-05-25 21:00:05.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2015-05-25 21:16:40.000000000 +0900
@@ -1701,7 +1701,10 @@ xhci_handle_event(struct xhci_softc * co
 		xs = &sc->sc_slots[slot];
 		xr = &xs->xs_ep[dci].xe_tr;
 		/* sanity check */
-		KASSERT(xs->xs_idx != 0);
+		if (xs->xs_idx == 0 || xs->xs_idx >= sc->sc_maxslots) {
+			DPRINTFN(1, "invalid slot %u", xs->xs_idx, 0, 0, 0);
+			break;
+		}
 
 		if ((trb_3 & XHCI_TRB_3_ED_BIT) == 0) {
 			bus_addr_t trbp = xhci_ring_trbp(xr, 0);
@@ -1721,8 +1724,24 @@ xhci_handle_event(struct xhci_softc * co
 		} else {
 			xx = (void *)(uintptr_t)(trb_0 & ~0x3);
 		}
+		/* XXX this may not happen */
+		if (xx == NULL) {
+			DPRINTFN(1, "xfer done: xx is NULL", 0, 0, 0, 0);
+			break;
+		}
 		xfer = &xx->xx_xfer;
+		/* XXX this may happen when detaching */
+		if (xfer == NULL) {
+			DPRINTFN(1, "xfer done: xfer is NULL", 0, 0, 0, 0);
+			break;
+		}
 		DPRINTFN(14, "xfer %p", xfer, 0, 0, 0);
+		/* XXX I dunno why this happens */
+		if (!xfer->ux_pipe->up_repeat &&
+		    SIMPLEQ_EMPTY(&xfer->ux_pipe->up_queue)) {
+			DPRINTFN(1, "xfer done: xfer not started", 0, 0, 0, 0);
+			break;
+		}
 
 		if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {
 			DPRINTFN(14, "transfer event data: "




--- src/sys/dev/usb/xhci.c.orig	2015-05-25 21:16:40.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2015-05-25 21:23:00.000000000 +0900
@@ -1753,17 +1753,19 @@ xhci_handle_event(struct xhci_softc * co
 			}
 		}
 
-		if (trberr == XHCI_TRB_ERROR_SUCCESS ||
-		    trberr == XHCI_TRB_ERROR_SHORT_PKT) {
+		switch (trberr) {
+		case XHCI_TRB_ERROR_SHORT_PKT:
+		case XHCI_TRB_ERROR_SUCCESS:
 			xfer->ux_actlen =
 			    xfer->ux_length - XHCI_TRB_2_REM_GET(trb_2);
 			err = USBD_NORMAL_COMPLETION;
-		} else if (trberr == XHCI_TRB_ERROR_STALL ||
-			   trberr == XHCI_TRB_ERROR_BABBLE) {
-			err = USBD_STALLED;
-			xr->is_halted = true;
+			break;
+		case XHCI_TRB_ERROR_STALL:
+		case XHCI_TRB_ERROR_BABBLE:
 			DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
 			    trberr, slot, dci, 0);
+			xr->is_halted = true;
+			err = USBD_STALLED;
 #if 1 /* XXX experimental */
 			/*
 			 * Stalled endpoints can be recoverd by issuing
@@ -1780,12 +1782,22 @@ xhci_handle_event(struct xhci_softc * co
 			 */
 			xfer->ux_status = err;
 			xhci_clear_endpoint_stall_async(xfer);
+			return;
+#else
 			break;
 #endif
-		} else {
+		case XHCI_TRB_ERROR_CMD_ABORTED:
+		case XHCI_TRB_ERROR_STOPPED:
+			err = USBD_CANCELLED;
+			break;
+		case XHCI_TRB_ERROR_NO_SLOTS:
+			err = USBD_NO_ADDR;
+			break;
+		default:
 			DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
 			    trberr, slot, dci, 0);
 			err = USBD_IOERROR;
+			break;
 		}
 		xfer->ux_status = err;
 




--- src/sys/dev/usb/xhci.c.orig	2015-05-25 21:23:00.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2015-05-25 21:33:48.000000000 +0900
@@ -1010,31 +1010,52 @@ xhci_intr1(struct xhci_softc * const sc)
  *	ioctl interface uses these values too.
  * port_status speed
  *	definition: UPS_*_SPEED in usb.h
- *	They are used in usb_port_status_t.
- *	Some 3.0 values overlap with 2.0 values.
+ *	They are used in usb_port_status_t and valid only for USB 2.0.
+ *	Speed value is 0 for Super Speed or more.
+ *	Note that some 3.0 values overlap with 2.0 values.
  *	(e.g. 0x200 means UPS_POER_POWER_SS in SS and
  *	            means UPS_LOW_SPEED in HS.)
  *	port status sent from hub also uses these values.
- *	(but I've never seen UPS_SUPER_SPEED in port_status from hub.)
  * xspeed:
  *	definition: Protocol Speed ID (PSI) (xHCI 1.1 7.2.1)
  *	They are used in only slot context and PORTSC reg of xhci.
- *	The difference between usbdi speed and them are that
- *	FS and LS values are swapped.
+ *	The difference between usbdi speed and xspeed is
+ *	that FS and LS values are swapped.
  */
 
+/* convert usbdi speed to xspeed */
 static int
 xhci_speed2xspeed(int speed)
 {
 	switch (speed) {
 	case USB_SPEED_LOW:	return 2;
 	case USB_SPEED_FULL:	return 1;
-	case USB_SPEED_HIGH:	return 3;
-	case USB_SPEED_SUPER:	return 4;
-	default:
-		break;
+	default:		return speed;
+	}
+}
+
+/* convert xspeed to usbdi speed */
+static int
+xhci_xspeed2speed(int xspeed)
+{
+	switch (xspeed) {
+	case 1: return USB_SPEED_FULL;
+	case 2: return USB_SPEED_LOW;
+	default: return xspeed;
+	}
+}
+
+/* convert xspeed to port status speed */
+static int
+xhci_xspeed2psspeed(int xspeed)
+{
+	switch (xspeed) {
+	case 0: return 0;
+	case 1: return UPS_FULL_SPEED;
+	case 2: return UPS_LOW_SPEED;
+	case 3: return UPS_HIGH_SPEED;
+	default: return UPS_OTHER_SPEED;
 	}
-	return 0;
 }
 
 /* construct slot context */
@@ -1185,7 +1206,7 @@ xhci_configure_endpoint(struct usbd_pipe
 	if (xfertype != UE_ISOCHRONOUS)
 		cp[1] |= htole32(XHCI_EPCTX_1_CERR_SET(3));
 
-	if (speed == USB_SPEED_SUPER) {
+	if (USB_IS_SS(speed)) {
 		usbd_desc_iter_t iter;
 		const usb_cdc_descriptor_t *cdcd;
 		const usb_endpoint_ss_comp_descriptor_t * esscd = NULL;
@@ -1239,7 +1260,7 @@ xhci_configure_endpoint(struct usbd_pipe
 		} else {
 			ival = ival > 15 ? 15 : ival;
 		}
-		if (speed == USB_SPEED_SUPER) {
+		if (USB_IS_SS(speed)) {
 			if (maxb > 0)
 				mps = 1024;
 		} else {
@@ -1252,7 +1273,7 @@ xhci_configure_endpoint(struct usbd_pipe
 		    );
 		break;
 	case UE_CONTROL:
-		if (speed == USB_SPEED_SUPER)
+		if (USB_IS_SS(speed))
 			mps = 512;
 		else
 			mps = mps ? mps : 8;
@@ -1267,7 +1288,7 @@ xhci_configure_endpoint(struct usbd_pipe
 		} else {
 			ival = ival > 15 ? 15 : ival;
 		}
-		if (speed == USB_SPEED_SUPER) {
+		if (USB_IS_SS(speed)) {
 			mps = 1024;
 		} else {
 			mps = mps ? mps : 1024;
@@ -1277,7 +1298,7 @@ xhci_configure_endpoint(struct usbd_pipe
 		break;
 #endif
 	default:
-		if (speed == USB_SPEED_SUPER)
+		if (USB_IS_SS(speed))
 			mps = 1024;
 		else
 			mps = mps ? mps : 512;
@@ -1990,10 +2011,10 @@ xhci_new_device(device_t parent, struct 
 	dev->ud_ep0desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
 	dev->ud_ep0desc.bmAttributes = UE_CONTROL;
 	/* 4.3,  4.8.2.1 */
-	switch (speed) {
-	case USB_SPEED_SUPER:
+	if (USB_IS_SS(speed)) {
 		USETW(dev->ud_ep0desc.wMaxPacketSize, USB_3_MAX_CTRL_PACKET);
-		break;
+	} else
+	switch (speed) {
 	case USB_SPEED_FULL:
 		/* XXX using 64 as initial mps of ep0 in FS */
 	case USB_SPEED_HIGH:
@@ -2124,7 +2145,7 @@ xhci_new_device(device_t parent, struct 
 		if (err)
 			goto bad;
 		/* 4.8.2.1 */
-		if (speed == USB_SPEED_SUPER) {
+		if (USB_IS_SS(speed)) {
 			if (dd->bMaxPacketSize != 9) {
 				printf("xhci%d: invalid mps 2^%u for SS ep0,"
 				    " using 512\n",
@@ -2771,34 +2792,20 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 		}
 		v = xhci_op_read_4(sc, XHCI_PORTSC(index));
 		DPRINTFN(4, "getrhportsc %d %08x", index, v, 0, 0);
-		switch (XHCI_PS_SPEED_GET(v)) {
-		case 1:
-			i = UPS_FULL_SPEED;
-			break;
-		case 2:
-			i = UPS_LOW_SPEED;
-			break;
-		case 3:
-			i = UPS_HIGH_SPEED;
-			break;
-		case 4:
-			i = UPS_SUPER_SPEED;
-			break;
-		default:
-			i = 0;
-			break;
-		}
+		i = xhci_xspeed2psspeed(XHCI_PS_SPEED_GET(v));
 		if (v & XHCI_PS_CCS)	i |= UPS_CURRENT_CONNECT_STATUS;
 		if (v & XHCI_PS_PED)	i |= UPS_PORT_ENABLED;
 		if (v & XHCI_PS_OCA)	i |= UPS_OVERCURRENT_INDICATOR;
 		//if (v & XHCI_PS_SUSP)	i |= UPS_SUSPEND;
 		if (v & XHCI_PS_PR)	i |= UPS_RESET;
 		if (v & XHCI_PS_PP) {
-			if (i & UPS_SUPER_SPEED)
+			if (i & UPS_OTHER_SPEED)
 					i |= UPS_PORT_POWER_SS;
 			else
 					i |= UPS_PORT_POWER;
 		}
+		if (i & UPS_OTHER_SPEED)
+			i |= UPS_PORT_LS_SET(XHCI_PS_PLS_GET(v));
 		USETW(ps.wPortStatus, i);
 		i = 0;
 		if (v & XHCI_PS_CSC)    i |= UPS_C_CONNECT_STATUS;
@@ -2858,7 +2865,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 			xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
 			break;
 		case UHF_PORT_U1_TIMEOUT:
-			if (XHCI_PS_SPEED_GET(v) != 4) {
+			if (USB_IS_SS(xhci_xspeed2speed(XHCI_PS_SPEED_GET(v)))){
 				return -1;
 			}
 			port = XHCI_PORTPMSC(index);
@@ -2868,7 +2875,7 @@ xhci_roothub_ctrl(struct usbd_bus *bus, 
 			xhci_op_write_4(sc, port, v);
 			break;
 		case UHF_PORT_U2_TIMEOUT:
-			if (XHCI_PS_SPEED_GET(v) != 4) {
+			if (USB_IS_SS(xhci_xspeed2speed(XHCI_PS_SPEED_GET(v)))){
 				return -1;
 			}
 			port = XHCI_PORTPMSC(index);
--- src/sys/dev/usb/usb.h.orig	2015-04-07 01:29:01.000000000 +0900
+++ src/sys/dev/usb/usb.h	2015-05-14 08:05:42.000000000 +0900
@@ -561,7 +561,9 @@
 #define UPS_OVERCURRENT_INDICATOR	0x0008
 #define UPS_RESET			0x0010
 #define UPS_PORT_L1			0x0020
-#define UPS_PORT_LS_GET(x)		__SHIFTOUT(x, __BITS(8,5))
+#define UPS_PORT_LS_MASK		__BITS(8,5)
+#define UPS_PORT_LS_GET(x)		__SHIFTOUT(x, UPS_PORT_LS_MASK)
+#define UPS_PORT_LS_SET(x)		__SHIFTIN(x, UPS_PORT_LS_MASK)
 #define UPS_PORT_LS_U0			0x00
 #define UPS_PORT_LS_U1			0x01
 #define UPS_PORT_LS_U2			0x02
@@ -580,9 +582,9 @@
 #define UPS_FULL_SPEED			0x0000	/* for completeness */
 #define UPS_LOW_SPEED			0x0200
 #define UPS_HIGH_SPEED			0x0400
-#define UPS_SUPER_SPEED			0x0800
 #define UPS_PORT_TEST			0x0800
 #define UPS_PORT_INDICATOR		0x1000
+#define UPS_OTHER_SPEED			0x2000	/* currently NetBSD specific */
 	uWord		wPortChange;
 #define UPS_C_CONNECT_STATUS		0x0001
 #define UPS_C_PORT_ENABLED		0x0002
@@ -852,6 +854,7 @@
 #define USB_SPEED_FULL 2
 #define USB_SPEED_HIGH 3
 #define USB_SPEED_SUPER 4
+#define USB_IS_SS(X) ((X) == USB_SPEED_SUPER)
 	int		udi_power;	/* power consumption in mA, 0 if selfpowered */
 	int		udi_nports;
 	char		udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN];




--- src/sys/dev/pci/xhci_pci.c.orig	2015-04-07 01:28:57.000000000 +0900
+++ src/sys/dev/pci/xhci_pci.c	2015-05-24 00:23:37.000000000 +0900
@@ -1,4 +1,5 @@
 /*	$NetBSD: xhci_pci.c,v 1.4.2.2 2015/04/06 12:17:30 skrll Exp $	*/
+/*	OpenBSD: xhci_pci.c,v 1.4 2014/07/12 17:38:51 yuo Exp	*/
 
 /*
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -43,6 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: xhci_pci.c,v
 #include <sys/bus.h>
 
 #include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
 
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
@@ -52,6 +54,17 @@ __KERNEL_RCSID(0, "$NetBSD: xhci_pci.c,v
 #include <dev/usb/xhcireg.h>
 #include <dev/usb/xhcivar.h>
 
+struct xhci_pci_quirk {
+	pci_vendor_id_t		vendor;
+	pci_product_id_t	product;
+	int			quirks;
+};
+
+static const struct xhci_pci_quirk xhci_pci_quirks[] = {
+	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_CORE4G_M_XHCI,
+	    XHCI_QUIRK_FORCE_INTR },
+};
+
 struct xhci_pci_softc {
 	struct xhci_softc	sc_xhci;
 	pci_chipset_tag_t	sc_pc;
@@ -59,6 +72,18 @@ struct xhci_pci_softc {
 };
 
 static int
+xhci_pci_has_quirk(pci_vendor_id_t vendor, pci_product_id_t product)
+{
+	int i;
+
+	for (i = 0; i < __arraycount(xhci_pci_quirks); i++)
+		if (vendor == xhci_pci_quirks[i].vendor &&
+		    product == xhci_pci_quirks[i].product)
+			return xhci_pci_quirks[i].quirks;
+	return 0;
+}
+
+static int
 xhci_pci_match(device_t parent, cfdata_t match, void *aux)
 {
 	struct pci_attach_args *pa = (struct pci_attach_args *) aux;
@@ -71,6 +96,42 @@ xhci_pci_match(device_t parent, cfdata_t
 	return 0;
 }
 
+static int
+xhci_pci_port_route(struct xhci_pci_softc *psc)
+{
+	struct xhci_softc * const sc = &psc->sc_xhci;
+
+	pcireg_t val;
+
+	/*
+	 * Check USB3 Port Routing Mask register that indicates the ports
+	 * can be changed from OS, and turn on by USB3 Port SS Enable register.
+	 */
+	val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_USB3PRM);
+	aprint_debug_dev(sc->sc_dev,
+	    "USB3PRM / USB3.0 configurable ports: 0x%08x\n", val);
+
+	pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_USB3_PSSEN, val);
+	val = pci_conf_read(psc->sc_pc, psc->sc_tag,PCI_XHCI_INTEL_USB3_PSSEN);
+	aprint_debug_dev(sc->sc_dev,
+	    "USB3_PSSEN / Enabled USB3.0 ports under xHCI: 0x%08x\n", val);
+
+	/*
+	 * Check USB2 Port Routing Mask register that indicates the USB2.0
+	 * ports to be controlled by xHCI HC, and switch them to xHCI HC.
+	 */
+	val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_USB2PRM);
+	aprint_debug_dev(sc->sc_dev,
+	    "XUSB2PRM / USB2.0 ports can switch from EHCI to xHCI:"
+	    "0x%08x\n", val);
+	pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_XUSB2PR, val);
+	val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_XUSB2PR);
+	aprint_debug_dev(sc->sc_dev,
+	    "XUSB2PR / USB2.0 ports under xHCI: 0x%08x\n", val);
+
+	return 0;
+}
+
 static void
 xhci_pci_attach(device_t parent, device_t self, void *aux)
 {
@@ -92,6 +153,10 @@ xhci_pci_attach(device_t parent, device_
 
 	pci_aprint_devinfo(pa, "USB Controller");
 
+	/* Check for quirks */
+	sc->sc_quirks = xhci_pci_has_quirk(PCI_VENDOR(pa->pa_id),
+						PCI_PRODUCT(pa->pa_id));
+
 	/* check if memory space access is enabled */
 	csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
 #ifdef DEBUG
@@ -122,9 +187,9 @@ xhci_pci_attach(device_t parent, device_
 	psc->sc_pc = pc;
 	psc->sc_tag = tag;
 
-	hccparams = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0x10);
+	hccparams = bus_space_read_4(sc->sc_iot, sc->sc_ioh, XHCI_HCCPARAMS);
 
-	if (pci_dma64_available(pa) && ((hccparams&1)==1))
+	if (pci_dma64_available(pa) && (XHCI_HCC_AC64(hccparams) != 0))
 		sc->sc_bus.ub_dmatag = pa->pa_dmat64;
 	else
 		sc->sc_bus.ub_dmatag = pa->pa_dmat;
@@ -160,12 +225,24 @@ xhci_pci_attach(device_t parent, device_
 	    sc->sc_id_vendor);
 #endif
 
+	/* Intel chipset requires SuperSpeed enable and USB2 port routing */
+	switch (PCI_VENDOR(pa->pa_id)) {
+	case PCI_VENDOR_INTEL:
+		sc->sc_quirks |= XHCI_QUIRK_INTEL;
+		break;
+	default:
+		break;
+	}
+
 	err = xhci_init(sc);
 	if (err) {
 		aprint_error_dev(self, "init failed, error=%d\n", err);
 		goto fail;
 	}
 
+	if ((sc->sc_quirks & XHCI_QUIRK_INTEL) != 0)
+		xhci_pci_port_route(psc);
+
 	if (!pmf_device_register1(self, xhci_suspend, xhci_resume,
 	                          xhci_shutdown))
 		aprint_error_dev(self, "couldn't establish power handler\n");
--- src/sys/dev/usb/xhci.c.orig	2015-05-25 21:33:48.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2015-05-25 21:37:09.000000000 +0900
@@ -910,13 +910,13 @@ xhci_init(struct xhci_softc *sc)
 #endif
 
 	xhci_rt_write_4(sc, XHCI_IMAN(0), XHCI_IMAN_INTR_ENA);
-#ifdef XHCI_QUIRK_INTEL
 	if ((sc->sc_quirks & XHCI_QUIRK_INTEL) != 0)
 		/* Intel xhci needs interrupt rate moderated. */
 		xhci_rt_write_4(sc, XHCI_IMOD(0), XHCI_IMOD_DEFAULT_LP);
 	else
-#endif /* XHCI_QUIRK_INTEL */
 		xhci_rt_write_4(sc, XHCI_IMOD(0), 0);
+	aprint_debug_dev(sc->sc_dev, "setting IMOD %u\n",
+	    xhci_rt_read_4(sc, XHCI_IMOD(0)));
 
 	xhci_op_write_4(sc, XHCI_USBCMD, XHCI_CMD_INTE|XHCI_CMD_RS); /* Go! */
 	aprint_debug_dev(sc->sc_dev, "USBCMD %08"PRIx32"\n",
@@ -977,7 +977,6 @@ xhci_intr1(struct xhci_softc * const sc)
 
 	iman = xhci_rt_read_4(sc, XHCI_IMAN(0));
 	DPRINTFN(16, "IMAN0 %08x", iman, 0, 0, 0);
-#ifdef XHCI_QUIRK_FORCE_INTR
 
 	if (!(sc->sc_quirks & XHCI_QUIRK_FORCE_INTR)) {
 		if ((iman & XHCI_IMAN_INTR_PEND) == 0) {
@@ -985,11 +984,6 @@ xhci_intr1(struct xhci_softc * const sc)
 		}
 	}
 
-#else
-	if ((iman & XHCI_IMAN_INTR_PEND) == 0) {
-		return 0;
-	}
-#endif /* XHCI_QUIRK_FORCE_INTR */
 	xhci_rt_write_4(sc, XHCI_IMAN(0), iman);
 	iman = xhci_rt_read_4(sc, XHCI_IMAN(0));
 	DPRINTFN(16, "IMAN0 %08x", iman, 0, 0, 0);






Home | Main Index | Thread Index | Old Index