XHCI hardware fixes, ordering of writes, send noop to test
All checks were successful
Build ISO image / build-and-deploy (push) Successful in 6m20s
Build documentation / build-and-deploy (push) Successful in 2m21s

This commit is contained in:
2026-03-24 23:59:30 +01:00
parent 0478570b2b
commit c71b1cc97d
3 changed files with 41 additions and 22 deletions

View File

@@ -4,7 +4,10 @@
#define INTR_PS2KB 32 #define INTR_PS2KB 32
#define INTR_IDE_DRIVE_PRIM 33 #define INTR_IDE_DRIVE_PRIM 33
#define INTR_IDE_DRIVE_SCND 34 #define INTR_IDE_DRIVE_SCND 34
#define INTR_XHCI 35 #define INTR_XHCI0 35
#define INTR_XHCI1 36
#define INTR_XHCI2 37
#define INTR_XHCI3 38
#define INTR_SCHED_PREEMPT_TIMER 80 #define INTR_SCHED_PREEMPT_TIMER 80
#define INTR_CPU_REQUEST_SCHED 82 #define INTR_CPU_REQUEST_SCHED 82

View File

@@ -21,6 +21,11 @@ static int xhci_counter = 0;
bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_info pci_info) { bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_info pci_info) {
struct limine_hhdm_response* hhdm = limine_hhdm_request.response; struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
if (xhci_counter == 3) {
DEBUG ("Cannot initialize more XHCI controllers\n");
return false;
}
uint8_t progif = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_PROG_IF); uint8_t progif = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_PROG_IF);
/* not an XHCI controller */ /* not an XHCI controller */
@@ -64,13 +69,15 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i
bool irqs_support = false; bool irqs_support = false;
if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, INTR_XHCI, thiscpu->lapic_id)) { uint32_t irq = INTR_XHCI0 + xhci_counter;
if (!pci_msi_init (pci_info.bus, pci_info.slot, pci_info.func, irq, thiscpu->lapic_id)) {
uint8_t intr_line = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_INTERRUPT_LINE); 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); uint8_t intr_pin = pci_read8 (pci_info.bus, pci_info.slot, pci_info.func, PCI_INTERRUPT_PIN);
if (intr_pin != 0) { if (intr_pin != 0) {
irqs_support = true; irqs_support = true;
ioapic_route_irq (INTR_XHCI, intr_line, 0, thiscpu->lapic_id); ioapic_route_irq (irq, intr_line, 0, thiscpu->lapic_id);
} }
} else { } else {
irqs_support = true; irqs_support = true;
@@ -84,7 +91,7 @@ bool pci_xhci_init (struct proc* proc, struct reschedule_ctx* rctx, struct pci_i
struct xhci_init init = { struct xhci_init init = {
.xhci_mmio_base = xhci_base, .xhci_mmio_base = xhci_base,
.irqs_support = irqs_support, .irqs_support = irqs_support,
.irq = INTR_XHCI, .irq = irq,
}; };
device_op_func_t ops[] = {0}; device_op_func_t ops[] = {0};

View File

@@ -180,6 +180,7 @@ static void xhci_irq (void* arg, void* regs, bool user, struct reschedule_ctx* r
/* ack */ /* ack */
xhci_write32 (ir_base, XHCI_IMAN, xhci_read32 (ir_base, XHCI_IMAN) | (1 << 0)); xhci_write32 (ir_base, XHCI_IMAN, xhci_read32 (ir_base, XHCI_IMAN) | (1 << 0));
xhci_write32 (xhci->xhci_oper_base, XHCI_USBSTS, (1 << 3));
xhci_poll_events (xhci); xhci_poll_events (xhci);
@@ -214,9 +215,16 @@ void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t
xhci_write32 (xhci->xhci_doorbell_base, 0, 0); xhci_write32 (xhci->xhci_doorbell_base, 0, 0);
spin_unlock (&xhci->device->lock, fd); spin_unlock (&xhci->device->lock, fd);
while (atomic_load (&xhci->pending))
spin_lock_relax (); int timeout = 100;
while (atomic_load (&xhci->pending) && --timeout > 0)
stall_ms (1);
spin_lock (&xhci->device->lock, &fd); spin_lock (&xhci->device->lock, &fd);
if (timeout == 0)
DEBUG ("timed out\n");
} else { } else {
while (atomic_load (&xhci->pending)) { while (atomic_load (&xhci->pending)) {
xhci_poll_events (xhci); xhci_poll_events (xhci);
@@ -227,6 +235,7 @@ void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, uint32_t
spin_unlock (&xhci->device->lock, fd); spin_unlock (&xhci->device->lock, fd);
} }
/* Make or break on real hardware. We need to take over ownership from the BIOS. */
static void xhci_bios_handover (struct xhci* xhci) { static void xhci_bios_handover (struct xhci* xhci) {
uint32_t hccparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCCPARAMS1); uint32_t hccparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCCPARAMS1);
uint32_t ext_offset = (hccparams1 >> 16) << 2; uint32_t ext_offset = (hccparams1 >> 16) << 2;
@@ -246,18 +255,17 @@ static void xhci_bios_handover (struct xhci* xhci) {
xhci_write8 (cap_ptr, 3, 1); xhci_write8 (cap_ptr, 3, 1);
/* Wait for BIOS Semaphore owned bit to be cleared */
int timeout = 1000; int timeout = 1000;
while (timeout--) { while (--timeout > 0) {
uint32_t val = xhci_read32 (cap_ptr, 0); uint32_t val = xhci_read32 (cap_ptr, 0);
if (!(val & (1 << 16)) && (val & (1 << 24))) if (!(val & (1 << 16)) && (val & (1 << 24)))
break; break;
stall_ms (1);
stall_ms (100);
} }
if (timeout <= 0) DEBUG ("XHCI Handover OK\n");
DEBUG ("Warning: XHCI BIOS handover timed out!\n");
else
DEBUG ("XHCI Handover successful.\n");
} }
break; break;
} }
@@ -265,6 +273,7 @@ static void xhci_bios_handover (struct xhci* xhci) {
uint8_t next = (cap >> 8) & 0xFF; uint8_t next = (cap >> 8) & 0xFF;
if (!next) if (!next)
break; break;
ext_offset += (next << 2); ext_offset += (next << 2);
} }
} }
@@ -318,7 +327,8 @@ DEFINE_DEVICE_INIT (xhci_init) {
usbcmd |= (1 << 1); usbcmd |= (1 << 1);
xhci_write32 (xhci->xhci_oper_base, XHCI_USBCMD, usbcmd); xhci_write32 (xhci->xhci_oper_base, XHCI_USBCMD, usbcmd);
stall_ms (1000); while (xhci_read32 (xhci->xhci_oper_base, XHCI_USBSTS) & (1 << 11))
spin_lock_relax ();
DEBUG ("controller reset\n"); DEBUG ("controller reset\n");
@@ -349,10 +359,10 @@ DEFINE_DEVICE_INIT (xhci_init) {
xhci->xhci_dcbaa[0] = xhci->scratchpads_phys; xhci->xhci_dcbaa[0] = xhci->scratchpads_phys;
} }
xhci_write32 (xhci->xhci_oper_base, XHCI_DCBAAP + 4, (uint32_t)(xhci->xhci_dcbaa_phys >> 32));
xhci_write32 (xhci->xhci_oper_base, XHCI_DCBAAP, (uint32_t)xhci->xhci_dcbaa_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_aligned (1, 64); xhci->cmd_ring_phys = pmm_alloc (1);
xhci->cmd_ring = (struct xhci_trb*)(xhci->cmd_ring_phys + (uintptr_t)hhdm->offset); xhci->cmd_ring = (struct xhci_trb*)(xhci->cmd_ring_phys + (uintptr_t)hhdm->offset);
memset (xhci->cmd_ring, 0, PAGE_SIZE); memset (xhci->cmd_ring, 0, PAGE_SIZE);
xhci->cmd_ring_size = PAGE_SIZE / sizeof (struct xhci_trb); xhci->cmd_ring_size = PAGE_SIZE / sizeof (struct xhci_trb);
@@ -360,17 +370,17 @@ DEFINE_DEVICE_INIT (xhci_init) {
xhci->cmd_cycle_bit = 1; xhci->cmd_cycle_bit = 1;
uint64_t crcr = xhci->cmd_ring_phys | xhci->cmd_cycle_bit; uint64_t crcr = xhci->cmd_ring_phys | xhci->cmd_cycle_bit;
xhci_write32 (xhci->xhci_oper_base, XHCI_CRCR + 4, (uint32_t)(crcr >> 32));
xhci_write32 (xhci->xhci_oper_base, XHCI_CRCR, (uint32_t)crcr); 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_aligned (1, 64); xhci->event_ring_phys = pmm_alloc (1);
xhci->event_ring = (struct xhci_trb*)(xhci->event_ring_phys + (uintptr_t)hhdm->offset); xhci->event_ring = (struct xhci_trb*)(xhci->event_ring_phys + (uintptr_t)hhdm->offset);
memset (xhci->event_ring, 0, PAGE_SIZE); memset (xhci->event_ring, 0, PAGE_SIZE);
xhci->event_ring_size = PAGE_SIZE / sizeof (struct xhci_trb); xhci->event_ring_size = PAGE_SIZE / sizeof (struct xhci_trb);
xhci->event_ring_idx = 0; xhci->event_ring_idx = 0;
xhci->event_cycle_bit = 1; xhci->event_cycle_bit = 1;
xhci->erst_phys = pmm_alloc_aligned (1, 64); xhci->erst_phys = pmm_alloc (1);
xhci->erst = (struct xhci_erst_entry*)(xhci->erst_phys + (uintptr_t)hhdm->offset); xhci->erst = (struct xhci_erst_entry*)(xhci->erst_phys + (uintptr_t)hhdm->offset);
memset (xhci->erst, 0, PAGE_SIZE); memset (xhci->erst, 0, PAGE_SIZE);
xhci->erst[0].ptr = xhci->event_ring_phys; xhci->erst[0].ptr = xhci->event_ring_phys;
@@ -382,8 +392,8 @@ DEFINE_DEVICE_INIT (xhci_init) {
xhci_write32 (ir_base, XHCI_ERSTBA, (uint32_t)xhci->erst_phys); 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_ERSTBA + 4, (uint32_t)(xhci->erst_phys >> 32));
xhci_write32 (ir_base, XHCI_ERDP + 4, (uint32_t)(xhci->event_ring_phys >> 32));
xhci_write32 (ir_base, XHCI_ERDP, (uint32_t)xhci->event_ring_phys | (1 << 3)); 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) { if (xhci->irqs_support) {
/* enable interrupter */ /* enable interrupter */
@@ -394,11 +404,10 @@ DEFINE_DEVICE_INIT (xhci_init) {
usbcmd = xhci_read32 (xhci->xhci_oper_base, XHCI_USBCMD); usbcmd = xhci_read32 (xhci->xhci_oper_base, XHCI_USBCMD);
xhci_write32 (xhci->xhci_oper_base, XHCI_USBCMD, usbcmd | (1 << 0) | (1 << 2)); xhci_write32 (xhci->xhci_oper_base, XHCI_USBCMD, usbcmd | (1 << 0) | (1 << 2));
while (xhci_read32 (xhci->xhci_oper_base, XHCI_USBSTS) & (1 << 11))
spin_lock_relax ();
xhci_send_cmd (xhci, 0, 0, XHCI_TRB_SLOT_ENAB_CMD << 10); xhci_send_cmd (xhci, 0, 0, XHCI_TRB_SLOT_ENAB_CMD << 10);
xhci_send_cmd (xhci, 0, 0, XHCI_TRB_NOOP_CMD << 10);
return true; return true;
} }