tech-kern archive

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

Re: Help: USB 3.0 xHCI driver does not support non-root hub



hi,

On 09/15/14 23:46, Ryo ONODERA wrote:
Hi,

Our xHCI USB 3.0 driver with Intel Lynx Point/Lynx Point-LP, Renesas uPD70202
and Fresco Logic 0x1b73/0x1100 xHCI chips does not support non-root hub
as following.
I believe our xHCI driver have no non-root hub support.

I have tested some USB 1.1/2.0/3.0 hubs, and gotten same results.
Address Device Command TRB execution just after Enable Slot Command TRB
execution fails with USB Transaction Error.

I got PARAMETER error when i connected usb 2.0 thumb drive to
my uPD720200 xhci via 2.0 hub.

I have spent some weeks, but I cannot find why Address Device Command fails.
(If your want to use Intel Lynx Point/Lynx Point-LP xHC, please
apply a patch in http://gnats.netbsd.org/49076.)

I think that's because incorrect route string (always 0x0) and
incorrect root hub port is set in slot context.

Anyone have a clue for xHCI's non-root hub support?
I really need any clue for non-root hub support.

Can you try this patch?

This patch tries to add route string support for hubs.
Caveats:
- SS hub is currently not supported.
  SS hub will work as HS hub.
  I'm not sure both of SS and HS hub in SS hub can be
  attached on one roothub port.
- Detaching hub may cause panic.
  xhci may try to transfer on unplugged port.
- HUB,MTT,TTT and TT* fields in slot context is not set.


--- src/sys/dev/usb/xhci.c.orig	2014-10-03 21:18:24.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2014-10-04 08:59:16.000000000 +0900
@@ -615,8 +760,12 @@ xhci_init(struct xhci_softc *sc)
XHCIHIST_FUNC(); XHCIHIST_CALLED(); +#if 0
+	sc->sc_bus.usbrev = USBREV_3_0;
+#else
 	/* XXX Low/Full/High speeds for now */
 	sc->sc_bus.usbrev = USBREV_2_0;
+#endif
cap = xhci_read_4(sc, XHCI_CAPLENGTH);
 	caplength = XHCI_CAP_CAPLENGTH(cap);
@@ -1139,8 +1449,7 @@ xhci_open(usbd_pipe_handle pipe)
 		return USBD_IOERROR;
/* Root Hub */
-	if (dev->depth == 0 && dev->powersrc->portno == 0 &&
-	    dev->speed != USB_SPEED_SUPER) {
+	if (dev->depth == 0 && dev->powersrc->portno == 0) {
 		switch (ed->bEndpointAddress) {
 		case USB_CONTROL_ENDPOINT:
 			pipe->methods = &xhci_root_ctrl_methods;
@@ -1194,13 +1631,24 @@ xhci_rhpsc(struct xhci_softc * const sc,
 	if (xfer == NULL)
 		return;
- if (!(port >= sc->sc_hs_port_start &&
-	    port < sc->sc_hs_port_start + sc->sc_hs_port_count))
-		return;
+	xfer->pipe->device->speed =
+	    XHCI_PS_SPEED_GET(xhci_op_read_4(sc, XHCI_PORTSC(port)));
- port -= sc->sc_hs_port_start;
-	port += 1;
-	DPRINTFN(4, "hs port %u status change", port, 0, 0, 0);
+	if (port >= sc->sc_hs_port_start &&
+	    port < sc->sc_hs_port_start + sc->sc_hs_port_count) {
+		port -= sc->sc_hs_port_start;
+		port += 1;
+		DPRINTFN(4, "hs port %u status change", port, 0, 0, 0);
+	} else if (port >= sc->sc_ss_port_start &&
+	    port < sc->sc_ss_port_start + sc->sc_ss_port_count) {
+		port -= sc->sc_ss_port_start;
+		port += 1;
+		DPRINTFN(4, "ss port %u status change", port, 0, 0, 0);
+	} else {
+		/* cannot happen */
+		DPRINTFN(0, "port %u out of range", port, 0, 0, 0);
+		return;
+	}
p = KERNADDR(&xfer->dmabuf, 0);
 	memset(p, 0, xfer->length);
@@ -1468,7 +1974,7 @@ xhci_new_device(device_t parent, usbd_bu
 	usbd_status err;
 	usb_device_descriptor_t *dd;
 	struct usbd_device *hub;
-	struct usbd_device *adev;
+	uint32_t route = 0;
 	int rhport = 0;
 	struct xhci_slot *xs;
 	uint32_t *cp;
@@ -1515,28 +2017,32 @@ xhci_new_device(device_t parent, usbd_bu
 	up->device = dev;
/* Locate root hub port */
-	for (adev = dev, hub = dev;
-	    hub != NULL;
-	    adev = hub, hub = hub->myhub) {
-		DPRINTFN(4, "hub %p", hub, 0, 0, 0);
-	}
-	DPRINTFN(4, "hub %p", hub, 0, 0, 0);
-
-	if (hub != NULL) {
-		for (int p = 0; p < hub->hub->hubdesc.bNbrPorts; p++) {
-			if (hub->hub->ports[p].device == adev) {
-				rhport = p;
-			}
-		}
-	} else {
-		rhport = port;
+	for (hub = dev; hub != NULL; hub = hub->myhub) {
+		uint32_t dep;
+
+		DPRINTFN(4, "hub %p depth %d upport %p upportno %d",
+		    hub, hub->depth, hub->powersrc,
+		    hub->powersrc ? hub->powersrc->portno : 0);
+
+		if (hub->powersrc == NULL)
+			continue;
+		dep = hub->depth;
+		if (dep == 0)
+			continue;
+
+		route |= hub->powersrc->portno << ((dep - 1) * 4);
 	}
+	DPRINTFN(4, "hub %p route %05x", hub, route, 0, 0);
+
 	if (speed == USB_SPEED_SUPER) {
-		rhport += sc->sc_ss_port_start - 1;
+		route = (route & ~0xf) |
+			(((route & 0xf) + sc->sc_ss_port_start - 1) & 0xf);
 	} else {
-		rhport += sc->sc_hs_port_start - 1;
+		route = (route & ~0xf) |
+			(((route & 0xf) + sc->sc_hs_port_start - 1) & 0xf);
 	}
-	DPRINTFN(4, "rhport %d", rhport, 0, 0, 0);
+	rhport = route & 0xf;
+	DPRINTFN(4, "rhport %d route %05x", rhport, route, 0, 0);
dev->speed = speed;
 	dev->langid = USBD_NOLANG;
@@ -1565,7 +2076,7 @@ xhci_new_device(device_t parent, usbd_bu
 		err = xhci_enable_slot(sc, &slot);
 		if (err)
 			return err;
-		err = xhci_init_slot(sc, slot, depth, speed, port, rhport);
+		err = xhci_init_slot(sc, slot, depth, speed, route, rhport);
 		if (err)
 			return err;
 		xs = &sc->sc_slots[slot];
@@ -1988,6 +2555,7 @@ xhci_init_slot(struct xhci_softc * const
 	cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
 	cp[0] = htole32(
 		XHCI_SCTX_0_CTX_NUM_SET(1) |
+		XHCI_SCTX_0_ROUTE_SET(port) |
 		XHCI_SCTX_0_SPEED_SET(xspeed)
 		);
 	cp[1] = htole32(
@@ -2144,6 +2871,8 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 	int len, value, index;
 	int l, totlen = 0;
 	int port, i;
+	int ridx;
+	int speed = xfer->pipe->device->speed;
 	uint32_t v;
XHCIHIST_FUNC(); XHCIHIST_CALLED();
@@ -2290,13 +3024,21 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER):
 		DPRINTFN(4, "UR_CLEAR_PORT_FEATURE port=%d feature=%d",
 			     index, value, 0, 0);
-		if (index < 1 || index > sc->sc_hs_port_count) {
+		if (speed == USB_SPEED_SUPER &&
+		    (index < 1 || index > sc->sc_ss_port_count)) {
+			err = USBD_IOERROR;
+			goto ret;
+		} else if (speed != USB_SPEED_SUPER &&
+		    (index < 1 || index > sc->sc_hs_port_count)) {
 			err = USBD_IOERROR;
 			goto ret;
 		}
-		port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
+		if (speed == USB_SPEED_SUPER)
+			port = XHCI_PORTSC(sc->sc_ss_port_start - 1 + index);
+		else
+			port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
 		v = xhci_op_read_4(sc, port);
-		DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
+		DPRINTFN(4, "portsc(%u)=0x%08x", index, v, 0, 0);
 		v &= ~XHCI_PS_CLEAR;
 		switch (value) {
 		case UHF_PORT_ENABLE:
@@ -2335,6 +3077,35 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 			err = USBD_IOERROR;
 			goto ret;
 		}
+#if 0
+		if (speed == USB_SPEED_SUPER) {
+			usb_hub_ss_descriptor_t hubssd;
+	
+			hubssd = xhci_hubssd;
+			hubssd.bNbrPorts = sc->sc_ss_port_count;
+			/* XXX */
+			USETW(hubssd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
+			hubssd.bPwrOn2PwrGood = 200;
+			hubssd.DeviceRemovable[0] = 0;
+			hubssd.DeviceRemovable[1] = 0;
+			l = min(len, hubssd.bLength);
+			totlen = l;
+			memcpy(buf, &hubssd, l);
+		} else {
+			hubd = xhci_hubd;
+			hubd.bNbrPorts = sc->sc_hs_port_count;
+			USETW(hubd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
+			hubd.bPwrOn2PwrGood = 200;
+			for (i = 0, l = sc->sc_hs_port_count;
+			    l > 0; i++, l -= 8)
+				/* XXX can't find out? */
+				hubd.DeviceRemovable[i++] = 0;
+			hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
+			l = min(len, hubd.bDescLength);
+			totlen = l;
+			memcpy(buf, &hubd, l);
+		}
+#else
 		hubd = xhci_hubd;
 		hubd.bNbrPorts = sc->sc_hs_port_count;
 		USETW(hubd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
@@ -2345,6 +3116,7 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 		l = min(len, hubd.bDescLength);
 		totlen = l;
 		memcpy(buf, &hubd, l);
+#endif
 		break;
 	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
 		if (len != 4) {
@@ -2364,10 +3129,14 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 			err = USBD_IOERROR;
 			goto ret;
 		}
-		v = xhci_op_read_4(sc, XHCI_PORTSC(sc->sc_hs_port_start - 1 +
-		    index));
+		if (speed == USB_SPEED_SUPER) {
+			ridx = sc->sc_ss_port_start - 1 + index;
+		} else {
+			ridx = sc->sc_hs_port_start - 1 + index;
+		}
+		v = xhci_op_read_4(sc, XHCI_PORTSC(ridx));
 		DPRINTFN(4, "READ_CLASS_OTHER GET_STATUS PORTSC %d (%d) %08x",
-		    index, sc->sc_hs_port_start - 1 + index, v, 0);
+		    index, ridx, v, 0);
 		switch (XHCI_PS_SPEED_GET(v)) {
 		case 1:
 			i = UPS_FULL_SPEED;
@@ -2378,6 +3147,9 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 		case 3:
 			i = UPS_HIGH_SPEED;
 			break;
+		case 4:
+			i = UPS_SUPER_SPEED;
+			break;
 		default:
 			i = 0;
 			break;
@@ -2405,11 +3185,19 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
 		break;
 	case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
-		if (index < 1 || index > sc->sc_hs_port_count) {
+		if (speed == USB_SPEED_SUPER &&
+		    (index < 1 || index > sc->sc_ss_port_count)) {
+			err = USBD_IOERROR;
+			goto ret;
+		} else if (speed != USB_SPEED_SUPER &&
+		    (index < 1 || index > sc->sc_hs_port_count)) {
 			err = USBD_IOERROR;
 			goto ret;
 		}
-		port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
+		if (speed == USB_SPEED_SUPER)
+			port = XHCI_PORTSC(sc->sc_ss_port_start - 1 + index);
+		else
+			port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
 		v = xhci_op_read_4(sc, port);
 		DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
 		v &= ~XHCI_PS_CLEAR;


Thanks,
--
t-hash


Home | Main Index | Thread Index | Old Index