Paul Goyette | 19 Apr 09:40 2015

Missing rump_kthread_destroy() ?

In my on-going efforts to further modularize the NetBSD kernel, I'm 
currently prying apart the pieces of sysmon...

One of those pieces would be sysmon_taskq, which provides a lwp 
environment to execute callouts.  In the sysmon_taskq_init() routine 
there is a call to kthread_create(), so it would seem reasonable that 
sysmon_taskq_fini() would call kthread_destroy().

Unfortunately, when building rump_allserver I discover that there is no 
rump emulation for kthread_destroy().  There is _create(), _join(), 
_exit(), and _init(), but no _destroy().

Is there a reason for not providing kthread_desetroy()?  How difficult 
would it be to add it?

-------------------------------------------------------------------------
| Paul Goyette     | PGP Key fingerprint:     | E-mail addresses:       |
| (Retired)        | FA29 0E3B 35AF E8AE 6651 | paul at whooppee.com    |
| Kernel Developer | 0786 F758 55DE 53BA 7731 | pgoyette at netbsd.org  |
-------------------------------------------------------------------------

Michael van Elst | 18 Apr 12:28 2015
Picon

Extending the GPIO framework


The current gpio(4) framework supports simple I/O pins, you
can define a pin as input or output and select some common
hardware features like software-controllable pullup resistors.

Once defined, you can only read the state of an input pin or
set an output pin to low or high. But once defined, there is
no way to reconfigure the pins, for example to reverse
the direction or disable an output (in a secure kernel).

Some hardware can re-use the GPIO pins for different functions.
The gpio(4) framework allows other drivers to reserve pins
that are then no longer available for GPIO. But there is
no way to control this in a running system except by loading
and unloading driver modules... assuming you support modular
drivers and again don't use a secure kernel.

A small extension to the gpio framework would help in solving either problem.

Add an additional capability flag to each pin that allows changing
the pin configuration.

#define GPIO_PIN_CHANGE         0x00008000      /* allow reconfiguration */

This would be a flag controlling the framework like GPIO_PIN_SET.
A pin with this capability can be reconfigured. Usually this would
mean that possible changes are arbitrary, but the driver could
limit the capability bits when a pin is configured to those that
can actually be updated.

(Continue reading)

Paul Goyette | 16 Apr 10:34 2015

config_init_component(), ioconf, and pseudo-devices

I'm working on turning swwdog (for now, eventually others) into a kernel 
module, and I'm running into some difficulty with the autoconfig stuff.

I've got an IOCONF=swwdog.ioconf in my Makefile, and swwdog.ioconf 
contains

 	ioconf swwdog
 	include "conf/files"
 	include "dev/sysmon/files.sysmon"
 	pseudo-device   swwdog

In files.sysmon there is

 	defpseudodev swwdog: sysmon_wdog
 	file    dev/sysmon/swwdog.c             swwdog

In the swwdog_modcmd()'s init code, I am calling

 	config_init_component(cfdriver_ioconf_swwdog,
 	    cfattach_ioconf_swwdog, cfdata_ioconf_swwdog);

where the arguments are all references to data structures defined in the 
generated ioconf.[ch] files.

The problem occurs a bit later on when I create a local struct cfattach

 	cf.cf_name = "swwdog";
 	cf.cf_atname = "swwdog";
 	cf.cf_unit = 0;
 	cf.cf_fstate = FSTATE_STAR;
(Continue reading)

Ryota Ozaki | 15 Apr 09:48 2015
Picon

Removing USE_RADIX in ip_encap.c

Hi,

It seems USE_RADIX switch in ip_encap.c is always
on for years and nobody uses non-USE_RADIX case.
(It even cannot be built w/o USE_RADIX.)

I'll remove the switch in a few days if there is
no objection.

  ozaki-r

Kamil Rytarowski | 12 Apr 19:24 2015
Picon

ACPICA-20150410, request for review

tech-pkg:

I request for review wip/acpica-utils and to upgrade sysutils/acpica-utils with it.

Changes against sysutils/acpica-utils
- Upgrade from 20090625 to 20150410
  Changelog: https://github.com/acpica/acpica/blob/master/documents/changes.txt

- New dual license: modified-bsd OR gnu-gpl-v2

- Add new category: sysutils

- NetBSD has sem_timedwait(). Hey I miss the .Sh HISTORY notes about it!

- Drop local tweaks for DragonflyBSD. For this platform please see new
  upstream patch:
  https://github.com/acpica/acpica/commit/3e93431674abe947202b0f9a0afa7b625b17caa6

CVS commit: https://mail-index.netbsd.org/pkgsrc-wip-cvs/2015/04/12/msg037946.html

The package could be pushed during the freeze for 2015Q1,
as at least for me acpica-utils from pkgsrc is broken.

Tested on NetBSD-current/amd64.

tech-kern:

I request for upgrade the in-kernel ACPICA subsystem.
This will help me to debug ACPI related problems and upstream more local changes.

(Continue reading)

Yue Chen | 11 Apr 22:11 2015
Picon

Situations about PC values in kernel data

Hi,

We are working on a project about OS security.
We wonder in which situations the program counter (PC) value (e.g., the value in %RIP on x86_64, i.e, instruction address) could be in kernel (module) data segments (including stack, heap, .rodata, etc.).

Here we mainly care about the addresses/values that are NOT function entry points since there exist a number of function pointers. Also, we only consider the normal cases because one can write arbitrary values into a variable/pointer. And we mainly consider i386, AMD64 and ARM.

Here are some situations I can think about:
function/interrupt/exception/syscall return address on stack; switch/case jump table target; page fault handler (pcb_onfault on *BSD); restartable atomic sequences (RAS) registry; thread/process context structure like Task state segment (TSS), process control block (PCB) and thread control block (TCB); situations for debugging purposes (e.g., like those in ``segment not present'' exception handler on FreeBSD, and trace exception handler on NetBSD).  Any other cases?

Additionally, does any of these addresses have offset formats, or special encodings?
For example, on x86_64, we may use 32-bit RIP-relative (addressing) offset to represent a 64-bit full address. In glibc's setjmp/longjmp jmp_buf, they use a special encoding (PTR_MANGLE) for saved register values.

Best thanks and regards,
Yue

Taylor R Campbell | 11 Apr 23:51 2015
Picon

reference counts

I would like to introduce an easy-to-use-correctly abstraction for
MP-safe reference counts.  I proposed the attached API, based on many
examples and on discussion with dholland <at> .

It is designed to address three different use cases:

- Object with lifetime ended by a specific operation which needs to
wait until all users are done.

Example: autoconf device with cdevsw nodes.  xyz_detach must wait for
all open files to be closed, and xyz_open/xyz_close must maintain the
reference count and notify xyz_detach when the last close happens.
(We don't exactly do this currently, but that's a bug.)

- Object in global cache with last-user-frees.

Example: vnodes in vcache.  Last reference must be dropped under the
same lock as removing the vnode from the vcache or at least marking it
unusable.  Otherwise, maintenance of the vnode reference count can be
done with atomic operations.

- Shared objects, not in any global tables, with last-user-frees.

Example: process credentials.  Last user just calls kmem_free, no
table or locks involved.

Thoughts?
/*	$NetBSD$	*/

/*-
 * Copyright (c) 2015 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Taylor R. Campbell.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef	_SYS_REFCOUNT_H
#define	_SYS_REFCOUNT_H

#include <sys/types.h>
#include <sys/atomic.h>
#include <sys/condvar.h>
#include <sys/errno.h>
#include <sys/mutex.h>
#include <sys/systm.h>

#include <machine/limits.h>

struct refcount {
	volatile unsigned	rc_value;
};

#if DIAGNOSTIC
static inline bool
refcount_referenced_p(struct refcount *refcount)
{

	return 0 < refcount->rc_value;
}

static inline bool
refcount_exclusive_p(struct refcount *refcount)
{

	KASSERT(refcount_referenced_p(refcount));
	return refcount->rc_value == 1;
}
#endif

static inline void
refcount_init(struct refcount *refcount)
{

	refcount->rc_value = 1;
}

static inline void
refcount_fini(struct refcount *refcount)
{

	KASSERT(!refcount_referenced_p(refcount));
	refcount->rc_value = UINT_MAX;
}

static inline int
refcount_inc(struct refcount *refcount)
{
	unsigned old, new;

	do {
		old = refcount->rc_value;
		if (old == UINT_MAX)
			return EBUSY;
		KASSERT(0 < old);
		new = old + 1;
	} while (atomic_cas_uint(&refcount->rc_value, old, new) != old);

	return 0;
}

static inline bool
refcount_dec_local(struct refcount *refcount)
{
	unsigned old, new;

	do {
		old = refcount->rc_value;
		if (old == 1) {
			/*
			 * Avoid an atomic if we don't need it.  Caller
			 * guarantees that if the reference count is 1,
			 * nobody else can acquire new references.
			 */
			refcount->rc_value = 0;
			return true;
		}
		KASSERT(0 < old);
		new = old - 1;
	} while (atomic_cas_uint(&refcount->rc_value, old, new) != old);

	KASSERT(0 < new);
	return false;
}

static inline bool
refcount_dec_lock(struct refcount *refcount, kmutex_t *interlock)
{
	unsigned old, new;

	do {
		old = refcount->rc_value;
		KASSERT(0 < old);
		if (old == 1) {
			/*
			 * Transition from 1->0 is allowed only under
			 * the interlock.
			 */
			mutex_enter(interlock);
			new = atomic_dec_uint_nv(&refcount->rc_value);
			KASSERT(new != UINT_MAX);
			if (new == 0)
				return true;
			mutex_exit(interlock);
			return false;
		}
		new = old - 1;
	} while (atomic_cas_uint(&refcount->rc_value, old, new) != old);

	return false;
}

static inline void
refcount_dec_signal(struct refcount *refcount, kmutex_t *interlock,
    kcondvar_t *cv)
{

	if (refcount_dec_lock(refcount, interlock)) {
		cv_signal(cv);
		mutex_exit(interlock);
	}
}

static inline void
refcount_dec_broadcast(struct refcount *refcount, kmutex_t *interlock,
    kcondvar_t *cv)
{

	if (refcount_dec_lock(refcount, interlock)) {
		cv_broadcast(cv);
		mutex_exit(interlock);
	}
}

static inline void
refcount_dec_drain(struct refcount *refcount, kmutex_t *interlock,
    kcondvar_t *cv)
{

	ASSERT_SLEEPABLE();
	KASSERT(mutex_owned(interlock));

	if (0 < atomic_dec_uint_nv(&refcount->rc_value))
		do cv_wait(cv, interlock); while (0 < refcount->rc_value);
}

#endif	/* _SYS_REFCOUNT_H */
.\"	$NetBSD$
.\"
.\" Copyright (c) 2015 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Taylor R. Campbell.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\"    notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\"    notice, this list of conditions and the following disclaimer in the
.\"    documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd April 11, 2015
.Dt REFCOUNT 9
.Os
.Sh NAME
.Nm REFCOUNT
.Nd reference counting
.Sh SYNOPSIS
.In sys/refcount.h
.Ft void
.Fn refcount_init "struct refcount *refcount"
.Ft void
.Fn refcount_fini "struct refcount *refcount"
.Ft int
.Fn refcount_inc "struct refcount *refcount"
.Ft bool
.Fn refcount_dec_local "struct refcount *refcount"
.Ft bool
.Fn refcount_dec_lock "struct refcount *refcount" "kmutex_t *interlock"
.Ft void
.Fn refcount_dec_signal "struct refcount *refcount" "kmutex_t *interlock" \
        "kcondvar_t *cv"
.Ft void
.Fn refcount_dec_broadcast "struct refcount *refcount" "kmutex_t *interlock" \
        "kcondvar_t *cv"
.Ft void
.Fn refcount_dec_drain "struct refcount *refcount" "kmutex_t *interlock" \
        "kcondvar_t *cv"
.Sh DESCRIPTION
.Nm
is an abstraction for maintaining reference counts to objects that may
be shared between multiple threads.
Each object with a reference count should embed a
.Li "struct refcount" ,
which users should treat as opaque and should not inspect or copy.
The
.Li "struct refcount"
must be initialized with
.Fn refcount_init
before use, and finalized with
.Fn refcount_fini
when done.
When acquiring a reference to an object, use
.Fn refcount_inc ,
which increments its reference count.
When releasing a reference to an object, use one of the
.Fn refcount_dec_*
routines.
.Pp
The
.Nm
abstraction supports multiple approaches to freeing objects when they
are no longer referenced:
.Bl -dash
.It
The object's lifetime is ended by an explicit free operation, and the
reference count serves only to notify the free operation when the
object is no longer in use.
.Pp
Users of the object should use
.Fn refcount_dec_signal
or
.Fn refcount_dec_broadcast
to notify the free operation when they are done, and the free operation
should use
.Fn refcount_dec_drain
to wait until there are no users left.
.It
The object is stored in a global cache, and has no explicit free
operation -- its lifetime ends when the last user is done with it, at
which point it must be removed from the cache and freed.
.Pp
Each user of the object should use
.Fn refcount_dec_lock
when done, which returns true and enters a mutex if and only if that
user is the last one.
This allows the last user to safely remove the object from the global
cache without a window during which new references can be acquired.
.It
The object has no explicit free operation and is not stored in any
global tables.
.Pp
Each user of the object should use
.Fn refcount_dec_local
when done, which returns true if and only if that user is the last one,
who can then free the object.
.El
.Pp
The transition from nonzero to zero references is permanent.
It is also guaranteed to happen under an interlock excluding new
references whenever there is a possibility that one thread may acquire
a new reference at the same time another is releasing what would have
been the last one.
.Sh FUNCTIONS
.Bl -tag -width abcd
.It Fn refcount_init refcount
Initialize
.Fa refcount
for use with
.Nm .
.It Fn refcount_fini refcount
Finalize
.Fa refcount .
Further use with
.Nm
is not allowed.
.It Fn refcount_inc refcount
Try to increment
.Fa refcount .
If there are too many other references
.Pq Dv UINT_MAX ,
return
.Dv EBUSY .
Otherwise, return zero.
.It Fn refcount_dec_local refcount
Decrement
.Fa refcount .
If it drops to zero, return true.
Otherwise return false.
.Pp
This is useful
.Em only
when the object whose references are counted by
.Fa refcount
is not stored in any global tables or caches, so that, without
interlocks, if the reference count
.Em would
drop to zero, there is no way for other threads to acquire new
references.
.It Fn refcount_dec_lock refcount interlock
Decrement
.Fa refcount .
If it drops to zero, enter the mutex
.Fa interlock
and return true.
Otherwise return false.
.Pp
May enter
.Fa interlock
even if it returns false, in case another thread acquired a reference
at the same time.
.It Fn refcount_dec_signal refcount interlock cv
Decrement
.Fa refcount .
If it drops to zero, enter the mutex
.Fa interlock ,
signal
.Fa cv ,
and exit
.Fa interlock .
.Pp
May enter
.Fa interlock
even if it does not signal
.Fa cv ,
in case another thread acquired a reference at the same time.
.It Fn refcount_dec_broadcast refcount interlock cv
Decrement
.Fa refcount .
If it drops to zero, enter the mutex
.Fa interlock ,
broadcast
.Fa cv ,
and exit
.Fa interlock .
.Pp
May enter
.Fa interlock
even if it does not broadcast
.Fa cv ,
in case another thread acquired a reference at the same time.
.It Fn refcount_dec_drain refcount interlock cv
Decrement
.Fa refcount ,
and wait under
.Fa interlock
on
.Fa cv
until the reference count drops to zero.
.Pp
The caller must hold
.Fa interlock .
.Pp
May sleep.
.It Fn refcount_referenced_p refcount
Return true if the reference count of
.Fa refcount
is positive, false if zero.
.Pp
May be used only under
.Dv DIAGNOSTIC
for assertions.
Do not make run-time decisions on the basis of
.Fn refcount_referenced_p .
.It Fn refcount_exclusive_p refcount
Return true if caller's reference to
.Fa refcount
is exclusive -- that is, if the reference count of
.Fa refcount
is one.
Otherwise return false.
.Fa refcount
must be referenced: the reference count may not be zero.
.Pp
May be used only under
.Dv DIAGNOSTIC
for assertions.
Do not make run-time decisions on the basis of
.Fn refcount_exclusive_p .
.El
.Sh CODE REFERENCES
The
.Nm
abstraction is implemented in
.Pa sys/sys/refcount.h .
.Sh SEE ALSO
.Xr condvar 9 ,
.Xr mutex 9
.Sh BUGS
There are no examples in this man page.
.Pp
The implementation is untested.
Kengo NAKAHARA | 9 Apr 12:44 2015
Picon

