XHCI test sending noop command
This commit is contained in:
@@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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 ();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user