XHCI test sending noop command
All checks were successful
Build ISO image / build-and-deploy (push) Successful in 3m12s
Build documentation / build-and-deploy (push) Successful in 3m13s

This commit is contained in:
2026-03-22 23:09:21 +01:00
parent 5cdeb87393
commit b35fc5545c
11 changed files with 360 additions and 31 deletions

View File

@@ -239,12 +239,12 @@ static uint32_t lapic_calibrate (uint32_t us) {
lapic_write (LAPIC_DCR, DIVIDER_VALUE);
lapic_write (LAPIC_LVTTR, SCHED_PREEMPT_TIMER | (1 << 16));
lapic_write (LAPIC_LVTTR, INTR_SCHED_PREEMPT_TIMER | (1 << 16));
lapic_write (LAPIC_TIMICT, 0xFFFFFFFF);
sleep_micro (us);
lapic_write (LAPIC_LVTTR, SCHED_PREEMPT_TIMER | (0 << 16));
lapic_write (LAPIC_LVTTR, INTR_SCHED_PREEMPT_TIMER | (0 << 16));
uint32_t ticks = 0xFFFFFFFF - lapic_read (LAPIC_TIMCCT);
DEBUG ("timer ticks = %u\n", ticks);
@@ -261,7 +261,7 @@ static uint32_t lapic_calibrate (uint32_t us) {
static void lapic_start (uint32_t ticks) {
lapic_write (LAPIC_DCR, DIVIDER_VALUE);
lapic_write (LAPIC_TIMICT, ticks);
lapic_write (LAPIC_LVTTR, SCHED_PREEMPT_TIMER | (1 << 17));
lapic_write (LAPIC_LVTTR, INTR_SCHED_PREEMPT_TIMER | (1 << 17));
}
/*

View File

@@ -78,8 +78,8 @@ void bootmain (void) {
struct device* temp0 = device_find ("temp0");
vfs_create_volume (thiscpu->kproc, &rctx, "temp", FS_FAT16, temp0, true);
irq_attach (&proc_irq_sched, NULL, SCHED_PREEMPT_TIMER);
irq_attach (&proc_irq_sched, NULL, CPU_REQUEST_SCHED);
irq_attach (&proc_irq_sched, NULL, INTR_SCHED_PREEMPT_TIMER);
irq_attach (&proc_irq_sched, NULL, INTR_CPU_REQUEST_SCHED);
smp_init ();

View File

@@ -126,9 +126,9 @@ static void idt_init (void) {
IDT_ENTRY (40, 2); IDT_ENTRY (41, 2); IDT_ENTRY (42, 2); IDT_ENTRY (43, 2);
IDT_ENTRY (44, 2); IDT_ENTRY (45, 2); IDT_ENTRY (46, 2); IDT_ENTRY (47, 2);
IDT_ENTRY (SCHED_PREEMPT_TIMER, 2);
IDT_ENTRY (CPU_REQUEST_SCHED, 2);
IDT_ENTRY (CPU_SPURIOUS, 2);
IDT_ENTRY (INTR_SCHED_PREEMPT_TIMER, 2);
IDT_ENTRY (INTR_CPU_REQUEST_SCHED, 2);
IDT_ENTRY (INTR_CPU_SPURIOUS, 2);
/* clang-format on */
#undef IDT_ENTRY

View File

@@ -1,12 +1,13 @@
#ifndef _KERNEL_AMD64_INTR_DEFS_H
#define _KERNEL_AMD64_INTR_DEFS_H
#define PS2KB 32
#define IDE_DRIVE_PRIM 33
#define IDE_DRIVE_SCND 34
#define INTR_PS2KB 32
#define INTR_IDE_DRIVE_PRIM 33
#define INTR_IDE_DRIVE_SCND 34
#define INTR_XHCI 35
#define SCHED_PREEMPT_TIMER 80
#define CPU_REQUEST_SCHED 82
#define CPU_SPURIOUS 255
#define INTR_SCHED_PREEMPT_TIMER 80
#define INTR_CPU_REQUEST_SCHED 82
#define INTR_CPU_SPURIOUS 255
#endif // _KERNEL_AMD64_INTR_DEFS_H

View File

@@ -91,6 +91,6 @@ make_intr_stub(no_err, 45)
make_intr_stub(no_err, 46)
make_intr_stub(no_err, 47)
make_intr_stub(no_err, SCHED_PREEMPT_TIMER)
make_intr_stub(no_err, CPU_REQUEST_SCHED)
make_intr_stub(no_err, CPU_SPURIOUS)
make_intr_stub(no_err, INTR_SCHED_PREEMPT_TIMER)
make_intr_stub(no_err, INTR_CPU_REQUEST_SCHED)
make_intr_stub(no_err, INTR_CPU_SPURIOUS)

View File

@@ -52,7 +52,7 @@ void cpu_request_sched (struct cpu* cpu, bool user) {
return;
}
lapic_ipi (cpu->lapic_id, CPU_REQUEST_SCHED);
lapic_ipi (cpu->lapic_id, INTR_CPU_REQUEST_SCHED);
}
struct cpu* cpu_find_lightest (void) {

View File

@@ -124,10 +124,10 @@ bool pci_ide_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_in
} else {
irqs_support = true;
if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, IDE_DRIVE_PRIM,
if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, INTR_IDE_DRIVE_PRIM,
thiscpu->lapic_id)) {
ioapic_route_irq (IDE_DRIVE_PRIM, 14, 0, thiscpu->lapic_id);
ioapic_route_irq (IDE_DRIVE_SCND, 15, 0, thiscpu->lapic_id);
ioapic_route_irq (INTR_IDE_DRIVE_PRIM, 14, 0, thiscpu->lapic_id);
ioapic_route_irq (INTR_IDE_DRIVE_SCND, 15, 0, thiscpu->lapic_id);
DEBUG ("Fallback to IOAPIC interrupt routing\n");
}
}
@@ -136,7 +136,8 @@ bool pci_ide_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_in
DEBUG ("scmd=%x, sctrl=%x\n", scmd, sctrl);
DEBUG ("IRQ support=%d\n", irqs_support);
uint16_t channels[2][3] = {{pcmd, pctrl, IDE_DRIVE_PRIM}, {scmd, sctrl, IDE_DRIVE_SCND}};
uint16_t channels[2][3] = {{pcmd, pctrl, INTR_IDE_DRIVE_PRIM},
{scmd, sctrl, INTR_IDE_DRIVE_SCND}};
for (size_t i = 0; i < lengthof (channels); i++) {
uint16_t cmd = channels[i][0];

View File

@@ -1,3 +1,5 @@
#include <amd64/apic.h>
#include <amd64/intr_defs.h>
#include <device/def_device_op.h>
#include <device/device.h>
#include <device/pci.h>
@@ -28,7 +30,7 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i
uint16_t pci_cmd = pci_read16 (pci_info.bus, pci_info.slot, pci_info.func, PCI_COMMAND);
uint16_t new_cmd = (pci_cmd | (1 << 1) | (1 << 2));
uint16_t new_cmd = (pci_cmd | (1 << 1) | (1 << 2)) & ~(1 << 10);
if (pci_cmd != new_cmd) {
pci_write16 (pci_info.bus, pci_info.slot, pci_info.func, PCI_COMMAND, new_cmd);
@@ -55,13 +57,35 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i
uintptr_t xhci_base = xhci_phys + (uintptr_t)hhdm->offset;
/* 2 pages should cover the mmio space */
mm_map_kernel_page (xhci_phys, xhci_base, MM_PG_RW | MM_PG_PRESENT);
mm_map_kernel_page (xhci_phys + PAGE_SIZE, xhci_base + PAGE_SIZE, MM_PG_RW | MM_PG_PRESENT);
for (size_t page = 0; page < 8; page++) {
mm_map_kernel_page (xhci_phys + page * PAGE_SIZE, xhci_base + page * PAGE_SIZE,
MM_PG_RW | MM_PG_PRESENT);
}
bool irqs_support = false;
if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, INTR_XHCI, thiscpu->lapic_id)) {
uint8_t intr_line = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_INTERRUPT_LINE);
uint8_t intr_pin = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_INTERRUPT_PIN);
if (intr_pin != 0) {
irqs_support = true;
ioapic_route_irq (INTR_XHCI, intr_line, 0, thiscpu->lapic_id);
}
} else {
irqs_support = true;
}
DEBUG ("IRQ support=%d\n", irqs_support);
char key[32];
snprintf (key, sizeof (key), "xhci%d", xhci_counter++);
struct xhci_init init = {.xhci_mmio_base = xhci_base};
struct xhci_init init = {
.xhci_mmio_base = xhci_base,
.irqs_support = irqs_support,
.irq = INTR_XHCI,
};
device_op_func_t ops[] = {0};