x86 MD MSI/MSI-X implementation

Hi,

I implement x86 MD MSI/MSI-X support code. Here is the patch:
    http://www.netbsd.org/~knakahara/md-msi-msix/x86-md-msi-msix.patch

Furthermore, here is the usage example of if_wm:
    http://www.netbsd.org/~knakahara/md-msi-msix/if_wm-msi-msix.patch

I believe this MD implementation help to decide the MI APIs.
One of MI MSI/MSI-X API is dyoung <at> n.o's bus_msi(9),
    http://mail-index.netbsd.org/tech-kern/2014/06/06/msg017209.html
another is matt <at> n.o's API,
    http://mail-index.netbsd.org/tech-kern/2011/08/05/msg011130.html
The other is mine, above patch includes my API manual.

I want feedback from various device driver MSI/MSI-X implementations,
such as usability, portablity, performance, and potential issues.
So, I would like to commit above patch. If no one opposites, I commit
above patch after one or two weeks.
# Of course, I will commit by dividing each component.

Could you comment this implementation?

Thanks,

--

-- 
//////////////////////////////////////////////////////////////////////
Internet Initiative Japan Inc.

Device Engineering Section,
Core Product Development Department,
Product Division,
Technology Unit

Kengo NAKAHARA <k-nakahara <at> iij.ad.jp>

Martin Husemann | 7 Apr 10:52 2015
Picon

Diagnostic verification of vnode VOCALLs

Hey folks,

I sometimes (like once every other month) see a kernel crash on sparc64
that looks like the kernel jumped through a bogus function pointer.
At the time of the crash, the stack seems to be corrupted, at least
ddb backtrace does not work. Register window information seems to point
at a call stack from the vnode cleaner thread via VCALL() -> VOCALL and
the issue might be anything from a compiler bug to random memory corruption
or just some use-after-free vnode/filesystem bug.

To catch it earlier (and have better ddb data available) I would like
to avoid the deadly jump and have the VOCALL macro verify integrity of
the ops vector.

I thought about a MD macro to KASSERT general function pointers (like on
sparc* check for % 4 == 0, test for >= kernel_start and maybe <= the
end of the module map region), and for DEBUG kernels that makro could
even do a pmap_extract().

Additionally (and maybe the easiest start) we could add some magic pointer
value to the start (and end?) of the ops vector and have VOCALL verify that
magic value.

Is that a sane idea?
Could we easily identify all ops vectors?

Martin
P.S.: in sys/sys/vnode.h, the comments about VOCALL not being used seem
to be exagerated, or I misread them.

Takahiro HAYASHI | 6 Apr 14:52 2015
Picon

xhci patch for nick-nhusb branch

Hello,

These are usb 3.0 patches for nick-nhusb branch.
Mostly same as patches I posted previously for current.

nh-xhci-cosmetic.diff
	whitespace

nh-xhci-fixtypo.diff
	fix typo in comment

nh-xhci-main.diff
	main patch
	(mostly same as I posted previously for -current)

nh-xhci-comments.diff
	sprinkle comments

nh-xhci-compat.diff
	share sources with other branches

nh-uhub-usbhistify.diff
	convert to use usbhist

nh-uhub-usb3.diff
	add support for usb3 hub

nh-misc.diff
+ usb.h
	fix SS and LS speed definition was swapped
	rename usb_usb2ext_descriptor_t to usb_devcap_usb2ext_descriptor_t
	add SS current definition
	add comments

+ usb_subr.c
	add UPS_PORT_POWER_SS treatment

+ xhcireg.h
	add definitions of port routing and capability ids

+ xhcivar.h
	add sc_quirks and definitions for it

-- 
t-hash
--- src/sys/dev/usb/xhci.c.orig	2015-03-27 15:05:03.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2015-04-04 16:43:18.000000000 +0900
 <at>  <at>  -62,7 +62,7  <at>  <at>  __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.2
 #ifdef USB_DEBUG
 #ifndef XHCI_DEBUG
 #define xhcidebug 0
-#else
+#else /* !XHCI_DEBUG */
 static int xhcidebug = 0;

 SYSCTL_SETUP(sysctl_hw_xhci_setup, "sysctl hw.xhci setup")
 <at>  <at>  -92,7 +92,7  <at>  <at>  fail:
 	aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err);
 }

-#endif /* XHCI_DEBUG */
+#endif /* !XHCI_DEBUG */
 #endif /* USB_DEBUG */

 #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(xhcidebug,N,FMT,A,B,C,D)
 <at>  <at>  -1109,7 +1109,7  <at>  <at>  xhci_set_dequeue(struct usbd_pipe *pipe)
 static usbd_status
 xhci_open(struct usbd_pipe *pipe)
 {
-	struct usbd_device *const dev = pipe->up_dev;
+	struct usbd_device * const dev = pipe->up_dev;
 	struct xhci_softc * const sc = dev->ud_bus->ub_hcpriv;
 	usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
 	const uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
 <at>  <at>  -1168,7 +1168,7  <at>  <at>  xhci_open(struct usbd_pipe *pipe)
 static void
 xhci_rhpsc(struct xhci_softc * const sc, u_int port)
 {
-	struct usbd_xfer *const xfer = sc->sc_intrxfer;
+	struct usbd_xfer * const xfer = sc->sc_intrxfer;
 	uint8_t *p;

 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 <at>  <at>  -1303,7 +1303,7  <at>  <at>  xhci_handle_event(struct xhci_softc * co
 static void
 xhci_softintr(void *v)
 {
-	struct usbd_bus *const bus = v;
+	struct usbd_bus * const bus = v;
 	struct xhci_softc * const sc = bus->ub_hcpriv;
 	struct xhci_ring * const er = &sc->sc_er;
 	struct xhci_trb *trb;
 <at>  <at>  -1983,7 +1983,8  <at>  <at>  xhci_noop(struct usbd_pipe *pipe)
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 }

-static int xhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
+static int
+xhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
     void *buf, int buflen)
 {
 	struct xhci_softc * const sc = bus->ub_hcpriv;
 <at>  <at>  -2666,7 +2667,7  <at>  <at>  static void
 xhci_timeout(void *addr)
 {
 	struct xhci_xfer * const xx = addr;
-	struct usbd_xfer *const xfer = &xx->xx_xfer;
+	struct usbd_xfer * const xfer = &xx->xx_xfer;
 	struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;

 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 <at>  <at>  -2684,7 +2685,7  <at>  <at>  xhci_timeout(void *addr)
 static void
 xhci_timeout_task(void *addr)
 {
-	struct usbd_xfer *const xfer = addr;
+	struct usbd_xfer * const xfer = addr;
 	struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;

 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
--- src/sys/dev/usb/xhci.c.orig	2015-04-04 16:43:18.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2015-04-04 16:47:39.000000000 +0900
 <at>  <at>  -2189,7 +2189,7  <at>  <at>  xhci_roothub_ctrl(struct usbd_bus *bus, 
 	return totlen;
 }

-/* root hub intrerrupt */
+/* root hub interrupt */

 static usbd_status
 xhci_root_intr_transfer(struct usbd_xfer *xfer)
--- src/sys/dev/usb/xhci.c.orig	2015-04-04 17:01:37.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2015-04-05 05:53:30.000000000 +0900
 <at>  <at>  -50,6 +50,7  <at>  <at>  __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>
 <at>  <at>  -126,18 +127,22  <at>  <at>  static int xhci_roothub_ctrl(struct usbd
     void *, int);

 static usbd_status xhci_configure_endpoint(struct usbd_pipe *);
-static usbd_status xhci_unconfigure_endpoint(struct usbd_pipe *);
+//static usbd_status xhci_unconfigure_endpoint(struct usbd_pipe *);
 static usbd_status xhci_reset_endpoint(struct usbd_pipe *);
-//static usbd_status xhci_stop_endpoint(struct usbd_pipe *);
+static usbd_status xhci_stop_endpoint(struct usbd_pipe *);

 static usbd_status xhci_set_dequeue(struct usbd_pipe *);

 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_command1(struct xhci_softc * const,
+    struct xhci_trb * const, int, int);
+static usbd_status xhci_do_command_locked(struct xhci_softc * const,
+    struct xhci_trb * const, int);
+static usbd_status xhci_init_slot(struct usbd_device *, 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,
 <at>  <at>  -228,11 +233,24  <at>  <at>  static const struct usbd_pipe_methods xh
 };

 static inline uint32_t
+xhci_read_1(const struct xhci_softc * const sc, bus_size_t offset)
+{
+	return bus_space_read_1(sc->sc_iot, sc->sc_ioh, offset);
+}
+
+static inline uint32_t
 xhci_read_4(const struct xhci_softc * const sc, bus_size_t offset)
 {
 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
 }

+static inline void
+xhci_write_1(const struct xhci_softc * const sc, bus_size_t offset,
+    uint32_t value)
+{
+	bus_space_write_1(sc->sc_iot, sc->sc_ioh, offset, value);
+}
+
 #if 0 /* unused */
 static inline void
 xhci_write_4(const struct xhci_softc * const sc, bus_size_t offset,
 <at>  <at>  -374,7 +392,7  <at>  <at>  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:
 <at>  <at>  -517,6 +535,7  <at>  <at>  xhci_detach(struct xhci_softc *sc, int f

 	mutex_destroy(&sc->sc_lock);
 	mutex_destroy(&sc->sc_intr_lock);
+	cv_destroy(&sc->sc_softwake_cv);

 	pool_cache_destroy(sc->sc_xferpool);

 <at>  <at>  -658,6 +677,28  <at>  <at>  xhci_init(struct xhci_softc *sc)
 			}
 			break;
 		}
+		case XHCI_ID_USB_LEGACY: {
+			uint8_t bios_sem;
+
+			/* Take host controller from BIOS */
+			bios_sem = xhci_read_1(sc, ecp + XHCI_XECP_BIOS_SEM);
+			if (bios_sem) {
+				/* sets xHCI to be owned by OS */
+				xhci_write_1(sc, ecp + XHCI_XECP_OS_SEM, 1);
+				aprint_debug(
+				    "waiting for BIOS to give up control\n");
+				for (i = 0; i < 5000; i++) {
+					bios_sem = xhci_read_1(sc, ecp +
+					    XHCI_XECP_BIOS_SEM);
+					if (bios_sem == 0)
+						break;
+					DELAY(1000);
+				}
+				if (bios_sem)
+					printf("timed out waiting for BIOS\n");
+			}
+			break;
+		}
 		default:
 			break;
 		}
 <at>  <at>  -732,6 +773,7  <at>  <at>  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;

 <at>  <at>  -825,6 +867,16  <at>  <at>  xhci_init(struct xhci_softc *sc)
 	    KM_SLEEP);

 	cv_init(&sc->sc_command_cv, "xhcicmd");
+	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
+	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
+	cv_init(&sc->sc_softwake_cv, "xhciab");
+
+	sc->sc_xferpool = pool_cache_init(sizeof(struct xhci_xfer), 0, 0, 0,
+	    "xhcixfer", NULL, IPL_USB, NULL, NULL, NULL);
+
+	/* Set up the bus struct. */
+	sc->sc_bus.ub_methods = &xhci_bus_methods;
+	sc->sc_bus.ub_pipesize = sizeof(struct xhci_pipe);

 	struct xhci_erste *erst;
 	erst = KERNADDR(&sc->sc_eventst_dma, 0);
 <at>  <at>  -848,23 +900,18  <at>  <at>  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);
+#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);

 	xhci_op_write_4(sc, XHCI_USBCMD, XHCI_CMD_INTE|XHCI_CMD_RS); /* Go! */
 	aprint_debug_dev(sc->sc_dev, "USBCMD %08"PRIx32"\n",
 	    xhci_op_read_4(sc, XHCI_USBCMD));

-	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
-	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
-	cv_init(&sc->sc_softwake_cv, "xhciab");
-
-	sc->sc_xferpool = pool_cache_init(sizeof(struct xhci_xfer), 0, 0, 0,
-	    "xhcixfer", NULL, IPL_USB, NULL, NULL, NULL);
-
-	/* Set up the bus struct. */
-	sc->sc_bus.ub_methods = &xhci_bus_methods;
-	sc->sc_bus.ub_pipesize = sizeof(struct xhci_pipe);
-
 	return USBD_NORMAL_COMPLETION;
 }

 <at>  <at>  -920,9 +967,19  <at>  <at>  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) {
+			return 0;
+		}
+	}
+
+#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);
 <at>  <at>  -934,6 +991,138  <at>  <at>  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 struct usbd_device 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 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.
