Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F143131766
D53472.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
97 KB
Referenced Files
None
Subscribers
None
D53472.diff
View Options
diff --git a/stand/efi/loader/Makefile b/stand/efi/loader/Makefile
--- a/stand/efi/loader/Makefile
+++ b/stand/efi/loader/Makefile
@@ -1,6 +1,7 @@
LOADER_NET_SUPPORT?= yes
LOADER_MSDOS_SUPPORT?= yes
LOADER_UFS_SUPPORT?= yes
+LOADER_USBDBC_SUPPORT?= no
LOADER_CD9660_SUPPORT?= no
LOADER_EXT2FS_SUPPORT?= no
@@ -30,6 +31,13 @@
gfx_fb.c \
8x16.c
+.if ${LOADER_USBDBC_SUPPORT} == "yes"
+.PATH: ${SRCTOP}/sys/dev/usb/controller
+SRCS+= xhci_dbc.c \
+ xhci_dbc_cons.c \
+ xhci_dbc_dma.c
+.endif
+
SRCS+= acpi_detect.c
.PATH: ${EFISRC}/acpica
CFLAGS+= -I${EFISRC}/acpica/include
diff --git a/stand/efi/loader/bootinfo.c b/stand/efi/loader/bootinfo.c
--- a/stand/efi/loader/bootinfo.c
+++ b/stand/efi/loader/bootinfo.c
@@ -64,6 +64,15 @@
#include "geliboot.h"
#endif
+#if defined(LOADER_USBDBC_SUPPORT)
+#include <dev/usb/controller/xhci_private.h>
+#include <dev/usb/controller/xhcireg.h>
+#include "xhci_dbc_pci.h" /* device_t */
+#include <dev/usb/controller/xhci_dbc.h>
+#include <dev/usb/controller/xhci_dbc_private.h>
+#include "xhci_dbc_cons.h" /* udb_sc */
+#endif /* usb dbc */
+
static int
bi_getboothowto(char *kargs)
{
@@ -449,6 +458,16 @@
file_addmetadata(kfp, MODINFOMD_EFI_ARCH, sizeof(MACHINE_ARCH),
MACHINE_ARCH);
#endif
+#if defined(LOADER_USBDBC_SUPPORT)
+ /*
+ * Pass the xhci debug struct through to the kernel if we have managed
+ * to configure it.
+ */
+ if (udb_sc0 != NULL) {
+ file_addmetadata(kfp, MODINFOMD_XHCI_DEBUG,
+ sizeof(struct xhci_debug_softc *), &udb_sc0);
+ }
+#endif
#endif
#ifdef LOADER_GELI_SUPPORT
geli_export_key_metadata(kfp);
diff --git a/stand/efi/loader/conf.c b/stand/efi/loader/conf.c
--- a/stand/efi/loader/conf.c
+++ b/stand/efi/loader/conf.c
@@ -78,6 +78,9 @@
extern struct console efi_console;
extern struct console eficom;
+#if defined(LOADER_USBDBC_SUPPORT)
+extern struct console udb_console;
+#endif
#if defined(__aarch64__) && __FreeBSD_version < 1500000
/* Hack for backward compatibility -- but only for a while */
extern struct console comconsole;
@@ -91,6 +94,9 @@
struct console *consoles[] = {
&efi_console,
&eficom,
+#if defined(LOADER_USBDBC_SUPPORT)
+ &udb_console,
+#endif
#if defined(__aarch64__) && __FreeBSD_version < 1500000
&comconsole,
#endif
diff --git a/stand/efi/loader/xhci_dbc_cons.h b/stand/efi/loader/xhci_dbc_cons.h
new file mode 100644
--- /dev/null
+++ b/stand/efi/loader/xhci_dbc_cons.h
@@ -0,0 +1,34 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019-2024 Hiroki Sato <hrs@FreeBSD.org>
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ */
+extern struct console udb_console;
+
+extern struct xhci_debug_softc *udb_sc0;
+extern struct xhci_debug_softc *udb_sc;
+
+extern const char *udb_hostname;
+extern const char *udb_serial;
diff --git a/stand/efi/loader/xhci_dbc_cons.c b/stand/efi/loader/xhci_dbc_cons.c
new file mode 100644
--- /dev/null
+++ b/stand/efi/loader/xhci_dbc_cons.c
@@ -0,0 +1,309 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019-2024 Hiroki Sato <hrs@FreeBSD.org>
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ */
+#include <sys/param.h>
+#include <dev/pci/pcireg.h>
+#include <dev/usb/controller/xhcireg.h>
+
+#include <bootstrap.h>
+#include <efi.h>
+#include <efilib.h>
+
+#include "xhci_dbc_cons.h"
+#include "xhci_dbc_pci.h"
+#include "xhci_dbc_dma.h"
+#include <dev/usb/controller/xhci_pci.h>
+#include <dev/usb/controller/xhci_private.h>
+#include <dev/usb/controller/xhci_dbc.h>
+#include <dev/usb/controller/xhci_dbc_private.h>
+
+static void udbc_probe(struct console *);
+static bool udbc_alloc(struct console *, EFI_PCI_IO_PROTOCOL *, EFI_HANDLE *);
+
+static int udbc_getc(void);
+static void udbc_putc(int);
+static int udbc_ischar(void);
+static int udbc_init(int);
+struct console udb_console = {
+ .c_name = "udbc",
+ .c_desc = "USB DbC serial port",
+ .c_flags = 0,
+ .c_probe = udbc_probe,
+ .c_init = udbc_init,
+ .c_out = udbc_putc,
+ .c_in = udbc_getc,
+ .c_ready = udbc_ischar
+};
+
+struct xhci_debug_softc *udb_sc0; /* linked-list */
+struct xhci_debug_softc *udb_sc; /* active instance */
+const char *udb_hostname;
+const char *udb_serial;
+
+static void
+udbc_probe(struct console *cons)
+{
+ EFI_STATUS status;
+ EFI_PCI_IO_PROTOCOL *pciio;
+ EFI_HANDLE *h0, *h;
+ UINTN hlen;
+ device_t dev;
+
+ h0 = h = NULL;
+ if (udb_sc0 != NULL)
+ return;
+
+ /* Get PCI I/O handle. */
+ hlen = 0;
+ status = BS->LocateHandleBuffer(
+ ByProtocol,
+ &pciio_guid,
+ NULL,
+ &hlen,
+ &h0);
+ if (EFI_ERROR(status))
+ goto error;
+
+ for (UINTN i = 0; i < hlen; i++) {
+ h = h0[i];
+ status = BS->HandleProtocol(
+ h,
+ &pciio_guid,
+ (VOID **)&pciio);
+ if (EFI_ERROR(status))
+ continue;
+ status = pciio->Pci.Read(
+ pciio,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof(dev) >> 2, /* 32-bit access */
+ &dev);
+ if (EFI_ERROR(status))
+ continue;
+ if (pci_get_headertype(dev) != PCIM_HDRTYPE_NORMAL &&
+ pci_get_headertype(dev) != PCIM_MFDEV)
+ continue;
+ if (xhci_pci_match(dev) != NULL)
+ (void) udbc_alloc(cons, pciio, h);
+ }
+
+ if (udb_sc0 != NULL) {
+ cons->c_flags = C_PRESENTIN | C_PRESENTOUT;
+ return;
+ }
+error:
+ DEBUG_PRINTF(1, ("%s: Compatible xHC not found.\n", __func__));
+ (void) BS->FreePool(h0);
+ return;
+}
+
+static bool
+udbc_alloc(struct console *cons, EFI_PCI_IO_PROTOCOL *pciio, EFI_HANDLE *h)
+{
+ struct xhci_debug_softc *sc;
+ UINTN SegmentNumber, BusNumber, DeviceNumber, FunctionNumber;
+ EFI_STATUS status;
+ int error;
+
+ if (pciio == NULL || h == NULL)
+ return (false);
+ status = pciio->GetLocation(
+ pciio,
+ &SegmentNumber,
+ &BusNumber,
+ &DeviceNumber,
+ &FunctionNumber);
+ if (EFI_ERROR(status))
+ return (false);
+ sc = udb_alloc_softc(sizeof(*sc), h, pciio);
+ if (sc == NULL)
+ return (false);
+ sc->sc_pci_rid = PCI_RID(BusNumber, DeviceNumber, FunctionNumber);
+ sc->sc_efi_pciio = pciio;
+ sc->sc_efi_hand = h;
+
+ sc->sc_dbc_off = xhci_debug_get_xecp(sc);
+ if (sc->sc_dbc_off == 0)
+ goto error;
+
+ xhci_debug_disable(sc);
+ xhci_debug_update_state(sc);
+
+ DEBUG_PRINTF(2, ("%s: before init\n", __func__));
+ if (sc->sc_init == false) {
+ error = xhci_debug_init_dma(sc);
+ if (error) {
+ DEBUG_PRINTF(1, ("USB DbC DMA configuration error\n"));
+ goto error;
+ }
+ error = xhci_debug_init_ring(sc);
+ if (error) {
+ DEBUG_PRINTF(1, ("USB DbC TRB ring configuration error\n"));
+ goto error;
+ }
+ sc->sc_init = true;
+ sc->sc_cookie = XHCI_DC_COOKIE;
+ }
+ xhci_debug_enable(sc);
+
+ /* Add a new entry */
+ if (udb_sc0 != NULL)
+ sc->sc_next = udb_sc0;
+ udb_sc0 = sc;
+
+ (void) udbc_init(0); /* XXX: Asks udbc to init now */
+
+ return (true);
+error:
+ /* XXX: free softc */
+ return (false);
+}
+
+static int
+udbc_init(int arg)
+{
+ struct xhci_debug_softc *sc;
+ uint32_t rid;
+ char *p, *endp;
+ bool gdb;
+
+ if (udb_sc != NULL) /* already initialized */
+ return (CMD_OK);
+
+ /* Initialize all instances */
+ for (sc = udb_sc0; sc != NULL; sc = sc->sc_next)
+ xhci_debug_enable(sc);
+
+ /* If called in c_probe, udb_sc will not be initialized. */
+ if (arg == 1)
+ return (CMD_OK);
+
+ p = getenv("hw.usb.xhci.dbc.enable");
+ if (p != NULL && p[0] == '0')
+ return (CMD_OK);
+
+ p = getenv("hw.usb.xhci.dbc.debug");
+ if (p != NULL) {
+ dbc_debug = strtol(p, &endp, 0);
+ if (*endp != '\0')
+ dbc_debug = 0;
+ }
+
+ rid = 0;
+ p = getenv("hw.usb.xhci.dbc.pci_rid");
+ if (p != NULL) {
+ rid = strtol(p, &endp, 0);
+ if (*endp != '\0')
+ rid = 0;
+ }
+
+ /* XXX: too late */
+ udb_hostname = getenv("hw.usb.xhci.dbc.hostname");
+ udb_serial = getenv("hw.usb.xhci.dbc.serial");
+ p = getenv("hw.usb.xhci.dbc.gdb");
+ gdb = (p != NULL && p[0] != '0');
+
+ /* Initialize flags */
+ for (sc = udb_sc0; sc != NULL; sc = sc->sc_next)
+ if (gdb)
+ sc->sc_flags |= XHCI_DEBUG_FLAGS_GDB;
+
+ for (sc = udb_sc0; sc != NULL; sc = sc->sc_next) {
+ /* If RID is not specified, use the first one. */
+ if ((rid == 0 || rid == sc->sc_pci_rid) &&
+ sc->sc_dbc_off != 0)
+ break;
+ }
+ if (sc == NULL) {
+ DEBUG_PRINTF(1, ("USB DbC not found\n"));
+ return (CMD_ERROR);
+ }
+
+ /* Define the console */
+ udb_sc = sc;
+ xhci_debug_event_dequeue(sc);
+
+ return (CMD_OK);
+}
+
+static void
+udbc_putc(int c0)
+{
+ struct xhci_debug_softc *sc = udb_sc;
+ u_char c = (0xff & c0);
+
+ if (sc == NULL)
+ return;
+
+ /* XXXTHJ: Try to avoid getting stuck */
+ while (DC_WORK_RING_FULL(&sc->udb_oring)) {
+ xhci_debug_bulk_transfer(sc);
+ xhci_debug_event_dequeue(sc);
+ delay(100);
+ }
+
+ if (work_enqueue(&sc->udb_oring, &c, sizeof(c)) != sizeof(c))
+ return;
+
+ xhci_debug_bulk_transfer(sc);
+ /*
+ * This dequeue just after the transfer is important.
+ * Do not remove this.
+ */
+ xhci_debug_event_dequeue(sc);
+}
+
+/* udbc_getc() is called periodically. */
+static int
+udbc_getc(void)
+{
+ struct xhci_debug_softc *sc = udb_sc;
+
+ if (sc == NULL)
+ return (-1);
+
+ /* Use udbc_ischar() to receive data */
+ return (udbc_ischar() ? work_dequeue(&sc->udb_iring) : -1);
+}
+
+static int
+udbc_ischar(void)
+{
+ struct xhci_debug_softc *sc = udb_sc;
+ struct xhci_debug_ring *iring;
+
+ if (sc == NULL)
+ return (0);
+ iring = &sc->udb_iring;
+ if (!DC_WORK_RING_EMPTY(iring))
+ return (1);
+
+ xhci_debug_bulk_transfer(sc);
+ xhci_debug_event_dequeue(sc);
+
+ return (!DC_WORK_RING_EMPTY(iring));
+}
diff --git a/stand/efi/loader/xhci_dbc_dma.h b/stand/efi/loader/xhci_dbc_dma.h
new file mode 100644
--- /dev/null
+++ b/stand/efi/loader/xhci_dbc_dma.h
@@ -0,0 +1,32 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019-2024 Hiroki Sato <hrs@FreeBSD.org>
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ */
+int xhci_debug_init_dma(struct xhci_debug_softc *);
+void xhci_debug_uninit_dma(struct xhci_debug_softc *);
+
+struct xhci_debug_softc *udb_alloc_softc(size_t, EFI_HANDLE *,
+ EFI_PCI_IO_PROTOCOL *);
diff --git a/stand/efi/loader/xhci_dbc_dma.c b/stand/efi/loader/xhci_dbc_dma.c
new file mode 100644
--- /dev/null
+++ b/stand/efi/loader/xhci_dbc_dma.c
@@ -0,0 +1,298 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019-2024 Hiroki Sato <hrs@FreeBSD.org>
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ */
+#include <sys/param.h>
+#include <dev/pci/pcireg.h>
+#include <dev/usb/controller/xhcireg.h>
+#include <machine/atomic.h>
+
+#include <assert.h>
+
+#include <bootstrap.h>
+#include <efi.h>
+#include <efilib.h>
+#include <dev/usb/controller/xhci_private.h>
+#include "xhci_dbc_pci.h"
+#include <dev/usb/controller/xhci_dbc.h>
+#include <dev/usb/controller/xhci_dbc_private.h>
+#include "xhci_dbc_cons.h"
+#include "xhci_dbc_dma.h"
+
+EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID;
+
+static void *udb_alloc_dma(struct xhci_debug_softc *, uint64_t);
+static void udb_free_dma(struct xhci_debug_softc *, VOID *);
+static uint64_t v2p(struct xhci_debug_softc *, void *);
+
+uint64_t
+v2p(struct xhci_debug_softc *sc, void *virt)
+{
+ UINTN i;
+ UINTN p;
+ UINTN offset;
+ UINTN needed;
+ UINTN mapped;
+ struct dma *dma;
+ EFI_STATUS status;
+ EFI_PHYSICAL_ADDRESS paddr;
+ VOID *mapping;
+
+ dma = NULL;
+ for (i = 0; i < nitems(sc->dma_desc); i++) {
+ dma = &sc->dma_desc[i];
+
+ DEBUG_PRINTF(1, ("%s: dma_desc[%lu].cpu_addr = %p\n", __func__,
+ i, dma->cpu_addr));
+ for (p = 0; p < dma->pages; p++) {
+ UINTN addr = (UINTN)dma->cpu_addr + (p * PAGE_SIZE);
+
+ DEBUG_PRINTF(1, ("%s: check addr: %lu = %lu + %lu * %u\n",
+ __func__, addr, (UINTN)dma->cpu_addr, p, PAGE_SIZE));
+ if ((UINTN)virt == addr) {
+ offset = addr - (UINTN)dma->cpu_addr;
+ goto found;
+ }
+ }
+ dma = NULL;
+ }
+ if (dma == NULL) {
+ DEBUG_PRINTF(1, ("CPU addr %p not found in DMA descriptor\n", virt));
+ return 0;
+ }
+
+found:
+#if 0
+ DEBUG_PRINTF(1, "%s: found, i = %lu, dma->paddr = %lu, offset = %lu\n",
+ __func__, i, dma->paddr, offset);
+#endif
+ if (dma->paddr && dma->mapping)
+ return (dma->paddr + offset);
+
+ needed = dma->pages << EFI_PAGE_SHIFT;
+ mapped = needed;
+ status = sc->sc_efi_pciio->Map(sc->sc_efi_pciio,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ (void *)virt, &mapped, &paddr, &mapping);
+ if (EFI_ERROR(status) || mapped != needed) {
+ DEBUG_PRINTF(1, ("pciio->Map failed: rc: 0x%lx, mapped: %lu, needed: %lu\n",
+ status, mapped, needed));
+ return (0);
+ }
+ dma->paddr = paddr;
+ dma->mapping = mapping;
+
+ if ((const void *)paddr != virt) {
+ DEBUG_PRINTF(1, ("Non-identity DMA mapping: dma: 0x%lx cpu: %p\n",
+ paddr, virt));
+ }
+
+ return (paddr);
+}
+
+struct xhci_debug_softc *
+udb_alloc_softc(size_t len, EFI_HANDLE *h, EFI_PCI_IO_PROTOCOL *pciio)
+{
+ struct xhci_debug_softc *sc;
+ EFI_STATUS status;
+ VOID *addr;
+ int pages;
+
+ DEBUG_PRINTF(2, ("%s: called\n", __func__));
+ sc = NULL;
+ pages = sizeof(*sc) / PAGE_SIZE + 1;
+ status = pciio->AllocateBuffer(pciio,
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ sizeof(*sc) / PAGE_SIZE + 1,
+ &addr,
+ EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED);
+ if (EFI_ERROR(status)) {
+ DEBUG_PRINTF(1, ("%s: AllocateBuffer failed: 0x%lx\n",
+ __func__, status));
+ return (NULL);
+ }
+ memset(addr, 0, sizeof(*sc));
+ sc = (struct xhci_debug_softc *)addr;
+
+ sc->dma_desc[0].pages = pages;
+ sc->dma_desc[0].cpu_addr = addr;
+ sc->sc_efi_pciio = pciio;
+ sc->sc_efi_hand = h;
+ sc->sc_init_dma = false;
+ sc->sc_init = false;
+ if (udb_hostname != NULL)
+ strlcpy(sc->sc_hostname, udb_hostname, sizeof(sc->sc_hostname));
+ if (udb_serial != NULL)
+ strlcpy(sc->sc_serialno, udb_serial, sizeof(sc->sc_serialno));
+
+ return (sc);
+}
+
+int
+xhci_debug_init_dma(struct xhci_debug_softc *sc)
+{
+#define ALLOC_DMA(p, type, order) \
+ do { \
+ p = (type)udb_alloc_dma(sc, order); \
+ if (p == NULL) { \
+ xhci_debug_uninit_dma(sc); \
+ return (1); \
+ } \
+ } while (0)
+
+ if (sc->sc_init_dma)
+ return (0);
+
+ ALLOC_DMA(sc->udb_ctx, struct xhci_debug_ctx *, 0);
+ ALLOC_DMA(sc->udb_erst, struct xhci_event_ring_seg *, 0);
+ ALLOC_DMA(sc->udb_str, char *, 0);
+ ALLOC_DMA(sc->udb_ering.trb, struct xhci_trb *, DC_TRB_RING_ORDER);
+ ALLOC_DMA(sc->udb_iring.trb, struct xhci_trb *, DC_TRB_RING_ORDER);
+ ALLOC_DMA(sc->udb_oring.trb, struct xhci_trb *, DC_TRB_RING_ORDER);
+ ALLOC_DMA(sc->udb_ering.work.buf, uint8_t *, DC_WORK_RING_ORDER);
+ ALLOC_DMA(sc->udb_iring.work.buf, uint8_t *, DC_WORK_RING_ORDER);
+ ALLOC_DMA(sc->udb_oring.work.buf, uint8_t *, DC_WORK_RING_ORDER);
+
+ /* Export CTX, ERST, and STR */
+#define SETADDR(n, len) do { \
+ sc->udb_##n##_paddr = (uintptr_t)v2p(sc, sc->udb_##n); \
+ sc->udb_##n##_len = len; \
+ } while (0)
+ SETADDR(ctx, PAGE_SIZE);
+ SETADDR(erst, PAGE_SIZE);
+ SETADDR(str, PAGE_SIZE);
+
+ /* Export TRB rings. */
+#define SETADDR_RING(n, paddr, lenp, buf, len) do { \
+ sc->udb_##paddr = (uintptr_t)v2p(sc, sc->udb_##buf); \
+ sc->udb_##lenp = len; \
+ } while (0)
+
+ SETADDR_RING(ering, ering.paddr, ering.len, ering.trb,
+ PAGE_SIZE * (1UL << DC_TRB_RING_ORDER));
+ SETADDR_RING(iring, iring.paddr, iring.len, iring.trb,
+ PAGE_SIZE * (1UL << DC_TRB_RING_ORDER));
+ SETADDR_RING(oring, oring.paddr, oring.len, oring.trb,
+ PAGE_SIZE * (1UL << DC_TRB_RING_ORDER));
+ SETADDR_RING(ering.work, ering.work.paddr, ering.work.len,
+ ering.work.buf, PAGE_SIZE * (1UL << DC_WORK_RING_ORDER));
+ SETADDR_RING(iring.work, iring.work.paddr, iring.work.len,
+ iring.work.buf, PAGE_SIZE * (1UL << DC_WORK_RING_ORDER));
+ SETADDR_RING(oring.work, oring.work.paddr, oring.work.len,
+ oring.work.buf, PAGE_SIZE * (1UL << DC_WORK_RING_ORDER));
+
+ sc->sc_init_dma = true;
+
+ return (0);
+#undef ALLOC_DMA
+}
+
+static void *
+udb_alloc_dma(struct xhci_debug_softc *sc, uint64_t order)
+{
+ struct dma *dma;
+ EFI_STATUS status;
+ VOID *addr;
+ UINTN pages = 1UL << order;
+ UINTN i;
+
+ for (i = 0; i < nitems(sc->dma_desc); i++) {
+ dma = &sc->dma_desc[i];
+ if (dma->cpu_addr == NULL)
+ break;
+ }
+ if (i == nitems(sc->dma_desc)) {
+ DEBUG_PRINTF(1, ("%s: Out of DMA descriptor\n", __func__));
+ return (NULL);
+ }
+ status = sc->sc_efi_pciio->AllocateBuffer(sc->sc_efi_pciio,
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ pages,
+ &addr,
+ EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED);
+ if (EFI_ERROR(status)) {
+ DEBUG_PRINTF(1, ("%s: AllocateBuffer failed: 0x%lx\n",
+ __func__, status));
+ return (NULL);
+ }
+
+ dma->pages = pages;
+ dma->cpu_addr = addr;
+ DEBUG_PRINTF(1, ("%s: i = %lu, cpu_addr = %p, pages = %lu\n", __func__,
+ i, dma->cpu_addr, pages));
+
+ return (addr);
+}
+
+static void
+udb_free_dma(struct xhci_debug_softc *sc, VOID *addr)
+{
+ struct dma *dma;
+ EFI_STATUS status;
+ UINTN i;
+
+ for (i = 0; i < nitems(sc->dma_desc); i++) {
+ dma = &sc->dma_desc[i];
+ if (dma->cpu_addr == addr)
+ break;
+ }
+ if (i == nitems(sc->dma_desc))
+ return;
+ if (dma->mapping) {
+ status = sc->sc_efi_pciio->Unmap(sc->sc_efi_pciio,
+ dma->mapping);
+ if (EFI_ERROR(status)) {
+ DEBUG_PRINTF(1, ("%s: Unmap failed: 0x%lx\n",
+ __func__, status));
+ return;
+ }
+ }
+ status = sc->sc_efi_pciio->FreeBuffer(sc->sc_efi_pciio, dma->pages,
+ addr);
+ if (EFI_ERROR(status)) {
+ DEBUG_PRINTF(1, ("%s: FreeBuffer failed: 0x%lx\n",
+ __func__, status));
+ return;
+ }
+ memset(&dma, 0, sizeof(*dma));
+}
+
+void
+xhci_debug_uninit_dma(struct xhci_debug_softc *sc)
+{
+ udb_free_dma(sc, sc->udb_ctx);
+ udb_free_dma(sc, sc->udb_erst);
+ udb_free_dma(sc, sc->udb_ering.trb);
+ udb_free_dma(sc, sc->udb_oring.trb);
+ udb_free_dma(sc, sc->udb_iring.trb);
+ udb_free_dma(sc, sc->udb_ering.work.buf);
+ udb_free_dma(sc, sc->udb_oring.work.buf);
+ udb_free_dma(sc, sc->udb_iring.work.buf);
+
+ sc->sc_init_dma = false;
+}
diff --git a/stand/efi/loader/xhci_dbc_pci.h b/stand/efi/loader/xhci_dbc_pci.h
new file mode 100644
--- /dev/null
+++ b/stand/efi/loader/xhci_dbc_pci.h
@@ -0,0 +1,94 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019-2024 Hiroki Sato <hrs@FreeBSD.org>
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+extern EFI_GUID pciio_guid;
+
+/*
+ * Dummy functions to use xhci_pci_match(). Note that device_t is defined
+ * as PCI Type 00 header.
+ */
+typedef struct {
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT16 Command;
+ UINT16 Status;
+ UINT8 RevisionID;
+ UINT8 ClassCode[3];
+ UINT8 CacheLineSize;
+ UINT8 LatencyTimer;
+ UINT8 HeaderType;
+ UINT8 BIST;
+} PCI_DEVICE_INDEPENDENT_REGION;
+
+typedef struct {
+ UINT32 Bar[6];
+ UINT32 CISPtr;
+ UINT16 SubsystemVendorID;
+ UINT16 SubsystemID;
+ UINT32 ExpansionRomBar;
+ UINT8 CapabilityPtr;
+ UINT8 Reserved1[3];
+ UINT32 Reserved2;
+ UINT8 InterruptLine;
+ UINT8 InterruptPin;
+ UINT8 MinGnt;
+ UINT8 MaxLat;
+} PCI_DEVICE_HEADER_TYPE_REGION;
+
+typedef struct {
+ PCI_DEVICE_INDEPENDENT_REGION Hdr;
+ PCI_DEVICE_HEADER_TYPE_REGION Device;
+} PCI_TYPE00;
+
+typedef PCI_TYPE00 device_t;
+
+static inline uint32_t
+pci_get_devid(device_t dev)
+{
+ return ((dev.Hdr.DeviceId << 16) | dev.Hdr.VendorId);
+}
+static inline uint8_t
+pci_get_class(device_t dev)
+{
+ return (dev.Hdr.ClassCode[0]);
+}
+static inline uint8_t
+pci_get_subclass(device_t dev)
+{
+ return (dev.Hdr.ClassCode[1]);
+}
+static inline uint8_t
+pci_get_progif(device_t dev)
+{
+ return (dev.Hdr.ClassCode[2]);
+}
+static inline uint8_t
+pci_get_headertype(device_t dev)
+{
+ return (dev.Hdr.HeaderType);
+}
diff --git a/stand/efi/loader_ia32/Makefile b/stand/efi/loader_ia32/Makefile
--- a/stand/efi/loader_ia32/Makefile
+++ b/stand/efi/loader_ia32/Makefile
@@ -1,5 +1,6 @@
DO32=1
INSTALL_LOADER_HELP_FILE=no
+LOADER_USBDBC_SUPPORT=no
NEWVERSWHAT?= "EFI loader" amd64-ia32
diff --git a/stand/loader.mk b/stand/loader.mk
--- a/stand/loader.mk
+++ b/stand/loader.mk
@@ -53,6 +53,7 @@
# LOADER_NFS_SUPPORT Add NFS support
# LOADER_TFTP_SUPPORT Add TFTP support
# LOADER_UFS_SUPPORT Add support for UFS filesystems
+# LOADER_USBDBC_SUPPORT Add USB debug capability support
# LOADER_ZFS_SUPPORT Add support for ZFS filesystems
#
@@ -131,6 +132,11 @@
CFLAGS+= -DLOADER_BZIP2_SUPPORT
.endif
+# Debugging
+.if ${LOADER_USBDBC_SUPPORT:Uno} == "yes"
+CFLAGS+= -DLOADER_USBDBC_SUPPORT
+.endif
+
# Network related things
.if ${LOADER_NET_SUPPORT:Uno} == "yes"
CFLAGS+= -DLOADER_NET_SUPPORT
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2508,6 +2508,8 @@
device uark
# USB support for Belkin F5U103 and compatible serial adapters
device ubsa
+# USB support for XHCI USB DbC.GP serial device
+device udbc
# USB support for serial adapters based on the FT8U100AX and FT8U232AM
device uftdi
# USB support for some Windows CE based serial communication.
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3396,6 +3396,7 @@
dev/usb/serial/ubser.c optional ubser
dev/usb/serial/uchcom.c optional uchcom
dev/usb/serial/ucycom.c optional ucycom
+dev/usb/serial/udbc.c optional udbc
dev/usb/serial/ufoma.c optional ufoma
dev/usb/serial/uftdi.c optional uftdi
dev/usb/serial/ugensa.c optional ugensa
@@ -3410,10 +3411,10 @@
dev/usb/serial/uvisor.c optional uvisor
dev/usb/serial/uvscom.c optional uvscom
dev/usb/serial/usb_serial.c optional ucom | u3g | uark | ubsa | ubser | \
- uchcom | ucycom | ufoma | uftdi | \
- ugensa | uipaq | umcs | umct | \
- umodem | umoscom | uplcom | usie | \
- uslcom | uvisor | uvscom
+ uchcom | ucycom | udbc | ufoma | \
+ uftdi | ugensa | uipaq | umcs | \
+ umct | umodem | umoscom | uplcom | \
+ usie | uslcom | uvisor | uvscom
#
# USB misc drivers
#
diff --git a/sys/dev/usb/controller/xhci_dbc.h b/sys/dev/usb/controller/xhci_dbc.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/usb/controller/xhci_dbc.h
@@ -0,0 +1,231 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019-2024 Hiroki Sato <hrs@FreeBSD.org>
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ */
+extern int dbc_debug;
+
+#ifndef _KERNEL
+/* for struct mtx in xhci_debug_softc */
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+inline void mtx_lock_spin(struct mtx *m) { }
+inline int mtx_trylock_spin(struct mtx *m) { return (1); }
+inline void mtx_unlock_spin(struct mtx *m) { }
+#endif
+
+/* DbC idVendor and idProduct */
+#define DC_VENDOR 0x1d6b /* Linux Foundation */
+#define DC_PRODUCT 0x0011 /* Linux */
+#define DC_PROTOCOL 0x0000 /* GNU GDB = 1 */
+#define DC_REVISION 0x0010 /* 0.10 */
+
+#define DC_STRING_MANUFACTURER "The FreeBSD Foundation"
+#define DC_STRING_PRODUCT "FreeBSD USB DbC.GP Device"
+#define DC_STRING_SERIAL "12345678"
+
+/* DbC endpoint types */
+enum {
+ EP_BULK_OUT = 2,
+ EP_BULK_IN = 6
+};
+
+#define DC_TRB_PER_PAGE (XHCI_PAGE_SIZE / sizeof(struct xhci_trb))
+
+/* Defines the size in bytes of TRB rings as 2^DC_TRB_RING_ORDER * 4096 */
+#define DC_TRB_RING_ORDER 4
+#define DC_TRB_RING_LEN (DC_TRB_PER_PAGE * (1ULL << DC_TRB_RING_ORDER))
+#define DC_TRB_RING_OFFSET_MASK (DC_TRB_RING_LEN - 1U)
+#define DC_TRB_RING_LAST (DC_TRB_RING_LEN - 1U)
+#define DC_TRB_RING_BYTES (DC_TRB_RING_LEN * sizeof(struct xhci_trb))
+#define DC_TRB_RING_MASK (DC_TRB_RING_BYTES - 1U)
+
+/* Defines the size in bytes of work rings as 2^WORK_RING_ORDER * 4096 */
+#define DC_WORK_RING_ORDER 3
+#define DC_WORK_RING_LEN (XHCI_PAGE_SIZE * (1ULL << DC_WORK_RING_ORDER))
+#define DC_WORK_RING_OFFSET_MASK (DC_WORK_RING_LEN - 1U)
+#define DC_WORK_RING_LAST (DC_WORK_RING_LEN - 1U)
+#define DC_WORK_RING_BYTES DC_WORK_RING_LEN
+
+#define DC_WORK_RING_FULL(r) \
+ ((((r)->work.w_enq + 1) & DC_WORK_RING_OFFSET_MASK) == (r)->work.w_deq)
+#define DC_WORK_RING_EMPTY(r) \
+ ((r)->work.w_enq == (r)->work.w_deq)
+#define XHCI_DC_RING_FULL(r) \
+ ((((r)->enq + 1) & DC_TRB_RING_OFFSET_MASK) == (r)->deq)
+#define XHCI_DC_RING_EMPTY(r) \
+ ((r)->enq == (r)->deq)
+/* TRB ring has a link TRB at the tail of the queue. */
+#define XHCI_DC_RING_SLOTS(r) ( \
+ (((r)->deq <= (r)->enq) ? (r)->deq + DC_TRB_RING_LEN - 1 : (r)->deq) \
+ - (r)->enq)
+#define DC_WORK_RING_SLOTS(r) ( \
+ (((r)->w_deq <= (r)->w_enq) ? (r)->w_deq + DC_WORK_RING_LEN : (r)->w_deq) \
+ - (r)->w_enq)
+
+struct xhci_debug_ctx {
+ uint32_t info[16];
+ struct xhci_endp_ctx64 ep_out;
+ struct xhci_endp_ctx64 ep_in;
+};
+
+struct xhci_debug_work_ring {
+ uint8_t *buf;
+ uint32_t w_enq;
+ uint32_t w_deq;
+ uint64_t paddr;
+ uint64_t len;
+};
+
+struct xhci_debug_ring {
+ struct xhci_trb *trb; /* Array of TRBs */
+ uint64_t paddr; /* base address of TRBs */
+ uint64_t len; /* length of TRBs */
+ uint32_t enq; /* The offset of the enqueue ptr */
+ uint32_t deq; /* The offset of the dequeue ptr */
+ uint8_t cyc; /* Cycle state toggled on each wrap-around */
+ uint32_t doorbell; /* Doorbell target */
+#define XHCI_DC_RING_IN(ring) ((ring)->doorbell == XHCI_DCDB_IN)
+#define XHCI_DC_RING_OUT(ring) ((ring)->doorbell == XHCI_DCDB_OUT)
+#define XHCI_DC_RING_EV(ring) ((ring)->doorbell == XHCI_DCDB_INVALID)
+ struct xhci_debug_work_ring work;
+
+ struct mtx mtx;
+ uint32_t flags;
+#define XHCI_DC_RING_F_IN_PROGRESS 0x0001
+ uint32_t lasterror;
+ uint32_t lastenq;
+ uint32_t lastdeq;
+/*
+ * Bitmap for completion report.
+ *
+ * Set when enqueuing a normal TRB, and
+ * reset when receiving the corrensponding transfer event TRB.
+ */
+ uint8_t iocbitmap[DC_TRB_RING_LEN / 8 + 1];
+#define IOCBITMAP_GET(ring, n) \
+ (((ring)->iocbitmap[(n) / 8] >> ((uint8_t)(n) % 8)) & (uint8_t)1)
+#define IOCBITMAP_SET(ring, n) \
+ ((ring)->iocbitmap[(n) / 8] |= ((uint8_t)1 << (uint8_t)((n) % 8)))
+#define IOCBITMAP_CLEAR(ring, n) \
+ ((ring)->iocbitmap[(n) / 8] &= ~((uint8_t)1 << (uint8_t)((n) % 8)))
+
+ uint64_t ec[256]; /* error counter */
+#define XHCI_TRB_ERROR_EVLOCKED 0x30
+#define XHCI_TRB_ERROR_CALLED 0x31
+#define XHCI_TRB_ERROR_WORKQ_FULL 0x32
+#define XHCI_TRB_ERROR_UNKNOWN 0xff
+};
+
+#ifndef _KERNEL
+#define DMA_DESC_CAP 16
+struct dma {
+ UINTN pages;
+ EFI_PHYSICAL_ADDRESS paddr;
+ VOID *cpu_addr;
+ VOID *mapping;
+};
+#endif
+
+/*
+ * This softc is used in kernel and loader.
+ */
+struct xhci_softc;
+struct udbcons_priv;
+#define XHCI_DC_COOKIE 0x4d79b718
+struct xhci_debug_softc {
+ struct xhci_debug_softc *sc_next;
+ bool sc_next_fixup;
+ struct mtx sc_mtx;
+ uint32_t sc_cookie;
+
+ struct xhci_debug_ctx *udb_ctx;
+ uint64_t udb_ctx_paddr;
+ uint64_t udb_ctx_len;
+
+ struct xhci_event_ring_seg *udb_erst;
+ uint64_t udb_erst_paddr;
+ uint64_t udb_erst_len;
+
+ struct xhci_debug_ring udb_ering;
+ struct xhci_debug_ring udb_oring;
+ struct xhci_debug_ring udb_iring;
+
+ char *udb_str;
+ uint64_t udb_str_paddr;
+ uint64_t udb_str_len;
+
+ uint32_t sc_state;
+ uint32_t sc_flags;
+#define XHCI_DEBUG_FLAGS_GDB 0x0001
+ uint64_t sc_polling_count;
+#define XHCI_DC_POLLING_TIME 50
+ uint32_t sc_polling_time;
+ uint64_t sc_dequeue_count;
+ bool sc_init;
+ bool sc_init_dma;
+ bool sc_fixup_done;
+ bool sc_open;
+ char sc_hostname[256];
+ char sc_serialno[256];
+
+ /* In kernel, sc_*_off in struct xhci_softc is used. */
+ struct xhci_softc *sc_xhci; /* used in _X{READ,WRITE} */
+ uint32_t sc_dbc_off;
+ uint32_t sc_capa_off; /* zero */
+ uint32_t sc_pci_rid;
+
+#ifdef _KERNEL
+ device_t sc_dev; /* used in kernel only */
+ struct udbcons_priv *sc_cons; /* used in kernel only */
+ uint8_t dummy[1456]; /* XXX: pad to 10240 bytes */
+#else
+ struct console *sc_cons; /* used in loader only */
+ EFI_PCI_IO_PROTOCOL *sc_efi_pciio;
+ EFI_HANDLE sc_efi_hand;
+ struct dma dma_desc[DMA_DESC_CAP];
+ uint8_t dummy[936]; /* XXX: pad to 10240 bytes */
+#endif
+};
+
+
+void xhci_debug_reg_read(struct xhci_debug_softc *);
+void xhci_debug_reg_restore(struct xhci_debug_softc *);
+
+uint32_t xhci_debug_get_xecp(struct xhci_debug_softc *);
+bool xhci_debug_enable(struct xhci_debug_softc *);
+void xhci_debug_disable(struct xhci_debug_softc *);
+
+int xhci_debug_init_ring(struct xhci_debug_softc *);
+uint32_t xhci_debug_update_state(struct xhci_debug_softc *);
+
+uint64_t xhci_debug_bulk_transfer(struct xhci_debug_softc *);
+void xhci_debug_event_dequeue(struct xhci_debug_softc *);
+
+int work_dequeue(struct xhci_debug_ring *);
+int64_t work_enqueue(struct xhci_debug_ring *, const char *, int64_t);
+
+void udb_dump_info(struct xhci_debug_softc *);
diff --git a/sys/dev/usb/controller/xhci_dbc.c b/sys/dev/usb/controller/xhci_dbc.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/usb/controller/xhci_dbc.c
@@ -0,0 +1,1126 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019-2024 Hiroki Sato <hrs@FreeBSD.org>
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ */
+#include <sys/param.h>
+#include <sys/condvar.h>
+#include <sys/systm.h> /* getenv_quad */
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <machine/atomic.h>
+
+#ifndef _KERNEL
+#include <bootstrap.h>
+#include <efi.h>
+#include <efilib.h>
+#include <xhci_dbc_pci.h> /* device_t */
+#include <dev/usb/controller/xhci_private.h>
+#include <dev/usb/controller/xhci_dbc.h>
+#include "xhci_dbc_cons.h"
+#include "xhci_dbc_dma.h"
+#endif
+
+static void flush_range(void *, uint32_t);
+
+static bool xhci_debug_update_regbit(struct xhci_debug_softc *, int, int, int,
+ bool);
+static bool xhci_debug_set_regbit(struct xhci_debug_softc *, int, int, int);
+static bool xhci_debug_reset_regbit(struct xhci_debug_softc *, int, int, int);
+
+static bool xhci_debug_wait_connection(struct xhci_debug_softc *, uint32_t);
+
+static struct xhci_debug_softc * xhci_debug_alloc_softc(device_t);
+static bool xhci_debug_softc_fixup(struct xhci_debug_softc *);
+static void xhci_debug_ring_init(struct xhci_debug_softc *,
+ struct xhci_debug_ring *, int, uint32_t);
+struct usb_strdesc;
+static void atou16cpy(struct usb_strdesc *, const char *);
+static void xhci_debug_init_strings(struct xhci_debug_softc *, uint32_t [16]);
+
+static void xhci_debug_ring_doorbell(struct xhci_debug_softc *, uint32_t);
+static uint64_t xhci_debug_bulk_transfer0(struct xhci_debug_softc *,
+ struct xhci_debug_ring *);
+
+static void xhci_debug_init_ep(struct xhci_endp_ctx64 *, uint64_t, uint32_t,
+ uint64_t);
+
+#if 0
+static bool xhci_debug_event_ready(struct xhci_debug_softc *);
+#endif
+static uint32_t xhci_debug_ring_boundary(struct xhci_debug_ring *, bool);
+
+static void xhci_debug_transfer_event_handler(struct xhci_debug_softc *,
+ uint64_t, uint32_t, uint32_t);
+static uint64_t trb_tx_enqueue_locked(struct xhci_debug_softc *sc,
+ struct xhci_debug_ring *);
+static uint64_t trb_rx_enqueue_locked(struct xhci_debug_softc *sc,
+ struct xhci_debug_ring *);
+static uint64_t trb_push_locked(struct xhci_debug_softc *sc,
+ struct xhci_debug_ring *, uint64_t, uint64_t);
+
+/* sc_state */
+#define STRSTATE(x) [XHCI_DCPORT_ST_##x] = #x
+static const char *strstate[] = {
+ STRSTATE(OFF),
+ STRSTATE(DISCONNECTED_RUNNING), /* not in spec */
+ STRSTATE(DISCONNECTED),
+ STRSTATE(DISABLED),
+ STRSTATE(RESETTING),
+ STRSTATE(ENABLED),
+ STRSTATE(CONFIGURED)
+};
+
+/* sysctls */
+
+int dbc_debug;
+int dbc_reset;
+int dbc_enable = 1;
+int dbc_baud = 115200;
+int dbc_gdb;
+uint32_t dbc_pci_rid;
+
+vm_paddr_t udbc_console;
+
+static struct xhci_debug_reg {
+ uint32_t erstsz;
+ uint64_t erstba;
+ uint64_t erdp;
+ uint64_t cp;
+ uint32_t ddi1;
+ uint32_t ddi2;
+} udbc_reg;
+
+void
+xhci_debug_reg_read(struct xhci_debug_softc *sc)
+{
+
+ if (sc == NULL)
+ return;
+
+ udbc_reg.erstsz = _XREAD4(sc, dbc, XHCI_DCERSTSZ);
+ udbc_reg.erstba = _XREAD44LH(sc, dbc, XHCI_DCERSTBA);
+ udbc_reg.erdp = _XREAD44LH(sc, dbc, XHCI_DCERDP);
+ udbc_reg.cp = _XREAD44LH(sc, dbc, XHCI_DCCP);
+ udbc_reg.ddi1 = _XREAD4(sc, dbc, XHCI_DCDDI1);
+ udbc_reg.ddi2 = _XREAD4(sc, dbc, XHCI_DCDDI2);
+}
+void
+xhci_debug_reg_restore(struct xhci_debug_softc *sc)
+{
+
+ if (sc == NULL)
+ return;
+
+ _XWRITE4(sc, dbc, XHCI_DCERSTSZ, udbc_reg.erstsz);
+ _XWRITE44LH(sc, dbc, XHCI_DCERSTBA, udbc_reg.erstba);
+ _XWRITE44LH(sc, dbc, XHCI_DCERDP, udbc_reg.erdp);
+ _XWRITE44LH(sc, dbc, XHCI_DCCP, udbc_reg.cp);
+ _XWRITE4(sc, dbc, XHCI_DCDDI1, udbc_reg.ddi1);
+ _XWRITE4(sc, dbc, XHCI_DCDDI2, udbc_reg.ddi2);
+}
+
+static void
+flush_range(void *ptr, uint32_t bytes)
+{
+#ifndef _KERNEL
+ uint32_t i;
+ const uint32_t clshft = 6;
+ const uint32_t clsize = (1UL << clshft);
+ const uint32_t clmask = clsize - 1;
+ uint32_t lines = (bytes >> clshft);
+ lines += (bytes & clmask) != 0;
+
+ if (bytes == 0)
+ return;
+
+# if defined(__amd64__)
+#define CLFLUSH(ptr) \
+ __asm volatile("clflush %0" : "+m"(*(volatile char *)ptr))
+
+ for (i = 0; i < lines; i++)
+ CLFLUSH((void *)((uint64_t)ptr + (i * clsize)));
+#undef CLFLUSH
+#endif
+#endif
+}
+
+uint32_t
+xhci_debug_update_state(struct xhci_debug_softc *sc)
+{
+ uint32_t ctrl;
+ uint32_t portsc;
+ uint32_t sc_state_old;
+
+ ctrl = _XREAD4(sc, dbc, XHCI_DCCTRL);
+ portsc = _XREAD4(sc, dbc, XHCI_DCPORTSC);
+ sc_state_old = sc->sc_state;
+ sc->sc_state = XHCI_DCSTATUS(ctrl, portsc);
+ if (sc->sc_state != sc_state_old)
+ device_printf(sc->sc_dev, "state: %s(0x%02x) -> %s(0x%02x)\n",
+ strstate[sc_state_old], sc_state_old,
+ strstate[sc->sc_state], sc->sc_state);
+ return (sc->sc_state);
+}
+
+static bool
+xhci_debug_update_regbit(struct xhci_debug_softc *sc, int reg, int bit,
+ int timeout, bool reset)
+{
+ uint32_t temp;
+ int expected;
+
+ timeout *= 10; /* ms */
+ temp = le32toh(_XREAD4(sc, dbc, reg));
+ if (reset)
+ temp &= ~bit;
+ else
+ temp |= bit;
+ _XWRITE4(sc, dbc, reg, htole32(temp));
+ expected = (reset) ? 0 : bit;
+ while ((le32toh(_XREAD4(sc, dbc, reg)) & bit) != expected &&
+ timeout != 0) {
+ delay(100);
+ timeout--;
+ }
+ return (timeout > 0);
+}
+static bool
+xhci_debug_set_regbit(struct xhci_debug_softc *sc, int reg, int bit,
+ int timeout)
+{
+
+ return (xhci_debug_update_regbit(sc, reg, bit, timeout, false));
+}
+static bool
+xhci_debug_reset_regbit(struct xhci_debug_softc *sc, int reg, int bit,
+ int timeout)
+{
+
+ return (xhci_debug_update_regbit(sc, reg, bit, timeout, true));
+}
+
+bool
+xhci_debug_enable(struct xhci_debug_softc *sc)
+{
+ uint32_t state;
+
+ if (sc == NULL)
+ return (false);
+
+ state = xhci_debug_update_state(sc);
+ if (state == XHCI_DCPORT_ST_OFF ||
+ state == XHCI_DCPORT_ST_DISCONNECTED) {
+ if (!xhci_debug_set_regbit(sc, XHCI_DCCTRL, XHCI_DCCTRL_DCE,
+ 1)) {
+ device_printf(sc->sc_dev, "initialization failed\n");
+ return (false);
+ }
+
+ }
+
+ /* If success, check the cable. */
+ return (xhci_debug_wait_connection(sc, 1));
+}
+
+static bool
+xhci_debug_wait_connection(struct xhci_debug_softc *sc, uint32_t timeout)
+{
+ bool ret;
+
+ if (xhci_debug_update_state(sc) == XHCI_DCPORT_ST_DISCONNECTED) {
+ ret = xhci_debug_set_regbit(sc, XHCI_DCPORTSC,
+ XHCI_DCPORTSC_PED, 1000); /* XXX: 1 was not enough */
+ if (ret == false) {
+ device_printf(sc->sc_dev, "No DbC cable detected\n");
+ return (ret);
+ }
+ }
+ timeout = 10000;
+ device_printf(sc->sc_dev, "waiting for a cable\n");
+ while (xhci_debug_update_state(sc) != XHCI_DCPORT_ST_CONFIGURED) {
+ delay(500);
+ if (--timeout == 0) {
+ device_printf(sc->sc_dev,
+ "DbC cable detection timed out\n");
+ return (false);
+ }
+ }
+
+ device_printf(sc->sc_dev, "DbC cable detected\n");
+
+ return (true);
+}
+
+void
+xhci_debug_disable(struct xhci_debug_softc *sc)
+{
+ bool ret;
+
+ xhci_debug_reset_regbit(sc, XHCI_DCPORTSC, XHCI_DCPORTSC_PED, 0);
+ ret = xhci_debug_reset_regbit(sc, XHCI_DCCTRL, XHCI_DCCTRL_DCE, 1000);
+ if (ret == false)
+ DEBUG_PRINTF(1, ("%s: clearing XHCI_DCCTRL_DCE failed\n",
+ __func__));
+ xhci_debug_update_state(sc);
+}
+
+int
+xhci_debug_init_ring(struct xhci_debug_softc *sc)
+{
+ uint64_t erdp, out, in;
+ uint32_t temp;
+
+ if (sc->sc_dbc_off == 0) {
+ DEBUG_PRINTF(1, ("%s: register is empty\n", __func__));
+ return (-1);
+ }
+ /* Create an event ring. */
+ xhci_debug_ring_init(sc, &sc->udb_ering, 0, XHCI_DCDB_INVAL);
+ erdp = sc->udb_ering.paddr;
+ memset(sc->udb_erst, 0, sizeof(*sc->udb_erst));
+ sc->udb_erst->qwEvrsTablePtr = htole64(erdp);
+ sc->udb_erst->dwEvrsTableSize = htole32(DC_TRB_RING_LEN);
+ DEBUG_PRINTF(2, ("%s: ERDP=0x%016llx\n", __func__,
+ (unsigned long long)erdp));
+
+ /* Create an output ring. */
+ xhci_debug_ring_init(sc, &sc->udb_oring, 1, XHCI_DCDB_OUT);
+ out = sc->udb_oring.paddr;
+
+ /* Create an input ring. */
+ xhci_debug_ring_init(sc, &sc->udb_iring, 1, XHCI_DCDB_IN);
+ in = sc->udb_iring.paddr;
+
+ /* Initialize DbC context. */
+ memset(sc->udb_ctx, 0, sizeof(*sc->udb_ctx));
+ xhci_debug_init_strings(sc, sc->udb_ctx->info);
+
+ /* Initialize endpoints. */
+ temp = _XREAD4(sc, dbc, XHCI_DCCTRL);
+ xhci_debug_init_ep(&sc->udb_ctx->ep_out,
+ (uint64_t)XHCI_DCCTRL_MBS_GET(le32toh(temp)), EP_BULK_OUT, out);
+ xhci_debug_init_ep(&sc->udb_ctx->ep_in,
+ (uint64_t)XHCI_DCCTRL_MBS_GET(le32toh(temp)), EP_BULK_IN, in);
+
+ /* Configure register values. */
+ _XWRITE4(sc, dbc, XHCI_DCERSTSZ, htole32(1));
+ _XWRITE44LH(sc, dbc, XHCI_DCERSTBA, htole64(sc->udb_erst_paddr));
+ _XWRITE44LH(sc, dbc, XHCI_DCERDP, htole64(erdp));
+ _XWRITE44LH(sc, dbc, XHCI_DCCP, htole64(sc->udb_ctx_paddr));
+ _XWRITE4(sc, dbc, XHCI_DCDDI1,
+ htole32((DC_VENDOR << 16) | DC_PROTOCOL));
+ _XWRITE4(sc, dbc, XHCI_DCDDI2,
+ htole32((DC_REVISION << 16) | DC_PRODUCT));
+ flush_range(sc->udb_ctx, sizeof(*sc->udb_ctx));
+ flush_range(sc->udb_erst, sizeof(*sc->udb_erst));
+ flush_range(sc->udb_ering.trb, DC_TRB_RING_BYTES);
+ flush_range(sc->udb_oring.trb, DC_TRB_RING_BYTES);
+ flush_range(sc->udb_iring.trb, DC_TRB_RING_BYTES);
+ flush_range(sc->udb_oring.work.buf, DC_WORK_RING_BYTES);
+ flush_range(sc->udb_iring.work.buf, DC_WORK_RING_BYTES);
+
+ return (0);
+}
+
+uint32_t
+xhci_debug_get_xecp(struct xhci_debug_softc *sc)
+{
+ uint32_t hccp1;
+ uint32_t eec;
+ uint32_t eecp;
+
+ if (sc == NULL)
+ return (0);
+
+ hccp1 = _XREAD4(sc, capa, XHCI_HCSPARAMS0);
+
+ if (XHCI_HCS0_XECP(hccp1) == 0)
+ goto notfound;
+
+ eec = -1; /* XXX */
+ for (eecp = XHCI_HCS0_XECP(hccp1) << 2;
+ eecp != 0 && XHCI_XECP_NEXT(eec) != 0;
+ eecp += XHCI_XECP_NEXT(eec) << 2) {
+ eec = _XREAD4(sc, capa, eecp);
+
+ DEBUG_PRINTF(1, ("%s: Looking for xECP: "
+ "expected=%02x, found=%02x, next=%04x\n", __func__,
+ XHCI_ID_USB_DEBUG, XHCI_XECP_ID(eec),
+ XHCI_XECP_NEXT(eec) << 2));
+
+ if (XHCI_XECP_ID(eec) == XHCI_ID_USB_DEBUG)
+ break;
+ }
+ if (eecp == 0 || XHCI_XECP_ID(eec) == 0)
+ goto notfound;
+
+ DEBUG_PRINTF(1, ("%s: DbC was found at %08x\n", __func__, eecp));
+
+ return (eecp);
+notfound:
+ DEBUG_PRINTF(1, ("%s: DbC was not found\n", __func__));
+
+ return (0);
+}
+
+static bool
+xhci_debug_softc_fixup(struct xhci_debug_softc *sc)
+{
+ return (true);
+}
+
+static void
+xhci_debug_ring_init(struct xhci_debug_softc *sc,
+ struct xhci_debug_ring *ring, int producer, uint32_t doorbell)
+{
+ memset(ring->trb, 0, DC_TRB_RING_BYTES);
+ memset(ring->work.buf, 0, DC_WORK_RING_BYTES);
+
+ ring->enq = 0;
+ ring->deq = 0;
+ ring->cyc = 1;
+ ring->doorbell = doorbell;
+ ring->work.w_enq = 0;
+ ring->work.w_deq = 0;
+
+ /* Place a link TRB at the tail if producer == 1. */
+ if (producer) {
+ /* Fields for link TRBs (section 6.4.4.1) */
+
+ ring->trb[DC_TRB_RING_LAST] = (struct xhci_trb){
+ .qwTrb0 = htole64(ring->paddr),
+ .dwTrb3 = htole32(
+ XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_LINK) |
+ XHCI_TRB_3_TC_BIT
+ )
+ };
+ }
+}
+
+#define DC_STRDESC_STRING0 0
+#define DC_STRDESC_MANUFACTURER 1
+#define DC_STRDESC_PRODUCT 2
+#define DC_STRDESC_SERIAL 3
+#define USB_DESC_TYPE_STRING 3
+static struct usb_strdesc {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t chars[62]; /* UTF-16LE */
+} strdesc[] = {
+ [DC_STRDESC_STRING0] = {
+ .bLength = 2 + 4,
+ .bDescriptorType = USB_DESC_TYPE_STRING,
+ .chars = { 9, 0, 4, 0 }, /* 0x0409 = English */
+ },
+ [DC_STRDESC_MANUFACTURER] = {
+ .bLength = 2,
+ .bDescriptorType = USB_DESC_TYPE_STRING,
+ },
+ [DC_STRDESC_PRODUCT] = {
+ .bLength = 2,
+ .bDescriptorType = USB_DESC_TYPE_STRING,
+ },
+ [DC_STRDESC_SERIAL] = {
+ .bLength = 2,
+ .bDescriptorType = USB_DESC_TYPE_STRING,
+ }
+};
+static void
+atou16cpy(struct usb_strdesc *desc, const char *str)
+{
+ int i;
+
+ for (i = 0; i < strlen(str) && i * 2 < sizeof(desc->chars) - 1; i++) {
+ desc->chars[i * 2] = str[i];
+ desc->chars[i * 2 + 1] = '\0';
+ }
+ desc->bLength += i * 2;
+ desc->chars[sizeof(desc->chars) - 1] = '\0';
+}
+
+/* Initialize the DbC info with USB string descriptor addresses. */
+static void
+xhci_debug_init_strings(struct xhci_debug_softc *sc, uint32_t info[16])
+{
+ const char *serial;
+ char hostname[256];
+ char *p;
+
+ /*
+ * The product string will be "DC_STRING_PRODUCT (hostname)".
+ */
+ p = hostname;
+ strlcpy(hostname, DC_STRING_PRODUCT, sizeof(hostname));
+ if (sc->sc_hostname[0] != '\0' &&
+ strlen(sc->sc_hostname)
+ < sizeof(hostname) - sizeof(DC_STRING_PRODUCT) - 4) {
+ p = hostname + strlen(hostname);
+ *p++ = ' ';
+ *p++ = '(';
+ strlcpy(p, sc->sc_hostname, sizeof(hostname) - (p - hostname));
+ p = hostname + strlen(hostname);
+ *p++ = ')';
+ *p++ = '\0';
+ }
+ serial = (sc->sc_serialno[0] != '\0')
+ ? sc->sc_serialno : DC_STRING_SERIAL;
+ atou16cpy(&strdesc[DC_STRDESC_MANUFACTURER], DC_STRING_MANUFACTURER);
+ atou16cpy(&strdesc[DC_STRDESC_PRODUCT], hostname);
+ atou16cpy(&strdesc[DC_STRDESC_SERIAL], serial);
+
+ /* udb_str is 1 page buffer longer than sizeof(strdesc) */
+ memcpy(sc->udb_str, strdesc, sizeof(strdesc));
+
+#define STRADDR0(index) \
+ ((uint64_t)sc->udb_str_paddr + index * sizeof(struct usb_strdesc))
+#define STRADDR_LO(index) \
+ ((uint32_t)(STRADDR0(index) & 0xffffffff))
+#define STRADDR_HI(index) \
+ ((uint32_t)((STRADDR0(index) >> 32) & 0xffffffff))
+
+ info[XHCI_DCDBCIC_STR0DESC_LO] = STRADDR_LO(DC_STRDESC_STRING0);
+ info[XHCI_DCDBCIC_STR0DESC_HI] = STRADDR_HI(DC_STRDESC_STRING0);
+ info[XHCI_DCDBCIC_MANUDESC_LO] = STRADDR_LO(DC_STRDESC_MANUFACTURER);
+ info[XHCI_DCDBCIC_MANUDESC_HI] = STRADDR_HI(DC_STRDESC_MANUFACTURER);
+ info[XHCI_DCDBCIC_PRODDESC_LO] = STRADDR_LO(DC_STRDESC_PRODUCT);
+ info[XHCI_DCDBCIC_PRODDESC_HI] = STRADDR_HI(DC_STRDESC_PRODUCT);
+ info[XHCI_DCDBCIC_SERIALDESC_LO] = STRADDR_LO(DC_STRDESC_SERIAL);
+ info[XHCI_DCDBCIC_SERIALDESC_HI] = STRADDR_HI(DC_STRDESC_SERIAL);
+ info[XHCI_DCDBCIC_DESCLEN] =
+ XHCI_DCDBCIC_STR0DESC_LEN_SET(strdesc[DC_STRDESC_STRING0].bLength) |
+ XHCI_DCDBCIC_MANUDESC_LEN_SET(strdesc[DC_STRDESC_MANUFACTURER].bLength) |
+ XHCI_DCDBCIC_PRODDESC_LEN_SET(strdesc[DC_STRDESC_PRODUCT].bLength) |
+ XHCI_DCDBCIC_SERIALDESC_LEN_SET(strdesc[DC_STRDESC_SERIAL].bLength);
+
+#undef STRADDR0
+#undef STRADDR_LO
+#undef STRADDR_HI
+}
+
+static void
+xhci_debug_ring_doorbell(struct xhci_debug_softc *sc, uint32_t target)
+{
+ uint32_t doorbell;
+
+ /* The other bits in DCDB are RsvdP. */
+ /* XXXHRS: the spec has contradiction between Figure 7-9 and Table 7-18. */
+ doorbell = _XREAD4(sc, dbc, XHCI_DCDB) & ~XHCI_DCDB_MASK;
+ doorbell |= target;
+ _XWRITE4(sc, dbc, XHCI_DCDB, doorbell);
+
+ DEBUG_PRINTF(2, ("%s: doorbell = %04x\n", __func__, doorbell));
+}
+
+uint64_t
+xhci_debug_bulk_transfer(struct xhci_debug_softc *sc)
+{
+ return (
+ xhci_debug_bulk_transfer0(sc, &sc->udb_iring) +
+ xhci_debug_bulk_transfer0(sc, &sc->udb_oring));
+}
+
+static uint64_t
+xhci_debug_bulk_transfer0(struct xhci_debug_softc *sc,
+ struct xhci_debug_ring *ring)
+{
+ uint64_t len;
+ uint32_t temp;
+
+ xhci_debug_event_dequeue(sc);
+
+ len = 0;
+ if (mtx_trylock_spin(&sc->udb_ering.mtx) == 0)
+ goto end0;
+ if (mtx_trylock_spin(&ring->mtx) == 0)
+ goto end1;
+ if (XHCI_DC_RING_FULL(ring)) /* TRB queue is full */
+ goto end2;
+ /*
+ * DRC bit is asserted when it exits the CONFIGURED state.
+ * Clear the bit because DCDB is disabled until clearing the DRC bit.
+ * (sec 7.6.8.4)
+ * The timeout is ignored because this is a best-effort attempt.
+ */
+ temp = _XREAD4(sc, dbc, XHCI_DCCTRL);
+ if ((le32toh(temp) & XHCI_DCCTRL_DRC) != 0)
+ xhci_debug_reset_regbit(sc, XHCI_DCCTRL, XHCI_DCCTRL_DRC, 1);
+ /*
+ * Updating the state in bulk_transfer() is critical in loader.
+ * Do not remove this.
+ */
+ xhci_debug_update_state(sc);
+
+ len = (XHCI_DC_RING_IN(ring))
+ ? trb_rx_enqueue_locked(sc, ring)
+ : trb_tx_enqueue_locked(sc, ring);
+end2:
+ mtx_unlock_spin(&ring->mtx);
+end1:
+ mtx_unlock_spin(&sc->udb_ering.mtx);
+end0:
+ return (len);
+}
+
+/*
+ * Initializes the endpoint as specified in sections 7.6.3.2 and 7.6.9.2.
+ * Each endpoint is Bulk, so the MaxPStreams, LSA, HID, CErr, FE,
+ * Interval, Mult, and Max ESIT Payload fields are all 0.
+ *
+ * Max packet size: 1024
+ * Max burst size: mbs
+ * EP type: 2 for OUT bulk, 6 for IN bulk
+ * TR dequeue ptr: physical base address of transfer ring
+ * Avg TRB length: software defined (see 4.14.1.1 for suggested defaults, 3kB)
+ */
+static void
+xhci_debug_init_ep(struct xhci_endp_ctx64 *ep64, uint64_t mbs,
+ uint32_t type, uint64_t ring_paddr)
+{
+ struct xhci_endp_ctx *ep;
+
+ if (ep64 == NULL)
+ return;
+ ep = &ep64->ctx;
+ memset(ep64, 0, sizeof(*ep64));
+
+ /* Do we need XHCI_EPCTX_1_CERR_SET(3) in Sec 6.2.3 ? */
+ ep->dwEpCtx1 = htole32(
+ XHCI_EPCTX_1_MAXP_SIZE_SET(1024) |
+ XHCI_EPCTX_1_MAXB_SET((uint32_t)mbs) |
+ XHCI_EPCTX_1_EPTYPE_SET(type));
+ ep->qwEpCtx2 = htole64(
+ (ring_paddr & XHCI_EPCTX_2_TR_DQ_PTR_MASK) |
+ XHCI_EPCTX_2_DCS_SET(1));
+ ep->dwEpCtx4 = htole32(
+ XHCI_EPCTX_4_AVG_TRB_LEN_SET(1024 * 3));
+}
+
+#if 0
+static bool
+xhci_debug_event_ready(struct xhci_debug_softc *sc)
+{
+ uint32_t temp;
+
+ /* Seems inaccurate */
+ temp = _XREAD4(sc, dbc, XHCI_DCST);
+ return ((le32toh(temp) & XHCI_DCST_ER) == XHCI_DCST_ER);
+}
+#endif
+
+static uint32_t
+xhci_debug_ring_boundary(struct xhci_debug_ring *ring, bool update_enq)
+{
+ struct xhci_trb *trb = &ring->trb[ring->deq];
+ uint32_t dwTrb3;
+ uint32_t cyc;
+ uint32_t deq;
+
+ cyc = ring->cyc;
+ deq = ring->deq;
+ rmb();
+ dwTrb3 = le32toh(trb->dwTrb3);
+
+ while ((dwTrb3 & XHCI_TRB_3_CYCLE_BIT) == cyc) {
+ cyc = (deq == DC_TRB_RING_LAST)
+ ? cyc ^ 1
+ : cyc;
+ deq = (deq + 1) & DC_TRB_RING_OFFSET_MASK;
+ trb = &ring->trb[deq];
+ rmb();
+ dwTrb3 = le32toh(trb->dwTrb3);
+ }
+ if (update_enq)
+ ring->enq = deq;
+
+ return (deq);
+}
+
+static void
+xhci_debug_transfer_event_handler(struct xhci_debug_softc *sc,
+ uint64_t qwTrb0, uint32_t dwTrb2, uint32_t dwTrb3)
+{
+ struct xhci_trb *trb;
+ struct xhci_debug_ring *ring;
+ uint64_t qwEpCtx2;
+ uint32_t epid;
+ uint32_t error, len;
+ uint32_t deq_old;
+
+ /* EP ID is an index of context. */
+ epid = XHCI_TRB_3_EP_GET(dwTrb3);
+ error = XHCI_TRB_2_ERROR_GET(dwTrb2);
+
+ switch (epid) {
+ case XHCI_DC_EPID_OUT:
+ case XHCI_DC_EPID_OUT_INTEL:
+ ring = &sc->udb_oring;
+ break;
+ case XHCI_DC_EPID_IN:
+ case XHCI_DC_EPID_IN_INTEL:
+ ring = &sc->udb_iring;
+ break;
+ default:
+ ring = &sc->udb_ering;
+ }
+ ring->lasterror = error;
+
+ if (error != XHCI_TRB_ERROR_SUCCESS &&
+ error != XHCI_TRB_ERROR_SHORT_PKT) {
+ DEBUG_PRINTF(1, ("%s: transfer error (%u)", __func__, error));
+ ring->ec[error]++;
+
+ switch (error) {
+ case XHCI_TRB_ERROR_RING_UNDERRUN:
+ DEBUG_PRINTF(1, (": RING_UNDERRUN\n"));
+ break;
+ case XHCI_TRB_ERROR_RING_OVERRUN:
+ DEBUG_PRINTF(1, (": RING_OVERRUN\n"));
+ break;
+ case XHCI_TRB_ERROR_TRB:
+ DEBUG_PRINTF(1, (": TRB\n"));
+ break;
+ case XHCI_TRB_ERROR_STALL:
+ DEBUG_PRINTF(1, (": STALL\n"));
+ break;
+ default:
+ DEBUG_PRINTF(1, ("\n"));
+ }
+ }
+ if (ring != &sc->udb_ering)
+ mtx_lock_spin(&ring->mtx);
+ if (epid == XHCI_DC_EPID_OUT || epid == XHCI_DC_EPID_OUT_INTEL ||
+ epid == XHCI_DC_EPID_IN || epid == XHCI_DC_EPID_IN_INTEL) {
+ if ((dwTrb3 & XHCI_TRB_3_ISP_BIT) != 0) {
+ /* Event Data */
+ goto end;
+ }
+ deq_old = ring->deq;
+ rmb();
+
+ if (error == XHCI_TRB_ERROR_STALL) {
+ /* Halted state (sec 7.6.4.3) */
+ /* Update the deq pointer using ctx. */
+
+ rmb();
+ qwEpCtx2 = (ring == &sc->udb_oring)
+ ? le64toh(sc->udb_ctx->
+ ep_out.ctx.qwEpCtx2) &
+ XHCI_EPCTX_2_TR_DQ_PTR_MASK
+ : le64toh(sc->udb_ctx->
+ ep_in.ctx.qwEpCtx2) &
+ XHCI_EPCTX_2_TR_DQ_PTR_MASK;
+
+ ring->deq = qwEpCtx2 - (uint64_t)ring->paddr;
+ ring->deq /= sizeof(struct xhci_trb);
+ ring->deq &= DC_TRB_RING_OFFSET_MASK;
+ /*
+ * XXXHRS: Rollback the enqueued TRB.
+ *
+ * I am unsure of whether this is correct or not, but
+ * the enqueued old TRB will not be processed or
+ * generate another event TRB with
+ * XHCI_TRB_ERROR_SUCCESS after this event,
+ * while the internal dequeue pointer seems to remain.
+ * Enqueuing another TRB into the same address
+ * and ringing the doorbell seems to work.
+ */
+ ring->enq = ring->deq;
+ IOCBITMAP_CLEAR(ring, ring->enq);
+
+ trb = &ring->trb[ring->deq];
+ } else if (error == XHCI_TRB_ERROR_INVALID) {
+
+ /* do nothing */
+
+ trb = NULL;
+ } else if (error == XHCI_TRB_ERROR_SUCCESS &&
+ XHCI_TRB_2_BYTES_GET(dwTrb2) == 0 && qwTrb0 == 0) {
+ /*
+ * Use the current deq value
+ * because Transfer Event TRBs with
+ * zero length have no valid TRB
+ * pointer.
+ * XXXHRS: where is this in the spec?
+ */
+
+ /*
+ * Use the next of deq_old because the request TRB
+ * seems be ignored in this case.
+ */
+ ring->deq = deq_old + 1;
+ ring->deq &= DC_TRB_RING_OFFSET_MASK;
+ IOCBITMAP_CLEAR(ring, ring->deq);
+
+ ring->lastdeq = ring->deq;
+ trb = NULL;
+ } else {
+ /* Update the deq pointer using ER. */
+ /* XXX: should be optimized. */
+ /* (qwTrb0 & MASK) >> 4 (16 bytes) ? */
+
+ ring->deq = qwTrb0 - (uint64_t)ring->paddr;
+ ring->deq /= sizeof(struct xhci_trb);
+ ring->deq &= DC_TRB_RING_OFFSET_MASK;
+
+ IOCBITMAP_CLEAR(ring, ring->deq);
+ ring->lastdeq = ring->deq;
+ trb = &ring->trb[ring->deq];
+
+ /*
+ * XXX: Workaround for Forward jump. This is
+ * the biggest problem. Dequeue pointers reported
+ * in event TRBs are not sometimes monotonic.
+ * If a jump is detected, use the +1 address instead.
+ */
+ if (ring->deq < deq_old &&
+ 1 < (ring->deq + DC_TRB_RING_LEN) - deq_old) {
+ ring->deq = deq_old + 1;
+ ring->deq &= DC_TRB_RING_OFFSET_MASK;
+ } else if (deq_old < ring->deq &&
+ 1 < ring->deq - deq_old) {
+
+ ring->deq = deq_old + 1;
+ ring->deq &= DC_TRB_RING_OFFSET_MASK;
+ }
+ }
+ }
+ /* debug printf() */
+ if (epid == XHCI_DC_EPID_OUT || epid == XHCI_DC_EPID_OUT_INTEL ||
+ epid == XHCI_DC_EPID_IN || epid == XHCI_DC_EPID_IN_INTEL) {
+ if ((error == XHCI_TRB_ERROR_SUCCESS ||
+ error == XHCI_TRB_ERROR_SHORT_PKT) &&
+ trb != NULL) {
+ len = XHCI_TRB_2_BYTES_GET(le32toh(trb->dwTrb2))
+ - XHCI_TRB_2_BYTES_GET(dwTrb2);
+
+ DEBUG_PRINTF(2, ("%s: er->deq=%u, transfer length = "
+ "%u - %u = %u\n",
+ __func__, sc->udb_ering.deq,
+ XHCI_TRB_2_BYTES_GET(le32toh(trb->dwTrb2)),
+ XHCI_TRB_2_BYTES_GET(dwTrb2),
+ len));
+ }
+ }
+ if (epid == XHCI_DC_EPID_IN || epid == XHCI_DC_EPID_IN_INTEL) {
+ if (error == XHCI_TRB_ERROR_SUCCESS ||
+ error == XHCI_TRB_ERROR_SHORT_PKT) {
+ /*
+ * The new dequeue pointer is the next of
+ * the reported one.
+ */
+ if (!XHCI_DC_RING_EMPTY(ring))
+ ring->deq = (ring->deq + 1) &
+ DC_TRB_RING_OFFSET_MASK;
+
+ if (trb != NULL) {
+ len = XHCI_TRB_2_BYTES_GET(le32toh(trb->dwTrb2))
+ - XHCI_TRB_2_BYTES_GET(dwTrb2);
+
+ /* Advance the enq of work q */
+ flush_range(&ring->work.buf[ring->work.w_enq],
+ len);
+ ring->work.w_enq = (ring->work.w_enq + len)
+ & DC_WORK_RING_OFFSET_MASK;
+ }
+ }
+ }
+ if (epid == XHCI_DC_EPID_OUT || epid == XHCI_DC_EPID_OUT_INTEL ||
+ epid == XHCI_DC_EPID_IN || epid == XHCI_DC_EPID_IN_INTEL) {
+ /* printf() debug */
+ }
+ if (epid != XHCI_DC_EPID_OUT && epid != XHCI_DC_EPID_OUT_INTEL &&
+ epid != XHCI_DC_EPID_IN && epid != XHCI_DC_EPID_IN_INTEL) {
+ ring->ec[XHCI_TRB_ERROR_UNKNOWN]++;
+ }
+end:
+ if (ring != &sc->udb_ering)
+ mtx_unlock_spin(&ring->mtx);
+}
+
+void
+xhci_debug_event_dequeue(struct xhci_debug_softc *sc)
+{
+ struct xhci_debug_ring *er;
+ struct xhci_trb *ev;
+ uint64_t qwTrb0;
+ uint32_t dwTrb3, dwTrb2;
+ uint64_t erdp;
+ bool erdp_update;
+ uint32_t temp;
+
+ er = &sc->udb_ering;
+ er->ec[XHCI_TRB_ERROR_CALLED]++;
+ if (mtx_trylock_spin(&er->mtx) == 0) {
+ er->ec[XHCI_TRB_ERROR_EVLOCKED]++;
+ return;
+ }
+
+ ev = &er->trb[er->deq];
+ sc->sc_dequeue_count++;
+ erdp_update = false;
+
+ rmb();
+ qwTrb0 = le64toh(ev->qwTrb0);
+ dwTrb2 = le32toh(ev->dwTrb2);
+ dwTrb3 = le32toh(ev->dwTrb3);
+ while ((dwTrb3 & XHCI_TRB_3_CYCLE_BIT) == er->cyc) {
+ switch (XHCI_TRB_3_TYPE_GET(dwTrb3)) {
+ case XHCI_TRB_EVENT_TRANSFER:
+ xhci_debug_transfer_event_handler(sc, qwTrb0, dwTrb2,
+ dwTrb3);
+ break;
+ case XHCI_TRB_EVENT_PORT_STS_CHANGE:
+ temp = _XREAD4(sc, dbc, XHCI_DCPORTSC);
+ if (XHCI_DCPORTSC_CSC_GET(le32toh(temp))) {
+ device_printf(sc->sc_dev,
+ "DbC cable status changed%s\n",
+ (XHCI_DCPORTSC_CCS_GET(le32toh(temp)))
+ ? ""
+ : ": unplugged");
+ }
+ _XWRITE4(sc, dbc, XHCI_DCPORTSC,
+ temp & htole32(XHCI_DCPORTSC_ACK_MASK));
+ break;
+ default:
+ er->ec[XHCI_TRB_ERROR_UNKNOWN]++;
+
+ DEBUG_PRINTF(1,
+ ("%s: er->deq=%u"
+ ", er: qwTrb0=%lx"
+ ", dwTrb2=%x"
+ ", dwTrb3=%x"
+ ", type=%d (unknown)"
+ ", ec_unknown=%lu\n",
+ __func__,
+ er->deq,
+ qwTrb0,
+ dwTrb2,
+ dwTrb3,
+ XHCI_TRB_3_TYPE_GET(dwTrb3),
+ er->ec[XHCI_TRB_ERROR_UNKNOWN]));
+ break;
+ }
+ if (er->deq == DC_TRB_RING_LAST)
+ er->cyc ^= 1;
+ er->deq = (er->deq + 1) & DC_TRB_RING_OFFSET_MASK;
+ erdp_update = true;
+
+ ev = &er->trb[er->deq];
+ rmb();
+ qwTrb0 = le64toh(ev->qwTrb0);
+ dwTrb2 = le32toh(ev->dwTrb2);
+ dwTrb3 = le32toh(ev->dwTrb3);
+ }
+ if (erdp_update) {
+ erdp = _XREAD44LH(sc, dbc, XHCI_DCERDP);
+ erdp &= ~DC_TRB_RING_MASK;
+ erdp |= er->deq * sizeof(struct xhci_trb);
+ _XWRITE44LH(sc, dbc, XHCI_DCERDP, erdp);
+ }
+ mtx_unlock_spin(&er->mtx);
+}
+
+static uint64_t
+trb_rx_enqueue_locked(struct xhci_debug_softc *sc, struct xhci_debug_ring *ring)
+{
+ struct xhci_debug_work_ring *work;
+ uint64_t addr;
+ uint64_t len;
+
+ if (ring == NULL)
+ return (0);
+ if ((work = &ring->work) == NULL)
+ return (0);
+ /* Skip if in-progress */
+ if (ring->flags != 0)
+ return (0);
+ /* Skip if there are pending TRB */
+ if (!XHCI_DC_RING_EMPTY(ring))
+ return (0);
+ /* Skip if there are received data */
+ if (!DC_WORK_RING_EMPTY(ring))
+ return (0);
+
+ addr = work->paddr + work->w_enq;
+ len = (work->w_enq < work->w_deq) ? work->w_deq : DC_WORK_RING_LEN;
+ len -= work->w_enq;
+
+ return (trb_push_locked(sc, ring, addr, len));
+}
+
+static uint64_t
+trb_tx_enqueue_locked(struct xhci_debug_softc *sc, struct xhci_debug_ring *ring)
+{
+ struct xhci_debug_work_ring *work;
+ uint64_t addr;
+ uint64_t len0, len1;
+
+ if (ring == NULL)
+ return (0);
+ if ((work = &ring->work) == NULL)
+ return (0);
+ if (ring->flags != 0)
+ return (0);
+ if (DC_WORK_RING_EMPTY(ring))
+ return (0);
+
+ /* XXX: pending check? */
+
+ len0 = len1 = 0;
+ if (work->w_deq < work->w_enq) {
+ addr = work->paddr + work->w_deq;
+ len0 = trb_push_locked(sc, ring, addr, work->w_enq - work->w_deq);
+
+ work->w_deq += len0;
+ } else {
+ addr = work->paddr + work->w_deq;
+ len0 = trb_push_locked(sc, ring, addr,
+ DC_WORK_RING_LEN - work->w_deq);
+
+ work->w_deq += len0;
+ work->w_deq &= DC_WORK_RING_OFFSET_MASK;
+
+ if (work->w_deq == 0 &&
+ !DC_WORK_RING_EMPTY(ring) &&
+ !XHCI_DC_RING_FULL(ring)) {
+ addr = work->paddr;
+ len1 = trb_push_locked(sc, ring, addr, work->w_enq);
+
+ work->w_deq += len1;
+ }
+ }
+ return (len0 + len1);
+}
+
+static uint64_t
+trb_push_locked(struct xhci_debug_softc *sc, struct xhci_debug_ring *ring,
+ uint64_t addr, uint64_t len)
+{
+ struct xhci_trb trb;
+
+ if (ring->enq == DC_TRB_RING_LAST) {
+ /*
+ * If it is the last entry, whose TRB type is LINK,
+ * cyc is set and ring->enq is advanced.
+ * The next enq should always be zero.
+ */
+ ring->trb[ring->enq].dwTrb3 &= ~htole32(XHCI_TRB_3_CYCLE_BIT);
+ ring->trb[ring->enq].dwTrb3 |= htole32(ring->cyc);
+ flush_range(&ring->trb[ring->enq], sizeof(ring->trb[0]));
+
+ /* Must be zero */
+ ring->enq = (ring->enq + 1) & DC_TRB_RING_OFFSET_MASK;
+ ring->cyc ^= 1;
+ }
+ trb = (struct xhci_trb){
+ .qwTrb0 = htole64(addr),
+ .dwTrb2 = htole32(XHCI_TRB_2_BYTES_SET((uint32_t)len)),
+ .dwTrb3 = htole32(
+ XHCI_TRB_3_TYPE_SET(XHCI_TRB_TYPE_NORMAL)
+ | ring->cyc | XHCI_TRB_3_IOC_BIT
+ )
+ };
+
+ /* XXX: overwrite check of iocbitmap? */
+
+ /* Note that the last entry never have a bit in the iocbitmap. */
+ IOCBITMAP_SET(ring, ring->enq);
+ ring->lastenq = ring->enq;
+
+ DEBUG_PRINTF(1, ("%s: enqueue: %s: enq=%d, len=%lu, deq=%d\n", __func__,
+ label, ring->enq, len, ring->deq));
+ memcpy(&ring->trb[ring->enq], &trb, sizeof(ring->trb[0]));
+ flush_range(&ring->trb[ring->enq], sizeof(ring->trb[0]));
+ ring->enq = (ring->enq + 1) & DC_TRB_RING_OFFSET_MASK;
+
+ xhci_debug_ring_doorbell(sc, ring->doorbell);
+
+ return (len);
+}
+
+int
+work_dequeue(struct xhci_debug_ring *ring)
+{
+ struct xhci_debug_work_ring *work;
+ int c;
+
+ if (ring == NULL)
+ return (-1);
+ if ((work = &ring->work) == NULL)
+ return (-1);
+
+ c = -1;
+ mtx_lock_spin(&ring->mtx);
+ if (!DC_WORK_RING_EMPTY(ring)) {
+ c = (int)work->buf[work->w_deq];
+ work->w_deq = (work->w_deq + 1) & DC_WORK_RING_OFFSET_MASK;
+ DEBUG_PRINTF(2, ("%s: [%c(%02x)]\n", __func__,
+ (char)c, (char)c));
+ }
+ mtx_unlock_spin(&ring->mtx);
+ return (c);
+}
+
+int64_t
+work_enqueue(struct xhci_debug_ring *ring, const char *buf, int64_t len)
+{
+ struct xhci_debug_work_ring *work;
+ uint32_t start, end;
+ int64_t i;
+
+ if (ring == NULL)
+ return (0);
+ if ((work = &ring->work) == NULL)
+ return (0);
+
+ i = 0;
+ end = 0;
+ mtx_lock_spin(&ring->mtx);
+ if (DC_WORK_RING_SLOTS(work) < len) {
+ ring->ec[XHCI_TRB_ERROR_WORKQ_FULL]++;
+ goto end;
+ }
+ start = work->w_enq;
+ DEBUG_PRINTF(1, ("%s: %s: len=%lu: ", __func__,
+ XHCI_DC_RING_IN(ring) ? "IR" : "OR", len));
+ while (!DC_WORK_RING_FULL(ring) && i < len) {
+ DEBUG_PRINTF(2, ("[%c(%02x)]", buf[i], buf[i]));
+ work->buf[work->w_enq++] = buf[i++];
+ work->w_enq &= DC_WORK_RING_OFFSET_MASK;
+ }
+ end = work->w_enq;
+ DEBUG_PRINTF(1, (": start=%u, end=%u\n", start, end));
+
+ if (start < end)
+ flush_range(&work->buf[start], end - start);
+ else if (0 < i) {
+ flush_range(&work->buf[start], DC_WORK_RING_LEN - start);
+ flush_range(&work->buf[0], end);
+ }
+end:
+ mtx_unlock_spin(&ring->mtx);
+ return (i);
+}
diff --git a/sys/dev/usb/controller/xhci_dbc_private.h b/sys/dev/usb/controller/xhci_dbc_private.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/usb/controller/xhci_dbc_private.h
@@ -0,0 +1,101 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019-2024 Hiroki Sato <hrs@FreeBSD.org>
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ */
+extern int dbc_debug;
+
+#if _KERNEL
+
+#define DEBUG_PRINTF(level, args )do { \
+ if (dbc_debug >= level) printf args; \
+ } while (0)
+
+/* PCI register access via bus_dma in kernel */
+#define _XREAD4(sc, what, a) XREAD4((sc)->sc_xhci, what, a)
+#define _XWRITE4(sc, what, a, x) XWRITE4((sc)->sc_xhci, what, a, (x))
+#define _XREAD44LH(sc, what, a) XREAD44LH((sc)->sc_xhci, what, a)
+#define _XWRITE44LH(sc, what, a, x) XWRITE44LH((sc)->sc_xhci, what, a, (x))
+/* sys/systm.h */
+#define delay(x) DELAY(x)
+
+#else
+
+#define device_printf(dev, ...) \
+ printf(__VA_ARGS__)
+
+/* PCI register access via UEFI service in loader */
+static inline volatile uint32_t
+_XREAD4_0(struct xhci_debug_softc *sc, uint64_t offset)
+{
+ volatile uint32_t temp;
+
+ sc->sc_efi_pciio->Mem.Read(
+ sc->sc_efi_pciio,
+ EfiPciIoWidthUint32,
+ 0,
+ offset,
+ 1,
+ (VOID *)&temp);
+
+ return (temp);
+}
+static inline void
+_XWRITE4_0(struct xhci_debug_softc *sc, uint64_t offset, uint32_t temp)
+{
+ sc->sc_efi_pciio->Mem.Write(
+ sc->sc_efi_pciio,
+ EfiPciIoWidthUint32,
+ 0,
+ offset,
+ 1,
+ (VOID *)&temp);
+#if 0
+ /*
+ * wmb is defined in atomics.h, which we don't have. On amd64 it will
+ * issue an sfench. I am not entirely sure if this is needed or if it
+ * is the correct ordering primitive.
+ *
+ * The pci memory is mapped as cacheable for the dma structures and the
+ * softc (EFI_PCI_ATTRIBUTE_MEMORY_CACHED).
+ *
+ * On my test systems this functions as far as I can tell.
+ */
+ wmb();
+#endif
+}
+#define _XREAD4(sc, what, a) \
+ _XREAD4_0(sc, (a) + (sc)->sc_##what##_off)
+#define _XREAD44LH(sc, what, a) \
+ ((volatile uint64_t)_XREAD4(sc, what, a##_LO) | \
+ ((volatile uint64_t)_XREAD4(sc, what, a##_HI) << 32))
+#define _XWRITE4(sc, what, a, x) \
+ _XWRITE4_0(sc, (a) + (sc)->sc_##what##_off, (x))
+#define _XWRITE44LH(sc, what, a, x) \
+ do { \
+ _XWRITE4(sc, what, a##_LO, (uint32_t)((x) & 0xffffffff)); \
+ _XWRITE4(sc, what, a##_HI, (uint32_t)((x) >> 32)); \
+ } while (0)
+#endif
diff --git a/sys/dev/usb/controller/xhci_pci.h b/sys/dev/usb/controller/xhci_pci.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/usb/controller/xhci_pci.h
@@ -0,0 +1,187 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2010-2022 Hans Petter Selasky
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/param.h>
+#include <sys/cdefs.h>
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+
+#define PCI_XHCI_VENDORID_AMD 0x1022
+#define PCI_XHCI_VENDORID_INTEL 0x8086
+#define PCI_XHCI_VENDORID_VMWARE 0x15ad
+#define PCI_XHCI_VENDORID_ZHAOXIN 0x1d17
+
+static inline const char *
+xhci_pci_match(device_t self)
+{
+ uint32_t device_id = pci_get_devid(self);
+
+ switch (device_id) {
+ case 0x145c1022:
+ return ("AMD KERNCZ USB 3.0 controller");
+ case 0x148c1022:
+ return ("AMD Starship USB 3.0 controller");
+ case 0x149c1022:
+ return ("AMD Matisse USB 3.0 controller");
+ case 0x15e01022:
+ case 0x15e11022:
+ return ("AMD Raven USB 3.1 controller");
+ case 0x43ba1022:
+ return ("AMD X399 USB 3.0 controller");
+ case 0x43b91022: /* X370 */
+ case 0x43bb1022: /* B350 */
+ return ("AMD 300 Series USB 3.1 controller");
+ case 0x43d51022:
+ return ("AMD 400 Series USB 3.1 controller");
+ case 0x78121022:
+ case 0x78141022:
+ case 0x79141022:
+ return ("AMD FCH USB 3.0 controller");
+
+ case 0x077815ad:
+ case 0x077915ad:
+ return ("VMware USB 3.0 controller");
+
+ case 0x145f1d94:
+ return ("Hygon USB 3.0 controller");
+
+ case 0x01941033:
+ return ("NEC uPD720200 USB 3.0 controller");
+ case 0x00151912:
+ return ("NEC uPD720202 USB 3.0 controller");
+
+ case 0x10001b73:
+ return ("Fresco Logic FL1000G USB 3.0 controller");
+ case 0x10091b73:
+ return ("Fresco Logic FL1009 USB 3.0 controller");
+ case 0x11001b73:
+ return ("Fresco Logic FL1100 USB 3.0 controller");
+
+ case 0x10421b21:
+ return ("ASMedia ASM1042 USB 3.0 controller");
+ case 0x11421b21:
+ return ("ASMedia ASM1042A USB 3.0 controller");
+ case 0x13431b21:
+ return ("ASMedia ASM1143 USB 3.1 controller");
+ case 0x32421b21:
+ return ("ASMedia ASM3242 USB 3.2 controller");
+
+ case 0x02ed8086:
+ return ("Intel Comet Lake PCH-LP USB 3.1 controller");
+ case 0x0b278086:
+ return ("Intel Goshen Ridge Thunderbolt 4 USB controller");
+ case 0x0f358086:
+ return ("Intel BayTrail USB 3.0 controller");
+ case 0x11388086:
+ return ("Intel Maple Ridge Thunderbolt 4 USB controller");
+ case 0x15c18086:
+ case 0x15d48086:
+ case 0x15db8086:
+ return ("Intel Alpine Ridge Thunderbolt 3 USB controller");
+ case 0x15e98086:
+ case 0x15ec8086:
+ case 0x15f08086:
+ return ("Intel Titan Ridge Thunderbolt 3 USB controller");
+ case 0x19d08086:
+ return ("Intel Denverton USB 3.0 controller");
+ case 0x9c318086:
+ case 0x1e318086:
+ return ("Intel Panther Point USB 3.0 controller");
+ case 0x22b58086:
+ return ("Intel Braswell USB 3.0 controller");
+ case 0x31a88086:
+ return ("Intel Gemini Lake USB 3.0 controller");
+ case 0x34ed8086:
+ return ("Intel Ice Lake-LP USB 3.1 controller");
+ case 0x43ed8086:
+ return ("Intel Tiger Lake-H USB 3.2 controller");
+ case 0x461e8086:
+ return ("Intel Alder Lake-P Thunderbolt 4 USB controller");
+ case 0x51ed8086:
+ case 0x54ed8086:
+ case 0x5fed8086:
+ return ("Intel Alder Lake PCH USB 3.2 controller");
+ case 0x5aa88086:
+ return ("Intel Apollo Lake USB 3.0 controller");
+ case 0x7ae08086:
+ return ("Intel Alder Lake USB 3.2 controller");
+ case 0x8a138086:
+ return ("Intel Ice Lake Thunderbolt 3 USB controller");
+ case 0x8c318086:
+ return ("Intel Lynx Point USB 3.0 controller");
+ case 0x8cb18086:
+ return ("Intel Wildcat Point USB 3.0 controller");
+ case 0x8d318086:
+ return ("Intel Wellsburg USB 3.0 controller");
+ case 0x9a138086:
+ return ("Intel Tiger Lake-LP Thunderbolt 4 USB controller");
+ case 0x9a178086:
+ return ("Intel Tiger Lake-H Thunderbolt 4 USB controller");
+ case 0x9cb18086:
+ return ("Broadwell Integrated PCH-LP chipset USB 3.0 controller");
+ case 0x9d2f8086:
+ return ("Intel Sunrise Point-LP USB 3.0 controller");
+ case 0xa0ed8086:
+ return ("Intel Tiger Lake-LP USB 3.2 controller");
+ case 0xa12f8086:
+ return ("Intel Sunrise Point USB 3.0 controller");
+ case 0xa1af8086:
+ return ("Intel Lewisburg USB 3.0 controller");
+ case 0xa2af8086:
+ return ("Intel Union Point USB 3.0 controller");
+ case 0xa36d8086:
+ return ("Intel Cannon Lake USB 3.1 controller");
+ case 0xa71e8086:
+ return ("Intel Raptor Lake-P Thunderbolt 4 USB Controller");
+
+ case 0xa01b177d:
+ return ("Cavium ThunderX USB 3.0 controller");
+
+ case 0x1ada10de:
+ return ("NVIDIA TU106 USB 3.1 controller");
+
+ case 0x92021d17:
+ return ("Zhaoxin ZX-100 USB 3.0 controller");
+ case 0x92031d17:
+ return ("Zhaoxin ZX-200 USB 3.0 controller");
+ case 0x92041d17:
+ return ("Zhaoxin ZX-E USB 3.0 controller");
+
+ default:
+ break;
+ }
+
+ if ((pci_get_class(self) == PCIC_SERIALBUS)
+ && (pci_get_subclass(self) == PCIS_SERIALBUS_USB)
+ && (pci_get_progif(self) == PCIP_SERIALBUS_USB_XHCI)) {
+ return ("XHCI (generic) USB 3.0 controller");
+ }
+ return (NULL); /* dunno */
+}
diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c
--- a/sys/dev/usb/controller/xhci_pci.c
+++ b/sys/dev/usb/controller/xhci_pci.c
@@ -56,14 +56,10 @@
#include <dev/usb/usb_bus.h>
#include <dev/usb/usb_pci.h>
#include <dev/usb/controller/xhci.h>
+#include <dev/usb/controller/xhci_pci.h>
#include <dev/usb/controller/xhcireg.h>
#include "usb_if.h"
-#define PCI_XHCI_VENDORID_AMD 0x1022
-#define PCI_XHCI_VENDORID_INTEL 0x8086
-#define PCI_XHCI_VENDORID_VMWARE 0x15ad
-#define PCI_XHCI_VENDORID_ZHAOXIN 0x1d17
-
static device_probe_t xhci_pci_probe;
static device_detach_t xhci_pci_detach;
static usb_take_controller_t xhci_pci_take_controller;
@@ -87,157 +83,6 @@
DRIVER_MODULE(xhci, pci, xhci_pci_driver, NULL, NULL);
MODULE_DEPEND(xhci, usb, 1, 1, 1);
-static const char *
-xhci_pci_match(device_t self)
-{
- uint32_t device_id = pci_get_devid(self);
-
- switch (device_id) {
- case 0x145c1022:
- return ("AMD KERNCZ USB 3.0 controller");
- case 0x148c1022:
- return ("AMD Starship USB 3.0 controller");
- case 0x149c1022:
- return ("AMD Matisse USB 3.0 controller");
- case 0x15b61022:
- case 0x15b71022:
- return ("AMD Raphael/Granite Ridge USB 3.1 controller");
- case 0x15b81022:
- return ("AMD Raphael/Granite Ridge USB 2.0 controller");
- case 0x15e01022:
- case 0x15e11022:
- return ("AMD Raven USB 3.1 controller");
- case 0x43ba1022:
- return ("AMD X399 USB 3.0 controller");
- case 0x43b91022: /* X370 */
- case 0x43bb1022: /* B350 */
- return ("AMD 300 Series USB 3.1 controller");
- case 0x43d51022:
- return ("AMD 400 Series USB 3.1 controller");
- case 0x43f71022:
- return ("AMD 600 Series USB 3.2 controller");
- case 0x78121022:
- case 0x78141022:
- case 0x79141022:
- return ("AMD FCH USB 3.0 controller");
-
- case 0x077815ad:
- case 0x077915ad:
- return ("VMware USB 3.0 controller");
-
- case 0x145f1d94:
- return ("Hygon USB 3.0 controller");
-
- case 0x01941033:
- return ("NEC uPD720200 USB 3.0 controller");
- case 0x00151912:
- return ("NEC uPD720202 USB 3.0 controller");
-
- case 0x10001b73:
- return ("Fresco Logic FL1000G USB 3.0 controller");
- case 0x10091b73:
- return ("Fresco Logic FL1009 USB 3.0 controller");
- case 0x11001b73:
- return ("Fresco Logic FL1100 USB 3.0 controller");
-
- case 0x10421b21:
- return ("ASMedia ASM1042 USB 3.0 controller");
- case 0x11421b21:
- return ("ASMedia ASM1042A USB 3.0 controller");
- case 0x13431b21:
- return ("ASMedia ASM1143 USB 3.1 controller");
- case 0x32421b21:
- return ("ASMedia ASM3242 USB 3.2 controller");
-
- case 0x0b278086:
- return ("Intel Goshen Ridge Thunderbolt 4 USB controller");
- case 0x0f358086:
- return ("Intel BayTrail USB 3.0 controller");
- case 0x11388086:
- return ("Intel Maple Ridge Thunderbolt 4 USB controller");
- case 0x15c18086:
- case 0x15d48086:
- case 0x15db8086:
- return ("Intel Alpine Ridge Thunderbolt 3 USB controller");
- case 0x15e98086:
- case 0x15ec8086:
- case 0x15f08086:
- return ("Intel Titan Ridge Thunderbolt 3 USB controller");
- case 0x19d08086:
- return ("Intel Denverton USB 3.0 controller");
- case 0x9c318086:
- case 0x1e318086:
- return ("Intel Panther Point USB 3.0 controller");
- case 0x22b58086:
- return ("Intel Braswell USB 3.0 controller");
- case 0x31a88086:
- return ("Intel Gemini Lake USB 3.0 controller");
- case 0x34ed8086:
- return ("Intel Ice Lake-LP USB 3.1 controller");
- case 0x43ed8086:
- return ("Intel Tiger Lake-H USB 3.2 controller");
- case 0x461e8086:
- return ("Intel Alder Lake-P Thunderbolt 4 USB controller");
- case 0x4b7d8086:
- return ("Intel Elkhart Lake USB 3.1 controller");
- case 0x51ed8086:
- return ("Intel Alder Lake USB 3.2 controller");
- case 0x5aa88086:
- return ("Intel Apollo Lake USB 3.0 controller");
- case 0x7ae08086:
- return ("Intel Alder Lake USB 3.2 controller");
- case 0x8a138086:
- return ("Intel Ice Lake Thunderbolt 3 USB controller");
- case 0x8c318086:
- return ("Intel Lynx Point USB 3.0 controller");
- case 0x8cb18086:
- return ("Intel Wildcat Point USB 3.0 controller");
- case 0x8d318086:
- return ("Intel Wellsburg USB 3.0 controller");
- case 0x9a138086:
- return ("Intel Tiger Lake-LP Thunderbolt 4 USB controller");
- case 0x9a178086:
- return ("Intel Tiger Lake-H Thunderbolt 4 USB controller");
- case 0x9cb18086:
- return ("Broadwell Integrated PCH-LP chipset USB 3.0 controller");
- case 0x9d2f8086:
- return ("Intel Sunrise Point-LP USB 3.0 controller");
- case 0xa0ed8086:
- return ("Intel Tiger Lake-LP USB 3.2 controller");
- case 0xa12f8086:
- return ("Intel Sunrise Point USB 3.0 controller");
- case 0xa1af8086:
- return ("Intel Lewisburg USB 3.0 controller");
- case 0xa2af8086:
- return ("Intel Union Point USB 3.0 controller");
- case 0xa36d8086:
- return ("Intel Cannon Lake USB 3.1 controller");
-
- case 0xa01b177d:
- return ("Cavium ThunderX USB 3.0 controller");
-
- case 0x1ada10de:
- return ("NVIDIA TU106 USB 3.1 controller");
-
- case 0x92021d17:
- return ("Zhaoxin ZX-100 USB 3.0 controller");
- case 0x92031d17:
- return ("Zhaoxin ZX-200 USB 3.0 controller");
- case 0x92041d17:
- return ("Zhaoxin ZX-E USB 3.0 controller");
-
- default:
- break;
- }
-
- if ((pci_get_class(self) == PCIC_SERIALBUS)
- && (pci_get_subclass(self) == PCIS_SERIALBUS_USB)
- && (pci_get_progif(self) == PCIP_SERIALBUS_USB_XHCI)) {
- return ("XHCI (generic) USB 3.0 controller");
- }
- return (NULL); /* dunno */
-}
-
static int
xhci_pci_probe(device_t self)
{
diff --git a/sys/dev/usb/controller/xhci_private.h b/sys/dev/usb/controller/xhci_private.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/usb/controller/xhci_private.h
@@ -0,0 +1,228 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2010-2022 Hans Petter Selasky
+ * Copyright (c) 2020-2024 Hiroki Sato <hrs@FreeBSD.org>
+ *
+ * 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 AUTHOR 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 AUTHOR 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 _USB_XHCI_PRIVATE_H_
+#define _USB_XHCI_PRIVATE_H_
+
+#define XHCI_DEV_CTX_ADDR_ALIGN 64 /* bytes */
+#define XHCI_DEV_CTX_ALIGN 64 /* bytes */
+#define XHCI_INPUT_CTX_ALIGN 64 /* bytes */
+#define XHCI_SLOT_CTX_ALIGN 32 /* bytes */
+#define XHCI_ENDP_CTX_ALIGN 32 /* bytes */
+#define XHCI_STREAM_CTX_ALIGN 16 /* bytes */
+#define XHCI_TRANS_RING_SEG_ALIGN 16 /* bytes */
+#define XHCI_CMD_RING_SEG_ALIGN 64 /* bytes */
+#define XHCI_EVENT_RING_SEG_ALIGN 64 /* bytes */
+#define XHCI_SCRATCH_BUF_ARRAY_ALIGN 64 /* bytes */
+#define XHCI_SCRATCH_BUFFER_ALIGN USB_PAGE_SIZE
+#define XHCI_TRB_ALIGN 16 /* bytes */
+#define XHCI_TD_ALIGN 64 /* bytes */
+#define XHCI_PAGE_SIZE 4096 /* bytes */
+
+struct xhci_endp_ctx {
+ volatile uint32_t dwEpCtx0;
+#define XHCI_EPCTX_0_EPSTATE_SET(x) ((x) & 0x7)
+#define XHCI_EPCTX_0_EPSTATE_GET(x) ((x) & 0x7)
+#define XHCI_EPCTX_0_EPSTATE_DISABLED 0
+#define XHCI_EPCTX_0_EPSTATE_RUNNING 1
+#define XHCI_EPCTX_0_EPSTATE_HALTED 2
+#define XHCI_EPCTX_0_EPSTATE_STOPPED 3
+#define XHCI_EPCTX_0_EPSTATE_ERROR 4
+#define XHCI_EPCTX_0_EPSTATE_RESERVED_5 5
+#define XHCI_EPCTX_0_EPSTATE_RESERVED_6 6
+#define XHCI_EPCTX_0_EPSTATE_RESERVED_7 7
+#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)
+#define XHCI_EPCTX_0_MAXP_STREAMS_GET(x) (((x) >> 10) & 0x1F)
+#define XHCI_EPCTX_0_LSA_SET(x) (((x) & 0x1) << 15)
+#define XHCI_EPCTX_0_LSA_GET(x) (((x) >> 15) & 0x1)
+#define XHCI_EPCTX_0_IVAL_SET(x) (((x) & 0xFF) << 16)
+#define XHCI_EPCTX_0_IVAL_GET(x) (((x) >> 16) & 0xFF)
+ volatile uint32_t dwEpCtx1;
+#define XHCI_EPCTX_1_CERR_SET(x) (((x) & 0x3) << 1)
+#define XHCI_EPCTX_1_CERR_GET(x) (((x) >> 1) & 0x3)
+#define XHCI_EPCTX_1_EPTYPE_SET(x) (((x) & 0x7) << 3)
+#define XHCI_EPCTX_1_EPTYPE_GET(x) (((x) >> 3) & 0x7)
+#define XHCI_EPCTX_1_HID_SET(x) (((x) & 0x1) << 7)
+#define XHCI_EPCTX_1_HID_GET(x) (((x) >> 7) & 0x1)
+#define XHCI_EPCTX_1_MAXB_SET(x) (((x) & 0xFF) << 8)
+#define XHCI_EPCTX_1_MAXB_GET(x) (((x) >> 8) & 0xFF)
+#define XHCI_EPCTX_1_MAXP_SIZE_SET(x) (((x) & 0xFFFF) << 16)
+#define XHCI_EPCTX_1_MAXP_SIZE_GET(x) (((x) >> 16) & 0xFFFF)
+ volatile uint64_t qwEpCtx2;
+#define XHCI_EPCTX_2_DCS_SET(x) ((x) & 0x1)
+#define XHCI_EPCTX_2_DCS_GET(x) ((x) & 0x1)
+#define XHCI_EPCTX_2_TR_DQ_PTR_MASK 0xFFFFFFFFFFFFFFF0U
+ volatile uint32_t dwEpCtx4;
+#define XHCI_EPCTX_4_AVG_TRB_LEN_SET(x) ((x) & 0xFFFF)
+#define XHCI_EPCTX_4_AVG_TRB_LEN_GET(x) ((x) & 0xFFFF)
+#define XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_SET(x) (((x) & 0xFFFF) << 16)
+#define XHCI_EPCTX_4_MAX_ESIT_PAYLOAD_GET(x) (((x) >> 16) & 0xFFFF)
+ volatile uint32_t dwEpCtx5;
+ volatile uint32_t dwEpCtx6;
+ volatile uint32_t dwEpCtx7;
+};
+
+struct xhci_endp_ctx64 {
+ struct xhci_endp_ctx ctx;
+ volatile uint8_t padding[32];
+};
+
+struct xhci_trb {
+ volatile uint64_t qwTrb0;
+#define XHCI_TRB_0_DIR_IN_MASK (0x80ULL << 0)
+#define XHCI_TRB_0_WLENGTH_MASK (0xFFFFULL << 48)
+ volatile uint32_t dwTrb2;
+#define XHCI_TRB_2_ERROR_GET(x) (((x) >> 24) & 0xFF)
+#define XHCI_TRB_2_ERROR_SET(x) (((x) & 0xFF) << 24)
+#define XHCI_TRB_2_TDSZ_GET(x) (((x) >> 17) & 0x1F)
+#define XHCI_TRB_2_TDSZ_SET(x) (((x) & 0x1F) << 17)
+#define XHCI_TRB_2_REM_GET(x) ((x) & 0xFFFFFF)
+#define XHCI_TRB_2_REM_SET(x) ((x) & 0xFFFFFF)
+#define XHCI_TRB_2_BYTES_GET(x) ((x) & 0x1FFFF)
+#define XHCI_TRB_2_BYTES_SET(x) ((x) & 0x1FFFF)
+#define XHCI_TRB_2_IRQ_GET(x) (((x) >> 22) & 0x3FF)
+#define XHCI_TRB_2_IRQ_SET(x) (((x) & 0x3FF) << 22)
+#define XHCI_TRB_2_STREAM_GET(x) (((x) >> 16) & 0xFFFF)
+#define XHCI_TRB_2_STREAM_SET(x) (((x) & 0xFFFF) << 16)
+
+ volatile uint32_t dwTrb3;
+#define XHCI_TRB_3_TYPE_GET(x) (((x) >> 10) & 0x3F)
+#define XHCI_TRB_3_TYPE_SET(x) (((x) & 0x3F) << 10)
+#define XHCI_TRB_3_CYCLE_BIT (1U << 0)
+#define XHCI_TRB_3_TC_BIT (1U << 1) /* command ring only */
+#define XHCI_TRB_3_ENT_BIT (1U << 1) /* transfer ring only */
+#define XHCI_TRB_3_ISP_BIT (1U << 2)
+#define XHCI_TRB_3_NSNOOP_BIT (1U << 3)
+#define XHCI_TRB_3_CHAIN_BIT (1U << 4)
+#define XHCI_TRB_3_IOC_BIT (1U << 5)
+#define XHCI_TRB_3_IDT_BIT (1U << 6)
+#define XHCI_TRB_3_TBC_GET(x) (((x) >> 7) & 3)
+#define XHCI_TRB_3_TBC_SET(x) (((x) & 3) << 7)
+#define XHCI_TRB_3_BEI_BIT (1U << 9)
+#define XHCI_TRB_3_DCEP_BIT (1U << 9)
+#define XHCI_TRB_3_PRSV_BIT (1U << 9)
+#define XHCI_TRB_3_BSR_BIT (1U << 9)
+#define XHCI_TRB_3_TRT_MASK (3U << 16)
+#define XHCI_TRB_3_TRT_NONE (0U << 16)
+#define XHCI_TRB_3_TRT_OUT (2U << 16)
+#define XHCI_TRB_3_TRT_IN (3U << 16)
+#define XHCI_TRB_3_DIR_IN (1U << 16)
+#define XHCI_TRB_3_TLBPC_GET(x) (((x) >> 16) & 0xF)
+#define XHCI_TRB_3_TLBPC_SET(x) (((x) & 0xF) << 16)
+#define XHCI_TRB_3_EP_GET(x) (((x) >> 16) & 0x1F)
+#define XHCI_TRB_3_EP_SET(x) (((x) & 0x1F) << 16)
+#define XHCI_TRB_3_FRID_GET(x) (((x) >> 20) & 0x7FF)
+#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_SLOT_GET(x) (((x) >> 24) & 0xFF)
+#define XHCI_TRB_3_SLOT_SET(x) (((x) & 0xFF) << 24)
+
+/* Commands */
+#define XHCI_TRB_TYPE_RESERVED 0x00
+#define XHCI_TRB_TYPE_NORMAL 0x01
+#define XHCI_TRB_TYPE_SETUP_STAGE 0x02
+#define XHCI_TRB_TYPE_DATA_STAGE 0x03
+#define XHCI_TRB_TYPE_STATUS_STAGE 0x04
+#define XHCI_TRB_TYPE_ISOCH 0x05
+#define XHCI_TRB_TYPE_LINK 0x06
+#define XHCI_TRB_TYPE_EVENT_DATA 0x07
+#define XHCI_TRB_TYPE_NOOP 0x08
+#define XHCI_TRB_TYPE_ENABLE_SLOT 0x09
+#define XHCI_TRB_TYPE_DISABLE_SLOT 0x0A
+#define XHCI_TRB_TYPE_ADDRESS_DEVICE 0x0B
+#define XHCI_TRB_TYPE_CONFIGURE_EP 0x0C
+#define XHCI_TRB_TYPE_EVALUATE_CTX 0x0D
+#define XHCI_TRB_TYPE_RESET_EP 0x0E
+#define XHCI_TRB_TYPE_STOP_EP 0x0F
+#define XHCI_TRB_TYPE_SET_TR_DEQUEUE 0x10
+#define XHCI_TRB_TYPE_RESET_DEVICE 0x11
+#define XHCI_TRB_TYPE_FORCE_EVENT 0x12
+#define XHCI_TRB_TYPE_NEGOTIATE_BW 0x13
+#define XHCI_TRB_TYPE_SET_LATENCY_TOL 0x14
+#define XHCI_TRB_TYPE_GET_PORT_BW 0x15
+#define XHCI_TRB_TYPE_FORCE_HEADER 0x16
+#define XHCI_TRB_TYPE_NOOP_CMD 0x17
+
+/* Events */
+#define XHCI_TRB_EVENT_TRANSFER 0x20
+#define XHCI_TRB_EVENT_CMD_COMPLETE 0x21
+#define XHCI_TRB_EVENT_PORT_STS_CHANGE 0x22
+#define XHCI_TRB_EVENT_BW_REQUEST 0x23
+#define XHCI_TRB_EVENT_DOORBELL 0x24
+#define XHCI_TRB_EVENT_HOST_CTRL 0x25
+#define XHCI_TRB_EVENT_DEVICE_NOTIFY 0x26
+#define XHCI_TRB_EVENT_MFINDEX_WRAP 0x27
+
+/* Error codes */
+#define XHCI_TRB_ERROR_INVALID 0x00
+#define XHCI_TRB_ERROR_SUCCESS 0x01
+#define XHCI_TRB_ERROR_DATA_BUF 0x02
+#define XHCI_TRB_ERROR_BABBLE 0x03
+#define XHCI_TRB_ERROR_XACT 0x04
+#define XHCI_TRB_ERROR_TRB 0x05
+#define XHCI_TRB_ERROR_STALL 0x06
+#define XHCI_TRB_ERROR_RESOURCE 0x07
+#define XHCI_TRB_ERROR_BANDWIDTH 0x08
+#define XHCI_TRB_ERROR_NO_SLOTS 0x09
+#define XHCI_TRB_ERROR_STREAM_TYPE 0x0A
+#define XHCI_TRB_ERROR_SLOT_NOT_ON 0x0B
+#define XHCI_TRB_ERROR_ENDP_NOT_ON 0x0C
+#define XHCI_TRB_ERROR_SHORT_PKT 0x0D
+#define XHCI_TRB_ERROR_RING_UNDERRUN 0x0E
+#define XHCI_TRB_ERROR_RING_OVERRUN 0x0F
+#define XHCI_TRB_ERROR_VF_RING_FULL 0x10
+#define XHCI_TRB_ERROR_PARAMETER 0x11
+#define XHCI_TRB_ERROR_BW_OVERRUN 0x12
+#define XHCI_TRB_ERROR_CONTEXT_STATE 0x13
+#define XHCI_TRB_ERROR_NO_PING_RESP 0x14
+#define XHCI_TRB_ERROR_EV_RING_FULL 0x15
+#define XHCI_TRB_ERROR_INCOMPAT_DEV 0x16
+#define XHCI_TRB_ERROR_MISSED_SERVICE 0x17
+#define XHCI_TRB_ERROR_CMD_RING_STOP 0x18
+#define XHCI_TRB_ERROR_CMD_ABORTED 0x19
+#define XHCI_TRB_ERROR_STOPPED 0x1A
+#define XHCI_TRB_ERROR_LENGTH 0x1B
+#define XHCI_TRB_ERROR_BAD_MELAT 0x1D
+#define XHCI_TRB_ERROR_ISOC_OVERRUN 0x1F
+#define XHCI_TRB_ERROR_EVENT_LOST 0x20
+#define XHCI_TRB_ERROR_UNDEFINED 0x21
+#define XHCI_TRB_ERROR_INVALID_SID 0x22
+#define XHCI_TRB_ERROR_SEC_BW 0x23
+#define XHCI_TRB_ERROR_SPLIT_XACT 0x24
+} __aligned(4);
+
+struct xhci_event_ring_seg {
+ volatile uint64_t qwEvrsTablePtr;
+ volatile uint32_t dwEvrsTableSize;
+ volatile uint32_t dwEvrsReserved;
+};
+
+#endif /* _USB_XHCI_PRIVATE_H_ */
diff --git a/sys/dev/usb/controller/xhcireg.h b/sys/dev/usb/controller/xhcireg.h
--- a/sys/dev/usb/controller/xhcireg.h
+++ b/sys/dev/usb/controller/xhcireg.h
@@ -211,6 +211,129 @@
#define XHCI_ID_EXT_MSI 0x0011
#define XHCI_ID_USB3_TUN 0x0012
+/*
+ * XHCI Debug Capability
+ * From Section 7.6 of xHCI April 2023 Revision 1.2b.
+ */
+#define XHCI_DCID 0x0000
+
+#define XHCI_DCDB 0x0004
+#define XHCI_DCDB_GET(x) (((x) >> 8) & 0xFF)
+#define XHCI_DCDB_MASK 0x0000FF00
+#define XHCI_DCDB_OUT 0x0000
+#define XHCI_DCDB_IN 0x0100
+#define XHCI_DCDB_INVAL 0xFF00
+
+#define XHCI_DCERSTSZ 0x0008 /* Event Ring Segment Table size */
+#define XHCI_DCERSTBA_LO 0x0010
+#define XHCI_DCERSTBA_HI 0x0014
+#define XHCI_DCERDP_LO 0x0018
+#define XHCI_DCERDP_HI 0x001C
+
+#define XHCI_DCCTRL 0x0020 /* Debug Control */
+#define XHCI_DCCTRL_DCR 0x00000001
+#define XHCI_DCCTRL_DCR_GET(x) (((x) ) & 0x01)
+#define XHCI_DCCTRL_LSE 0x00000002
+#define XHCI_DCCTRL_LSE_GET(x) (((x) >> 1) & 0x01)
+#define XHCI_DCCTRL_HOT 0x00000004
+#define XHCI_DCCTRL_HOT_GET(x) (((x) >> 2) & 0x01)
+#define XHCI_DCCTRL_HIT 0x00000008
+#define XHCI_DCCTRL_HIT_GET(x) (((x) >> 3) & 0x01)
+#define XHCI_DCCTRL_DRC 0x00000010
+#define XHCI_DCCTRL_DRC_GET(x) (((x) >> 4) & 0x01)
+#define XHCI_DCCTRL_MBS_GET(x) (((x) >> 16) & 0xFF)
+#define XHCI_DCCTRL_ADDR_GET(x) (((x) >> 24) & 0x07)
+#define XHCI_DCCTRL_DCE 0x80000000
+#define XHCI_DCCTRL_DCE_GET(x) (((x) >> 31) & 0x01)
+
+#define XHCI_DCST 0x0024 /* Status */
+#define XHCI_DCST_ER 0x00000001
+#define XHCI_DCST_ER_GET(x) (((x) ) & 0x01)
+#define XHCI_DCST_SBR 0x00000004
+#define XHCI_DCST_SBR_GET(x) (((x) >> 2) & 0x01)
+#define XHCI_DCST_PORT_GET(x) (((x) >> 24) & 0xFF)
+
+#define XHCI_DCPORTSC 0x0028 /* Port Control */
+#define XHCI_DCPORTSC_CCS 0x00000001
+#define XHCI_DCPORTSC_CCS_GET(x) (((x) ) & 0x01)
+#define XHCI_DCPORTSC_PED 0x00000002
+#define XHCI_DCPORTSC_PED_GET(x) (((x) >> 1) & 0x01)
+#define XHCI_DCPORTSC_PR 0x00000010
+#define XHCI_DCPORTSC_PR_GET(x) (((x) >> 4) & 0x01)
+#define XHCI_DCPORTSC_PLS_GET(x) (((x) >> 5) & 0x0F)
+#define XHCI_DCPORTSC_PLS_U0 0x00
+#define XHCI_DCPORTSC_PLS_U1 0x01
+#define XHCI_DCPORTSC_PLS_U2 0x02
+#define XHCI_DCPORTSC_PLS_U3 0x03
+#define XHCI_DCPORTSC_PLS_DISABLED 0x04
+#define XHCI_DCPORTSC_PLS_RXDETECTED 0x05
+#define XHCI_DCPORTSC_PLS_INACTIVE 0x06
+#define XHCI_DCPORTSC_PLS_POLLING 0x07
+#define XHCI_DCPORTSC_PLS_RECOVERY 0x08
+#define XHCI_DCPORTSC_PLS_HOTRESET 0x09
+#define XHCI_DCPORTSC_SPEED_GET(x) (((x) >> 10) & 0x0F)
+#define XHCI_DCPORTSC_CSC 0x00020000
+#define XHCI_DCPORTSC_CSC_GET(x) (((x) >> 17) & 0x01)
+#define XHCI_DCPORTSC_PRC 0x00200000
+#define XHCI_DCPORTSC_PRC_GET(x) (((x) >> 21) & 0x01)
+#define XHCI_DCPORTSC_PLC 0x00400000
+#define XHCI_DCPORTSC_PLC_GET(x) (((x) >> 22) & 0x01)
+#define XHCI_DCPORTSC_CEC 0x00800000
+#define XHCI_DCPORTSC_CEC_GET(x) (((x) >> 23) & 0x01)
+#define XHCI_DCCP_LO 0x0030 /* Context Pointer */
+#define XHCI_DCCP_HI 0x0034
+#define XHCI_DCDDI1 0x0038 /* Device Descriptor Info */
+#define XHCI_DCDDI2 0x003C /* Device Descriptor Info */
+
+/* DbC CIC offset in uint32 */
+#define XHCI_DCDBCIC_STR0DESC_LO 0x0000
+#define XHCI_DCDBCIC_STR0DESC_HI 0x0001
+#define XHCI_DCDBCIC_MANUDESC_LO 0x0002
+#define XHCI_DCDBCIC_MANUDESC_HI 0x0003
+#define XHCI_DCDBCIC_PRODDESC_LO 0x0004
+#define XHCI_DCDBCIC_PRODDESC_HI 0x0005
+#define XHCI_DCDBCIC_SERIALDESC_LO 0x0006
+#define XHCI_DCDBCIC_SERIALDESC_HI 0x0007
+#define XHCI_DCDBCIC_DESCLEN 0x0008
+#define XHCI_DCDBCIC_STR0DESC_LEN_GET(x) (((x) >> 0) & 0xff)
+#define XHCI_DCDBCIC_STR0DESC_LEN_SET(x) (((x) & 0xff) << 0)
+#define XHCI_DCDBCIC_MANUDESC_LEN_GET(x) (((x) >> 8) & 0xff)
+#define XHCI_DCDBCIC_MANUDESC_LEN_SET(x) (((x) & 0xff) << 8)
+#define XHCI_DCDBCIC_PRODDESC_LEN_GET(x) (((x) >> 16) & 0xff)
+#define XHCI_DCDBCIC_PRODDESC_LEN_SET(x) (((x) & 0xff) << 16)
+#define XHCI_DCDBCIC_SERIALDESC_LEN_GET(x) (((x) >> 24) & 0xff)
+#define XHCI_DCDBCIC_SERIALDESC_LEN_SET(x) (((x) & 0xff) << 24)
+
+#define XHCI_DCSTATUS(ctrl, portsc) \
+ (XHCI_DCCTRL_DCE_GET(ctrl) << 4 | \
+ XHCI_DCPORTSC_CCS_GET(portsc) << 3 | \
+ XHCI_DCPORTSC_PED_GET(portsc) << 2 | \
+ XHCI_DCPORTSC_PR_GET(portsc) << 1 | \
+ XHCI_DCCTRL_DCR_GET(ctrl))
+#define XHCI_DCPORTSC_ACK_MASK \
+ (XHCI_DCPORTSC_PED | \
+ XHCI_DCPORTSC_CSC | XHCI_DCPORTSC_PRC | \
+ XHCI_DCPORTSC_PLC | XHCI_DCPORTSC_CEC)
+
+#define XHCI_DCPORT_ST_OFF 0x00
+#define XHCI_DCPORT_ST_DISCONNECTED 0x10 /* DCE only */
+#define XHCI_DCPORT_ST_DISCONNECTED_RUNNING 0x11 /* XXX: DCE + DCR */
+#define XHCI_DCPORT_ST_DISABLED 0x18 /* DCE + CCS */
+#define XHCI_DCPORT_ST_RESETTING 0x1a /* DCE + CCS + PR */
+#define XHCI_DCPORT_ST_ENABLED 0x1c /* DCE + CCS + PED */
+#define XHCI_DCPORT_ST_CONFIGURED 0x1d /* DCE + CCS + PED + DCR */
+
+#define XHCI_DC_MAXPACKETLEN 1024
+/*
+ * While Sec 7.6.3.2 describes Endpoint IDs should be 0 or 1,
+ * Intel chips use Device Context Index (Sec 4.5.1) instead.
+ */
+#define XHCI_DC_EPID_OUT 0
+#define XHCI_DC_EPID_IN 1
+#define XHCI_DC_EPID_OUT_INTEL 2
+#define XHCI_DC_EPID_IN_INTEL 3
+#define XHCI_DC_SLOT 1
+
/* XHCI register R/W wrappers */
#define XREAD1(sc, what, a) \
bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \
@@ -221,6 +344,9 @@
#define XREAD4(sc, what, a) \
bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, \
(a) + (sc)->sc_##what##_off)
+#define XREAD44LH(sc, what, a) \
+ ((uint64_t)XREAD4((sc), what, a##_LO) | \
+ ((uint64_t)XREAD4((sc), what, a##_HI) << 32))
#define XWRITE1(sc, what, a, x) \
bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \
(a) + (sc)->sc_##what##_off, (x))
@@ -230,5 +356,10 @@
#define XWRITE4(sc, what, a, x) \
bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, \
(a) + (sc)->sc_##what##_off, (x))
+#define XWRITE44LH(sc, what, a, x) \
+ do { \
+ XWRITE4((sc), what, a##_LO, (uint32_t)((x) & 0xffffffff)); \
+ XWRITE4((sc), what, a##_HI, (uint32_t)((x) >> 32)); \
+ } while (0)
#endif /* _XHCIREG_H_ */
diff --git a/sys/x86/include/metadata.h b/sys/x86/include/metadata.h
--- a/sys/x86/include/metadata.h
+++ b/sys/x86/include/metadata.h
@@ -35,6 +35,7 @@
#define MODINFOMD_MODULEP 0x1006
#define MODINFOMD_VBE_FB 0x1007
#define MODINFOMD_EFI_ARCH 0x1008
+#define MODINFOMD_XHCI_DEBUG 0x1009
/*
* This is not the same as the UEFI standard EFI_MEMORY_ATTRIBUTES_TABLE, though
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Jan 27, 9:25 AM (19 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28053661
Default Alt Text
D53472.diff (97 KB)
Attached To
Mode
D53472: Add loader support for xhci debug
Attached
Detach File
Event Timeline
Log In to Comment