View File

@@ -226,8 +226,8 @@ static void ps2kb_set_typematic (uint8_t delay, uint8_t rate) {
}
DEFINE_DEVICE_INIT (ps2kb_init) {
ioapic_route_irq (PS2KB, 1, 0, thiscpu->lapic_id);
irq_attach (&ps2kb_irq, NULL, PS2KB);
ioapic_route_irq (INTR_PS2KB, 1, 0, thiscpu->lapic_id);
irq_attach (&ps2kb_irq, NULL, INTR_PS2KB);
ringbuffer_init (&ps2kb_ringbuffer, PS2KB_RINGBUFFER_MAX, sizeof (uint8_t));
@@ -252,6 +252,6 @@ DEFINE_DEVICE_INIT (ps2kb_init) {
DEFINE_DEVICE_FINI (ps2kb_fini) {
(void)device, (void)proc, (void)rctx;
irq_detach (PS2KB);
irq_detach (INTR_PS2KB);
ringbuffer_fini (&ps2kb_ringbuffer);
}

View File

@@ -1,10 +1,13 @@
#include <device/def_device_op.h>
#include <device/device.h>
#include <device/xhci.h>
#include <irq/irq.h>
#include <libk/list.h>
#include <libk/std.h>
#include <libk/string.h>
#include <limine/requests.h>
#include <mm/malloc.h>
#include <mm/pmm.h>
#include <proc/proc.h>
#include <proc/reschedule.h>
#include <proc/suspension_q.h>
@@ -52,6 +55,41 @@
#define XHCI_ERSTBA 0x10
#define XHCI_ERDP 0x18
/* event types */
#define XHCI_TRB_NORMAL 1
#define XHCI_TRB_SETUP_STAGE 2
#define XHCI_TRB_DATA_STAGE 3
#define XHCI_TRB_STATUS_STAGE 4
#define XHCI_TRB_ISOCH 5
#define XHCI_TRB_LINK 6
#define XHCI_TRB_EVENT_DATA 7
#define XHCI_TRB_NOOP 8
#define XHCI_TRB_SLOT_ENAB_CMD 9
#define XHCI_TRB_SLOT_DISB_CMD 10
#define XHCI_TRB_ADDR_DEV_CMD 11
#define XHCI_TRB_CFG_ENDP_CMD 12
#define XHCI_TRB_EVAL_CTX_CMD 13
#define XHCI_TRB_RESET_ENDP_CMD 14
#define XHCI_TRB_STOP_ENDP_CMD 15
#define XHCI_TRB_SET_DRDQP_CMD 16
#define XHCI_TRB_RESET_DEV_CMD 17
#define XHCI_TRB_FORCE_EVT_CMD 18
#define XHCI_TRB_NEGO_BANDW_CMD 19
#define XHCI_TRB_SET_LTV_CMD 20
#define XHCI_TRB_PORT_BANDW_CMD 21
#define XHCI_TRB_FORCE_HEADER 22
#define XHCI_TRB_NOOP_CMD 23
#define XHCI_TRB_GET_EXTPRP_CMD 24
#define XHCI_TRB_SET_EXTPRP_CMD 25
#define XHCI_TRB_TRANSFER_EVENT 32
#define XHCI_TRB_CMD_CMPL_EVENT 33
#define XHCI_TRB_PORT_STS_CHNG 34
#define XHCI_TRB_BANDW_RQ_EVENT 35
#define XHCI_TRB_DOORBELL_EVENT 36
#define XHCI_TRB_HOST_CTRL_EVNT 37
#define XHCI_TRB_DEV_NOTIF_EVNT 38
#define XHCI_TRB_MFINDEX_WRAP 39
/* clang-format on */
static void xhci_write8 (uintptr_t base, uint32_t reg, uint8_t value) {
@@ -78,7 +116,130 @@ static uint32_t xhci_read32 (uintptr_t base, uint32_t reg) {
return *(volatile uint32_t*)(base + reg);
}
static void xhci_event_dispatch (struct xhci* xhci, struct xhci_trb* event, uint8_t type) {
switch (type) {
case XHCI_TRB_CMD_CMPL_EVENT: {
uintptr_t cmd_trb_phys = event->param;
uint8_t cmpl_code = (event->status >> 24) & 0xFF;
uint8_t slot_id = (event->ctrl >> 24) & 0xFF;
DEBUG ("cmd completion: phys=%p,code=%u,slot=%u\n", cmd_trb_phys, cmpl_code, slot_id);
} break;
default:
DEBUG ("Unhandled event type %u at %u\n", type, xhci->event_ring_idx);
break;
}
}
static void xhci_poll_events (struct xhci* xhci) {
uintptr_t ir_base = xhci->xhci_runtime_base + 0x20;
bool serviced = false;
for (;;) {
struct xhci_trb* event = &xhci->event_ring[xhci->event_ring_idx];
if ((event->ctrl & 0x1) != xhci->event_cycle_bit) {
break;
}
serviced = true;
uint8_t type = (event->ctrl >> 10) & 0x3F;
xhci_event_dispatch (xhci, event, type);
xhci->event_ring_idx++;
if (xhci->event_ring_idx >= xhci->event_ring_size) {
xhci->event_ring_idx = 0;
xhci->event_cycle_bit ^= 1;
}
}
if (serviced) {
uintptr_t dequeue_ptr =
xhci->event_ring_phys + (xhci->event_ring_idx * sizeof (struct xhci_trb));
xhci_write32 (ir_base, XHCI_ERDP, (uint32_t)dequeue_ptr | (1 << 3));
xhci_write32 (ir_base, XHCI_ERDP + 4, (uint32_t)(dequeue_ptr >> 32));
atomic_store (&xhci->pending, false);
}
}
static void xhci_irq (void* arg, void* regs, bool user, struct reschedule_ctx* rctx) {
(void)user, (void)regs, (void)rctx;
uint64_t fd;
struct xhci* xhci = arg;
spin_lock (&xhci->device->lock, &fd);
uintptr_t ir_base = xhci->xhci_runtime_base + 0x20;
/* ack */
uint32_t iman = xhci_read32 (ir_base, XHCI_IMAN);
xhci_write32 (ir_base, XHCI_IMAN, iman | 0x01);
uint32_t usbsts = xhci_read32 (xhci->xhci_oper_base, XHCI_USBSTS);
xhci_write32 (xhci->xhci_oper_base, XHCI_USBSTS, usbsts | (1 << 3));
/* clear event busy */
uint64_t erdp = (uint64_t)xhci_read32 (ir_base, XHCI_ERDP) |
((uint64_t)xhci_read32 (ir_base, XHCI_ERDP + 4) << 32);
xhci_write32 (ir_base, XHCI_ERDP, (uint32_t)erdp | (1 << 3));
xhci_poll_events (xhci);
spin_unlock (&xhci->device->lock, fd);
}
void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t ctrl) {
uint64_t fd;
spin_lock (&xhci->device->lock, &fd);
if (xhci->irqs_support) {
if (xhci->cmd_ring_idx == (xhci->cmd_ring_size - 1)) {
struct xhci_trb* link = &xhci->cmd_ring[xhci->cmd_ring_idx];
link->param = xhci->cmd_ring_phys;
link->status = 0;
link->ctrl = (6 << 10) | (1 << 1) | xhci->cmd_cycle_bit;
xhci->cmd_ring_idx = 0;
xhci->cmd_cycle_bit ^= 1;
}
struct xhci_trb* trb = &xhci->cmd_ring[xhci->cmd_ring_idx];
trb->param = param;
trb->status = status;
trb->ctrl = (ctrl & ~0x1) | xhci->cmd_cycle_bit;
xhci->cmd_ring_idx++;
atomic_store (&xhci->pending, true);
xhci_write32 (xhci->xhci_doorbell_base, 0, 0);
spin_unlock (&xhci->device->lock, fd);
while (atomic_load (&xhci->pending))
spin_lock_relax ();
spin_lock (&xhci->device->lock, &fd);
} else {
while (atomic_load (&xhci->pending)) {
xhci_poll_events (xhci);
spin_lock_relax ();
}
}
spin_unlock (&xhci->device->lock, fd);
}
DEFINE_DEVICE_INIT (xhci_init) {
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
struct xhci* xhci = malloc (sizeof (*xhci));
if (xhci == NULL)
@@ -89,6 +250,8 @@ DEFINE_DEVICE_INIT (xhci_init) {
memset (xhci, 0, sizeof (*xhci));
xhci->device = device;
xhci->xhci_mmio_base = init->xhci_mmio_base;
xhci->irqs_support = init->irqs_support;
xhci->irq = init->irq;
device->udata = xhci;
@@ -109,8 +272,7 @@ DEFINE_DEVICE_INIT (xhci_init) {
spin_lock_relax ();
/* STOP */
uint32_t usbcmd = xhci_read32 (xhci->xhci_oper_base, XHCI_USBCMD);
xhci_write32 (xhci->xhci_oper_base, XHCI_USBCMD, usbcmd & ~0x01);
xhci_write32 (xhci->xhci_oper_base, XHCI_USBCMD, 0);
/* wait for HCH bit */
int timeout = 100000;
@@ -133,11 +295,110 @@ DEFINE_DEVICE_INIT (xhci_init) {
DEBUG ("XHCI init done\n");
uint32_t hcsparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCSPARAMS1);
uint8_t max_slots = (uint8_t)(hcsparams1 & 0xFF);
/* enable slots */
uint32_t config = xhci_read32 (xhci->xhci_oper_base, XHCI_CONFIG);
xhci_write32 (xhci->xhci_oper_base, XHCI_CONFIG, (config & ~0xFF) | max_slots);
DEBUG ("enabled %u slots\n", max_slots);
uint32_t hcsparams2 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCSPARAMS2);
xhci->max_scratchpad = (hcsparams2 >> 27) & 0x1F;
uintptr_t dcbaa_phys = pmm_alloc (1);
xhci->xhci_dcbaa_phys = dcbaa_phys;
xhci->xhci_dcbaa = (uintptr_t*)(dcbaa_phys + (uintptr_t)hhdm->offset);
memset (xhci->xhci_dcbaa, 0, PAGE_SIZE);
if (xhci->max_scratchpad > 0) {
uintptr_t dev_array_phys = pmm_alloc (1);
uintptr_t* dev_array = (uintptr_t*)(dev_array_phys + (uintptr_t)hhdm->offset);
memset (dev_array, 0, PAGE_SIZE);
for (size_t i = 0; i < xhci->max_scratchpad; i++)
dev_array[i] = pmm_alloc (1);
xhci->xhci_dcbaa[0] = dev_array_phys;
}
xhci_write32 (xhci->xhci_oper_base, XHCI_DCBAAP, (uint32_t)xhci->xhci_dcbaa_phys);
xhci_write32 (xhci->xhci_oper_base, XHCI_DCBAAP + 4, (uint32_t)(xhci->xhci_dcbaa_phys >> 32));
xhci->cmd_ring_phys = pmm_alloc (1);
xhci->cmd_ring = (struct xhci_trb*)(xhci->cmd_ring_phys + (uintptr_t)hhdm->offset);
xhci->cmd_ring_size = PAGE_SIZE / sizeof (struct xhci_trb);
xhci->cmd_ring_idx = 0;
xhci->cmd_cycle_bit = 1;
memset (xhci->cmd_ring, 0, PAGE_SIZE);
uint64_t crcr = xhci->cmd_ring_phys | xhci->cmd_cycle_bit;
xhci_write32 (xhci->xhci_oper_base, XHCI_CRCR, (uint32_t)crcr);
xhci_write32 (xhci->xhci_oper_base, XHCI_CRCR + 4, (uint32_t)(crcr >> 32));
xhci->event_ring_phys = pmm_alloc (1);
xhci->event_ring = (struct xhci_trb*)(xhci->event_ring_phys + (uintptr_t)hhdm->offset);
xhci->event_ring_size = PAGE_SIZE / sizeof (struct xhci_trb);
xhci->event_ring_idx = 0;
xhci->event_cycle_bit = 1;
memset (xhci->event_ring, 0, PAGE_SIZE);
xhci->erst_phys = pmm_alloc (1);
xhci->erst = (struct xhci_erst_entry*)(xhci->erst_phys + (uintptr_t)hhdm->offset);
xhci->erst[0].ptr = xhci->event_ring_phys;
xhci->erst[0].size = xhci->event_ring_size;
xhci->erst[0]._rsvd = 0;
uintptr_t ir_base = xhci->xhci_runtime_base + 0x20;
xhci_write32 (ir_base, XHCI_ERSTSZ, 1);
xhci_write32 (ir_base, XHCI_ERSTBA, (uint32_t)xhci->erst_phys);
xhci_write32 (ir_base, XHCI_ERSTBA + 4, (uint32_t)(xhci->erst_phys >> 32));
xhci_write32 (ir_base, XHCI_ERDP, (uint32_t)xhci->event_ring_phys | (1 << 3));
xhci_write32 (ir_base, XHCI_ERDP + 4, (uint32_t)(xhci->event_ring_phys >> 32));
if (xhci->irqs_support) {
/* enable interrupter */
irq_attach (&xhci_irq, xhci, xhci->irq);
xhci_write32 (ir_base, XHCI_IMAN, xhci_read32 (ir_base, XHCI_IMAN) | 0x02);
}
uint32_t usbcmd = xhci_read32 (xhci->xhci_oper_base, XHCI_USBCMD);
xhci_write32 (xhci->xhci_oper_base, XHCI_USBCMD, usbcmd | 0x01 | (1 << 2));
xhci_send_cmd (xhci, 0, 0, (23 << 10));
return true;
}
DEFINE_DEVICE_FINI (xhci_fini) {
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
struct xhci* xhci = device->udata;
if (xhci->max_scratchpad > 0) {
uintptr_t dev_array_phys = xhci->xhci_dcbaa[0];
uintptr_t* dev_array = (uintptr_t*)(dev_array_phys + (uintptr_t)hhdm->offset);
for (size_t i = 0; i < xhci->max_scratchpad; i++) {
if (dev_array[i] != 0)
pmm_free (dev_array[i], 1);
}
pmm_free (dev_array_phys, 1);
}
pmm_free (xhci->xhci_dcbaa_phys, 1);
pmm_free (xhci->cmd_ring_phys, 1);
pmm_free (xhci->event_ring_phys, 1);
pmm_free (xhci->erst_phys, 1);
irq_detach (xhci->irq);
free (xhci);
}

View File

@@ -1,6 +1,7 @@
#ifndef _KERNEL_DEVICE_XHCI_H
#define _KERNEL_DEVICE_XHCI_H
#include <aux/compiler.h>
#include <device/def_device_op.h>
#include <libk/list.h>
#include <libk/std.h>
@@ -8,16 +9,57 @@
#include <proc/reschedule.h>
#include <proc/suspension_q.h>
/* event ring segment table entry */
struct xhci_erst_entry {
uint64_t ptr;
uint32_t size;
uint32_t _rsvd;
} PACKED;
/* transfer request block */
struct xhci_trb {
uint64_t param;
uint32_t status;
uint32_t ctrl;
} PACKED;
struct xhci_init {
uintptr_t xhci_mmio_base;
bool irqs_support;
uint8_t irq;
};
struct xhci {
struct device* device;
bool irqs_support;
uint8_t irq;
uintptr_t xhci_mmio_base;
uintptr_t xhci_oper_base;
uintptr_t xhci_runtime_base;
uintptr_t xhci_doorbell_base;
uintptr_t* xhci_dcbaa;
uintptr_t xhci_dcbaa_phys;
uint32_t max_scratchpad;
struct xhci_trb* cmd_ring;
uintptr_t cmd_ring_phys;
uint32_t cmd_ring_idx;
uint32_t cmd_ring_size;
uint8_t cmd_cycle_bit;
struct xhci_trb* event_ring;
uintptr_t event_ring_phys;
uint32_t event_ring_idx;
uint32_t event_ring_size;
uint8_t event_cycle_bit;
struct xhci_erst_entry* erst;
uintptr_t erst_phys;
atomic_bool pending;
};
DEFINE_DEVICE_INIT (xhci_init);