+ */
+
+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;
+}
+
+/* construct slot context */
+static void
+xhci_setup_sctx(struct usbd_device *dev, uint32_t *cp)
+{
+	usb_device_descriptor_t * const dd = &dev->ud_ddesc;
+	int speed = dev->ud_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 ||
+	 *   parent hub is not HS hub ||
+	 *   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 ||
+	 *   parent hub is not HS hub ||
+	 *   attached to root hub.
+	 */
+	if (dev->ud_myhsport != NULL &&
+	    dev->ud_myhub != NULL && dev->ud_myhub->ud_depth != 0 &&
+	    (dev->ud_myhub != NULL &&
+	     dev->ud_myhub->ud_speed == USB_SPEED_HIGH) &&
+	    (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL)) {
+		ttportnum = dev->ud_myhsport->up_portno;
+		/* XXX addr == slot ? */
+		tthubslot = dev->ud_myhsport->up_parent->ud_addr;
+	} else {
+		ttportnum = 0;
+		tthubslot = 0;
+	}
+	DPRINTFN(4, "myhsport %p ttportnum=%d tthubslot=%d",
+	    dev->ud_myhsport, ttportnum, tthubslot, 0);
+
+	/* ishub is valid after reading UDESC_DEVICE */
+	ishub = (dd->bDeviceClass == UDCLASS_HUB);
+
+	/* dev->ud_hub is valid after reading UDESC_HUB */
+	if (ishub && dev->ud_hub) {
+		usb_hub_descriptor_t *hd = &dev->ud_hub->uh_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->ud_myhub != NULL && dev->ud_myhub->ud_depth != 0 &&
+	     (dev->ud_myhub != NULL &&
+	      dev->ud_myhub->ud_speed == USB_SPEED_HIGH) &&
+	     dev->ud_myhsport != NULL &&
+	     IS_TTHUB(&dev->ud_myhsport->up_parent->ud_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(struct usbd_pipe *pipe)
 {
 <at>  <at>  -945,10 +1134,14  <at>  <at>  xhci_configure_endpoint(struct usbd_pipe
 	struct xhci_trb trb;
 	usbd_status err;
 	uint32_t *cp;
+	uint32_t mps = UGETW(ed->wMaxPacketSize);
+	uint32_t maxb = 0;
+	int speed = pipe->up_dev->ud_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? */

 <at>  <at>  -960,34 +1153,121  <at>  <at>  xhci_configure_endpoint(struct usbd_pipe

 	/* 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->up_dev, cp);
+	cp[0] |= htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));

-	uint8_t eptype = xhci_ep_get_type(pipe->up_endpoint->ue_edesc);
 	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 */
-		    );
-		cp[1] = htole32(
-		    XHCI_EPCTX_1_CERR_SET(3) |
-		    XHCI_EPCTX_1_EPTYPE_SET(eptype) |
-		    XHCI_EPCTX_1_MAXB_SET(0) |
-		    XHCI_EPCTX_1_MAXP_SIZE_SET(8) /* XXX */
-		    );
+	cp[0] = htole32(
+	    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_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) {
+		usbd_desc_iter_t iter;
+		const usb_cdc_descriptor_t *cdcd;
+		const usb_endpoint_ss_comp_descriptor_t * esscd = NULL;
+		uint8_t ep;
+
+		cdcd = (const usb_cdc_descriptor_t *)usb_find_desc(
+		    pipe->up_dev, UDESC_INTERFACE, USBD_CDCSUBTYPE_ANY);
+		usb_desc_iter_init(pipe->up_dev, &iter);
+		iter.cur = (const void *)cdcd;
+
+		/* find endpoint_ss_comp desc for ep of this pipe */
+		for(ep = 0;;) {
+			cdcd = (const usb_cdc_descriptor_t *)
+			    usb_desc_iter_next(&iter);
+			if (cdcd == NULL)
+				break;
+			if (ep == 0 &&
+			    cdcd->bDescriptorType == UDESC_ENDPOINT) {
+				ep = ((const usb_endpoint_descriptor_t *)cdcd)->
+				    bEndpointAddress;
+				if (UE_GET_ADDR(ep) ==
+				    UE_GET_ADDR(ed->bEndpointAddress)) {
+					cdcd = (const usb_cdc_descriptor_t *)
+					    usb_desc_iter_next(&iter);
+					break;
+				}
+				ep = 0;
+			}
+		}
+		if (cdcd != NULL &&
+		    cdcd->bDescriptorType == UDESC_ENDPOINT_SS_COMP) {
+			esscd = (const usb_endpoint_ss_comp_descriptor_t *)cdcd;
+			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)
-		    );
-	} else {
-		cp[0] = htole32(0);
-		cp[1] = htole32(
-		    XHCI_EPCTX_1_CERR_SET(3) |
-		    XHCI_EPCTX_1_EPTYPE_SET(eptype) |
-		    XHCI_EPCTX_1_MAXB_SET(0) |
-		    XHCI_EPCTX_1_MAXP_SIZE_SET(512) /* XXX */
+		    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) |
 <at>  <at>  -1014,6 +1294,7  <at>  <at>  xhci_configure_endpoint(struct usbd_pipe
 	return err;
 }

+#if 0
 static usbd_status
 xhci_unconfigure_endpoint(struct usbd_pipe *pipe)
 {
 <at>  <at>  -1026,6 +1307,7  <at>  <at>  xhci_unconfigure_endpoint(struct usbd_pi

 	return USBD_NORMAL_COMPLETION;
 }
+#endif

 static usbd_status
 xhci_reset_endpoint(struct usbd_pipe *pipe)
 <at>  <at>  -1037,7 +1319,9  <at>  <at>  xhci_reset_endpoint(struct usbd_pipe *pi
 	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);
+
+	KASSERT(!mutex_owned(&sc->sc_lock));

 	trb.trb_0 = 0;
 	trb.trb_2 = 0;
 <at>  <at>  -1050,7 +1334,6  <at>  <at>  xhci_reset_endpoint(struct usbd_pipe *pi
 	return err;
 }

-#if 0
 static usbd_status
 xhci_stop_endpoint(struct usbd_pipe *pipe)
 {
 <at>  <at>  -1061,7 +1344,9  <at>  <at>  xhci_stop_endpoint(struct usbd_pipe *pip
 	const u_int dci = xhci_ep_get_dci(pipe->up_endpoint->ue_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);
+
+	KASSERT(mutex_owned(&sc->sc_lock));

 	trb.trb_0 = 0;
 	trb.trb_2 = 0;
 <at>  <at>  -1069,11 +1354,10  <at>  <at>  xhci_stop_endpoint(struct usbd_pipe *pip
 	    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(struct usbd_pipe *pipe)
 <at>  <at>  -1116,14 +1400,14  <at>  <at>  xhci_open(struct usbd_pipe *pipe)

 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 	DPRINTFN(1, "addr %d depth %d port %d speed %d",
-	    dev->ud_addr, dev->ud_depth, dev->ud_powersrc->up_portno, dev->ud_speed);
+	    dev->ud_addr, dev->ud_depth, dev->ud_powersrc->up_portno,
+	    dev->ud_speed);

 	if (sc->sc_dying)
 		return USBD_IOERROR;

 	/* Root Hub */
-	if (dev->ud_depth == 0 && dev->ud_powersrc->up_portno == 0 &&
-	    dev->ud_speed != USB_SPEED_SUPER) {
+	if (dev->ud_depth == 0 && dev->ud_powersrc->up_portno == 0) {
 		switch (ed->bEndpointAddress) {
 		case USB_CONTROL_ENDPOINT:
 			pipe->up_methods = &roothub_ctrl_methods;
 <at>  <at>  -1160,11 +1444,146  <at>  <at>  xhci_open(struct usbd_pipe *pipe)
 	}

 	if (ed->bEndpointAddress != USB_CONTROL_ENDPOINT)
-		xhci_configure_endpoint(pipe);
+		return xhci_configure_endpoint(pipe);
+
+	return USBD_NORMAL_COMPLETION;
+}
+
+static usbd_status
+xhci_close_pipe(struct usbd_pipe *pipe)
+{
+	struct xhci_softc * const sc = pipe->up_dev->ud_bus->ub_hcpriv;
+	struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
+	usb_endpoint_descriptor_t * const ed = pipe->up_endpoint->ue_edesc;
+	const u_int dci = xhci_ep_get_dci(ed);
+	struct xhci_trb trb;
+	usbd_status err;
+	uint32_t *cp;
+
+	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+	if (sc->sc_dying)
+		return USBD_IOERROR;
+
+	if (xs == NULL || xs->xs_idx == 0)
+		/* xs is uninitialized before xhci_init_slot */
+		return USBD_IOERROR;
+
+	DPRINTFN(4, "slot %u dci %u", xs->xs_idx, dci, 0, 0);
+
+	KASSERTMSG(!cpu_intr_p() && !cpu_softintr_p(), "called from intr ctx");
+	KASSERT(mutex_owned(&sc->sc_lock));
+
+	if (pipe->up_dev->ud_depth == 0)
+		return USBD_NORMAL_COMPLETION;
+
+	if (dci == XHCI_DCI_EP_CONTROL) {
+		DPRINTFN(4, "closing ep0", 0, 0, 0, 0);
+		return xhci_disable_slot(sc, xs->xs_idx);
+	}
+
+	(void)xhci_stop_endpoint(pipe);
+
+	/*
+	 * set appropriate bit to be dropped.
+	 * don't set DC bit to 1, otherwise all endpoints
+	 * would be deconfigured.
+	 */
+	cp = xhci_slot_get_icv(sc, xs, XHCI_ICI_INPUT_CONTROL);
+	cp[0] = htole32(XHCI_INCTX_0_DROP_MASK(dci));
+	cp[1] = htole32(0);
+
+	/* XXX should be most significant one, not dci? */
+	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);
+
+	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;
+}
+
+static void
+xhci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
+{
+	struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+
+	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+	DPRINTFN(4, "xfer %p pipe %p status %d",
+	    xfer, xfer->ux_pipe, status, 0);
+
+	KASSERT(mutex_owned(&sc->sc_lock));
+
+	if (sc->sc_dying) {
+		/* If we're dying, just do the software part. */
+		DPRINTFN(4, "dying", 0, 0, 0, 0);
+		xfer->ux_status = status;  /* make software ignore it */
+		callout_stop(&xfer->ux_callout);
+		usb_transfer_complete(xfer);
+		return;
+	}
+
+	/* XXX need more stuff */
+	xfer->ux_status = status;
+	callout_stop(&xfer->ux_callout);
+	usb_transfer_complete(xfer);
+
+	KASSERT(mutex_owned(&sc->sc_lock));
+}
+
+#if 1 /* XXX experimental */
+static void
+xhci_clear_endpoint_stall_async_task(void *cookie)
+{
+	struct usbd_xfer * const xfer = cookie;
+	struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+	struct xhci_slot * const xs = xfer->ux_pipe->up_dev->ud_hcpriv;
+	const u_int dci = xhci_ep_get_dci(xfer->ux_pipe->up_endpoint->ue_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->ux_pipe);
+	xhci_set_dequeue(xfer->ux_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 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;
+
+	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+	DPRINTFN(4, "xfer %p", xfer, 0, 0, 0);
+
+	if (sc->sc_dying) {
+		return USBD_IOERROR;
+	}
+
+	usb_init_task(&xfer->ux_pipe->up_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);
+	DPRINTFN(4, "ends", 0, 0, 0, 0);

 	return USBD_NORMAL_COMPLETION;
 }

+#endif /* XXX experimental */
 static void
 xhci_rhpsc(struct xhci_softc * const sc, u_int port)
 {
 <at>  <at>  -1177,14 +1596,6  <at>  <at>  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 = xfer->ux_buf;
 	memset(p, 0, xfer->ux_length);
 	p[port/NBBY] |= 1 << (port%NBBY);
 <at>  <at>  -1199,17 +1610,19  <at>  <at>  xhci_handle_event(struct xhci_softc * co
 {
 	uint64_t trb_0;
 	uint32_t trb_2, trb_3;
+	uint8_t trberr;

 	XHCIHIST_FUNC(); XHCIHIST_CALLED();

 	trb_0 = le64toh(trb->trb_0);
 	trb_2 = le32toh(trb->trb_2);
 	trb_3 = le32toh(trb->trb_3);
+	trberr = XHCI_TRB_2_ERROR_GET(trb_2);

 	DPRINTFN(14, "event: %p 0x%016"PRIx64" 0x%08"PRIx32" 0x%08"PRIx32,
 	    trb, trb_0, trb_2, trb_3);

-	switch (XHCI_TRB_3_TYPE_GET(trb_3)){
+	switch (XHCI_TRB_3_TYPE_GET(trb_3)) {
 	case XHCI_TRB_EVENT_TRANSFER: {
 		u_int slot, dci;
 		struct xhci_slot *xs;
 <at>  <at>  -1223,10 +1636,24  <at>  <at>  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 ((trb_3 & XHCI_TRB_3_ED_BIT) == 0) {
-			xx = xr->xr_cookies[(trb_0 - xhci_ring_trbp(xr, 0))/
-			    sizeof(struct xhci_trb)];
+			bus_addr_t trbp = xhci_ring_trbp(xr, 0);
+
+			/* trb_0 range sanity check */
+			if (trb_0 < trbp ||
+			    (trb_0 - trbp) % sizeof(struct xhci_trb) != 0 ||
+			    (trb_0 - trbp) / sizeof(struct xhci_trb) >=
+			     xr->xr_ntrb) {
+				DPRINTFN(1,
+				    "invalid trb_0 0x%"PRIx64" trbp 0x%"PRIx64,
+				    trb_0, trbp, 0, 0);
+				break;
+			}
+			int idx = (trb_0 - trbp) / sizeof(struct xhci_trb);
+			xx = xr->xr_cookies[idx];
 		} else {
 			xx = (void *)(uintptr_t)(trb_0 & ~0x3);
 		}
 <at>  <at>  -1243,21 +1670,38  <at>  <at>  xhci_handle_event(struct xhci_softc * co
 			}
 		}

-		if (XHCI_TRB_2_ERROR_GET(trb_2) ==
-		    XHCI_TRB_ERROR_SUCCESS) {
-			xfer->ux_actlen = xfer->ux_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->ux_actlen = xfer->ux_length - XHCI_TRB_2_REM_GET(trb_2);
+		if (trberr == XHCI_TRB_ERROR_SUCCESS ||
+		    trberr == XHCI_TRB_ERROR_SHORT_PKT) {
+			xfer->ux_actlen =
+			    xfer->ux_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",
-			    XHCI_TRB_2_ERROR_GET(trb_2), slot, dci, 0);
+			DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
+			    trberr, slot, dci, 0);
+#if 1 /* XXX experimental */
+			/*
+			 * Stalled endpoints can be recoverd by issuing
+			 * command TRB TYPE_RESET_EP on xHCI instead of
+			 * issuing request CLEAR_PORT_FEATURE UF_ENDPOINT_HALT
+			 * on the endpoint. However, this function may be
+			 * called from softint context (e.g. from umass),
+			 * in that case driver gets KASSERT in cv_timedwait
+			 * in xhci_do_command.
+			 * To avoid this, this runs reset_endpoint and
+			 * usb_transfer_complete in usb task thread
+			 * asynchronously (and then umass issues clear
+			 * UF_ENDPOINT_HALT).
+			 */
+			xfer->ux_status = err;
+			xhci_clear_endpoint_stall_async(xfer);
+			break;
+#endif
 		} else {
+			DPRINTFN(1, "evh: xfer done: ERR %u slot %u dci %u",
+			    trberr, slot, dci, 0);
 			err = USBD_IOERROR;
 		}
 		xfer->ux_status = err;
 <at>  <at>  -1287,7 +1731,7  <at>  <at>  xhci_handle_event(struct xhci_softc * co
 			}
 			cv_signal(&sc->sc_command_cv);
 		} else {
-			DPRINTFN(1, "event: %p 0x%016"PRIx64" "
+			DPRINTFN(1, "spurious event: %p 0x%016"PRIx64" "
 			    "0x%08"PRIx32" 0x%08"PRIx32, trb, trb_0,
 			    trb_2, trb_3);
 		}
 <at>  <at>  -1418,7 +1862,8  <at>  <at>  xhci_new_device(device_t parent, struct 
 	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();
 <at>  <at>  -1439,11 +1884,21  <at>  <at>  xhci_new_device(device_t parent, struct 
 	dev->ud_ep0desc.bDescriptorType = UDESC_ENDPOINT;
 	dev->ud_ep0desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
 	dev->ud_ep0desc.bmAttributes = UE_CONTROL;
-	/* XXX */
-	if (speed == USB_SPEED_LOW)
+	/* 4.3,  4.8.2.1 */
+	switch (speed) {
+	case USB_SPEED_SUPER:
+		USETW(dev->ud_ep0desc.wMaxPacketSize, USB_3_MAX_CTRL_PACKET);
+		break;
+	case USB_SPEED_FULL:
+		/* XXX using 64 as initial mps of ep0 in FS */
+	case USB_SPEED_HIGH:
+		USETW(dev->ud_ep0desc.wMaxPacketSize, USB_2_MAX_CTRL_PACKET);
+		break;
+	case USB_SPEED_LOW:
+	default:
 		USETW(dev->ud_ep0desc.wMaxPacketSize, USB_MAX_IPACKET);
-	else
-		USETW(dev->ud_ep0desc.wMaxPacketSize, 64);
+		break;
+	}
 	dev->ud_ep0desc.bInterval = 0;

 	/* doesn't matter, just don't let it uninitialized */
 <at>  <at>  -1461,28 +1916,48  <at>  <at>  xhci_new_device(device_t parent, struct 
 	up->up_dev = dev;

 	/* Locate root hub port */
-	for (adev = dev, hub = dev;
-	    hub != NULL;
-	    adev = hub, hub = hub->ud_myhub) {
-		DPRINTFN(4, "hub %p", hub, 0, 0, 0);
-	}
-	DPRINTFN(4, "hub %p", hub, 0, 0, 0);
+	for (hub = dev; hub != NULL; hub = hub->ud_myhub) {
+		uint32_t dep;
+
+		DPRINTFN(4, "hub %p depth %d upport %p upportno %d",
+		    hub, hub->ud_depth, hub->ud_powersrc,
+		    hub->ud_powersrc ? hub->ud_powersrc->up_portno : -1);
+
+		if (hub->ud_powersrc == NULL)
+			break;
+		dep = hub->ud_depth;
+		if (dep == 0)
+			break;
+		rhport = hub->ud_powersrc->up_portno;
+		if (dep > USB_HUB_MAX_DEPTH)
+			continue;

-	if (hub != NULL) {
-		for (int p = 0; p < hub->ud_hub->uh_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->up_parent;
+	     hub != NULL && hub->ud_speed != USB_SPEED_HIGH;
+	     adev = hub, hub = hub->ud_myhub)
+		;
+	if (hub) {
+		int p;
+		for (p = 0; p < hub->ud_hub->uh_hubdesc.bNbrPorts; p++) {
 			if (hub->ud_hub->uh_ports[p].up_dev == adev) {
-				rhport = p;
+				dev->ud_myhsport = &hub->ud_hub->uh_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->ud_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->ud_speed = speed;
 	dev->ud_langid = USBD_NOLANG;
 <at>  <at>  -1492,8 +1967,7  <at>  <at>  xhci_new_device(device_t parent, struct 
 	err = usbd_setup_pipe(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL,
 	    &dev->ud_pipe0);
 	if (err) {
-		usbd_remove_device(dev, up);
-		return err;
+		goto bad;
 	}

 	dd = &dev->ud_ddesc;
 <at>  <at>  -1503,19 +1977,24  <at>  <at>  xhci_new_device(device_t parent, struct 
 		bus->ub_devices[dev->ud_addr] = 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);
-		if (err)
-			return err;
+			goto bad;
 		xs = &sc->sc_slots[slot];
 		dev->ud_hcpriv = xs;
+		err = xhci_init_slot(dev, slot, route, rhport);
+		if (err) {
+			dev->ud_hcpriv = NULL;
+			goto bad;
+		}
+
+		/* Allow device time to set new address */
+		usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
 		cp = xhci_slot_get_dcv(sc, xs, XHCI_DCI_SLOT);
 		//hexdump("slot context", cp, sc->sc_ctxsz);
 		addr = XHCI_SCTX_3_DEV_ADDR_GET(cp[3]);
 <at>  <at>  -1530,12 +2009,19  <at>  <at>  xhci_new_device(device_t parent, struct 

 		err = usbd_get_initial_ddesc(dev, dd);
 		if (err)
-			return err;
+			goto bad;
 		/* 4.8.2.1 */
-		if (speed == USB_SPEED_SUPER)
+		if (speed == USB_SPEED_SUPER) {
+			if (dd->bMaxPacketSize != 9) {
+				printf("%s: invalid mps 2^%u for SS ep0,"
+				    " using 512\n",
+				    device_xname(sc->sc_dev),
+				    dd->bMaxPacketSize);
+				dd->bMaxPacketSize = 9;
+			}
 			USETW(dev->ud_ep0desc.wMaxPacketSize,
 			    (1 << dd->bMaxPacketSize));
-		else
+		} else
 	 		USETW(dev->ud_ep0desc.wMaxPacketSize,
 			    dd->bMaxPacketSize);
 		DPRINTFN(4, "bMaxPacketSize %u", dd->bMaxPacketSize, 0, 0, 0);
 <at>  <at>  -1543,11 +2029,15  <at>  <at>  xhci_new_device(device_t parent, struct 
 		    UGETW(dev->ud_ep0desc.wMaxPacketSize));
 		err = usbd_reload_device_desc(dev);
 		if (err)
-			return err;
+			goto bad;

+#if 0
+		/* Re-establish the default pipe with the new MPS. */
+		/* In xhci this is done by xhci_update_ep0_mps. */
 		usbd_kill_pipe(dev->ud_pipe0);
 		err = usbd_setup_pipe(dev, 0, &dev->ud_ep0,
 		    USBD_DEFAULT_INTERVAL, &dev->ud_pipe0);
+#endif
 	}

 	DPRINTFN(1, "adding unit addr=%d, rev=%02x,",
 <at>  <at>  -1569,12 +2059,12  <at>  <at>  xhci_new_device(device_t parent, struct 

 
 	err = usbd_probe_and_attach(parent, dev, port, dev->ud_addr);
-	if (err) {
+ bad:
+	if (err != USBD_NORMAL_COMPLETION) {
 		usbd_remove_device(dev, up);
-		return err;
 	}

-	return USBD_NORMAL_COMPLETION;
+	return err;
 }

 static usbd_status
 <at>  <at>  -1713,8 +2203,8  <at>  <at>  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;
 <at>  <at>  -1723,7 +2213,10  <at>  <at>  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);
+	KASSERTMSG(!cpu_intr_p() && !cpu_softintr_p(), "called from intr ctx");
+
+	if (!locked)
+		mutex_enter(&sc->sc_lock);

 	KASSERT(sc->sc_command_addr == 0);
 	sc->sc_command_addr = xhci_ring_trbp(cr, cr->xr_ep);
 <at>  <at>  -1762,11 +2255,26  <at>  <at>  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;
 <at>  <at>  -1789,6 +2297,36  <at>  <at>  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->xs_idx != 0) {
+		for (int i = XHCI_DCI_SLOT + 1; i < 32; 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);
+		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)
 {
 <at>  <at>  -1855,46 +2393,20  <at>  <at>  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(struct usbd_device *dev, uint32_t slot, int route, int rhport)
 {
+	struct xhci_softc * const sc = dev->ud_bus->ub_hcpriv;
 	struct xhci_slot *xs;
 	usbd_status err;
 	u_int dci;
 	uint32_t *cp;
-	uint32_t mps;
-	uint32_t xspeed;
+	uint32_t mps = UGETW(dev->ud_ep0desc.wMaxPacketSize);

 	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);
-
-	switch (speed) {
-	case USB_SPEED_LOW:
-		xspeed = 2;
-		mps = USB_MAX_IPACKET;
-		break;
-	case USB_SPEED_FULL:
-		xspeed = 1;
-		mps = 64;
-		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:
-		DPRINTFN(0, "impossible speed: %x", speed, 0, 0, 0);
-		return USBD_INVAL;
-	}
+	DPRINTFN(4, "slot %u speed %d rhport %d route %05x",
+	    slot, dev->ud_speed, route, rhport);

 	xs = &sc->sc_slots[slot];
-	xs->xs_idx = slot;

 	/* allocate contexts */
 	err = usb_allocmem(&sc->sc_bus, sc->sc_pgsz, sc->sc_pgsz,
 <at>  <at>  -1906,7 +2418,7  <at>  <at>  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++) {
 <at>  <at>  -1918,7 +2430,7  <at>  <at>  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;
 		}
 	}

 <at>  <at>  -1930,17 +2442,10  <at>  <at>  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));
 <at>  <at>  -1972,6 +2477,20  <at>  <at>  xhci_init_slot(struct xhci_softc * const
 	hexdump("output context", xhci_slot_get_dcv(sc, xs, 0),
 	    sc->sc_ctxsz * 2);

+ bad2:
+	if (err == USBD_NORMAL_COMPLETION) {
+		xs->xs_idx = slot;
+	} else {
+		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);
+		xs->xs_idx = 0;
+	}
+
 	return err;
 }

 <at>  <at>  -2031,10 +2550,10  <at>  <at>  xhci_roothub_ctrl(struct usbd_bus *bus, 
 	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) {
 			return -1;
 		}
-		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;
 <at>  <at>  -2056,9 +2575,18  <at>  <at>  xhci_roothub_ctrl(struct usbd_bus *bus, 
 		case UHF_C_PORT_SUSPEND:
 		case UHF_C_PORT_OVER_CURRENT:
 			return -1;
+		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:
 			return -1;
 		}
 <at>  <at>  -2073,7 +2601,7  <at>  <at>  xhci_roothub_ctrl(struct usbd_bus *bus, 

 		totlen = min(buflen, sizeof(hubd));
 		memcpy(&hubd, buf, totlen);
-		hubd.bNbrPorts = sc->sc_hs_port_count;
+		hubd.bNbrPorts = sc->sc_maxports;
 		USETW(hubd.wHubCharacteristics, UHD_PWR_NO_SWITCH);
 		hubd.bPwrOn2PwrGood = 200;
 		for (i = 0, l = sc->sc_maxports; l > 0; i++, l -= 8)
 <at>  <at>  -2097,10 +2625,8  <at>  <at>  xhci_roothub_ctrl(struct usbd_bus *bus, 
 		if (len != 4) {
 			return -1;
 		}
-		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);
 		switch (XHCI_PS_SPEED_GET(v)) {
 		case 1:
 			i = UPS_FULL_SPEED;
 <at>  <at>  -2111,6 +2637,9  <at>  <at>  xhci_roothub_ctrl(struct usbd_bus *bus, 
 		case 3:
 			i = UPS_HIGH_SPEED;
 			break;
+		case 4:
+			i = UPS_SUPER_SPEED;
+			break;
 		default:
 			i = 0;
 			break;
 <at>  <at>  -2120,26 +2649,39  <at>  <at>  xhci_roothub_ctrl(struct usbd_bus *bus, 
 		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);
 		totlen = min(len, sizeof(ps));
 		memcpy(buf, &ps, totlen);
 		break;
 	case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE):
 		return -1;
+	case C(UR_SET_HUB_DEPTH, UT_WRITE_CLASS_DEVICE):
+		break;
 	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) {
+	{
+		int optval = (index >> 8) & 0xff;
+		index &= 0xff;
+		if (index < 1 || index > sc->sc_maxports) {
 			return -1;
 		}
-		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;
 <at>  <at>  -2172,9 +2714,30  <at>  <at>  xhci_roothub_ctrl(struct usbd_bus *bus, 
 		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) {
+				return -1;
+			}
+			port = XHCI_PORTPMSC(index);
+			v = xhci_op_read_4(sc, port);
+			v &= ~XHCI_PM3_U1TO_SET(0xff);
+			v |= XHCI_PM3_U1TO_SET(optval);
+			xhci_op_write_4(sc, port, v);
+			break;
+		case UHF_PORT_U2_TIMEOUT:
+			if (XHCI_PS_SPEED_GET(v) != 4) {
+				return -1;
+			}
+			port = XHCI_PORTPMSC(index);
+			v = xhci_op_read_4(sc, port);
+			v &= ~XHCI_PM3_U2TO_SET(0xff);
+			v |= XHCI_PM3_U2TO_SET(optval);
+			xhci_op_write_4(sc, port, v);
+			break;
 		default:
 			return -1;
 		}
+	}
 		break;
 	case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER):
 	case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER):
 <at>  <at>  -2237,8 +2800,6  <at>  <at>  xhci_root_intr_abort(struct usbd_xfer *x
 	KASSERT(mutex_owned(&sc->sc_lock));
 	KASSERT(xfer->ux_pipe->up_intrxfer == xfer);

-	DPRINTFN(1, "remove", 0, 0, 0, 0);
-
 	sc->sc_intrxfer = NULL;

 	xfer->ux_status = USBD_CANCELLED;
 <at>  <at>  -2311,6 +2872,8  <at>  <at>  xhci_device_ctrl_start(struct usbd_xfer 

 	/* XXX */
 	if (tr->is_halted) {
+		DPRINTFN(1, "ctrl xfer %p halted: slot %u dci %u",
+		    xfer, xs->xs_idx, dci, 0);
 		xhci_reset_endpoint(xfer->ux_pipe);
 		tr->is_halted = false;
 		xhci_set_dequeue(xfer->ux_pipe);
 <at>  <at>  -2400,12 +2963,16  <at>  <at>  static void
 xhci_device_ctrl_abort(struct usbd_xfer *xfer)
 {
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+	xhci_abort_xfer(xfer, USBD_CANCELLED);
 }

 static void
 xhci_device_ctrl_close(struct usbd_pipe *pipe)
 {
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+	(void)xhci_close_pipe(pipe);
 }

 /* ------------------ */
 <at>  <at>  -2518,12 +3085,16  <at>  <at>  static void
 xhci_device_bulk_abort(struct usbd_xfer *xfer)
 {
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+	xhci_abort_xfer(xfer, USBD_CANCELLED);
 }

 static void
 xhci_device_bulk_close(struct usbd_pipe *pipe)
 {
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+	(void)xhci_close_pipe(pipe);
 }

 /* ---------------- */
 <at>  <at>  -2646,8 +3217,7  <at>  <at>  xhci_device_intr_abort(struct usbd_xfer 
 	KASSERT(mutex_owned(&sc->sc_lock));
 	DPRINTFN(15, "%p", xfer, 0, 0, 0);
 	KASSERT(xfer->ux_pipe->up_intrxfer == xfer);
-	xfer->ux_status = USBD_CANCELLED;
-	usb_transfer_complete(xfer);
+	xhci_abort_xfer(xfer, USBD_CANCELLED);
 }

 static void
 <at>  <at>  -2658,7 +3228,7  <at>  <at>  xhci_device_intr_close(struct usbd_pipe 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 	DPRINTFN(15, "%p", pipe, 0, 0, 0);

-	xhci_unconfigure_endpoint(pipe);
+	(void)xhci_close_pipe(pipe);
 }

 /* ------------ */
--- src/sys/dev/usb/xhci.c.orig	2015-04-05 05:53:30.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2015-04-05 07:10:10.000000000 +0900
 <at>  <at>  -1123,6 +1123,12  <at>  <at>  xhci_setup_sctx(struct usbd_device *dev,
 	cp[3] |= htole32(0);
 }

+/*
+ * called
+ *  from xhci_open
+ *  from usbd_setup_pipe_flags
+ *  from usbd_open_pipe_ival
+ */
 static usbd_status
 xhci_configure_endpoint(struct usbd_pipe *pipe)
 {
 <at>  <at>  -1309,6 +1315,7  <at>  <at>  xhci_unconfigure_endpoint(struct usbd_pi
 }
 #endif

+/* 4.6.8, 6.4.3.7 */
 static usbd_status
 xhci_reset_endpoint(struct usbd_pipe *pipe)
 {
 <at>  <at>  -1334,6 +1341,11  <at>  <at>  xhci_reset_endpoint(struct usbd_pipe *pi
 	return err;
 }

+/*
+ * 4.6.9, 6.4.3.8
+ * Stop execution of TDs on xfer ring.
+ * Should be called with sc_lock held.
+ */
 static usbd_status
 xhci_stop_endpoint(struct usbd_pipe *pipe)
 {
 <at>  <at>  -1359,6 +1371,12  <at>  <at>  xhci_stop_endpoint(struct usbd_pipe *pip
 	return err;
 }

+/*
+ * Set TR Dequeue Pointer.
+ * xCHI 1.1  4.6.10  6.4.3.9
+ * Purge all of transfer requests in ring.
+ * EPSTATE of endpoint must be ERROR or STOPPED, or CONTEXT_STATE error.
+ */
 static usbd_status
 xhci_set_dequeue(struct usbd_pipe *pipe)
 {
 <at>  <at>  -1379,6 +1397,7  <at>  <at>  xhci_set_dequeue(struct usbd_pipe *pipe)
 	xr->xr_ep = 0;
 	xr->xr_cs = 1;

+	/* set DCS */
 	trb.trb_0 = xhci_ring_trbp(xr, 0) | 1; /* XXX */
 	trb.trb_2 = 0;
 	trb.trb_3 = XHCI_TRB_3_SLOT_SET(xs->xs_idx) |
 <at>  <at>  -1390,6 +1409,11  <at>  <at>  xhci_set_dequeue(struct usbd_pipe *pipe)
 	return err;
 }

+/*
+ * Open new pipe: called from usbd_setup_pipe_flags.
+ * Fills methods of pipe.
+ * If pipe is not for ep0, calls configure_endpoint.
+ */
 static usbd_status
 xhci_open(struct usbd_pipe *pipe)
 {
 <at>  <at>  -1449,6 +1473,11  <at>  <at>  xhci_open(struct usbd_pipe *pipe)
 	return USBD_NORMAL_COMPLETION;
 }

+/*
+ * Closes pipe, called from usbd_kill_pipe via close methods.
+ * If the endpoint to be closed is ep0, disable_slot.
+ * Should be called with sc_lock held.
+ */
 static usbd_status
 xhci_close_pipe(struct usbd_pipe *pipe)
 {
 <at>  <at>  -1482,6 +1511,10  <at>  <at>  xhci_close_pipe(struct usbd_pipe *pipe)
 		return xhci_disable_slot(sc, xs->xs_idx);
 	}

+	/*
+	 * This may fail in the case that xhci_close_pipe is called after
+	 * xhci_abort_xfer e.g. usbd_kill_pipe.
+	 */
 	(void)xhci_stop_endpoint(pipe);

 	/*
 <at>  <at>  -1511,6 +1544,11  <at>  <at>  xhci_close_pipe(struct usbd_pipe *pipe)
 	return err;
 }

+/*
+ * Abort transfer.
+ * Called with sc_lock held.
+ * May be called from softintr context.
+ */
 static void
 xhci_abort_xfer(struct usbd_xfer *xfer, usbd_status status)
 {
 <at>  <at>  -1540,6 +1578,7  <at>  <at>  xhci_abort_xfer(struct usbd_xfer *xfer, 
 }

 #if 1 /* XXX experimental */
+/* issue reset_ep and set_dequeue in thread context */
 static void
 xhci_clear_endpoint_stall_async_task(void *cookie)
 {
 <at>  <at>  -1574,6 +1613,7  <at>  <at>  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,
 	    xhci_clear_endpoint_stall_async_task, xfer, USB_TASKQ_MPSAFE);
 	usb_add_task(xfer->ux_pipe->up_dev, &xfer->ux_pipe->up_async_task,
 <at>  <at>  -1584,6 +1624,9  <at>  <at>  xhci_clear_endpoint_stall_async(struct u
 }

 #endif /* XXX experimental */
+/*
+ * Notify roothub port status/change to uhub_intr.
+ */
 static void
 xhci_rhpsc(struct xhci_softc * const sc, u_int port)
 {
 <at>  <at>  -1604,6 +1647,12  <at>  <at>  xhci_rhpsc(struct xhci_softc * const sc,
 	usb_transfer_complete(xfer);
 }

+/*
+ * Process events:
+ * + Transfer comeplete
+ * + Command complete
+ * + Roothub Port status/change
+ */
 static void
 xhci_handle_event(struct xhci_softc * const sc,
     const struct xhci_trb * const trb)
 <at>  <at>  -1849,6 +1898,16  <at>  <at>  xhci_get_lock(struct usbd_bus *bus, kmut

 extern uint32_t usb_cookie_no;

+/*
+ * Called if uhub_explore find new device (via usbd_new_device).
+ * Allocate and construct dev structure of default endpoint (ep0).
+ *   Determine initial MaxPacketSize (mps) by speed.
+ *   Determine route string and roothub port for slot of dev.
+ * Allocate pipe of ep0.
+ * Enable and initialize slot and Set Address.
+ * Read device descriptor.
+ * Register this device.
+ */
 static usbd_status
 xhci_new_device(device_t parent, struct usbd_bus *bus, int depth,
     int speed, int port, struct usbd_port *up)
 <at>  <at>  -2202,6 +2261,13  <at>  <at>  xhci_ring_put(struct xhci_softc * const 
 	DPRINTFN(12, "%p xr_ep 0x%x xr_cs %u", xr, xr->xr_ep, xr->xr_cs, 0);
 }

+/*
+ * Put a command on command ring, ring bell, set timer, and cv_timedwait.
+ * Command completion is notified by cv_signal from xhci_handle_event
+ * (called from interrupt from xHCI), or timed-out.
+ * Command validation is performed in xhci_handle_event by checking if
+ * trb_0 in CMD_COMPLETE TRB and sc->sc_command_addr are identical.
+ */
 static usbd_status
 xhci_do_command1(struct xhci_softc * const sc, struct xhci_trb * const trb,
     int timeout, int locked)
 <at>  <at>  -2218,6 +2284,7  <at>  <at>  xhci_do_command1(struct xhci_softc * con
 	if (!locked)
 		mutex_enter(&sc->sc_lock);

+	/* XXX KASSERT may fire when cv_timedwait unlocks sc_lock */
 	KASSERT(sc->sc_command_addr == 0);
 	sc->sc_command_addr = xhci_ring_trbp(cr, cr->xr_ep);

 <at>  <at>  -2267,6 +2334,11  <at>  <at>  xhci_do_command(struct xhci_softc * cons
 	return xhci_do_command1(sc, trb, timeout, 0);
 }

+/*
+ * This allows xhci_do_command with already sc_lock held.
+ * This is needed as USB stack calls close methods with sc_lock_held.
+ * (see usbdivar.h)
+ */
 static usbd_status
 xhci_do_command_locked(struct xhci_softc * const sc,
     struct xhci_trb * const trb, int timeout)
 <at>  <at>  -2296,6 +2368,10  <at>  <at>  xhci_enable_slot(struct xhci_softc * con
 	return err;
 }

+/*
+ * Deallocate DMA buffer and ring buffer, and disable_slot.
+ * Should be called with sc_lock held.
+ */
 static usbd_status
 xhci_disable_slot(struct xhci_softc * const sc, uint8_t slot)
 {
 <at>  <at>  -2326,6 +2402,12  <at>  <at>  xhci_disable_slot(struct xhci_softc * co
 	return xhci_do_command_locked(sc, &trb, USBD_DEFAULT_TIMEOUT);
 }

+/*
+ * Change slot state.
+ * bsr=0: ENABLED -> ADDRESSED
+ * bsr=1: ENABLED -> DEFAULT
+ * see xHCI 1.1  4.5.3, 3.3.4
+ */
 static usbd_status
 xhci_address_device(struct xhci_softc * const sc,
     uint64_t icp, uint8_t slot_id, bool bsr)
 <at>  <at>  -2392,6 +2474,11  <at>  <at>  xhci_set_dcba(struct xhci_softc * const 
 	    BUS_DMASYNC_PREWRITE);
 }

+/*
+ * Allocate DMA buffer and ring buffer for specified slot
+ * and set Device Context Base Address
+ * and issue Set Address device command.
+ */
 static usbd_status
 xhci_init_slot(struct usbd_device *dev, uint32_t slot, int route, int rhport)
 {
 <at>  <at>  -2502,6 +2589,9  <at>  <at>  xhci_noop(struct usbd_pipe *pipe)
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 }

+/*
+ * Process root hub request.
+ */
 static int
 xhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
     void *buf, int buflen)
 <at>  <at>  -2773,6 +2863,7  <at>  <at>  xhci_root_intr_transfer(struct usbd_xfer
 	return xhci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }

+/* Wait for roothub port status/change */
 static usbd_status
 xhci_root_intr_start(struct usbd_xfer *xfer)
 {
--- src/sys/dev/usb/xhci.c.orig	2015-04-05 07:10:10.000000000 +0900
+++ src/sys/dev/usb/xhci.c	2015-04-05 08:46:34.000000000 +0900
 <at>  <at>  -32,9 +32,17  <at>  <at>  __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.2
 #include "opt_usb.h"

 #include <sys/param.h>
+
+#if __NetBSD_Version__ >= 799000200
+#define USE_USBHIST
+#endif
+
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/kmem.h>
+#ifndef NHUSB
+#include <sys/malloc.h>
+#endif
 #include <sys/device.h>
 #include <sys/select.h>
 #include <sys/proc.h>
 <at>  <at>  -50,16 +58,96  <at>  <at>  __KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.2
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdivar.h>
+#undef NHUSB
+/* XXX any other better flag.. */
+#ifndef URQ_AUTO_DMABUF
+#define NHUSB
+#endif
 #include <dev/usb/usbdi_util.h>
+#ifdef USE_USBHIST
 #include <dev/usb/usbhist.h>
+#endif
 #include <dev/usb/usb_mem.h>
 #include <dev/usb/usb_quirks.h>

 #include <dev/usb/xhcireg.h>
 #include <dev/usb/xhcivar.h>
+#ifndef NHUSB
+#include <dev/usb/usbroothub_subr.h>
+#else
 #include <dev/usb/usbroothub.h>
+#endif
+

+#ifndef NHUSB
+/* usbd_xfer */
+#define ux_pipe		pipe
+#define ux_priv		priv
+#define ux_buffer	buffer
+#define ux_length	length
+#define ux_actlen	actlen
+#define ux_flags	flags
+#define ux_timeout	timeout
+#define ux_status	status
+#define ux_callback	callback
+#define ux_done		done
+#define ux_state	busy_free
+#define ux_request	request
+#define ux_frlengths	frlengths
+#define ux_nframes	nframes
+#define ux_dmabuf	dmabuf
+#define ux_rqflags	rqflags
+#define ux_hcpriv	hcpriv
+#define ux_hcflags	hcflags
+#define ux_callout	timeout_handle
+#define ux_hccv		hccv
+/* usbd_pipe */
+#define up_dev		device
+#define up_endpoint	endpoint
+#define up_queue	queue
+#define up_async_task	async_task
+#define up_intrxfer	intrxfer
+#define up_repeat	repeat
+#define up_interval	interval
+#define up_methods	methods
+/* usbd_device */
+#define ud_bus		bus
+#define ud_pipe0	default_pipe
+#define ud_addr		address
+#define ud_depth	depth
+#define ud_speed	speed
+#define ud_langid	langid
+#define ud_cookie	cookie
+#define ud_powersrc	powersrc
+#define ud_myhub	myhub
+#define ud_myhsport	myhsport
+#define ud_ep0desc	def_ep_desc
+#define ud_ep0		def_ep
+#define ud_ddesc	ddesc
+#define ud_quirks	quirks
+#define ud_hub		hub
+#define ud_hcpriv	hci_private
+/* usbd_endpoint */
+#define ue_edesc	edesc
+#define ue_toggle	datatoggle
+/* usbd_bus */
+#define ub_hcpriv	hci_private
+#define ub_revision	usbrev
+#define ub_methods	methods
+#define ub_pipesize	pipe_size
+#define ub_roothub	root_hub
+#define ub_devices	devices
+#define ub_usepolling	use_polling
+/* usbd_hub */
+#define uh_hubdesc	hubdesc
+#define uh_ports	ports
+/* usbd_port */
+#define up_portno	portno
+#define up_parent	parent
+/* usb_dma_block */
+#define udma_block	block

+#endif
 #ifdef USB_DEBUG
 #ifndef XHCI_DEBUG
 #define xhcidebug 0
 <at>  <at>  -96,9 +184,34  <at>  <at>  fail:
 #endif /* !XHCI_DEBUG */
 #endif /* USB_DEBUG */

+#ifdef USE_USBHIST
 #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(xhcidebug,N,FMT,A,B,C,D)
 #define XHCIHIST_FUNC() USBHIST_FUNC()
 #define XHCIHIST_CALLED(name) USBHIST_CALLED(xhcidebug)
+#else /* USE_USBHIST */
+# if defined(USB_DEBUG) && defined(XHCI_DEBUG)
+/* fake USBHIST_LOGN() for netbsd-7 */
+static void
+xhci_histprint(const char *fmt, u_long a0, u_long a1, u_long a2, u_long a3)
+{
+	printf(fmt, a0, a1, a2, a3);
+}
+#  define DPRINTFN(N,FMT,A,B,C,D) do {					\
+	if (xhcidebug >= (N)) {						\
+		printf("%s: ", __func__);				\
+		xhci_histprint((FMT),					\
+		    (u_long)(A), (u_long)(B), (u_long)(C), (u_long)(D));\
+		printf("\n");						\
+	}								\
+    } while(0)
+#  define XHCIHIST_FUNC() do {} while(0)
+#  define XHCIHIST_CALLED(name) do {} while(0)
+# else /* defined(USB_DEBUG) && defined(XHCI_DEBUG) */
+#  define DPRINTFN(N,FMT,A,B,C,D) do {} while(0)
+#  define XHCIHIST_FUNC() do {} while(0)
+#  define XHCIHIST_CALLED(name) do {} while(0)
+# endif /* defined(USB_DEBUG) && defined(XHCI_DEBUG) */
+#endif /* USE_USBHIST */

 #define XHCI_DCI_SLOT 0
 #define XHCI_DCI_EP_CONTROL 1
 <at>  <at>  -109,6 +222,9  <at>  <at>  struct xhci_pipe {
 	struct usbd_pipe xp_pipe;
 };

+#ifndef NHUSB
+#define USBROOTHUB_INTR_ENDPT 1
+#endif
 #define XHCI_COMMAND_RING_TRBS 256
 #define XHCI_EVENT_RING_TRBS 256
 #define XHCI_EVENT_RING_SEGMENTS 1
 <at>  <at>  -118,13 +234,19  <at>  <at>  static usbd_status xhci_open(struct usbd
 static int xhci_intr1(struct xhci_softc * const);
 static void xhci_softintr(void *);
 static void xhci_poll(struct usbd_bus *);
+#ifndef NHUSB
+static usbd_status xhci_allocm(struct usbd_bus *, usb_dma_t *, uint32_t);
+static void xhci_freem(struct usbd_bus *, usb_dma_t *);
+#endif
 static struct usbd_xfer *xhci_allocx(struct usbd_bus *);
 static void xhci_freex(struct usbd_bus *, struct usbd_xfer *);
 static void xhci_get_lock(struct usbd_bus *, kmutex_t **);
 static usbd_status xhci_new_device(device_t, struct usbd_bus *, int, int, int,
     struct usbd_port *);
+#ifdef NHUSB
 static int xhci_roothub_ctrl(struct usbd_bus *, usb_device_request_t *,
     void *, int);
+#endif

 static usbd_status xhci_configure_endpoint(struct usbd_pipe *);
 //static usbd_status xhci_unconfigure_endpoint(struct usbd_pipe *);
 <at>  <at>  -153,6 +275,14  <at>  <at>  static void xhci_ring_free(struct xhci_s

 static void xhci_noop(struct usbd_pipe *);

+#ifndef NHUSB
+static usbd_status xhci_root_ctrl_transfer(struct usbd_xfer *);
+static usbd_status xhci_root_ctrl_start(struct usbd_xfer *);
+static void xhci_root_ctrl_abort(struct usbd_xfer *);
+static void xhci_root_ctrl_close(struct usbd_pipe *);
+static void xhci_root_ctrl_done(struct usbd_xfer *);
+
+#endif
 static usbd_status xhci_root_intr_transfer(struct usbd_xfer *);
 static usbd_status xhci_root_intr_start(struct usbd_xfer *);
 static void xhci_root_intr_abort(struct usbd_xfer *);
 <at>  <at>  -181,6 +311,17  <at>  <at>  static void xhci_timeout(void *);
 static void xhci_timeout_task(void *);

 static const struct usbd_bus_methods xhci_bus_methods = {
+#ifndef NHUSB
+	.open_pipe = xhci_open,
+	.soft_intr = xhci_softintr,
+	.do_poll = xhci_poll,
+	.allocm = xhci_allocm,
+	.freem = xhci_freem,
+	.allocx = xhci_allocx,
+	.freex = xhci_freex,
+	.get_lock = xhci_get_lock,
+	.new_device = xhci_new_device,
+#else
 	.ubm_open = xhci_open,
 	.ubm_softint = xhci_softintr,
 	.ubm_dopoll = xhci_poll,
 <at>  <at>  -189,47 +330,99  <at>  <at>  static const struct usbd_bus_methods xhc
 	.ubm_getlock = xhci_get_lock,
 	.ubm_newdev = xhci_new_device,
 	.ubm_rhctrl = xhci_roothub_ctrl,
+#endif
+};
+
+#ifndef NHUSB
+static const struct usbd_pipe_methods xhci_root_ctrl_methods = {
+	.transfer = xhci_root_ctrl_transfer,
+	.start = xhci_root_ctrl_start,
+	.abort = xhci_root_ctrl_abort,
+	.close = xhci_root_ctrl_close,
+	.cleartoggle = xhci_noop,
+	.done = xhci_root_ctrl_done,
 };

+#endif
 static const struct usbd_pipe_methods xhci_root_intr_methods = {
+#ifndef NHUSB
+	.transfer = xhci_root_intr_transfer,
+	.start = xhci_root_intr_start,
+	.abort = xhci_root_intr_abort,
+	.close = xhci_root_intr_close,
+	.cleartoggle = xhci_noop,
+	.done = xhci_root_intr_done,
+#else
 	.upm_transfer = xhci_root_intr_transfer,
 	.upm_start = xhci_root_intr_start,
 	.upm_abort = xhci_root_intr_abort,
 	.upm_close = xhci_root_intr_close,
 	.upm_cleartoggle = xhci_noop,
 	.upm_done = xhci_root_intr_done,
+#endif
 };

 
 static const struct usbd_pipe_methods xhci_device_ctrl_methods = {
+#ifndef NHUSB
+	.transfer = xhci_device_ctrl_transfer,
+	.start = xhci_device_ctrl_start,
+	.abort = xhci_device_ctrl_abort,
+	.close = xhci_device_ctrl_close,
+	.cleartoggle = xhci_noop,
+	.done = xhci_device_ctrl_done,
+#else
 	.upm_transfer = xhci_device_ctrl_transfer,
 	.upm_start = xhci_device_ctrl_start,
 	.upm_abort = xhci_device_ctrl_abort,
 	.upm_close = xhci_device_ctrl_close,
 	.upm_cleartoggle = xhci_noop,
 	.upm_done = xhci_device_ctrl_done,
+#endif
 };

 static const struct usbd_pipe_methods xhci_device_isoc_methods = {
+#ifndef NHUSB
+	.cleartoggle = xhci_noop,
+#else
 	.upm_cleartoggle = xhci_noop,
+#endif
 };

 static const struct usbd_pipe_methods xhci_device_bulk_methods = {
+#ifndef NHUSB
+	.transfer = xhci_device_bulk_transfer,
+	.start = xhci_device_bulk_start,
+	.abort = xhci_device_bulk_abort,
+	.close = xhci_device_bulk_close,
+	.cleartoggle = xhci_noop,
+	.done = xhci_device_bulk_done,
+#else
 	.upm_transfer = xhci_device_bulk_transfer,
 	.upm_start = xhci_device_bulk_start,
 	.upm_abort = xhci_device_bulk_abort,
 	.upm_close = xhci_device_bulk_close,
 	.upm_cleartoggle = xhci_noop,
 	.upm_done = xhci_device_bulk_done,
+#endif
 };

 static const struct usbd_pipe_methods xhci_device_intr_methods = {
+#ifndef NHUSB
+	.transfer = xhci_device_intr_transfer,
+	.start = xhci_device_intr_start,
+	.abort = xhci_device_intr_abort,
+	.close = xhci_device_intr_close,
+	.cleartoggle = xhci_noop,
+	.done = xhci_device_intr_done,
+#else
 	.upm_transfer = xhci_device_intr_transfer,
 	.upm_start = xhci_device_intr_start,
 	.upm_abort = xhci_device_intr_abort,
 	.upm_close = xhci_device_intr_close,
 	.upm_cleartoggle = xhci_noop,
 	.upm_done = xhci_device_intr_done,
+#endif
 };

 static inline uint32_t
 <at>  <at>  -618,7 +811,9  <at>  <at>  xhci_init(struct xhci_softc *sc)

 	/* XXX Low/Full/High speeds for now */
 	sc->sc_bus.ub_revision = USBREV_2_0;
+#ifdef NHUSB
 	sc->sc_bus.ub_usedma = true;
+#endif

 	cap = xhci_read_4(sc, XHCI_CAPLENGTH);
 	caplength = XHCI_CAP_CAPLENGTH(cap);
 <at>  <at>  -1434,7 +1629,11  <at>  <at>  xhci_open(struct usbd_pipe *pipe)
 	if (dev->ud_depth == 0 && dev->ud_powersrc->up_portno == 0) {
 		switch (ed->bEndpointAddress) {
 		case USB_CONTROL_ENDPOINT:
+#ifndef NHUSB
+			pipe->up_methods = &xhci_root_ctrl_methods;
+#else
 			pipe->up_methods = &roothub_ctrl_methods;
+#endif
 			break;
 		case UE_DIR_IN | USBROOTHUB_INTR_ENDPT:
 			pipe->up_methods = &xhci_root_intr_methods;
 <at>  <at>  -1639,7 +1838,11  <at>  <at>  xhci_rhpsc(struct xhci_softc * const sc,
 	if (xfer == NULL)
 		return;

+#ifndef NHUSB
+	p = KERNADDR(&xfer->ux_dmabuf, 0);
+#else
 	p = xfer->ux_buf;
+#endif
 	memset(p, 0, xfer->ux_length);
 	p[port/NBBY] |= 1 << (port%NBBY);
 	xfer->ux_actlen = xfer->ux_length;
 <at>  <at>  -1852,6 +2055,45  <at>  <at>  xhci_poll(struct usbd_bus *bus)
 	return;
 }

+#ifndef NHUSB
+static usbd_status
+xhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, uint32_t size)
+{
+	struct xhci_softc * const sc = bus->ub_hcpriv;
+	usbd_status err;
+
+	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+	err = usb_allocmem(&sc->sc_bus, size, 0, dma);
+#if 0
+	if (err == USBD_NOMEM)
+		err = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size);
+#endif
+#ifdef XHCI_DEBUG
+	if (err)
+		DPRINTFN(1, "usb_allocmem(%u)=%d", err, size, 0, 0);
+#endif
+
+	return err;
+}
+
+static void
+xhci_freem(struct usbd_bus *bus, usb_dma_t *dma)
+{
+	struct xhci_softc * const sc = bus->ub_hcpriv;
+
+	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+#if 0
+	if (dma->udma_block->flags & USB_DMA_RESERVE) {
+		usb_reserve_freem(&sc->sc_dma_reserve, dma);
+		return;
+	}
+#endif
+	usb_freemem(&sc->sc_bus, dma);
+}
+
+#endif /* !NHUSB */
 static struct usbd_xfer *
 xhci_allocx(struct usbd_bus *bus)
 {
 <at>  <at>  -1929,7 +2171,11  <at>  <at>  xhci_new_device(device_t parent, struct 
 	DPRINTFN(4, "port=%d depth=%d speed=%d upport %d",
 		 port, depth, speed, up->up_portno);

+#ifndef NHUSB
+	dev = malloc(sizeof *dev, M_USB, M_NOWAIT|M_ZERO);
+#else
 	dev = kmem_zalloc(sizeof(*dev), KM_SLEEP);
+#endif
 	if (dev == NULL)
 		return USBD_NOMEM;

 <at>  <at>  -2589,6 +2835,489  <at>  <at>  xhci_noop(struct usbd_pipe *pipe)
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 }

+#ifndef NHUSB
+/* 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 */
+};
+
+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
+};
+
+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 */
+};
+
+static const usb_interface_descriptor_t xhci_ifcd = {
+	USB_INTERFACE_DESCRIPTOR_SIZE,
+	UDESC_INTERFACE,
+	0,
+	0,
+	1,
+	UICLASS_HUB,
+	UISUBCLASS_HUB,
+	UIPROTO_HSHUBSTT,
+	0
+};
+
+static const usb_endpoint_descriptor_t xhci_endpd = {
+	USB_ENDPOINT_DESCRIPTOR_SIZE,
+	UDESC_ENDPOINT,
+	UE_DIR_IN | USBROOTHUB_INTR_ENDPT,
+	UE_INTERRUPT,
+	{8, 0},                 /* max packet */
+	12
+};
+
+static const usb_hub_descriptor_t xhci_hubd = {
+	USB_HUB_DESCRIPTOR_SIZE,
+	UDESC_HUB,
+	0,
+	{0,0},
+	0,
+	0,
+	{""},
+	{""},
+};
+
+/* root hub control */
+
+static usbd_status
+xhci_root_ctrl_transfer(struct usbd_xfer *xfer)
+{
+	struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+	usbd_status err;
+
+	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+	/* Insert last in queue. */
+	mutex_enter(&sc->sc_lock);
+	err = usb_insert_transfer(xfer);
+	mutex_exit(&sc->sc_lock);
+	if (err)
+		return err;
+
+	/* Pipe isn't running, start first */
+	return xhci_root_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
+}
+
+/*
+ * Process root hub request.
+ */
+static usbd_status
+xhci_root_ctrl_start(struct usbd_xfer *xfer)
+{
+	struct xhci_softc * const sc = xfer->ux_pipe->up_dev->ud_bus->ub_hcpriv;
+	usb_port_status_t ps;
+	usb_device_request_t *req;
+	void *buf = NULL;
+	usbd_status err;
+	int len, value, index;
+	int l, totlen = 0;
+	int port, i;
+	uint32_t v;
+
+	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+	if (sc->sc_dying)
+		return USBD_IOERROR;
+
+	req = &xfer->ux_request;
+
+	len = UGETW(req->wLength);
+	value = UGETW(req->wValue);
+	index = UGETW(req->wIndex);
+
+	if (len != 0)
+		buf = KERNADDR(&xfer->ux_dmabuf, 0);
+
+	DPRINTFN(12, "rhreq: %04x %04x %04x %04x",
+	    req->bmRequestType | (req->bRequest << 8), value, index, len);
+
+#define C(x,y) ((x) | ((y) << 8))
+	switch (C(req->bRequest, req->bmRequestType)) {
+	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
+	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
+	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
+		/*
+		 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
+		 * for the integrated root hub.
+		 */
+		break;
+	case C(UR_GET_CONFIG, UT_READ_DEVICE):
+		if (len > 0) {
+			*(uint8_t *)buf = sc->sc_conf;
+			totlen = 1;
+		}
+		break;
+	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
+		DPRINTFN(8, "getdesc: wValue=0x%04x", value, 0, 0, 0);
+		if (len == 0)
+			break;
+		switch (value >> 8) {
+		case UDESC_DEVICE:
+			if ((value & 0xff) != 0) {
+				err = USBD_IOERROR;
+				goto ret;
+			}
+			totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
+			memcpy(buf, &xhci_devd, min(l, sizeof(xhci_devd)));
+			break;
+		case UDESC_DEVICE_QUALIFIER:
+			if ((value & 0xff) != 0) {
+			}
+			totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE);
+			memcpy(buf, &xhci_odevd, min(l, sizeof(xhci_odevd)));
+			break;
+		case UDESC_OTHER_SPEED_CONFIGURATION:
+		case UDESC_CONFIG:
+			if ((value & 0xff) != 0) {
+				err = USBD_IOERROR;
+				goto ret;
+			}
+			totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE);
+			memcpy(buf, &xhci_confd, min(l, sizeof(xhci_confd)));
+			((usb_config_descriptor_t *)buf)->bDescriptorType =
+			    value >> 8;
+			buf = (char *)buf + l;
+			len -= l;
+			l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE);
+			totlen += l;
+			memcpy(buf, &xhci_ifcd, min(l, sizeof(xhci_ifcd)));
+			buf = (char *)buf + l;
+			len -= l;
+			l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE);
+			totlen += l;
+			memcpy(buf, &xhci_endpd, min(l, sizeof(xhci_endpd)));
+			break;
+		case UDESC_STRING:
+#define sd ((usb_string_descriptor_t *)buf)
+			switch (value & 0xff) {
+			case 0: /* Language table */
+				totlen = usb_makelangtbl(sd, len);
+				break;
+			case 1: /* Vendor */
+				totlen = usb_makestrdesc(sd, len, "NetBSD");
+				break;
+			case 2: /* Product */
+				totlen = usb_makestrdesc(sd, len,
+				    "xHCI Root Hub");
+				break;
+			}
+#undef sd
+			break;
+		default:
+			err = USBD_IOERROR;
+			goto ret;
+		}
+		break;
+	case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
+		if (len > 0) {
+			*(uint8_t *)buf = 0;
+			totlen = 1;
+		}
+		break;
+	case C(UR_GET_STATUS, UT_READ_DEVICE):
+		if (len > 1) {
+			USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED);
+			totlen = 2;
+		}
+		break;
+	case C(UR_GET_STATUS, UT_READ_INTERFACE):
+	case C(UR_GET_STATUS, UT_READ_ENDPOINT):
+		if (len > 1) {
+			USETW(((usb_status_t *)buf)->wStatus, 0);
+			totlen = 2;
+		}
+		break;
+	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
+		if (value >= USB_MAX_DEVICES) {
+			err = USBD_IOERROR;
+			goto ret;
+		}
+		//sc->sc_addr = value;
+		break;
+	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
+		if (value != 0 && value != 1) {
+			err = USBD_IOERROR;
+			goto ret;
+		}
+		sc->sc_conf = value;
+		break;
+	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
+		break;
+	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
+	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
+	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
+		err = USBD_IOERROR;
+		goto ret;
+	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
+		break;
+	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
+		break;
+	/* 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_maxports) {
+			err = USBD_IOERROR;
+			goto ret;
+		}
+		port = XHCI_PORTSC(index);
+		v = xhci_op_read_4(sc, port);
+		DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
+		v &= ~XHCI_PS_CLEAR;
+		switch (value) {
+		case UHF_PORT_ENABLE:
+			xhci_op_write_4(sc, port, v &~ XHCI_PS_PED);
+			break;
+		case UHF_PORT_SUSPEND:
+			err = USBD_IOERROR;
+			goto ret;
+		case UHF_PORT_POWER:
+			break;
+		case UHF_PORT_TEST:
+		case UHF_PORT_INDICATOR:
+			err = USBD_IOERROR;
+			goto ret;
+		case UHF_C_PORT_CONNECTION:
+			xhci_op_write_4(sc, port, v | XHCI_PS_CSC);
+			break;
+		case UHF_C_PORT_ENABLE:
+		case UHF_C_PORT_SUSPEND:
+		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;
+		}
+
+		break;
+	case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
+		if (len == 0)
+			break;
+		if ((value & 0xff) != 0) {
+			err = USBD_IOERROR;
+			goto ret;
+		}
+		usb_hub_descriptor_t hubd = xhci_hubd;
+
+		hubd.bNbrPorts = sc->sc_maxports;
+		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);
+		break;
+	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE):
+		if (len != 4) {
+			err = USBD_IOERROR;
+			goto ret;
+		}
+		memset(buf, 0, len); /* ? XXX */
+		totlen = len;
+		break;
+	case C(UR_GET_STATUS, UT_READ_CLASS_OTHER):
+		DPRINTFN(8, "get port status i=%d", index, 0, 0, 0);
+		if (index < 1 || index > sc->sc_maxports) {
+			err = USBD_IOERROR;
+			goto ret;
+		}
+		if (len != 4) {
+			err = USBD_IOERROR;
+			goto ret;
+		}
+		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;
+			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;
+		}
+		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)
+					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);
+		totlen = l;
+		break;
+	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):
+	{
+		int optval = (index >> 8) & 0xff;
+		index &= 0xff;
+		if (index < 1 || index > sc->sc_maxports) {
+			err = USBD_IOERROR;
+			goto ret;
+		}
+		port = XHCI_PORTSC(index);
+		v = xhci_op_read_4(sc, port);
+		DPRINTFN(4, "portsc=0x%08x", v, 0, 0, 0);
+		v &= ~XHCI_PS_CLEAR;
+		switch (value) {
+		case UHF_PORT_ENABLE:
+			xhci_op_write_4(sc, port, v | XHCI_PS_PED);
+			break;
+		case UHF_PORT_SUSPEND:
+			/* XXX suspend */
+			break;
+		case UHF_PORT_RESET:
+			v &= ~ (XHCI_PS_PED | XHCI_PS_PR);
+			xhci_op_write_4(sc, port, v | XHCI_PS_PR);
+			/* Wait for reset to complete. */
+			usb_delay_ms(&sc->sc_bus, USB_PORT_ROOT_RESET_DELAY);
+			if (sc->sc_dying) {
+				err = USBD_IOERROR;
+				goto ret;
+			}
+			v = xhci_op_read_4(sc, port);
+			if (v & XHCI_PS_PR) {
+				xhci_op_write_4(sc, port, v & ~XHCI_PS_PR);
+				usb_delay_ms(&sc->sc_bus, 10);
+				/* XXX */
+			}
+			break;
+		case UHF_PORT_POWER:
+			/* XXX power control */
+			break;
+		/* XXX more */
+		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;
+			}
+			port = XHCI_PORTPMSC(index);
+			v = xhci_op_read_4(sc, port);
+			v &= ~XHCI_PM3_U1TO_SET(0xff);
+			v |= XHCI_PM3_U1TO_SET(optval);
+			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;
+			}
+			port = XHCI_PORTPMSC(index);
+			v = xhci_op_read_4(sc, port);
+			v &= ~XHCI_PM3_U2TO_SET(0xff);
+			v |= XHCI_PM3_U2TO_SET(optval);
+			xhci_op_write_4(sc, port, v);
+			break;
+		default:
+			err = USBD_IOERROR;
+			goto ret;
+		}
+
+		}
+		break;
+	case C(UR_CLEAR_TT_BUFFER, UT_WRITE_CLASS_OTHER):
+	case C(UR_RESET_TT, UT_WRITE_CLASS_OTHER):
+	case C(UR_GET_TT_STATE, UT_READ_CLASS_OTHER):
+	case C(UR_STOP_TT, UT_WRITE_CLASS_OTHER):
+		break;
+	default:
+		err = USBD_IOERROR;
+		goto ret;
+	}
+	xfer->ux_actlen = totlen;
+	err = USBD_NORMAL_COMPLETION;
+ret:
+	xfer->ux_status = err;
+	mutex_enter(&sc->sc_lock);
+	usb_transfer_complete(xfer);
+	mutex_exit(&sc->sc_lock);
+	return USBD_IN_PROGRESS;
+}
+
+#else /* !NHUSB */
 /*
  * Process root hub request.
  */
 <at>  <at>  -2842,6 +3571,32  <at>  <at>  xhci_roothub_ctrl(struct usbd_bus *bus, 
 	return totlen;
 }

+#endif /* !NHUSB */
+#ifndef NHUSB
+static void
+xhci_root_ctrl_abort(struct usbd_xfer *xfer)
+{
+	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+	/* Nothing to do, all transfers are synchronous. */
+}
+
+
+static void
+xhci_root_ctrl_close(struct usbd_pipe *pipe)
+{
+	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+	/* Nothing to do. */
+}
+
+static void
+xhci_root_ctrl_done(struct usbd_xfer *xfer)
+{
+	XHCIHIST_FUNC(); XHCIHIST_CALLED();
+
+	xfer->ux_hcpriv = NULL;
+}
+
+#endif /* !NHUSB */
 /* root hub interrupt */

 static usbd_status
--- src/sys/dev/usb/uhub.c.orig	2015-03-27 15:05:01.000000000 +0900
+++ src/sys/dev/usb/uhub.c	2015-04-05 16:51:55.000000000 +0900
 <at>  <at>  -39,11 +39,13  <at>  <at> 
 __KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126.2.8 2015/03/21 11:33:37 skrll Exp $");

 #include <sys/param.h>
+
 #include <sys/systm.h>
+#include <sys/device.h>
 #include <sys/kernel.h>
 #include <sys/kmem.h>
-#include <sys/device.h>
 #include <sys/proc.h>
+#include <sys/sysctl.h>

 #include <sys/bus.h>

 <at>  <at>  -51,15 +53,48  <at>  <at>  __KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.1
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdi_util.h>
 #include <dev/usb/usbdivar.h>
+#include <dev/usb/usbhist.h>

-#ifdef UHUB_DEBUG
-#define DPRINTF(x)	if (uhubdebug) printf x
-#define DPRINTFN(n,x)	if (uhubdebug>(n)) printf x
-int	uhubdebug = 0;
+#ifdef USB_DEBUG
+#ifndef UHUB_DEBUG
+#define uhubdebug 0
 #else
-#define DPRINTF(x)
-#define DPRINTFN(n,x)
-#endif
+static int uhubdebug = 0;
+
+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 */
+#endif /* USB_DEBUG */
+
+#define DPRINTF(FMT,A,B,C,D)	USBHIST_LOGN(uhubdebug,1,FMT,A,B,C,D)
+#define DPRINTFN(N,FMT,A,B,C,D)	USBHIST_LOGN(uhubdebug,N,FMT,A,B,C,D)
+#define UHUBHIST_FUNC() USBHIST_FUNC()
+#define UHUBHIST_CALLED(name) USBHIST_CALLED(uhubdebug)

 struct uhub_softc {
 	device_t		sc_dev;		/* base device */
 <at>  <at>  -118,12 +153,14  <at>  <at>  uhub_match(device_t parent, cfdata_t mat
 	struct usb_attach_arg *uaa = aux;
 	int matchvalue;

+	UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
 	if (uhub_ubermatch)
 		matchvalue = UMATCH_HIGHEST+1;
 	else
 		matchvalue = UMATCH_DEVCLASS_DEVSUBCLASS;

-	DPRINTFN(5,("uhub_match, uaa=%p\n", uaa));
+	DPRINTFN(5, "uaa=%p", uaa, 0, 0, 0);
 	/*
 	 * The subclass for hubs seems to be 0 for some and 1 for others,
 	 * so we just ignore the subclass.
 <at>  <at>  -151,7 +188,8  <at>  <at>  uhub_attach(device_t parent, device_t se
 	struct usbd_tt *tts = NULL;
 #endif

-	DPRINTFN(1,("uhub_attach\n"));
+	UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
 	sc->sc_dev = self;
 	sc->sc_hub = dev;
 	sc->sc_proto = uaa->uaa_proto;
 <at>  <at>  -169,8 +207,7  <at>  <at>  uhub_attach(device_t parent, device_t se

 	err = usbd_set_config_index(dev, 0, 1);
 	if (err) {
-		DPRINTF(("%s: configuration failed, error=%s\n",
-		    device_xname(sc->sc_dev), usbd_errstr(err)));
+		DPRINTF("configuration failed, sc %p error %d", sc, err, 0, 0);
 		return;
 	}

 <at>  <at>  -187,7 +224,7  <at>  <at>  uhub_attach(device_t parent, device_t se
 	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__));
+	DPRINTF("uhub %d getting hub descriptor", device_unit(self), 0, 0, 0);
 	err = usbd_do_request(dev, &req, &hubdesc);
 	nports = hubdesc.bNbrPorts;
 	if (!err && nports > 7) {
 <at>  <at>  -195,8 +232,8  <at>  <at>  uhub_attach(device_t parent, device_t se
 		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)));
+		DPRINTF("getting hub descriptor failed, uhub %d error %d",
+		    device_unit(self), err, 0, 0);
 		return;
 	}

 <at>  <at>  -338,7 +375,8  <at>  <at>  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("uhub %d turn on port %d power", device_unit(self),
+		    port, 0, 0);
 	}

 	/* Wait for stable power if we are not a root hub */
 <at>  <at>  -377,7 +415,10  <at>  <at>  uhub_explore(struct usbd_device *dev)
 	int port;
 	int change, status, reconnect;

-	DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->ud_addr));
+	UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
+	DPRINTFN(10, "uhub %d dev=%p addr=%d speed=%u",
+	    device_unit(sc->sc_dev), dev, dev->ud_addr, dev->ud_speed);

 	if (!sc->sc_running)
 		return USBD_NOT_STARTED;
 <at>  <at>  -391,12 +432,15  <at>  <at>  uhub_explore(struct usbd_device *dev)

 		err = usbd_get_hub_status(dev, &hs);
 		if (err) {
-			DPRINTF(("%s: get hub status failed, err=%d\n",
-				 device_xname(sc->sc_dev), err));
+			DPRINTF("uhub %d get hub status failed, err %d",
+			    device_unit(sc->sc_dev), err, 0, 0);
 		} else {
 			/* just acknowledge */
 			status = UGETW(hs.wHubStatus);
 			change = UGETW(hs.wHubChange);
+			DPRINTF("uhub %d s/c=%x/%x", device_unit(sc->sc_dev),
+			    status, change, 0);
+
 			if (change & UHS_LOCAL_POWER)
 				usbd_clear_hub_feature(dev,
 						       UHF_C_HUB_LOCAL_POWER);
 <at>  <at>  -419,16 +463,15  <at>  <at>  uhub_explore(struct usbd_device *dev)
 		if (PORTSTAT_ISSET(sc, port) || reconnect) {
 			err = usbd_get_port_status(dev, port, &up->up_status);
 			if (err) {
-				DPRINTF(("uhub_explore: get port stat failed, "
-					 "error=%s\n", usbd_errstr(err)));
+				DPRINTF("uhub %d get port stat failed, err %d",
+				    device_unit(sc->sc_dev), err, 0, 0);
 				continue;
 			}
 			status = UGETW(up->up_status.wPortStatus);
 			change = UGETW(up->up_status.wPortChange);
-#if 0
-			printf("%s port %d: s/c=%x/%x\n",
-			       device_xname(sc->sc_dev), port, status, change);
-#endif
+
+			DPRINTF("uhub %d port %d: s/c=%x/%x",
+			    device_unit(sc->sc_dev), port, status, change);
 		}
 		if (!change && !reconnect) {
 			/* No status change, just do recursive explore. */
 <at>  <at>  -438,7 +481,8  <at>  <at>  uhub_explore(struct usbd_device *dev)
 		}

 		if (change & UPS_C_PORT_ENABLED) {
-			DPRINTF(("uhub_explore: C_PORT_ENABLED\n"));
+			DPRINTF("uhub %d port %d C_PORT_ENABLED",
+			    device_unit(sc->sc_dev), port, 0, 0);
 			usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
 			if (change & UPS_C_CONNECT_STATUS) {
 				/* Ignore the port error if the device
 <at>  <at>  -473,8 +517,8  <at>  <at>  uhub_explore(struct usbd_device *dev)

 		/* We have a connect status change, handle it. */

-		DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
-			 dev->ud_addr, port));
+		DPRINTF("status change hub=%d port=%d", dev->ud_addr, port, 0,
+		    0);
 		usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
 		/*
 		 * If there is already a device on the port the change status
 <at>  <at>  -486,20 +530,23  <at>  <at>  uhub_explore(struct usbd_device *dev)
 	disco:
 		if (up->up_dev != NULL) {
 			/* Disconnected */
-			DPRINTF(("uhub_explore: device addr=%d disappeared "
-				 "on port %d\n", up->up_dev->ud_addr, port));
+			DPRINTF("uhub %d device addr=%d disappeared on port %d",
+			    device_unit(sc->sc_dev), up->up_dev->ud_addr, port,
+			    0);
 			usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE);
 			usbd_clear_port_feature(dev, port,
 						UHF_C_PORT_CONNECTION);
 		}
 		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
 			/* Nothing connected, just ignore it. */
-			DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
-				    "_STATUS\n", port));
+			DPRINTFN(3, "uhub %d port=%d !CURRENT_CONNECT_STATUS",
+			    device_unit(sc->sc_dev), port, 0, 0);
 			continue;
 		}

 		/* Connected */
+		DPRINTF("unit %d dev->ud_speed=%u dev->ud_depth=%u",
+		    device_unit(sc->sc_dev), dev->ud_speed, dev->ud_depth, 0);

 		if (!(status & UPS_PORT_POWER))
 			aprint_normal_dev(sc->sc_dev,
 <at>  <at>  -517,12 +564,15  <at>  <at>  uhub_explore(struct usbd_device *dev)
 		/* Get port status again, it might have changed during reset */
 		err = usbd_get_port_status(dev, port, &up->up_status);
 		if (err) {
-			DPRINTF(("uhub_explore: get port status failed, "
-				 "error=%s\n", usbd_errstr(err)));
+			DPRINTF("uhub %d port=%d get port status failed, "
+			    "err %d", device_unit(sc->sc_dev), port, err, 0);
 			continue;
 		}
 		status = UGETW(up->up_status.wPortStatus);
 		change = UGETW(up->up_status.wPortChange);
+		DPRINTF("hub %d port %d reset: s/c=%x/%x",
+		       device_unit(sc->sc_dev), port, status, change);
+
 		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
 			/* Nothing connected, just ignore it. */
 #ifdef DIAGNOSTIC
 <at>  <at>  -557,8 +607,8  <at>  <at>  uhub_explore(struct usbd_device *dev)
 			  dev->ud_depth + 1, speed, port, up);
 		/* XXX retry a few times? */
 		if (err) {
-			DPRINTFN(-1,("uhub_explore: usbd_new_device failed, "
-				     "error=%s\n", usbd_errstr(err)));
+			DPRINTF("usbd_new_device failed, error %d", err, 0, 0,
+			    0);
 			/* Avoid addressing problems by disabling. */
 			/* usbd_reset_port(dev, port, &up->status); */

 <at>  <at>  -597,7 +647,9  <at>  <at>  uhub_detach(device_t self, int flags)
 	struct usbd_port *rup;
 	int nports, port, rc;

-	DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags));
+	UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
+	DPRINTF("uhub %d sc=%p flags=%d", device_unit(self), sc, flags, 0);

 	if (hub == NULL)		/* Must be partially working */
 		return 0;
 <at>  <at>  -708,7 +760,9  <at>  <at>  uhub_intr(struct usbd_xfer *xfer, void *
 {
 	struct uhub_softc *sc = addr;

-	DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
+	UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
+	DPRINTFN(5, "uhub %d sc=%p", device_unit(sc->sc_dev), sc, 0, 0);

 	if (status == USBD_STALLED)
 		usbd_clear_endpoint_stall_async(sc->sc_ipipe);
--- ../nick-nhusb/src/sys/dev/usb/uhub.c.orig	2015-04-05 16:51:55.000000000 +0900
+++ ../nick-nhusb/src/sys/dev/usb/uhub.c	2015-04-05 17:21:44.000000000 +0900
 <at>  <at>  -108,11 +108,13  <at>  <at>  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) \
 <at>  <at>  -147,6 +149,76  <at>  <at>  CFATTACH_DECL2_NEW(uroothub, sizeof(stru
  */
 int uhub_ubermatch = 0;

+static usbd_status
+usbd_get_hub_desc(struct usbd_device *dev, usb_hub_descriptor_t *hd, int speed)
+{
+	usb_device_request_t req;
+	usbd_status err;
+	int nports;
+
+	UHUBHIST_FUNC(); UHUBHIST_CALLED();
+
+	/* don't issue UDESC_HUB to SS hub, or it would stall */
+	if (dev->ud_depth != 0 && dev->ud_speed == USB_SPEED_SUPER) {
+		usb_hub_ss_descriptor_t hssd;
+		int rmvlen;
+
+		memset(&hssd, 0, sizeof(hssd));
+		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, "getting sshub descriptor", 0, 0, 0, 0);
+		err = usbd_do_request(dev, &req, &hssd);
+		nports = hssd.bNbrPorts;
+		if (dev->ud_depth != 0 && nports > UHD_SS_NPORTS_MAX) {
+			DPRINTF("num of ports %d exceeds maxports %d",
+			    nports, UHD_SS_NPORTS_MAX, 0, 0);
+			nports = hd->bNbrPorts = UHD_SS_NPORTS_MAX;
+		}
+		rmvlen = (nports + 7) / 8;
+		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;
+	} 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, "getting hub descriptor", 0, 0, 0, 0);
+		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(struct usbd_device *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)
 {
 <at>  <at>  -179,7 +251,6  <at>  <at>  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;
 	struct usbd_interface *iface;
 <at>  <at>  -219,18 +290,9  <at>  <at>  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);
-	DPRINTF("uhub %d getting hub descriptor", device_unit(self), 0, 0, 0);
-	err = usbd_do_request(dev, &req, &hubdesc);
+	memset(&hubdesc, 0, sizeof(hubdesc));
+	err = usbd_get_hub_desc(dev, &hubdesc, dev->ud_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("getting hub descriptor failed, uhub %d error %d",
 		    device_unit(self), err, 0, 0);
 <at>  <at>  -258,6 +320,16  <at>  <at>  uhub_attach(device_t parent, device_t se
 	hub->uh_explore = uhub_explore;
 	hub->uh_hubdesc = hubdesc;

+	if (dev->ud_speed == USB_SPEED_SUPER && dev->ud_depth != 0) {
+		aprint_debug_dev(self, "setting hub depth %u\n",
+		    dev->ud_depth-1);
+		err = usbd_set_hub_depth(dev, dev->ud_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) {
 <at>  <at>  -290,6 +362,8  <at>  <at>  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);
 <at>  <at>  -317,9 +391,10  <at>  <at>  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
 <at>  <at>  -505,6 +580,19  <at>  <at>  uhub_explore(struct usbd_device *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! */

 <at>  <at>  -548,7 +636,14  <at>  <at>  uhub_explore(struct usbd_device *dev)
 		DPRINTF("unit %d dev->ud_speed=%u dev->ud_depth=%u",
 		    device_unit(sc->sc_dev), dev->ud_speed, dev->ud_depth, 0);

-		if (!(status & UPS_PORT_POWER))
+		if ((!(status & UPS_PORT_POWER) &&
+		    /* check POWER for root/non-root hub if non-SS */
+		    ((dev->ud_depth == 0 && !(status & UPS_SUPER_SPEED)) ||
+		    (dev->ud_depth != 0 && dev->ud_speed != USB_SPEED_SUPER)))||
+		    /* check POWER_SS for root/non-root hub if SS */
+		    (!(status & UPS_PORT_POWER_SS) &&
+		    ((dev->ud_depth == 0 && (status & UPS_SUPER_SPEED)) ||
+		     (dev->ud_depth != 0 && dev->ud_speed == USB_SPEED_SUPER))))
 			aprint_normal_dev(sc->sc_dev,
 			    "strange, connected port %d has no power\n", port);

 <at>  <at>  -591,8 +686,9  <at>  <at>  uhub_explore(struct usbd_device *dev)
 		}

 		/* Figure out device speed */
-#if 0
-		if (status & UPS_SUPER_SPEED)
+#if 1
+		if ((status & UPS_SUPER_SPEED) ||
+		    (dev->ud_speed == USB_SPEED_SUPER && dev->ud_depth != 0))
 			speed = USB_SPEED_SUPER;
 		else
 #endif
 <at>  <at>  -602,6 +698,8  <at>  <at>  uhub_explore(struct usbd_device *dev)
 			speed = USB_SPEED_LOW;
 		else
 			speed = USB_SPEED_FULL;
+		DPRINTF("unit %d: speed %u\n", device_unit(sc->sc_dev), speed,
+		    0, 0);
 		/* Get device info and set its address. */
 		err = usbd_new_device(sc->sc_dev, dev->ud_bus,
 			  dev->ud_depth + 1, speed, port, up);
 <at>  <at>  -629,7 +727,7  <at>  <at>  uhub_explore(struct usbd_device *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;
 <at>  <at>  -785,4 +883,12  <at>  <at>  uhub_intr(struct usbd_xfer *xfer, void *
 	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-12-04 07:43:25.000000000 +0900
+++ src/sys/dev/usb/usb.h	2014-12-04 08:54:56.000000000 +0900
 <at>  <at>  -244,6 +247,7  <at>  <at>  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

 <at>  <at>  -301,6 +305,7  <at>  <at>  typedef struct {
 } UPACKED usb_endpoint_descriptor_t;
 #define USB_ENDPOINT_DESCRIPTOR_SIZE 7

+/* USB 3.0 9.6.2, Table 9-12 */
 typedef struct {
 	uByte		bLength;
 	uByte		bDescriptorType;
 <at>  <at>  -314,6 +319,7  <at>  <at>  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;
 <at>  <at>  -322,10 +328,12  <at>  <at>  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
 <at>  <at>  -341,17 +349,19  <at>  <at>  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;
 <at>  <at>  -359,16 +369,17  <at>  <at>  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;
 <at>  <at>  -733,7 +744,9  <at>  <at>  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	2015-03-27 15:05:02.000000000 +0900
+++ src/sys/dev/usb/usb_subr.c	2015-03-27 15:11:01.000000000 +0900
 <at>  <at>  -1411,6 +1411,13  <at>  <at>  usbd_fill_deviceinfo(struct usbd_device 
 					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->ud_speed == USB_SPEED_SUPER)
+					err = USB_PORT_POWERED;
 				else if (s & UPS_PORT_POWER)
 					err = USB_PORT_POWERED;
 				else
--- src/sys/dev/usb/xhcireg.h.orig	2014-11-18 21:02:04.000000000 +0900
+++ src/sys/dev/usb/xhcireg.h	2015-04-05 09:01:54.000000000 +0900
 <at>  <at>  -38,6 +38,16  <at>  <at> 
 #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 */
+
+#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)
 <at>  <at>  -168,6 +178,7  <at>  <at> 
 #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)
 <at>  <at>  -188,18 +199,20  <at>  <at> 
 /* 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)

 <at>  <at>  -266,6 +279,8  <at>  <at>  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)

 <at>  <at>  -375,10 +390,20  <at>  <at>  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	2015-03-27 15:05:03.000000000 +0900
+++ src/sys/dev/usb/xhcivar.h	2015-03-27 15:53:58.000000000 +0900
 <at>  <at>  -109,6 +109,10  <at>  <at>  struct xhci_softc {

 	bool sc_ac64;
 	bool sc_dying;
+
+	int sc_quirks;
+#define XHCI_QUIRK_FORCE_INTR	__BIT(0) /* force interrupt reading */
+#define XHCI_QUIRK_INTEL	__BIT(1) /* Intel xhci chip */
 };

 int	xhci_init(struct xhci_softc *);
Maxime Villard | 4 Apr 15:25 2015
Picon

FFS: ffs_is_appleufs()

Hi,
here is a patch to put the AppleUFS detection code inside a function.

This changes the behavior a bit: if the kernel cannot determine whether the
disk is an AppleUFS one or not, it now considers it as a normal UFS rather
than returning an error and not mounting/reloading it.

Ok?

Tested on amd64, no regression seen.

Index: ffs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.328
diff -u -r1.328 ffs_vfsops.c
--- ffs_vfsops.c	4 Apr 2015 06:00:12 -0000	1.328
+++ ffs_vfsops.c	4 Apr 2015 13:14:09 -0000
 <at>  <at>  -113,6 +113,7  <at>  <at> 

 static int ffs_vfs_fsync(vnode_t *, int);
 static int ffs_superblock_validate(struct fs *);
+static int ffs_is_appleufs(struct vnode *, struct fs *);

 static int ffs_init_vnode(struct ufsmount *, struct vnode *, ino_t);
 static void ffs_deinit_vnode(struct ufsmount *, struct vnode *);
 <at>  <at>  -693,7 +694,6  <at>  <at> 
 	void *space;
 	struct buf *bp;
 	struct fs *fs, *newfs;
-	struct dkwedge_info dkw;
 	int i, bsize, blks, error;
 	int32_t *lp, fs_sbsize;
 	struct ufsmount *ump;
 <at>  <at>  -776,41 +776,18  <at>  <at> 
 	memcpy(fs, newfs, (u_int)fs_sbsize);
 	kmem_free(newfs, fs_sbsize);

-	/* Recheck for apple UFS filesystem */
-	ump->um_flags &= ~UFS_ISAPPLEUFS;
-	/* First check to see if this is tagged as an Apple UFS filesystem
-	 * in the disklabel
+	/*
+	 * Recheck for Apple UFS filesystem.
 	 */
-	if (getdiskinfo(devvp, &dkw) == 0 &&
-	    strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) == 0)
-		ump->um_flags |= UFS_ISAPPLEUFS;
+	ump->um_flags &= ~UFS_ISAPPLEUFS;
+	if (ffs_is_appleufs(devvp, fs)) {
 #ifdef APPLE_UFS
-	else {
-		/* Manually look for an apple ufs label, and if a valid one
-		 * is found, then treat it like an Apple UFS filesystem anyway
-		 *
-		 * EINVAL is most probably a blocksize or alignment problem,
-		 * it is unlikely that this is an Apple UFS filesystem then.
-		 */
-		error = bread(devvp,
-		    (daddr_t)(APPLEUFS_LABEL_OFFSET / DEV_BSIZE),
-		    APPLEUFS_LABEL_SIZE, 0, &bp);
-		if (error && error != EINVAL) {
-			return error;
-		}
-		if (error == 0) {
-			error = ffs_appleufs_validate(fs->fs_fsmnt,
-				(struct appleufslabel *)bp->b_data, NULL);
-			if (error == 0)
-				ump->um_flags |= UFS_ISAPPLEUFS;
-			brelse(bp, 0);
-		}
-		bp = NULL;
-	}
+		ump->um_flags |= UFS_ISAPPLEUFS;
 #else
-	if (ump->um_flags & UFS_ISAPPLEUFS)
-		return (EIO);
+		DPRINTF("AppleUFS not supported");
+		return (EIO); /* XXX: really? */
 #endif
+	}

 	if (UFS_MPISAPPLEUFS(ump)) {
 		/* see comment about NeXT below */
 <at>  <at>  -1006,6 +983,46  <at>  <at> 
 	return 1;
 }

+static int
+ffs_is_appleufs(struct vnode *devvp, struct fs *fs)
+{
+	struct dkwedge_info dkw;
+	int ret = 0;
+
+	/*
+	 * First check to see if this is tagged as an Apple UFS filesystem
+	 * in the disklabel.
+	 */
+	if (getdiskinfo(devvp, &dkw) == 0 &&
+	    strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) == 0)
+		ret = 1;
+#ifdef APPLE_UFS
+	else {
+		struct appleufslabel *applefs;
+		struct buf *bp;
+		daddr_t blkno = APPLEUFS_LABEL_OFFSET / DEV_BSIZE;
+		int error;
+
+		/*
+		 * Manually look for an Apple UFS label, and if a valid one
+		 * is found, then treat it like an Apple UFS filesystem anyway.
+		 */
+		error = bread(devvp, blkno, APPLEUFS_LABEL_SIZE, 0, &bp);
+		if (error) {
+			DPRINTF("bread <at> 0x%jx returned %d", (intmax_t)blkno, error);
+			return 0;
+		}
+		applefs = (struct appleufslabel *)bp->b_data;
+		error = ffs_appleufs_validate(fs->fs_fsmnt, applefs, NULL);
+		if (error == 0)
+			ret = 1;
+		brelse(bp, 0);
+	}
+#endif
+
+	return ret;
+}
+
 /*
  * Common code for mount and mountroot
  */
 <at>  <at>  -1016,7 +1033,6  <at>  <at> 
 	struct buf *bp = NULL;
 	struct fs *fs = NULL;
 	dev_t dev;
-	struct dkwedge_info dkw;
 	void *space;
 	daddr_t sblockloc = 0;
 	int blks, fstype = 0;
 <at>  <at>  -1239,42 +1255,15  <at>  <at> 
 		brelse(bp, 0);
 	bp = NULL;

-	/*
-	 * First check to see if this is tagged as an Apple UFS filesystem
-	 * in the disklabel
-	 */
-	if (getdiskinfo(devvp, &dkw) == 0 &&
-	    strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) == 0)
-		ump->um_flags |= UFS_ISAPPLEUFS;
+	if (ffs_is_appleufs(devvp, fs)) {
 #ifdef APPLE_UFS
-	else {
-		/*
-		 * Manually look for an apple ufs label, and if a valid one
-		 * is found, then treat it like an Apple UFS filesystem anyway
-		 */
-		error = bread(devvp,
-		    (daddr_t)(APPLEUFS_LABEL_OFFSET / DEV_BSIZE),
-		    APPLEUFS_LABEL_SIZE, 0, &bp);
-		if (error) {
-			DPRINTF("apple bread <at> 0x%jx returned %d",
-			    (intmax_t)(APPLEUFS_LABEL_OFFSET / DEV_BSIZE),
-			    error);
-			goto out;
-		}
-		error = ffs_appleufs_validate(fs->fs_fsmnt,
-		    (struct appleufslabel *)bp->b_data, NULL);
-		if (error == 0)
-			ump->um_flags |= UFS_ISAPPLEUFS;
-		brelse(bp, 0);
-		bp = NULL;
-	}
+		ump->um_flags |= UFS_ISAPPLEUFS;
 #else
-	if (ump->um_flags & UFS_ISAPPLEUFS) {
 		DPRINTF("AppleUFS not supported");
 		error = EINVAL;
 		goto out;
-	}
 #endif
+	}

 #if 0
 /*


Gmane