tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: patch: 3.0 hub support for xhci
Hello,
This patch tries to support USB 3.0 for xhci.
xhci is still at best experimental.
Don't use it on production servers even though it looks work well.
Fixes:
- USB hubs should work.
- The root hub of xhci is now changed to have separated SS and HS ports,
so that SS and HS hubs in 3.0 hub are hung from SS and HS roothub port
respectively.
- Fix more for FS and LS device recognition.
- Fix device recognition at boot.
I changed to force-rescan all ports of xhci root hub recursively.
- Temporarily set IMOD to 160 (25000 irq/sec).
Intel PantherPoint/LynxPoint/BayTrail need interrupt rate capped,
otherwise some devices seem to freeze.
This value is taken from linux xhci.c, but I'm not sure this is optimal.
- Temporarily USBHIST_CALLED in xhci_init() is disabled.
If USBHIST_CALLED is called before USBHIST_INIT, it panics.
Something has been changed recently.
- Support WRC PLC CEC port status changes.
- usb_bos_descriptor_t *bdesc is added to usbd_device_handle and
BOS descr is read in usb_subr.c if SS.
- The name of USB2 Extension descr is renamed to
usb_devcap_usb2ext_descriptor_t from usb_usb2ext_descriptor_t,
because this is one of device capability descriptors, which is
contained in BOS descriptor. (USB 3.0 9.6.2.1)
- Speed definitions of LS and SS in usb_devcap_ss_descriptor_t
were swapped. (shown in USB 3.0 9.6.2.2 Table 9-13)
- Apply fixed value as initial mps for Control endpoint.
Known bugs:
- HS hub under 3.0 port is disconnected and reconnected every
several minutes repeatedly.
- Detaching hubs or devices may cause panic or hang up.
It happens especially when the hub that hangs many devices is
disconnected.
I've added usb_transfer_complete with USBD_CANCELLED to
xhci_device_{ctrl,bulk}_abort(), like device_intr_abort does,
that might slightly reduce panic.
- Power management is not implemented.
- Some xhci chip recognizes ports as 'connected' but
'connect/status change' (CSC) bit not set randomly at boot.
This happens on my xhci expansion card with hub chip.
uhub ignores ports without CSC bit, so cannot detect hub on this card.
I'm not sure what is culprit.
- Size of DeviceRemovable in usb_hub_ss_descriptor_t should be expanded
from 2 to 32 as num of ports on root hub may exceeds 15.
- xhci_do_command may fire KASSERT(sc->sc_command_addr == 0).
I'm not sure yet what breaks serialization.
Misc bugs:
- Closing pipe does not work correctly,
e.g. ifconfig axen0 up -> down -> up won't work.
- Most of my 3.0 umass devices does not work due to STALL error.
They don't understand MODE_SENSE_{6,10} command but stalls.
To recover stalled ep the driver shall issue reset_endpoint and
set_dequeue commands, however, xhci_do_command calls cv_timedwait
that is not allowed to be called from softint context as mentioned
in softint(9).
This is because usb_transfer_complete is called from softint context.
I added experimental recovery code using usb_add_task, but
I think xhci_handle_event should be changed to be called from
thread context. (e.g. replacing usb_schedsoftint with usb_add_task,
however, usb_add_task needs usbd_device_handle as one of args,
which is difficult to prepare in xhci_intr.)
- xhci.c cannot handle cross-64k transfer yet.
- usbdevs(8) does not report correctly if num of ports > 16.
Size of udi_ports in struct usb_device_info should be
expanded from 16 to 256. Needs compat treatment.
- Memory leaks here and there in error and detach paths.
- Slot leaks.
Devices cannot be added more than 32 times on xhci.
I added experimental code that disables slot and frees ring memory
when ctrl endpoint is closed.
- Conexant CX93010 umodem is not recognized (fail with XACT).
- may not work on big endian machines.
- Address of root hub is 0.
- ep->refcnt in usbd_setup_pipe_flags() is not decremented when
it fails to open pipe.
--
t-hash
--- src/sys/dev/usb/uhub.c.orig 2014-09-09 11:25:38.000000000 +0900
+++ src/sys/dev/usb/uhub.c 2014-11-18 23:50:03.000000000 +0900
@@ -38,12 +38,15 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126 2014/08/13 06:26:32 skrll Exp $");
+#include "opt_usb.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/proc.h>
+#include <sys/sysctl.h>
#include <sys/bus.h>
@@ -52,14 +55,42 @@ __KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.1
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdivar.h>
-#ifdef UHUB_DEBUG
-#define DPRINTF(x) if (uhubdebug) printf x
-#define DPRINTFN(n,x) if (uhubdebug>(n)) printf x
-int uhubdebug = 0;
-#else
+#if !(defined(USB_DEBUG) && defined(UHUB_DEBUG))
+#define uhubdebug 0
#define DPRINTF(x)
#define DPRINTFN(n,x)
-#endif
+#else
+static int uhubdebug = 0;
+#define DPRINTF(x) if (uhubdebug) printf x
+#define DPRINTFN(n,x) if (uhubdebug>(n)) printf x
+
+SYSCTL_SETUP(sysctl_hw_uhub_setup, "sysctl hw.uhub setup")
+{
+ int err;
+ const struct sysctlnode *rnode;
+ const struct sysctlnode *cnode;
+
+ err = sysctl_createv(clog, 0, NULL, &rnode,
+ CTLFLAG_PERMANENT, CTLTYPE_NODE, "uhub",
+ SYSCTL_DESCR("uhub global controls"),
+ NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
+
+ if (err)
+ goto fail;
+
+ /* control debugging printfs */
+ err = sysctl_createv(clog, 0, &rnode, &cnode,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
+ "debug", SYSCTL_DESCR("Enable debugging output"),
+ NULL, 0, &uhubdebug, sizeof(uhubdebug), CTL_CREATE, CTL_EOL);
+ if (err)
+ goto fail;
+
+ return;
+fail:
+ aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err);
+}
+#endif /* !(UHUB_DEBUG && USB_DEBUG) */
struct uhub_softc {
device_t sc_dev; /* base device */
@@ -73,11 +104,13 @@ struct uhub_softc {
size_t sc_statuslen;
int sc_explorepending;
int sc_isehciroothub; /* see comment in uhub_intr() */
+ int sc_isxhciroothub;
u_char sc_running;
};
-#define UHUB_IS_HIGH_SPEED(sc) ((sc)->sc_proto != UDPROTO_FSHUB)
+#define UHUB_IS_HIGH_SPEED(sc) \
+ ((sc)->sc_proto == UDPROTO_HSHUBSTT || (sc)->sc_proto == UDPROTO_HSHUBMTT)
#define UHUB_IS_SINGLE_TT(sc) ((sc)->sc_proto == UDPROTO_HSHUBSTT)
#define PORTSTAT_ISSET(sc, port) \
@@ -112,6 +145,97 @@ CFATTACH_DECL2_NEW(uroothub, sizeof(stru
*/
int uhub_ubermatch = 0;
+static usbd_status
+usbd_get_hub_desc(usbd_device_handle dev, usb_hub_descriptor_t *hd, int speed)
+{
+ usb_device_request_t req;
+ usbd_status err;
+ int nports;
+
+ /* don't issue UDESC_HUB to SS hub, or it would stall */
+ if (dev->speed == USB_SPEED_SUPER) {
+#if 1
+ union {
+ usb_hub_ss_descriptor_t hd_ss;
+ uint8_t hd_buf[USB_HUB_SS_DESCRIPTOR_SIZE+32-2];
+ } uhd_ss;
+#define hssd uhd_ss.hd_ss
+#else
+ usb_hub_ss_descriptor_t hssd;
+#endif
+ int rmvlen;
+
+ /* XXX: should add member hubssdesc to usbd_hub ? */
+#if 1
+ memset(&uhd_ss, 0, sizeof(uhd_ss));
+#else
+ memset(&hssd, 0, sizeof(hssd));
+#endif
+ req.bmRequestType = UT_READ_CLASS_DEVICE;
+ req.bRequest = UR_GET_DESCRIPTOR;
+ USETW2(req.wValue, UDESC_SS_HUB, 0);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, USB_HUB_SS_DESCRIPTOR_SIZE);
+ DPRINTFN(1,("%s: getting sshub descriptor\n", __func__));
+ err = usbd_do_request(dev, &req, &hssd);
+ nports = hssd.bNbrPorts;
+ rmvlen = (nports + 7) / 8;
+ if (!err && dev->depth == 0 && nports > UHD_SS_NPORTS_MAX) {
+ USETW(req.wLength,
+ USB_HUB_SS_DESCRIPTOR_SIZE +
+ (rmvlen > 2 ? rmvlen : 2) - 2);
+ err = usbd_do_request(dev, &req, &hssd);
+ }
+ if (dev->depth != 0 && nports > UHD_SS_NPORTS_MAX) {
+ DPRINTF(("%s: num of ports %d exceeds maxports %d\n",
+ __func__,
+ nports, UHD_SS_NPORTS_MAX));
+ nports = hd->bNbrPorts = UHD_SS_NPORTS_MAX;
+ }
+ hd->bDescLength = USB_HUB_DESCRIPTOR_SIZE +
+ (rmvlen > 1 ? rmvlen : 1) - 1;
+ memcpy(hd->DeviceRemovable, hssd.DeviceRemovable, rmvlen);
+ hd->bDescriptorType = hssd.bDescriptorType;
+ hd->bNbrPorts = hssd.bNbrPorts;
+ hd->wHubCharacteristics[0] = hssd.wHubCharacteristics[0];
+ hd->wHubCharacteristics[1] = hssd.wHubCharacteristics[1];
+ hd->bPwrOn2PwrGood = hssd.bPwrOn2PwrGood;
+ hd->bHubContrCurrent = hssd.bHubContrCurrent;
+#if 1
+#undef hssd
+#endif
+ } else {
+ req.bmRequestType = UT_READ_CLASS_DEVICE;
+ req.bRequest = UR_GET_DESCRIPTOR;
+ USETW2(req.wValue, UDESC_HUB, 0);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
+ DPRINTFN(1,("%s: getting hub descriptor\n", __func__));
+ err = usbd_do_request(dev, &req, hd);
+ nports = hd->bNbrPorts;
+ if (!err && nports > 7) {
+ USETW(req.wLength,
+ USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
+ err = usbd_do_request(dev, &req, hd);
+ }
+ }
+
+ return err;
+}
+
+static usbd_status
+usbd_set_hub_depth(usbd_device_handle dev, int depth)
+{
+ usb_device_request_t req;
+
+ req.bmRequestType = UT_WRITE_CLASS_DEVICE;
+ req.bRequest = UR_SET_HUB_DEPTH;
+ USETW(req.wValue, depth);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, 0);
+ return usbd_do_request(dev, &req, 0);
+}
+
int
uhub_match(device_t parent, cfdata_t match, void *aux)
{
@@ -142,7 +266,6 @@ uhub_attach(device_t parent, device_t se
char *devinfop;
usbd_status err;
struct usbd_hub *hub = NULL;
- usb_device_request_t req;
usb_hub_descriptor_t hubdesc;
int p, port, nports, nremov, pwrdly;
usbd_interface_handle iface;
@@ -182,18 +305,9 @@ uhub_attach(device_t parent, device_t se
}
/* Get hub descriptor. */
- req.bmRequestType = UT_READ_CLASS_DEVICE;
- req.bRequest = UR_GET_DESCRIPTOR;
- USETW2(req.wValue, UDESC_HUB, 0);
- USETW(req.wIndex, 0);
- USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
- DPRINTFN(1,("%s: getting hub descriptor\n", __func__));
- err = usbd_do_request(dev, &req, &hubdesc);
+ memset(&hubdesc, 0, sizeof(hubdesc));
+ err = usbd_get_hub_desc(dev, &hubdesc, dev->speed);
nports = hubdesc.bNbrPorts;
- if (!err && nports > 7) {
- USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
- err = usbd_do_request(dev, &req, &hubdesc);
- }
if (err) {
DPRINTF(("%s: getting hub descriptor failed, error=%s\n",
device_xname(sc->sc_dev), usbd_errstr(err)));
@@ -221,6 +335,15 @@ uhub_attach(device_t parent, device_t se
hub->explore = uhub_explore;
hub->hubdesc = hubdesc;
+ if (dev->speed == USB_SPEED_SUPER && dev->depth != 0) {
+ aprint_debug_dev(self, "setting hub depth %u\n", dev->depth-1);
+ err = usbd_set_hub_depth(dev, dev->depth - 1);
+ if (err) {
+ aprint_error_dev(self, "can't set depth\n");
+ goto bad;
+ }
+ }
+
/* Set up interrupt pipe. */
err = usbd_device2interface_handle(dev, 0, &iface);
if (err) {
@@ -253,6 +376,8 @@ uhub_attach(device_t parent, device_t se
goto bad;
if (device_is_a(device_parent(device_parent(sc->sc_dev)), "ehci"))
sc->sc_isehciroothub = 1;
+ if (device_is_a(device_parent(device_parent(sc->sc_dev)), "xhci"))
+ sc->sc_isxhciroothub = 1;
/* force initial scan */
memset(sc->sc_status, 0xff, sc->sc_statuslen);
@@ -280,9 +405,10 @@ uhub_attach(device_t parent, device_t se
* These are the events on the bus when a hub is attached:
* Get device and config descriptors (see attach code)
* Get hub descriptor (see above)
+ * Set hub depth (if super speed)
* For all ports
* turn on power
- * wait for power to become stable
+ * wait for power to become stable
* (all below happens in explore code)
* For all ports
* clear C_PORT_CONNECTION
@@ -338,7 +464,8 @@ uhub_attach(device_t parent, device_t se
if (err)
aprint_error_dev(self, "port %d power on failed, %s\n",
port, usbd_errstr(err));
- DPRINTF(("usb_init_port: turn on port %d power\n", port));
+ DPRINTF(("%s: turn on port %d power\n",
+ device_xname(sc->sc_dev), port));
}
/* Wait for stable power if we are not a root hub */
@@ -376,7 +503,8 @@ uhub_explore(usbd_device_handle dev)
int port;
int change, status, reconnect;
- DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));
+ DPRINTFN(10, ("uhub_explore dev=%p addr=%d speed=%u at %s\n",
+ dev, dev->address, dev->speed, device_xname(sc->sc_dev)));
if (!sc->sc_running)
return (USBD_NOT_STARTED);
@@ -396,6 +524,8 @@ uhub_explore(usbd_device_handle dev)
/* just acknowledge */
status = UGETW(hs.wHubStatus);
change = UGETW(hs.wHubChange);
+ DPRINTF(("%s: hub s/c=%x/%x\n",
+ device_xname(sc->sc_dev), status, change));
if (change & UHS_LOCAL_POWER)
usbd_clear_hub_feature(dev,
UHF_C_HUB_LOCAL_POWER);
@@ -424,10 +554,8 @@ uhub_explore(usbd_device_handle dev)
}
status = UGETW(up->status.wPortStatus);
change = UGETW(up->status.wPortChange);
-#if 0
- printf("%s port %d: s/c=%x/%x\n",
- device_xname(sc->sc_dev), port, status, change);
-#endif
+ DPRINTF(("%s port %d: s/c=%x/%x\n",
+ device_xname(sc->sc_dev), port, status, change));
}
if (!change && !reconnect) {
/* No status change, just do recursive explore. */
@@ -460,6 +588,19 @@ uhub_explore(usbd_device_handle dev)
port);
}
}
+#if 1
+ if (change & UPS_C_PORT_RESET)
+ usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
+#endif
+ if (change & UPS_C_BH_PORT_RESET)
+ usbd_clear_port_feature(dev, port,
+ UHF_C_BH_PORT_RESET);
+ if (change & UPS_C_PORT_LINK_STATE)
+ usbd_clear_port_feature(dev, port,
+ UHF_C_PORT_LINK_STATE);
+ if (change & UPS_C_PORT_CONFIG_ERROR)
+ usbd_clear_port_feature(dev, port,
+ UHF_C_PORT_CONFIG_ERROR);
/* XXX handle overcurrent and resume events! */
@@ -500,7 +641,16 @@ uhub_explore(usbd_device_handle dev)
/* Connected */
- if (!(status & UPS_PORT_POWER))
+ DPRINTF(("%s: dev->speed=%u dev->depth=%u\n",
+ device_xname(sc->sc_dev), dev->speed, dev->depth));
+ if ((!(status & UPS_PORT_POWER) &&
+ /* check POWER for root/non-root hub if non-SS */
+ ((dev->depth == 0 && !(status & UPS_SUPER_SPEED)) ||
+ (dev->depth != 0 && dev->speed != USB_SPEED_SUPER))) ||
+ /* check POWER_SS for root/non-root hub if SS */
+ (!(status & UPS_PORT_POWER_SS) &&
+ ((dev->depth == 0 && (status & UPS_SUPER_SPEED)) ||
+ (dev->depth != 0 && dev->speed == USB_SPEED_SUPER))))
aprint_normal_dev(sc->sc_dev,
"strange, connected port %d has no power\n", port);
@@ -522,6 +672,8 @@ uhub_explore(usbd_device_handle dev)
}
status = UGETW(up->status.wPortStatus);
change = UGETW(up->status.wPortChange);
+ DPRINTF(("%s port %d reset: s/c=%x/%x\n",
+ device_xname(sc->sc_dev), port, status, change));
if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
/* Nothing connected, just ignore it. */
#ifdef DIAGNOSTIC
@@ -540,8 +692,9 @@ uhub_explore(usbd_device_handle dev)
}
/* Figure out device speed */
-#if 0
- if (status & UPS_SUPER_SPEED)
+#if 1
+ if ((status & UPS_SUPER_SPEED) ||
+ (dev->speed == USB_SPEED_SUPER && dev->depth != 0))
speed = USB_SPEED_SUPER;
else
#endif
@@ -551,6 +704,7 @@ uhub_explore(usbd_device_handle dev)
speed = USB_SPEED_LOW;
else
speed = USB_SPEED_FULL;
+ DPRINTF(("%s: speed %u\n", device_xname(sc->sc_dev), speed));
/* Get device info and set its address. */
err = usbd_new_device(sc->sc_dev, dev->bus,
dev->depth + 1, speed, port, up);
@@ -578,7 +732,7 @@ uhub_explore(usbd_device_handle dev)
}
}
/* enable status change notifications again */
- if (!sc->sc_isehciroothub)
+ if (!sc->sc_isehciroothub && !sc->sc_isxhciroothub)
memset(sc->sc_status, 0, sc->sc_statuslen);
sc->sc_explorepending = 0;
return (USBD_NORMAL_COMPLETION);
@@ -726,4 +880,12 @@ uhub_intr(usbd_xfer_handle xfer, usbd_pr
if (status == USBD_NORMAL_COMPLETION && sc->sc_explorepending &&
sc->sc_isehciroothub)
usb_needs_explore(sc->sc_hub);
+ /*
+ * XXX force re-scan all ports of xhci root hub
+ */
+ if (status == USBD_NORMAL_COMPLETION && sc->sc_explorepending &&
+ sc->sc_isxhciroothub) {
+ memset(sc->sc_status, 0xff, sc->sc_statuslen);
+ usb_needs_explore(sc->sc_hub);
+ }
}
--- src/sys/dev/usb/usb.h.orig 2014-11-09 08:28:09.000000000 +0900
+++ src/sys/dev/usb/usb.h 2014-11-16 12:48:52.000000000 +0900
@@ -260,6 +263,7 @@ typedef struct {
#define UC_REMOTE_WAKEUP 0x20
uByte bMaxPower; /* max current in 2 mA units */
#define UC_POWER_FACTOR 2
+#define UC_POWER_FACTOR_SS 8
} UPACKED usb_config_descriptor_t;
#define USB_CONFIG_DESCRIPTOR_SIZE 9
@@ -330,6 +334,7 @@ typedef struct {
} UPACKED usb_endpoint_ss_comp_descriptor_t;
#define USB_ENDPOINT_SS_COMP_DESCRIPTOR_SIZE 6
+/* USB 3.0 9.6.2, Table 9-12 */
typedef struct {
uByte bLength;
uByte bDescriptorType;
@@ -338,10 +343,12 @@ typedef struct {
} UPACKED usb_bos_descriptor_t;
#define USB_BOS_DESCRIPTOR_SIZE 5
+/* common members of device capability descriptors */
typedef struct {
uByte bLength;
uByte bDescriptorType;
uByte bDevCapabilityType;
+/* Table 9-14 */
#define USB_DEVCAP_RESERVED 0x00
#define USB_DEVCAP_WUSB 0x01
#define USB_DEVCAP_USB2EXT 0x02
@@ -357,17 +364,19 @@ typedef struct {
#define USB_DEVCAP_WUSB_EXT 0x0c
/* data ... */
} UPACKED usb_device_capability_descriptor_t;
-#define USB_DEVICE_CAPABILITY_DESCRIPTOR_SIZE 3 /* variable length */
+#define USB_DEVICE_CAPABILITY_DESCRIPTOR_SIZE 3 /* at least */
+/* 9.6.2.1 */
typedef struct {
uByte bLength;
uByte bDescriptorType;
uByte bDevCapabilityType;
uDWord bmAttributes;
#define USB_DEVCAP_USB2EXT_LPM __BIT(1)
-} UPACKED usb_usb2ext_descriptor_t;
+} UPACKED usb_devcap_usb2ext_descriptor_t;
#define USB_DEVCAP_USB2EXT_DESCRIPTOR_SIZE 7
+/* 9.6.2.2 */
typedef struct {
uByte bLength;
uByte bDescriptorType;
@@ -375,16 +384,17 @@ typedef struct {
uByte bmAttributes;
#define USB_DEVCAP_SS_LTM __BIT(1)
uWord wSpeedsSupported;
-#define USB_DEVCAP_SS_SPEED_SS __BIT(0)
+#define USB_DEVCAP_SS_SPEED_LS __BIT(0)
#define USB_DEVCAP_SS_SPEED_FS __BIT(1)
#define USB_DEVCAP_SS_SPEED_HS __BIT(2)
-#define USB_DEVCAP_SS_SPEED_LS __BIT(3)
+#define USB_DEVCAP_SS_SPEED_SS __BIT(3)
uByte bFunctionalitySupport;
uByte bU1DevExitLat;
uWord wU2DevExitLat;
} UPACKED usb_devcap_ss_descriptor_t;
#define USB_DEVCAP_SS_DESCRIPTOR_SIZE 10
+/* 9.6.2.4 */
typedef struct {
uByte bLength;
uByte bDescriptorType;
@@ -749,7 +759,9 @@ typedef struct {
#endif
#define USB_MIN_POWER 100 /* mA */
+#define USB_MIN_POWER_SS 150 /* mA */
#define USB_MAX_POWER 500 /* mA */
+#define USB_MAX_POWER_SS 900 /* mA */
#define USB_BUS_RESET_DELAY 100 /* ms XXX?*/
--- src/sys/dev/usb/usb_subr.c.orig 2014-09-22 02:57:10.000000000 +0900
+++ src/sys/dev/usb/usb_subr.c 2014-11-14 19:15:27.000000000 +0900
@@ -531,6 +531,7 @@ usbd_status
usbd_set_config_index(usbd_device_handle dev, int index, int msg)
{
usb_config_descriptor_t cd, *cdp;
+ usb_bos_descriptor_t bd, *bdp = NULL;
usbd_status err;
int i, ifcidx, nifc, len, selfpowered, power;
@@ -597,6 +598,42 @@ usbd_set_config_index(usbd_device_handle
goto bad;
}
+ if (dev->speed == USB_SPEED_SUPER) {
+ /* get short bos desc */
+ err = usbd_get_bos_desc(dev, index, &bd);
+ if (err) {
+ DPRINTF(("usbd_set_config_index: get_bos_desc=%d\n",
+ err));
+ goto bad;
+ }
+ len = UGETW(bd.wTotalLength);
+ bdp = malloc(len, M_USB, M_NOWAIT);
+ if (bdp == NULL) {
+ err = USBD_NOMEM;
+ goto bad;
+ }
+
+ /* Get the full desc */
+ for (i = 0; i < 3; i++) {
+ err = usbd_get_desc(dev, UDESC_BOS, index, len, bdp);
+ if (!err)
+ break;
+ usbd_delay_ms(dev, 200);
+ }
+ if (err) {
+ DPRINTF(("usbd_set_config_index: get_bos_desc=%d\n",
+ err));
+ goto bad;
+ }
+ if (bdp->bDescriptorType != UDESC_BOS) {
+ DPRINTFN(-1,("usbd_set_config_index: bad desc %d\n",
+ bdp->bDescriptorType));
+ err = USBD_INVAL;
+ goto bad;
+ }
+ }
+ dev->bdesc = bdp;
+
/*
* Figure out if the device is self or bus powered.
*/
@@ -689,6 +726,10 @@ usbd_set_config_index(usbd_device_handle
bad:
free(cdp, M_USB);
+ if (bdp != NULL) {
+ free(bdp, M_USB);
+ dev->bdesc = NULL;
+ }
return (err);
}
@@ -1126,7 +1167,7 @@ usbd_new_device(device_t parent, usbd_bu
goto found;
}
}
- panic("usbd_new_device: cannot find HS port\n");
+ panic("usbd_new_device: cannot find HS port");
found:
DPRINTFN(1,("usbd_new_device: high speed port %d\n", p));
} else {
@@ -1415,6 +1456,13 @@ usbd_fill_deviceinfo(usbd_device_handle
err = USB_PORT_ENABLED;
else if (s & UPS_SUSPEND)
err = USB_PORT_SUSPENDED;
+ /*
+ * UPS_PORT_POWER_SS is available only
+ * if SS, otherwise it means UPS_LOW_SPEED.
+ */
+ else if ((s & UPS_PORT_POWER_SS) &&
+ dev->speed == USB_SPEED_SUPER)
+ err = USB_PORT_POWERED;
else if (s & UPS_PORT_POWER)
err = USB_PORT_POWERED;
else
--- src/sys/dev/usb/usbdi_util.c.orig 2014-09-13 22:14:45.000000000 +0900
+++ src/sys/dev/usb/usbdi_util.c 2014-11-13 07:56:59.000000000 +0900
@@ -105,6 +105,33 @@ usbd_get_config_desc_full(usbd_device_ha
}
usbd_status
+usbd_get_bos_desc(usbd_device_handle dev, int confidx,
+ usb_bos_descriptor_t *d)
+{
+ usbd_status err;
+
+ DPRINTFN(3,("usbd_get_config_desc: confidx=%d\n", confidx));
+ err = usbd_get_desc(dev, UDESC_BOS, confidx,
+ USB_BOS_DESCRIPTOR_SIZE, d);
+ if (err)
+ return (err);
+ if (d->bDescriptorType != UDESC_BOS) {
+ DPRINTFN(-1,("usbd_get_bos_desc: confidx=%d, bad desc "
+ "len=%d type=%d\n",
+ confidx, d->bLength, d->bDescriptorType));
+ return (USBD_INVAL);
+ }
+ return (USBD_NORMAL_COMPLETION);
+}
+
+usbd_status
+usbd_get_bos_desc_full(usbd_device_handle dev, int conf, void *d, int size)
+{
+ DPRINTFN(3,("usbd_get_bos_desc_full: conf=%d\n", conf));
+ return (usbd_get_desc(dev, UDESC_BOS, conf, size, d));
+}
+
+usbd_status
usbd_get_device_desc(usbd_device_handle dev, usb_device_descriptor_t *d)
{
DPRINTFN(3,("usbd_get_device_desc:\n"));
--- src/sys/dev/usb/usbdi_util.h.orig 2013-09-28 09:25:34.000000000 +0900
+++ src/sys/dev/usb/usbdi_util.h 2014-11-13 07:59:24.000000000 +0900
@@ -40,6 +40,9 @@ usbd_status usbd_get_desc(usbd_device_ha
usbd_status usbd_get_config_desc(usbd_device_handle, int,
usb_config_descriptor_t *);
usbd_status usbd_get_config_desc_full(usbd_device_handle, int, void *, int);
+usbd_status usbd_get_bos_desc(usbd_device_handle, int,
+ usb_bos_descriptor_t *);
+usbd_status usbd_get_bos_desc_full(usbd_device_handle, int, void *, int);
usbd_status usbd_get_device_desc(usbd_device_handle dev,
usb_device_descriptor_t *d);
usbd_status usbd_set_address(usbd_device_handle dev, int addr);
--- src/sys/dev/usb/usbdivar.h.orig 2014-09-06 20:15:44.000000000 +0900
+++ src/sys/dev/usb/usbdivar.h 2014-11-13 08:09:30.000000000 +0900
@@ -191,6 +191,7 @@ struct usbd_device {
struct usbd_interface *ifaces; /* array of all interfaces */
usb_device_descriptor_t ddesc; /* device descriptor */
usb_config_descriptor_t *cdesc; /* full config descr */
+ usb_bos_descriptor_t *bdesc; /* full BOS descr */
const struct usbd_quirks *quirks; /* device quirks, always set */
struct usbd_hub *hub; /* only if this is a hub */
int subdevlen; /* array length of following */
--- src/sys/dev/usb/xhci.c.orig 2014-11-18 19:58:02.000000000 +0900
+++ src/sys/dev/usb/xhci.c 2014-11-18 23:45:22.000000000 +0900
@@ -51,6 +59,7 @@ __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.2
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
+#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbhist.h>
#include <dev/usb/usb_mem.h>
#include <dev/usb/usb_quirks.h>
@@ -60,8 +69,7 @@ __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.2
#include <dev/usb/usbroothub_subr.h>
-#ifdef USB_DEBUG
-#ifndef XHCI_DEBUG
+#if !(defined(USB_DEBUG) && defined(XHCI_DEBUG))
#define xhcidebug 0
#else
static int xhcidebug = 0;
@@ -93,8 +101,7 @@ fail:
aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err);
}
-#endif /* XHCI_DEBUG */
-#endif /* USB_DEBUG */
+#endif /* !(XHCI_DEBUG && USB_DEBUG) */
#define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(xhcidebug,N,FMT,A,B,C,D)
#define XHCIHIST_FUNC() USBHIST_FUNC()
@@ -105,6 +112,19 @@ fail:
#define XHCI_ICI_INPUT_CONTROL 0
+#define IS_VALID_XFER(X) \
+ ((X) != NULL && \
+ (X)->pipe != NULL && \
+ (X)->pipe->device != NULL && \
+ (X)->pipe->device->bus != NULL && \
+ (X)->pipe->device->bus->devices[(X)->pipe->device->address] != NULL &&\
+ !SIMPLEQ_EMPTY(&(X)->pipe->queue))
+
+#define usb_transfer_complete(X) do { \
+ if (IS_VALID_XFER(X)) \
+ usb_transfer_complete(X); \
+ } while(0)
+
struct xhci_pipe {
struct usbd_pipe xp_pipe;
};
@@ -130,16 +150,18 @@ static usbd_status xhci_new_device(devic
static usbd_status xhci_configure_endpoint(usbd_pipe_handle);
static usbd_status xhci_unconfigure_endpoint(usbd_pipe_handle);
static usbd_status xhci_reset_endpoint(usbd_pipe_handle);
-//static usbd_status xhci_stop_endpoint(usbd_pipe_handle);
+static usbd_status xhci_stop_endpoint(usbd_pipe_handle);
static usbd_status xhci_set_dequeue(usbd_pipe_handle);
static usbd_status xhci_do_command(struct xhci_softc * const,
struct xhci_trb * const, int);
-static usbd_status xhci_init_slot(struct xhci_softc * const, uint32_t,
- int, int, int, int);
+static usbd_status xhci_do_command_locked(struct xhci_softc * const,
+ struct xhci_trb * const, int);
+static usbd_status xhci_init_slot(usbd_device_handle, uint32_t, int, int);
static usbd_status xhci_enable_slot(struct xhci_softc * const,
uint8_t * const);
+static usbd_status xhci_disable_slot(struct xhci_softc * const, uint8_t);
static usbd_status xhci_address_device(struct xhci_softc * const,
uint64_t, uint8_t, bool);
static usbd_status xhci_update_ep0_mps(struct xhci_softc * const,
@@ -392,7 +414,7 @@ xhci_db_write_4(const struct xhci_softc
static inline uint8_t
xhci_ep_get_type(usb_endpoint_descriptor_t * const ed)
{
- u_int eptype;
+ u_int eptype = 0;
switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
case UE_CONTROL:
@@ -606,17 +628,17 @@ int
xhci_init(struct xhci_softc *sc)
{
bus_size_t bsz;
- uint32_t cap, hcs1, hcs2, hcc, dboff, rtsoff;
+ uint32_t cap, hcs1, hcs2, hcs3, hcc, dboff, rtsoff;
uint32_t ecp, ecr;
uint32_t usbcmd, usbsts, pagesize, config;
int i;
uint16_t hciversion;
uint8_t caplength;
- XHCIHIST_FUNC(); XHCIHIST_CALLED();
+ /* XXX If USBHIST_CALLED is called before USBHIST_INIT, it panics. */
+ //XHCIHIST_FUNC(); XHCIHIST_CALLED();
- /* XXX Low/Full/High speeds for now */
- sc->sc_bus.usbrev = USBREV_2_0;
+ sc->sc_bus.usbrev = USBREV_3_0;
cap = xhci_read_4(sc, XHCI_CAPLENGTH);
caplength = XHCI_CAP_CAPLENGTH(cap);
@@ -642,13 +664,24 @@ xhci_init(struct xhci_softc *sc)
sc->sc_maxintrs = XHCI_HCS1_MAXINTRS(hcs1);
sc->sc_maxports = XHCI_HCS1_MAXPORTS(hcs1);
hcs2 = xhci_cap_read_4(sc, XHCI_HCSPARAMS2);
- (void)xhci_cap_read_4(sc, XHCI_HCSPARAMS3);
+ hcs3 = xhci_cap_read_4(sc, XHCI_HCSPARAMS3);
+ sc->sc_rh_u1del = XHCI_HCS3_U1_DEL(hcs3);
+ sc->sc_rh_u2del = XHCI_HCS3_U2_DEL(hcs3);
hcc = xhci_cap_read_4(sc, XHCI_HCCPARAMS);
sc->sc_ac64 = XHCI_HCC_AC64(hcc);
sc->sc_ctxsz = XHCI_HCC_CSZ(hcc) ? 64 : 32;
aprint_debug_dev(sc->sc_dev, "ac64 %d ctxsz %d\n", sc->sc_ac64,
sc->sc_ctxsz);
+ char sbuf[128];
+ snprintb(sbuf, sizeof sbuf, "\177\020"
+ "f\020\020XECP\0f\014\4MAXPSA\0"
+ "b\7NSS\0b\6LTC\0b\5LHRC\0b\4PIND\0b\3PPC\0"
+ "b\2CZC\0b\1BNC\0b\0AC64\0\0",
+ hcc);
+ aprint_debug_dev(sc->sc_dev, "hcc=%s\n", sbuf);
+ aprint_debug_dev(sc->sc_dev, "u1del %u u2del %u\n",
+ sc->sc_rh_u1del, sc->sc_rh_u2del);
aprint_debug_dev(sc->sc_dev, "xECP %x\n", XHCI_HCC_XECP(hcc) * 4);
ecp = XHCI_HCC_XECP(hcc) * 4;
@@ -749,6 +782,7 @@ xhci_init(struct xhci_softc *sc)
aprint_debug_dev(sc->sc_dev, "sc_pgsz 0x%08x\n", (uint32_t)sc->sc_pgsz);
aprint_debug_dev(sc->sc_dev, "sc_maxslots 0x%08x\n",
(uint32_t)sc->sc_maxslots);
+ aprint_debug_dev(sc->sc_dev, "sc_maxports %d\n", sc->sc_maxports);
usbd_status err;
@@ -865,7 +899,15 @@ xhci_init(struct xhci_softc *sc)
#endif
xhci_rt_write_4(sc, XHCI_IMAN(0), XHCI_IMAN_INTR_ENA);
- xhci_rt_write_4(sc, XHCI_IMOD(0), 0);
+ /* Intel PantherPoint/LynxPoint/BayTrail need interrupt rate capped */
+#if 0
+ if (!(sc->sc_quirks & XHCI_QUIRK_INTEL_IMOD)) {
+ xhci_rt_write_4(sc, XHCI_IMOD(0), XHCI_IMOD_DEFAULT);
+ }
+#else
+ /* XXX add quirk later */
+ xhci_rt_write_4(sc, XHCI_IMOD(0), 160);
+#endif
xhci_op_write_4(sc, XHCI_USBCMD, XHCI_CMD_INTE|XHCI_CMD_RS); /* Go! */
aprint_debug_dev(sc->sc_dev, "USBCMD %08"PRIx32"\n",
@@ -952,6 +994,129 @@ xhci_intr1(struct xhci_softc * const sc)
return 1;
}
+/*
+ * 3 port speed types used in USB stack
+ *
+ * usbdi speed
+ * definition: USB_SPEED_* in usb.h
+ * They are used in usbd_device_handle in USB stack.
+ * 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.
+ * (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 3.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.
+ */
+
+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;
+ }
+ return 0;
+}
+
+static void
+xhci_setup_sctx(usbd_device_handle dev, uint32_t *cp)
+{
+ usb_device_descriptor_t * const dd = &dev->ddesc;
+ int speed = dev->speed;
+ int tthubslot, ttportnum;
+ bool ishub;
+ bool usemtt;
+
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+ /* 6.2.2 */
+ /*
+ * tthubslot:
+ * This is the slot ID of parent HS hub
+ * if LS/FS device is connected && connected through HS hub.
+ * This is 0 if device is not LS/FS device ||
+ * attached to root hub.
+ * ttportnum:
+ * This is the downstream facing port of parent HS hub
+ * if LS/FS device is connected.
+ * This is 0 if device is not LS/FS device ||
+ * attached to root hub.
+ */
+ if (dev->myhsport != NULL &&
+ (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL)) {
+ ttportnum = dev->myhsport->portno;
+ /* XXX addr == slot ? */
+ tthubslot = dev->myhsport->parent->address;
+ } else {
+ ttportnum = 0;
+ tthubslot = 0;
+ }
+ DPRINTFN(4, "myhsport %p ttportnum=%d tthubslot=%d",
+ dev->myhsport, ttportnum, tthubslot, 0);
+
+ /* ishub is valid after reading UDESC_DEVICE */
+ ishub = (dd->bDeviceClass == UDCLASS_HUB);
+
+ /* dev->hub is valid after reading UDESC_HUB */
+ if (ishub && dev->hub) {
+ usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
+
+ cp[1] |= htole32(XHCI_SCTX_1_NUM_PORTS_SET(hd->bNbrPorts));
+ cp[2] |= htole32(XHCI_SCTX_2_TT_THINK_TIME_SET(
+ __SHIFTOUT(UGETW(hd->wHubCharacteristics), UHD_TT_THINK)));
+ DPRINTFN(4, "nports=%d ttt=%d",
+ hd->bNbrPorts, XHCI_SCTX_2_TT_THINK_TIME_GET(cp[2]), 0, 0);
+ }
+
+#define IS_TTHUB(dd) \
+ ((dd)->bDeviceProtocol == UDPROTO_HSHUBSTT || \
+ (dd)->bDeviceProtocol == UDPROTO_HSHUBMTT)
+
+ /*
+ * MTT flag is set if
+ * 1. this is HS hub && MTT is enabled
+ * or
+ * 2. this is not hub && this is LS or FS device &&
+ * MTT of parent HS hub (and its parent, too) is enabled
+ */
+ if (ishub && speed == USB_SPEED_HIGH && IS_TTHUB(dd))
+ usemtt = true;
+ else if (!ishub &&
+ (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) &&
+ dev->myhsport != NULL &&
+ IS_TTHUB(&dev->myhsport->parent->ddesc))
+ usemtt = true;
+ else
+ usemtt = false;
+ DPRINTFN(4, "class %u proto %u ishub %d usemtt %d",
+ dd->bDeviceClass, dd->bDeviceProtocol, ishub, usemtt);
+
+ cp[0] |= htole32(
+ XHCI_SCTX_0_SPEED_SET(xhci_speed2xspeed(speed)) |
+ XHCI_SCTX_0_HUB_SET(ishub ? 1 : 0) |
+ XHCI_SCTX_0_MTT_SET(usemtt ? 1 : 0)
+ );
+ cp[1] |= htole32(0);
+ cp[2] |= htole32(
+ XHCI_SCTX_2_IRQ_TARGET_SET(0) |
+ XHCI_SCTX_2_TT_HUB_SID_SET(tthubslot) |
+ XHCI_SCTX_2_TT_PORT_NUM_SET(ttportnum)
+ );
+ cp[3] |= htole32(0);
+}
+
static usbd_status
xhci_configure_endpoint(usbd_pipe_handle pipe)
{
@@ -963,10 +1128,14 @@ xhci_configure_endpoint(usbd_pipe_handle
struct xhci_trb trb;
usbd_status err;
uint32_t *cp;
+ uint32_t mps = UGETW(ed->wMaxPacketSize);
+ uint32_t maxb = 0;
+ int speed = pipe->device->speed;
+ uint32_t ival = ed->bInterval;
XHCIHIST_FUNC(); XHCIHIST_CALLED();
- DPRINTFN(4, "dci %u epaddr 0x%02x attr 0x%02x",
- dci, ed->bEndpointAddress, ed->bmAttributes, 0);
+ DPRINTFN(4, "slot %u dci %u epaddr 0x%02x attr 0x%02x",
+ xs->xs_idx, dci, ed->bEndpointAddress, ed->bmAttributes);
/* XXX ensure input context is available? */
@@ -978,33 +1147,96 @@ xhci_configure_endpoint(usbd_pipe_handle
/* set up input slot context */
cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
- cp[0] = htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
- cp[1] = htole32(0);
- cp[2] = htole32(0);
- cp[3] = htole32(0);
+ xhci_setup_sctx(pipe->device, cp);
+ cp[0] |= htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(dci));
- if (xfertype == UE_INTERRUPT) {
cp[0] = htole32(
- XHCI_EPCTX_0_IVAL_SET(3) /* XXX */
+ XHCI_EPCTX_0_EPSTATE_SET(0) |
+ XHCI_EPCTX_0_MAXP_STREAMS_SET(0) |
+ XHCI_EPCTX_0_LSA_SET(0)
);
cp[1] = htole32(
- XHCI_EPCTX_1_CERR_SET(3) |
- XHCI_EPCTX_1_EPTYPE_SET(xhci_ep_get_type(pipe->endpoint->edesc)) |
- XHCI_EPCTX_1_MAXB_SET(0) |
- XHCI_EPCTX_1_MAXP_SIZE_SET(8) /* XXX */
- );
- cp[4] = htole32(
- XHCI_EPCTX_4_AVG_TRB_LEN_SET(8)
- );
- } else {
- cp[0] = htole32(0);
- cp[1] = htole32(
- XHCI_EPCTX_1_CERR_SET(3) |
- XHCI_EPCTX_1_EPTYPE_SET(xhci_ep_get_type(pipe->endpoint->edesc)) |
- XHCI_EPCTX_1_MAXB_SET(0) |
- XHCI_EPCTX_1_MAXP_SIZE_SET(512) /* XXX */
+ XHCI_EPCTX_1_EPTYPE_SET(xhci_ep_get_type(ed)) |
+ XHCI_EPCTX_1_MAXB_SET(0)
);
+ if (xfertype != UE_ISOCHRONOUS)
+ cp[1] |= htole32(XHCI_EPCTX_1_CERR_SET(3));
+
+ if (speed == USB_SPEED_SUPER) {
+ const usb_endpoint_ss_comp_descriptor_t * esscd;
+
+ /* XXX */
+ esscd = (const usb_endpoint_ss_comp_descriptor_t *)
+ usb_find_desc(pipe->device,
+ UDESC_ENDPOINT_SS_COMP, USBD_CDCSUBTYPE_ANY);
+ if (esscd != NULL) {
+ maxb = esscd->bMaxBurst;
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXB_SET(maxb));
+ DPRINTFN(4, "setting SS MaxBurst %u", maxb, 0, 0, 0);
+ }
+ }
+ if (speed == USB_SPEED_HIGH &&
+ (xfertype == UE_ISOCHRONOUS || xfertype == UE_INTERRUPT)) {
+ maxb = UE_GET_TRANS(UGETW(ed->wMaxPacketSize));
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXB_SET(maxb));
+ DPRINTFN(4, "setting HS MaxBurst %u", maxb, 0, 0, 0);
+ }
+
+ switch (xfertype) {
+ case UE_INTERRUPT:
+ /* 6.2.3.6 */
+ if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) {
+ ival = ival > 10 ? 10 : ival;
+ ival = ival < 3 ? 3 : ival;
+ } else {
+ ival = ival > 15 ? 15 : ival;
+ }
+ if (speed == USB_SPEED_SUPER) {
+ if (maxb > 0)
+ mps = 1024;
+ } else {
+ mps = mps ? mps : 8;
+ }
+ cp[0] |= htole32(XHCI_EPCTX_0_IVAL_SET(ival));
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
+ cp[4] = htole32(
+ XHCI_EPCTX_4_AVG_TRB_LEN_SET(8) /* XXX */
+ );
+ break;
+ case UE_CONTROL:
+ if (speed == USB_SPEED_SUPER)
+ mps = 512;
+ else
+ mps = mps ? mps : 8;
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
+ cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(8)); /* XXX */
+ break;
+#ifdef notyet
+ case UE_ISOCHRONOUS:
+ if (speed == USB_SPEED_FULL) {
+ ival = ival > 18 ? 18 : ival;
+ ival = ival < 3 ? 3 : ival;
+ } else {
+ ival = ival > 15 ? 15 : ival;
+ }
+ if (speed == USB_SPEED_SUPER) {
+ mps = 1024;
+ } else {
+ mps = mps ? mps : 1024;
+ }
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
+ cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(1024)); /* XXX */
+ break;
+#endif
+ default:
+ if (speed == USB_SPEED_SUPER)
+ mps = 1024;
+ else
+ mps = mps ? mps : 512;
+ cp[1] |= htole32(XHCI_EPCTX_1_MAXP_SIZE_SET(mps));
+ cp[4] = htole32(XHCI_EPCTX_4_AVG_TRB_LEN_SET(1024)); /* XXX */
+ break;
}
*(uint64_t *)(&cp[2]) = htole64(
xhci_ring_trbp(&xs->xs_ep[dci].xe_tr, 0) |
@@ -1034,16 +1266,82 @@ xhci_configure_endpoint(usbd_pipe_handle
static usbd_status
xhci_unconfigure_endpoint(usbd_pipe_handle pipe)
{
-#ifdef USB_DEBUG
+ struct xhci_softc * const sc = pipe->device->bus->hci_private;
struct xhci_slot * const xs = pipe->device->hci_private;
-#endif
+ usb_endpoint_descriptor_t * const ed = pipe->endpoint->edesc;
+ const u_int dci = xhci_ep_get_dci(ed);
+ struct xhci_trb trb;
+ usbd_status err;
+ uint32_t *cp;
XHCIHIST_FUNC(); XHCIHIST_CALLED();
- DPRINTFN(4, "slot %u", xs->xs_idx, 0, 0, 0);
- return USBD_NORMAL_COMPLETION;
+ if (sc->sc_dying)
+ return USBD_IOERROR;
+
+ if (xs == NULL)
+ /* xs is uninitialized before xhci_init_slot */
+ return USBD_IOERROR;
+
+ DPRINTFN(1, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
+
+ /* XXX RACE */
+ if (cpu_intr_p() || cpu_softintr_p()) {
+#ifdef DIAGNOSTIC
+ DPRINTFN(1, "WARNING: called from intr ctx, giving up",
+ 0, 0, 0, 0);
+ return USBD_IOERROR;
+#else
+ DPRINTFN(4, "WARNING: called from intr ctx", 0, 0, 0, 0);
+#endif
+ }
+
+ /* XXX RACE */
+ if (!mutex_owned(&sc->sc_lock)) {
+#ifdef DIAGNOSTIC
+ DPRINTFN(1, "WARNING: not locked, giving up", 0, 0, 0, 0);
+ return USBD_IOERROR;
+#else
+ DPRINTFN(4, "WARNING: not locked", 0, 0, 0, 0);
+#endif
+ }
+
+ if (dci == XHCI_DCI_EP_CONTROL) {
+ DPRINTFN(4, "closing ep0", 0, 0, 0, 0);
+ xhci_disable_slot(sc, xs->xs_idx);
+ return USBD_NORMAL_COMPLETION;
+ }
+
+ err = xhci_stop_endpoint(pipe);
+
+ memset(xhci_slot_get_icv(sc, xs, 0), 0, sc->sc_pgsz);
+
+ cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL);
+ cp[0] = htole32(XHCI_INCTX_0_DROP_MASK(dci));
+ cp[1] = htole32(0);
+
+ cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
+ cp[0] = htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
+
+ /* sync input contexts before they are read from memory */
+ usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);
+
+ /*
+ * don't set DC bit 1, otherwise all endpoints but ep0
+ * would be deconfigured.
+ */
+ trb.trb_0 = xhci_slot_get_icp(sc, xs, 0);
+ trb.trb_2 = 0;
+ trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
+ XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_CONFIGURE_EP);
+
+ err = xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ usb_syncmem(&xs->xs_dc_dma, 0, sc->sc_pgsz, BUS_DMASYNC_POSTREAD);
+
+ return err;
}
+/* 4.6.8, 6.4.3.7 */
static usbd_status
xhci_reset_endpoint(usbd_pipe_handle pipe)
{
@@ -1054,7 +1352,7 @@ xhci_reset_endpoint(usbd_pipe_handle pip
usbd_status err;
XHCIHIST_FUNC(); XHCIHIST_CALLED();
- DPRINTFN(4, "dci %u", dci, 0, 0, 0);
+ DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
trb.trb_0 = 0;
trb.trb_2 = 0;
@@ -1067,7 +1365,6 @@ xhci_reset_endpoint(usbd_pipe_handle pip
return err;
}
-#if 0
static usbd_status
xhci_stop_endpoint(usbd_pipe_handle pipe)
{
@@ -1078,7 +1375,7 @@ xhci_stop_endpoint(usbd_pipe_handle pipe
const u_int dci = xhci_ep_get_dci(pipe->endpoint->edesc);
XHCIHIST_FUNC(); XHCIHIST_CALLED();
- DPRINTFN(4, "dci %u", dci, 0, 0, 0);
+ DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
trb.trb_0 = 0;
trb.trb_2 = 0;
@@ -1086,11 +1383,10 @@ xhci_stop_endpoint(usbd_pipe_handle pipe
XHCI_TRB_3_EP_SET(dci) |
XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_STOP_EP);
- err = xhci_do_command(sc, &trb, USBD_DEFAULT_TIMEOUT);
+ err = xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
return err;
}
-#endif
static usbd_status
xhci_set_dequeue(usbd_pipe_handle pipe)
@@ -1139,8 +1435,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;
@@ -1177,11 +1472,54 @@ xhci_open(usbd_pipe_handle pipe)
}
if (ed->bEndpointAddress != USB_CONTROL_ENDPOINT)
- xhci_configure_endpoint(pipe);
+ return xhci_configure_endpoint(pipe);
return USBD_NORMAL_COMPLETION;
}
+#if 1 /* XXX experimental */
+static void
+xhci_clear_endpoint_stall_task(void *cookie)
+{
+ usbd_xfer_handle const xfer = cookie;
+ struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;
+ struct xhci_slot * const xs = xfer->pipe->device->hci_private;
+ const u_int dci = xhci_ep_get_dci(xfer->pipe->endpoint->edesc);
+ struct xhci_ring * const tr = &xs->xs_ep[dci].xe_tr;
+
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
+ DPRINTFN(4, "xfer %p slot %u dci %u", xfer, xs->xs_idx, dci, 0);
+
+ xhci_reset_endpoint(xfer->pipe);
+ xhci_set_dequeue(xfer->pipe);
+
+ mutex_enter(&sc->sc_lock);
+ tr->is_halted = false;
+ usb_transfer_complete(xfer);
+ mutex_exit(&sc->sc_lock);
+ DPRINTFN(4, "ends", 0, 0, 0, 0);
+}
+
+static void
+xhci_clear_endpoint_stall_async(usbd_xfer_handle xfer)
+{
+ struct xhci_softc * const sc = xfer->pipe->device->bus->hci_private;
+
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
+ DPRINTFN(4, "xfer %p", xfer, 0, 0, 0);
+
+ if (sc->sc_dying) {
+ return;
+ }
+
+ usb_init_task(&xfer->pipe->async_task, xhci_clear_endpoint_stall_task,
+ xfer, USB_TASKQ_MPSAFE);
+ usb_add_task(xfer->pipe->device, &xfer->pipe->async_task,
+ USB_TASKQ_HC);
+ DPRINTFN(4, "ends", 0, 0, 0, 0);
+}
+#endif /* XXX experimental */
+
static void
xhci_rhpsc(struct xhci_softc * const sc, u_int port)
{
@@ -1194,13 +1532,6 @@ 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;
-
- port -= sc->sc_hs_port_start;
- port += 1;
- DPRINTFN(4, "hs port %u status change", port, 0, 0, 0);
p = KERNADDR(&xfer->dmabuf, 0);
memset(p, 0, xfer->length);
@@ -1219,6 +1550,8 @@ xhci_handle_event(struct xhci_softc * co
XHCIHIST_FUNC(); XHCIHIST_CALLED();
+ KASSERT(mutex_owned(&sc->sc_lock));
+
trb_0 = le64toh(trb->trb_0);
trb_2 = le32toh(trb->trb_2);
trb_3 = le32toh(trb->trb_3);
@@ -1248,7 +1581,20 @@ xhci_handle_event(struct xhci_softc * co
xx = (void *)(uintptr_t)(trb_0 & ~0x3);
}
xfer = &xx->xx_xfer;
+ /*
+ * stop_endpoint may cause ERR_STOPPED_LENGTH_INVALID,
+ * in which case this condition happens.
+ */
+ if (xfer == NULL) {
+ DPRINTFN(1, "xfer done: xfer is NULL", 0, 0, 0, 0);
+ break;
+ }
+ /* XXX xfer needs more validation */
+
DPRINTFN(14, "xfer %p", xfer, 0, 0, 0);
+ /* may happen when detaching */
+ if (!IS_VALID_XFER(xfer))
+ break;
if ((trb_3 & XHCI_TRB_3_ED_BIT) != 0) {
DPRINTFN(14, "transfer event data: "
@@ -1260,20 +1606,30 @@ xhci_handle_event(struct xhci_softc * co
}
}
- if (XHCI_TRB_2_ERROR_GET(trb_2) ==
- XHCI_TRB_ERROR_SUCCESS) {
+ uint8_t trberr = XHCI_TRB_2_ERROR_GET(trb_2);
+ if (trberr == XHCI_TRB_ERROR_SUCCESS ||
+ trberr == XHCI_TRB_ERROR_SHORT_PKT) {
xfer->actlen = xfer->length - XHCI_TRB_2_REM_GET(trb_2);
err = USBD_NORMAL_COMPLETION;
- } else if (XHCI_TRB_2_ERROR_GET(trb_2) ==
- XHCI_TRB_ERROR_SHORT_PKT) {
- xfer->actlen = xfer->length - XHCI_TRB_2_REM_GET(trb_2);
- err = USBD_NORMAL_COMPLETION;
- } else if (XHCI_TRB_2_ERROR_GET(trb_2) ==
- XHCI_TRB_ERROR_STALL) {
+ } else if (trberr == XHCI_TRB_ERROR_STALL ||
+ trberr == XHCI_TRB_ERROR_BABBLE) {
err = USBD_STALLED;
xr->is_halted = true;
- DPRINTFN(1, "ev: xfer done: err %u slot %u dci %u",
+ DPRINTFN(1,
+ "evh: xfer done: ERR %u slot %u dci %u",
XHCI_TRB_2_ERROR_GET(trb_2), slot, dci, 0);
+#if 1 /* XXX experimental */
+ /*
+ * This tries to kick task to reset endpoint,
+ * drop tr->is_halted flag, and call
+ * usb_transfer_complete with err asynchronously
+ * in usb task thread.
+ * usb_transfer_complete will be call from thread ctx.
+ */
+ xfer->status = err;
+ xhci_clear_endpoint_stall_async(xfer);
+ break;
+#endif
} else {
err = USBD_IOERROR;
}
@@ -1472,7 +1828,8 @@ xhci_new_device(device_t parent, usbd_bu
int rhport = 0;
struct xhci_slot *xs;
uint32_t *cp;
- uint8_t slot;
+ uint32_t route = 0;
+ uint8_t slot = 0;
uint8_t addr;
XHCIHIST_FUNC(); XHCIHIST_CALLED();
@@ -1493,11 +1850,21 @@ xhci_new_device(device_t parent, usbd_bu
dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT;
dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
dev->def_ep_desc.bmAttributes = UE_CONTROL;
- /* XXX */
- if (speed == USB_SPEED_LOW)
- USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET);
- else
+ /* 4.3, 4.8.2.1 */
+ switch (speed) {
+ case USB_SPEED_SUPER:
+ USETW(dev->def_ep_desc.wMaxPacketSize, 512);
+ break;
+ case USB_SPEED_FULL:
+ /* XXX using 64 as initial mps of ep0 in FS */
+ case USB_SPEED_HIGH:
USETW(dev->def_ep_desc.wMaxPacketSize, 64);
+ break;
+ case USB_SPEED_LOW:
+ default:
+ USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET);
+ break;
+ }
dev->def_ep_desc.bInterval = 0;
/* doesn't matter, just don't let it uninitialized */
@@ -1515,28 +1882,50 @@ 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);
+ 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)
+ break;
+ dep = hub->depth;
+ if (dep == 0)
+ break;
+ rhport = hub->powersrc->portno;
+ if (dep > USB_HUB_MAX_DEPTH)
+ continue;
- if (hub != NULL) {
- for (int p = 0; p < hub->hub->hubdesc.bNbrPorts; p++) {
+ route |=
+ (rhport > UHD_SS_NPORTS_MAX ? UHD_SS_NPORTS_MAX : rhport)
+ << ((dep - 1) * 4);
+ }
+ route = route >> 4;
+
+
+ DPRINTFN(4, "rhport %d Route %05x hub %p", rhport, route, hub, 0);
+
+ /* Locate port on upstream high speed hub */
+ for (adev = dev, hub = up->parent;
+ hub != NULL && hub->speed != USB_SPEED_HIGH;
+ adev = hub, hub = hub->myhub)
+ ;
+ if (hub) {
+ int p;
+ for (p = 0; p < hub->hub->hubdesc.bNbrPorts; p++) {
if (hub->hub->ports[p].device == adev) {
- rhport = p;
+ dev->myhsport = &hub->hub->ports[p];
+ goto found;
}
}
+ panic("xhci_new_device: cannot find HS port");
+ found:
+ DPRINTFN(4, "high speed port %d", p, 0, 0, 0);
} else {
- rhport = port;
+ dev->myhsport = NULL;
}
- if (speed == USB_SPEED_SUPER) {
- rhport += sc->sc_ss_port_start - 1;
- } else {
- rhport += sc->sc_hs_port_start - 1;
- }
- DPRINTFN(4, "rhport %d", rhport, 0, 0, 0);
dev->speed = speed;
dev->langid = USBD_NOLANG;
@@ -1546,8 +1935,7 @@ xhci_new_device(device_t parent, usbd_bu
err = usbd_setup_pipe(dev, 0, &dev->def_ep, USBD_DEFAULT_INTERVAL,
&dev->default_pipe);
if (err) {
- usbd_remove_device(dev, up);
- return (err);
+ goto bad;
}
dd = &dev->ddesc;
@@ -1557,17 +1945,17 @@ xhci_new_device(device_t parent, usbd_bu
bus->devices[dev->address] = dev;
err = usbd_get_initial_ddesc(dev, dd);
if (err)
- return err;
+ goto bad;
err = usbd_reload_device_desc(dev);
if (err)
- return err;
+ goto bad;
} else {
err = xhci_enable_slot(sc, &slot);
if (err)
- return err;
- err = xhci_init_slot(sc, slot, depth, speed, port, rhport);
+ goto bad;
+ err = xhci_init_slot(dev, slot, route, rhport);
if (err)
- return err;
+ goto bad;
xs = &sc->sc_slots[slot];
dev->hci_private = xs;
cp = xhci_slot_get_dcv(sc, xs, XHCI_DCI_SLOT);
@@ -1582,9 +1970,10 @@ xhci_new_device(device_t parent, usbd_bu
KASSERT(bus->devices[dev->address] == NULL);
bus->devices[dev->address] = dev;
+ /* need retry? */
err = usbd_get_initial_ddesc(dev, dd);
if (err)
- return err;
+ goto bad;
/* 4.8.2.1 */
if (speed == USB_SPEED_SUPER)
USETW(dev->def_ep_desc.wMaxPacketSize,
@@ -1597,11 +1986,13 @@ xhci_new_device(device_t parent, usbd_bu
UGETW(dev->def_ep_desc.wMaxPacketSize));
err = usbd_reload_device_desc(dev);
if (err)
- return err;
+ goto bad;
+#if 0
usbd_kill_pipe(dev->default_pipe);
err = usbd_setup_pipe(dev, 0, &dev->def_ep,
USBD_DEFAULT_INTERVAL, &dev->default_pipe);
+#endif
}
DPRINTFN(1, "adding unit addr=%d, rev=%02x,",
@@ -1624,11 +2015,14 @@ xhci_new_device(device_t parent, usbd_bu
err = usbd_probe_and_attach(parent, dev, port, dev->address);
if (err) {
- usbd_remove_device(dev, up);
- return (err);
+ goto bad;
}
return USBD_NORMAL_COMPLETION;
+
+ bad:
+ usbd_remove_device(dev, up);
+ return err;
}
static usbd_status
@@ -1638,7 +2032,8 @@ xhci_ring_init(struct xhci_softc * const
usbd_status err;
size_t size = ntrb * XHCI_TRB_SIZE;
- XHCIHIST_FUNC(); XHCIHIST_CALLED();
+ /* XXX initialization order */
+ //XHCIHIST_FUNC(); XHCIHIST_CALLED();
err = usb_allocmem(&sc->sc_bus, size, align, &xr->xr_dma);
if (err)
@@ -1769,8 +2164,8 @@ xhci_ring_put(struct xhci_softc * const
}
static usbd_status
-xhci_do_command(struct xhci_softc * const sc, struct xhci_trb * const trb,
- int timeout)
+xhci_do_command1(struct xhci_softc * const sc, struct xhci_trb * const trb,
+ int timeout, int locked)
{
struct xhci_ring * const cr = &sc->sc_cr;
usbd_status err;
@@ -1779,8 +2174,10 @@ xhci_do_command(struct xhci_softc * cons
DPRINTFN(12, "input: 0x%016"PRIx64" 0x%08"PRIx32" 0x%08"PRIx32,
trb->trb_0, trb->trb_2, trb->trb_3, 0);
- mutex_enter(&sc->sc_lock);
+ if (!locked)
+ mutex_enter(&sc->sc_lock);
+ /* this might fire when cv_timedwait unlocks sc_lock */
KASSERT(sc->sc_command_addr == 0);
sc->sc_command_addr = xhci_ring_trbp(cr, cr->xr_ep);
@@ -1818,11 +2215,26 @@ xhci_do_command(struct xhci_softc * cons
timedout:
sc->sc_command_addr = 0;
- mutex_exit(&sc->sc_lock);
+ if (!locked)
+ mutex_exit(&sc->sc_lock);
return err;
}
static usbd_status
+xhci_do_command(struct xhci_softc * const sc, struct xhci_trb * const trb,
+ int timeout)
+{
+ return xhci_do_command1(sc, trb, timeout, 0);
+}
+
+static usbd_status
+xhci_do_command_locked(struct xhci_softc * const sc,
+ struct xhci_trb * const trb, int timeout)
+{
+ return xhci_do_command1(sc, trb, timeout, 1);
+}
+
+static usbd_status
xhci_enable_slot(struct xhci_softc * const sc, uint8_t * const slotp)
{
struct xhci_trb trb;
@@ -1845,6 +2257,38 @@ xhci_enable_slot(struct xhci_softc * con
}
static usbd_status
+xhci_disable_slot(struct xhci_softc * const sc, uint8_t slot)
+{
+ struct xhci_trb trb;
+ struct xhci_slot *xs;
+
+ XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+ if (sc->sc_dying)
+ return USBD_IOERROR;
+
+ xs = &sc->sc_slots[slot];
+ if (xs != NULL) {
+ for (int i = 0; i < 32; i++) {
+ if (i == XHCI_DCI_SLOT)
+ continue;
+ xhci_ring_free(sc, &xs->xs_ep[i].xe_tr);
+ memset(&xs->xs_ep[i], 0, sizeof(xs->xs_ep[i]));
+ }
+ usb_freemem(&sc->sc_bus, &xs->xs_ic_dma);
+ usb_freemem(&sc->sc_bus, &xs->xs_dc_dma);
+ }
+
+ trb.trb_0 = 0;
+ trb.trb_2 = 0;
+ trb.trb_3 = htole32(
+ XHCI_TRB_3_SLOT_SET(slot) |
+ XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_DISABLE_SLOT));
+
+ return xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
+}
+
+static usbd_status
xhci_address_device(struct xhci_softc * const sc,
uint64_t icp, uint8_t slot_id, bool bsr)
{
@@ -1911,37 +2355,39 @@ xhci_set_dcba(struct xhci_softc * const
}
static usbd_status
-xhci_init_slot(struct xhci_softc * const sc, uint32_t slot, int depth,
- int speed, int port, int rhport)
+xhci_init_slot(usbd_device_handle dev, uint32_t slot, int route, int rhport)
{
+ struct xhci_softc * const sc = dev->bus->hci_private;
+ int speed = dev->speed;
struct xhci_slot *xs;
usbd_status err;
u_int dci;
uint32_t *cp;
uint32_t mps;
- uint32_t xspeed;
XHCIHIST_FUNC(); XHCIHIST_CALLED();
- DPRINTFN(4, "slot %u depth %d speed %d",
- slot, depth, speed, 0);
- DPRINTFN(4, " port %d rhport %d",
- port, rhport, 0, 0);
+ DPRINTFN(4, "slot %u speed %d rhport %d route %05x",
+ slot, speed, route, rhport);
switch (speed) {
case USB_SPEED_LOW:
- xspeed = 2;
mps = USB_MAX_IPACKET;
break;
case USB_SPEED_FULL:
- xspeed = 1;
+#if 0
+ mps = 8;
+#else
+ /* XXX according to xHCI spec 1.1 sec 4.3 (7),
+ * mps in FS should be started with 8.
+ * (and updated later in xhci_update_ep0_mps)
+ */
mps = 64;
+#endif
break;
case USB_SPEED_HIGH:
- xspeed = 3;
mps = USB_2_MAX_CTRL_PACKET;
break;
case USB_SPEED_SUPER:
- xspeed = 4;
mps = USB_3_MAX_CTRL_PACKET;
break;
default:
@@ -1962,7 +2408,7 @@ xhci_init_slot(struct xhci_softc * const
err = usb_allocmem(&sc->sc_bus, sc->sc_pgsz, sc->sc_pgsz,
&xs->xs_ic_dma);
if (err)
- return err;
+ goto bad1;
memset(KERNADDR(&xs->xs_ic_dma, 0), 0, sc->sc_pgsz);
for (dci = 0; dci < 32; dci++) {
@@ -1974,10 +2420,12 @@ xhci_init_slot(struct xhci_softc * const
XHCI_TRANSFER_RING_TRBS, XHCI_TRB_ALIGN);
if (err) {
DPRINTFN(0, "ring init failure", 0, 0, 0, 0);
- return err;
+ goto bad2;
}
}
+ memset(xhci_slot_get_icv(sc, xs, 0), 0, sc->sc_pgsz);
+
/* set up initial input control context */
cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL);
cp[0] = htole32(0);
@@ -1986,17 +2434,10 @@ xhci_init_slot(struct xhci_softc * const
/* set up input slot context */
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_SPEED_SET(xspeed)
- );
- cp[1] = htole32(
- XHCI_SCTX_1_RH_PORT_SET(rhport)
- );
- cp[2] = htole32(
- XHCI_SCTX_2_IRQ_TARGET_SET(0)
- );
- cp[3] = htole32(0);
+ xhci_setup_sctx(dev, cp);
+ cp[0] |= htole32(XHCI_SCTX_0_CTX_NUM_SET(1));
+ cp[0] |= htole32(XHCI_SCTX_0_ROUTE_SET(route));
+ cp[1] |= htole32(XHCI_SCTX_1_RH_PORT_SET(rhport));
/* set up input EP0 context */
cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_EP_CONTROL));
@@ -2028,6 +2469,17 @@ xhci_init_slot(struct xhci_softc * const
hexdump("output context", xhci_slot_get_dcv(sc, xs, 0),
sc->sc_ctxsz * 2);
+ if (!err)
+ return err;
+
+ bad2:
+ for (int i = 1; i < dci; i++) {
+ xhci_ring_free(sc, &xs->xs_ep[i].xe_tr);
+ memset(&xs->xs_ep[i], 0, sizeof(xs->xs_ep[i]));
+ }
+ usb_freemem(&sc->sc_bus, &xs->xs_ic_dma);
+ bad1:
+ usb_freemem(&sc->sc_bus, &xs->xs_dc_dma);
return err;
}
@@ -2042,73 +2494,125 @@ xhci_noop(usbd_pipe_handle pipe)
/* root hub descriptors */
static const usb_device_descriptor_t xhci_devd = {
- USB_DEVICE_DESCRIPTOR_SIZE,
- UDESC_DEVICE, /* type */
- {0x00, 0x02}, /* USB version */
- UDCLASS_HUB, /* class */
- UDSUBCLASS_HUB, /* subclass */
- UDPROTO_HSHUBSTT, /* protocol */
- 64, /* max packet */
- {0},{0},{0x00,0x01}, /* device id */
- 1,2,0, /* string indexes */
- 1 /* # of configurations */
+ .bLength = USB_DEVICE_DESCRIPTOR_SIZE,
+ .bDescriptorType = UDESC_DEVICE, /* type */
+ .bcdUSB = {0x00, 0x02}, /* USB version */
+ .bDeviceClass = UDCLASS_HUB, /* class */
+ .bDeviceSubClass = UDSUBCLASS_HUB, /* subclass */
+ .bDeviceProtocol = UDPROTO_HSHUBSTT, /* protocol */
+ .bMaxPacketSize = 64, /* max packet */
+ .idVendor = {0},
+ .idProduct = {0},
+ .bcdDevice = {0x00, 0x01}, /* device id */
+ .iManufacturer = 1, /* string indexes */
+ .iProduct = 2,
+ .iSerialNumber = 0,
+ .bNumConfigurations = 1 /* # of configurations */
};
static const usb_device_qualifier_t xhci_odevd = {
- USB_DEVICE_DESCRIPTOR_SIZE,
- UDESC_DEVICE_QUALIFIER, /* type */
- {0x00, 0x02}, /* USB version */
- UDCLASS_HUB, /* class */
- UDSUBCLASS_HUB, /* subclass */
- UDPROTO_FSHUB, /* protocol */
- 64, /* max packet */
- 1, /* # of configurations */
- 0
+ .bLength = USB_DEVICE_DESCRIPTOR_SIZE,
+ .bDescriptorType = UDESC_DEVICE_QUALIFIER, /* type */
+ .bcdUSB = {0x00, 0x02}, /* USB version */
+ .bDeviceClass = UDCLASS_HUB, /* class */
+ .bDeviceSubClass = UDSUBCLASS_HUB, /* subclass */
+ .bDeviceProtocol = UDPROTO_FSHUB, /* protocol */
+ .bMaxPacketSize0 = 64, /* max packet */
+ .bNumConfigurations = 1, /* # of configurations */
+ .bReserved = 0
};
static const usb_config_descriptor_t xhci_confd = {
- USB_CONFIG_DESCRIPTOR_SIZE,
- UDESC_CONFIG,
- {USB_CONFIG_DESCRIPTOR_SIZE +
- USB_INTERFACE_DESCRIPTOR_SIZE +
- USB_ENDPOINT_DESCRIPTOR_SIZE},
- 1,
- 1,
- 0,
- UC_ATTR_MBO | UC_SELF_POWERED,
- 0 /* max power */
+ .bLength = USB_CONFIG_DESCRIPTOR_SIZE,
+ .bDescriptorType = UDESC_CONFIG,
+ .wTotalLength = {USB_CONFIG_DESCRIPTOR_SIZE +
+ USB_INTERFACE_DESCRIPTOR_SIZE +
+ USB_ENDPOINT_DESCRIPTOR_SIZE},
+ .bNumInterface = 1,
+ .bConfigurationValue = 1,
+ .iConfiguration = 0,
+ .bmAttributes = UC_ATTR_MBO | UC_SELF_POWERED,
+ .bMaxPower = 0 /* max current in 2 mA units */
+};
+
+static const usb_bos_descriptor_t xhci_bosd = {
+ .bLength = USB_BOS_DESCRIPTOR_SIZE,
+ .bDescriptorType = UDESC_BOS,
+ .wTotalLength = {USB_BOS_DESCRIPTOR_SIZE +
+ USB_DEVCAP_USB2EXT_DESCRIPTOR_SIZE +
+ USB_DEVCAP_SS_DESCRIPTOR_SIZE +
+ USB_DEVCAP_CONTAINER_ID_DESCRIPTOR_SIZE},
+ .bNumDeviceCaps = 3
+};
+
+static const usb_devcap_usb2ext_descriptor_t xhci_devcap_usb2extd = {
+ .bLength = USB_DEVCAP_USB2EXT_DESCRIPTOR_SIZE,
+ .bDescriptorType = UDESC_BOS,
+ .bDevCapabilityType = USB_DEVCAP_USB2EXT,
+ .bmAttributes = {""}
+};
+
+static const usb_devcap_ss_descriptor_t xhci_devcap_ssd = {
+ .bLength = USB_DEVCAP_SS_DESCRIPTOR_SIZE,
+ .bDescriptorType = UDESC_BOS,
+ .bDevCapabilityType = USB_DEVCAP_SUPER_SPEED,
+ .bmAttributes = 0,
+ .wSpeedsSupported = {""},
+ .bFunctionalitySupport = 0,
+ .bU1DevExitLat = 0,
+ .wU2DevExitLat = {""}
+};
+
+static const usb_devcap_container_id_descriptor_t xhci_devcap_containerid_d = {
+ .bLength = USB_DEVCAP_CONTAINER_ID_DESCRIPTOR_SIZE,
+ .bDescriptorType = UDESC_BOS,
+ .bDevCapabilityType = USB_DEVCAP_CONTAINER_ID,
+ .bReserved = 0,
+// .ContainerID[16]
};
static const usb_interface_descriptor_t xhci_ifcd = {
- USB_INTERFACE_DESCRIPTOR_SIZE,
- UDESC_INTERFACE,
- 0,
- 0,
- 1,
- UICLASS_HUB,
- UISUBCLASS_HUB,
- UIPROTO_HSHUBSTT,
- 0
+ .bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
+ .bDescriptorType = UDESC_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = UICLASS_HUB,
+ .bInterfaceSubClass = UISUBCLASS_HUB,
+ .bInterfaceProtocol = UIPROTO_HSHUBSTT,
+ .iInterface = 0
};
static const usb_endpoint_descriptor_t xhci_endpd = {
- USB_ENDPOINT_DESCRIPTOR_SIZE,
- UDESC_ENDPOINT,
- UE_DIR_IN | XHCI_INTR_ENDPT,
- UE_INTERRUPT,
- {8, 0}, /* max packet */
- 12
+ .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
+ .bDescriptorType = UDESC_ENDPOINT,
+ .bEndpointAddress = UE_DIR_IN | XHCI_INTR_ENDPT,
+ .bmAttributes = UE_INTERRUPT,
+ .wMaxPacketSize = {64, 0}, /* max packet */
+ .bInterval = 12
};
static const usb_hub_descriptor_t xhci_hubd = {
- USB_HUB_DESCRIPTOR_SIZE,
- UDESC_HUB,
- 0,
- {0,0},
- 0,
- 0,
- {""},
- {""},
+ .bDescLength = USB_HUB_DESCRIPTOR_SIZE,
+ .bDescriptorType = UDESC_HUB,
+ .bNbrPorts = 0,
+ .wHubCharacteristics = {0, 0},
+ .bPwrOn2PwrGood = 0, /* delay in 2 ms units */
+ .bHubContrCurrent = 0,
+ .DeviceRemovable = {""}, /* max 255 ports */
+ .PortPowerCtrlMask = {""}, /* deprecated */
+};
+
+static const usb_hub_ss_descriptor_t xhci_hubssd = {
+ .bLength = USB_HUB_SS_DESCRIPTOR_SIZE,
+ .bDescriptorType = UDESC_SS_HUB,
+ .bNbrPorts = 0,
+ .wHubCharacteristics = {0, 0},
+ .bPwrOn2PwrGood = 0, /* delay in 2 ms units */
+ .bHubContrCurrent = 0,
+ .bHubHdrDecLat = 0,
+ .wHubDelay = {0, 0},
+ .DeviceRemovable = {""}, /* max 255 ports */
};
/* root hub control */
@@ -2219,6 +2723,55 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
totlen += l;
memcpy(buf, &xhci_endpd, min(l, sizeof(xhci_endpd)));
break;
+ case UDESC_BOS:
+ if ((value & 0xff) != 0) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ totlen = l = min(len, USB_BOS_DESCRIPTOR_SIZE);
+ memcpy(buf, &xhci_bosd, min(l, sizeof(xhci_bosd)));
+
+ buf = (char *)buf + l;
+ len -= l;
+ l = min(len, USB_DEVCAP_USB2EXT_DESCRIPTOR_SIZE);
+ totlen += l;
+ memcpy(buf, &xhci_devcap_usb2extd,
+ min(l, sizeof(xhci_devcap_usb2extd)));
+ USETDW(((usb_devcap_usb2ext_descriptor_t *)buf)
+ ->bmAttributes, USB_DEVCAP_USB2EXT_LPM);
+
+ buf = (char *)buf + l;
+ len -= l;
+ l = min(len, USB_DEVCAP_SS_DESCRIPTOR_SIZE);
+ totlen += l;
+ memcpy(buf, &xhci_devcap_ssd,
+ min(l, sizeof(xhci_devcap_ssd)));
+ {
+ usb_devcap_ss_descriptor_t *dcssd = buf;
+
+ dcssd->bmAttributes = USB_DEVCAP_SS_LTM;
+ dcssd->bFunctionalitySupport =
+ USB_DEVCAP_SS_SPEED_SS |
+ USB_DEVCAP_SS_SPEED_FS |
+ USB_DEVCAP_SS_SPEED_HS |
+ USB_DEVCAP_SS_SPEED_LS;
+ USETW(dcssd->wSpeedsSupported,
+ dcssd->bFunctionalitySupport);
+ dcssd->bU1DevExitLat = sc->sc_rh_u1del;
+ if (dcssd->bU1DevExitLat > 10)
+ dcssd->bU1DevExitLat = 10;
+ USETW(dcssd->wU2DevExitLat, sc->sc_rh_u1del);
+ if (UGETW(dcssd->wU2DevExitLat) > 2047)
+ USETW(dcssd->wU2DevExitLat, 2047);
+ }
+
+ buf = (char *)buf + l;
+ len -= l;
+ l = min(len, USB_DEVCAP_CONTAINER_ID_DESCRIPTOR_SIZE);
+ totlen += l;
+ memcpy(buf, &xhci_devcap_containerid_d,
+ min(l, sizeof(xhci_devcap_containerid_d)));
+ break;
case UDESC_STRING:
#define sd ((usb_string_descriptor_t *)buf)
switch (value & 0xff) {
@@ -2287,14 +2840,15 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
/* Hub requests */
case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE):
break;
+ /* Hub Port request */
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 (index < 1 || index > sc->sc_maxports) {
err = USBD_IOERROR;
goto ret;
}
- port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
+ port = XHCI_PORTSC(index);
v = xhci_op_read_4(sc, port);
DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
v &= ~XHCI_PS_CLEAR;
@@ -2319,9 +2873,18 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
case UHF_C_PORT_OVER_CURRENT:
err = USBD_IOERROR;
goto ret;
+ case UHF_C_BH_PORT_RESET:
+ xhci_op_write_4(sc, port, v | XHCI_PS_WRC);
+ break;
case UHF_C_PORT_RESET:
xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
break;
+ case UHF_C_PORT_LINK_STATE:
+ xhci_op_write_4(sc, port, v | XHCI_PS_PLC);
+ break;
+ case UHF_C_PORT_CONFIG_ERROR:
+ xhci_op_write_4(sc, port, v | XHCI_PS_CEC);
+ break;
default:
err = USBD_IOERROR;
goto ret;
@@ -2335,16 +2898,58 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
err = USBD_IOERROR;
goto ret;
}
- 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_maxports; l > 0; i++, l -= 8)
- hubd.DeviceRemovable[i++] = 0; /* XXX can't find out? */
- hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i;
- l = min(len, hubd.bDescLength);
- totlen = l;
- memcpy(buf, &hubd, l);
+ if ((value >> 8) == UDESC_SS_HUB) {
+#if 1
+ union {
+ usb_hub_ss_descriptor_t hd_ss;
+ uint8_t
+ hd_buf[USB_HUB_SS_DESCRIPTOR_SIZE+32-2];
+ } uhd_ss;
+#define hssd uhd_ss.hd_ss
+#else
+ usb_hub_ss_descriptor_t hssd;
+#endif
+
+#if 1
+ memset(&hssd, 0, sizeof(uhd_ss));
+#else
+ memset(&hssd, 0, sizeof(hssd));
+#endif
+ hssd = xhci_hubssd;
+ hssd.bNbrPorts = sc->sc_maxports;
+ /* XXX not defined in SS hub */
+ USETW(hssd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
+ hssd.bPwrOn2PwrGood = 200;
+ for (i = 0, l = hssd.bNbrPorts;
+ l > 0; i++, l -= 8)
+ /* XXX can't find out? */
+ hssd.DeviceRemovable[i++] = 0;
+ hssd.bLength = USB_HUB_SS_DESCRIPTOR_SIZE + i;
+ l = min(len, hssd.bLength);
+ hssd.bLength = l;
+ totlen = l;
+ memcpy(buf, &hssd, l);
+#if 1
+#undef hssd
+#endif
+ } else if ((value >> 8) == UDESC_HUB) {
+ hubd = xhci_hubd;
+ hubd.bNbrPorts = sc->sc_maxports;
+ USETW(hubd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
+ hubd.bPwrOn2PwrGood = 200;
+ for (i = 0, l = hubd.bNbrPorts;
+ 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);
+ hubd.bDescLength = l;
+ totlen = l;
+ memcpy(buf, &hubd, l);
+ } else {
+ err = USBD_IOERROR;
+ goto ret;
+ }
break;
case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
if (len != 4) {
@@ -2364,10 +2969,9 @@ 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));
- DPRINTFN(4, "READ_CLASS_OTHER GET_STATUS PORTSC %d (%d) %08x",
- index, sc->sc_hs_port_start - 1 + index, v, 0);
+ v = xhci_op_read_4(sc, XHCI_PORTSC(index));
+ DPRINTFN(4, "getrhportsc %d %08x", index, v, 0, 0);
+ /* xspeed -> port_status value */
switch (XHCI_PS_SPEED_GET(v)) {
case 1:
i = UPS_FULL_SPEED;
@@ -2378,6 +2982,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;
@@ -2387,13 +2994,21 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
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) i |= UPS_PORT_POWER;
+ if (v & XHCI_PS_PP) {
+ if (i & UPS_SUPER_SPEED)
+ i |= UPS_PORT_POWER_SS;
+ else
+ i |= UPS_PORT_POWER;
+ }
USETW(ps.wPortStatus, i);
i = 0;
if (v & XHCI_PS_CSC) i |= UPS_C_CONNECT_STATUS;
if (v & XHCI_PS_PEC) i |= UPS_C_PORT_ENABLED;
if (v & XHCI_PS_OCC) i |= UPS_C_OVERCURRENT_INDICATOR;
if (v & XHCI_PS_PRC) i |= UPS_C_PORT_RESET;
+ if (v & XHCI_PS_WRC) i |= UPS_C_BH_PORT_RESET;
+ if (v & XHCI_PS_PLC) i |= UPS_C_PORT_LINK_STATE;
+ if (v & XHCI_PS_CEC) i |= UPS_C_PORT_CONFIG_ERROR;
USETW(ps.wPortChange, i);
l = min(len, sizeof ps);
memcpy(buf, &ps, l);
@@ -2402,14 +3017,17 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
err = USBD_IOERROR;
goto ret;
+ case C(UR_SET_HUB_DEPTH, UT_WRITE_CLASS_DEVICE):
+ break;
case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE):
break;
+ /* Hub Port request */
case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER):
- if (index < 1 || index > sc->sc_hs_port_count) {
+ if (index < 1 || index > sc->sc_maxports) {
err = USBD_IOERROR;
goto ret;
}
- port = XHCI_PORTSC(sc->sc_hs_port_start - 1 + index);
+ port = XHCI_PORTSC(index);
v = xhci_op_read_4(sc, port);
DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
v &= ~XHCI_PS_CLEAR;
@@ -2443,6 +3061,24 @@ xhci_root_ctrl_start(usbd_xfer_handle xf
case UHF_C_PORT_RESET:
xhci_op_write_4(sc, port, v | XHCI_PS_PRC);
break;
+ case UHF_PORT_U1_TIMEOUT:
+ if (XHCI_PS_SPEED_GET(v) != 4) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ v &= ~XHCI_PM3_U1TO_SET(0xff);
+ v |= XHCI_PM3_U1TO_SET(value);
+ xhci_op_write_4(sc, port, v);
+ break;
+ case UHF_PORT_U2_TIMEOUT:
+ if (XHCI_PS_SPEED_GET(v) != 4) {
+ err = USBD_IOERROR;
+ goto ret;
+ }
+ v &= ~XHCI_PM3_U2TO_SET(0xff);
+ v |= XHCI_PM3_U2TO_SET(value);
+ xhci_op_write_4(sc, port, v);
+ break;
default:
err = USBD_IOERROR;
goto ret;
@@ -2702,12 +3338,18 @@ static void
xhci_device_ctrl_abort(usbd_xfer_handle xfer)
{
XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+ /* XXX */
+ xfer->status = USBD_CANCELLED;
+ usb_transfer_complete(xfer);
}
static void
xhci_device_ctrl_close(usbd_pipe_handle pipe)
{
XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+ (void)xhci_unconfigure_endpoint(pipe);
}
/* ----------------- */
@@ -2822,12 +3464,18 @@ static void
xhci_device_bulk_abort(usbd_xfer_handle xfer)
{
XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+ /* XXX */
+ xfer->status = USBD_CANCELLED;
+ usb_transfer_complete(xfer);
}
static void
xhci_device_bulk_close(usbd_pipe_handle pipe)
{
XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+ (void)xhci_unconfigure_endpoint(pipe);
}
/* --------------- */
--- src/sys/dev/usb/xhcireg.h.orig 2014-11-18 21:02:04.000000000 +0900
+++ src/sys/dev/usb/xhcireg.h 2014-11-18 19:54:27.000000000 +0900
@@ -38,6 +38,11 @@
#define PCI_USBREV_3_0 0x30 /* USB 3.0 */
#define PCI_XHCI_FLADJ 0x61 /* RW frame length adjust */
+#define PCI_XHCI_INTEL_XUSB2PR 0xD0 /* Intel USB2 Port Routing */
+#define PCI_XHCI_INTEL_USB2PRM 0xD4 /* Intel USB2 Port Routing Mask */
+#define PCI_XHCI_INTEL_USB3_PSSEN 0xD8 /* Intel USB3 Port SuperSpeed Enable */
+#define PCI_XHCI_INTEL_USB3PRM 0xDC /* Intel USB3 Port Routing Mask */
+
/* XHCI capability registers */
#define XHCI_CAPLENGTH 0x00 /* RO capability */
#define XHCI_CAP_CAPLENGTH(x) ((x) & 0xFF)
@@ -168,6 +173,7 @@
#define XHCI_IMOD_ICNT_GET(x) (((x) >> 16) & 0xFFFF) /* 250ns unit */
#define XHCI_IMOD_ICNT_SET(x) (((x) & 0xFFFF) << 16) /* 250ns unit */
#define XHCI_IMOD_DEFAULT 0x000001F4U /* 8000 IRQ/second */
+#define XHCI_IMOD_DEFAULT_LP 0x000003E8U /* 4000 IRQ/sec for LynxPoint */
#define XHCI_ERSTSZ(n) (0x0028 + (0x20 * (n))) /* XHCI event ring segment table size */
#define XHCI_ERSTS_GET(x) ((x) & 0xFFFF)
#define XHCI_ERSTS_SET(x) ((x) & 0xFFFF)
@@ -188,18 +194,20 @@
/* XHCI legacy support */
#define XHCI_XECP_ID(x) ((x) & 0xFF)
#define XHCI_XECP_NEXT(x) (((x) >> 8) & 0xFF)
-#if 0
#define XHCI_XECP_BIOS_SEM 0x0002
#define XHCI_XECP_OS_SEM 0x0003
-#endif
-/* XHCI capability ID's */
-#define XHCI_ID_USB_LEGACY 0x0001
-#define XHCI_ID_PROTOCOLS 0x0002
-#define XHCI_ID_POWER_MGMT 0x0003
-#define XHCI_ID_VIRTUALIZATION 0x0004
-#define XHCI_ID_MSG_IRQ 0x0005
-#define XHCI_ID_USB_LOCAL_MEM 0x0006
+/* XHCI extended capability ID's */
+#define XHCI_ID_USB_LEGACY 0x0001 /* USB Legacy Support */
+#define XHCI_XECP_USBLESUP 0x0000 /* Legacy Support Capability Reg */
+#define XHCI_XECP_USBLEGCTLSTS 0x0004 /* Legacy Support Ctrl & Status Reg */
+#define XHCI_ID_PROTOCOLS 0x0002 /* Supported Protocol */
+#define XHCI_ID_POWER_MGMT 0x0003 /* Extended Power Management */
+#define XHCI_ID_VIRTUALIZATION 0x0004 /* I/O Virtualization */
+#define XHCI_ID_MSG_IRQ 0x0005 /* Message Interrupt */
+#define XHCI_ID_USB_LOCAL_MEM 0x0006 /* Local Memory */
+#define XHCI_ID_USB_DEBUG 0x000A /* USB Debug Capability */
+#define XHCI_ID_XMSG_IRQ 0x0011 /* Extended Message Interrupt */
#define XHCI_PAGE_SIZE(sc) ((sc)->sc_pgsz)
@@ -243,6 +251,7 @@ struct xhci_trb {
#define XHCI_TRB_3_TC_BIT (1U << 1) /* command ring only */
#define XHCI_TRB_3_ENT_BIT (1U << 1) /* transfer ring only */
#define XHCI_TRB_3_ISP_BIT (1U << 2)
+//#define XHCI_TRB_3_ED_BIT (1U << 2)
#define XHCI_TRB_3_NSNOOP_BIT (1U << 3)
#define XHCI_TRB_3_CHAIN_BIT (1U << 4)
#define XHCI_TRB_3_IOC_BIT (1U << 5)
@@ -266,6 +275,8 @@ struct xhci_trb {
#define XHCI_TRB_3_FRID_SET(x) (((x) & 0x7FF) << 20)
#define XHCI_TRB_3_ISO_SIA_BIT (1U << 31)
#define XHCI_TRB_3_SUSP_EP_BIT (1U << 23)
+#define XHCI_TRB_3_VFID_GET(x) (((x) >> 16) & 0xFF)
+#define XHCI_TRB_3_VFID_SET(x) (((x) & 0xFF) << 16)
#define XHCI_TRB_3_SLOT_GET(x) (((x) >> 24) & 0xFF)
#define XHCI_TRB_3_SLOT_SET(x) (((x) & 0xFF) << 24)
@@ -375,10 +386,20 @@ struct xhci_trb {
#define XHCI_SCTX_3_DEV_ADDR_GET(x) ((x) & 0xFF)
#define XHCI_SCTX_3_SLOT_STATE_SET(x) (((x) & 0x1F) << 27)
#define XHCI_SCTX_3_SLOT_STATE_GET(x) (((x) >> 27) & 0x1F)
+#define XHCI_SLOTSTATE_DISABLED 0 /* disabled or enabled */
+#define XHCI_SLOTSTATE_ENABLED 0
+#define XHCI_SLOTSTATE_DEFAULT 1
+#define XHCI_SLOTSTATE_ADDRESSED 2
+#define XHCI_SLOTSTATE_CONFIGURED 3
#define XHCI_EPCTX_0_EPSTATE_SET(x) ((x) & 0x7)
#define XHCI_EPCTX_0_EPSTATE_GET(x) ((x) & 0x7)
+#define XHCI_EPSTATE_DISABLED 0
+#define XHCI_EPSTATE_RUNNING 1
+#define XHCI_EPSTATE_HALTED 2
+#define XHCI_EPSTATE_STOPPED 3
+#define XHCI_EPSTATE_ERROR 4
#define XHCI_EPCTX_0_MULT_SET(x) (((x) & 0x3) << 8)
#define XHCI_EPCTX_0_MULT_GET(x) (((x) >> 8) & 0x3)
#define XHCI_EPCTX_0_MAXP_STREAMS_SET(x) (((x) & 0x1F) << 10)
--- src/sys/dev/usb/xhcivar.h.orig 2014-03-11 02:58:40.000000000 +0900
+++ src/sys/dev/usb/xhcivar.h 2014-11-12 16:28:07.000000000 +0900
@@ -86,6 +86,8 @@ struct xhci_softc {
int sc_maxintrs;
int sc_maxports;
int sc_maxspbuf;
+ uint16_t sc_rh_u1del;
+ uint16_t sc_rh_u2del;
/* XXX suboptimal */
int sc_hs_port_start;
@@ -114,6 +116,9 @@ struct xhci_softc {
uint8_t sc_addr;
uint8_t sc_conf;
+
+ int sc_quirks;
+#define XHCI_QUIRK_FORCE_INTR __BIT(0) /* force interrupt reading */
};
int xhci_init(struct xhci_softc *);
Home |
Main Index |
Thread Index |
Old Index