diff --git a/kernel/amd64/intr_defs.h b/kernel/amd64/intr_defs.h index 185a930..efe1cdb 100644 --- a/kernel/amd64/intr_defs.h +++ b/kernel/amd64/intr_defs.h @@ -4,7 +4,10 @@ #define INTR_PS2KB 32 #define INTR_IDE_DRIVE_PRIM 33 #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_CPU_REQUEST_SCHED 82 diff --git a/kernel/device/pci_xhci.c b/kernel/device/pci_xhci.c index 9527e6a..b3649b7 100644 --- a/kernel/device/pci_xhci.c +++ b/kernel/device/pci_xhci.c @@ -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) { 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); /* 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; - 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_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); + ioapic_route_irq (irq, intr_line, 0, thiscpu->lapic_id); } } else { 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 = { .xhci_mmio_base = xhci_base, .irqs_support = irqs_support, - .irq = INTR_XHCI, + .irq = irq, }; device_op_func_t ops[] = {0}; diff --git a/kernel/device/xhci.c b/kernel/device/xhci.c index a5ac70d..ecaa9e3 100644 --- a/kernel/device/xhci.c +++ b/kernel/device/xhci.c @@ -180,6 +180,7 @@ static void xhci_irq (void* arg, void* regs, bool user, struct reschedule_ctx* r /* ack */ 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); @@ -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); 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); + + if (timeout == 0) + DEBUG ("timed out\n"); } else { while (atomic_load (&xhci->pending)) { 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); } +/* Make or break on real hardware. We need to take over ownership from the BIOS. */ static void xhci_bios_handover (struct xhci* xhci) { uint32_t hccparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCCPARAMS1); 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); + /* Wait for BIOS Semaphore owned bit to be cleared */ int timeout = 1000; - while (timeout--) { + while (--timeout > 0) { uint32_t val = xhci_read32 (cap_ptr, 0); if (!(val & (1 << 16)) && (val & (1 << 24))) break; - stall_ms (1); + + stall_ms (100); } - if (timeout <= 0) - DEBUG ("Warning: XHCI BIOS handover timed out!\n"); - else - DEBUG ("XHCI Handover successful.\n"); + DEBUG ("XHCI Handover OK\n"); } break; } @@ -265,6 +273,7 @@ static void xhci_bios_handover (struct xhci* xhci) { uint8_t next = (cap >> 8) & 0xFF; if (!next) break; + ext_offset += (next << 2); } } @@ -318,7 +327,8 @@ DEFINE_DEVICE_INIT (xhci_init) { usbcmd |= (1 << 1); 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"); @@ -349,10 +359,10 @@ DEFINE_DEVICE_INIT (xhci_init) { 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 + 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); memset (xhci->cmd_ring, 0, PAGE_SIZE); xhci->cmd_ring_size = PAGE_SIZE / sizeof (struct xhci_trb); @@ -360,17 +370,17 @@ DEFINE_DEVICE_INIT (xhci_init) { xhci->cmd_cycle_bit = 1; 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 + 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); memset (xhci->event_ring, 0, PAGE_SIZE); xhci->event_ring_size = PAGE_SIZE / sizeof (struct xhci_trb); xhci->event_ring_idx = 0; 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); memset (xhci->erst, 0, PAGE_SIZE); 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 + 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 + 4, (uint32_t)(xhci->event_ring_phys >> 32)); if (xhci->irqs_support) { /* enable interrupter */ @@ -394,11 +404,10 @@ DEFINE_DEVICE_INIT (xhci_init) { usbcmd = xhci_read32 (xhci->xhci_oper_base, XHCI_USBCMD); 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_NOOP_CMD << 10); + return true; }