Artemis Milestone 2c: xHCI controller bring-up wired, DoE CSV export off by default
xhci_bringup() (HC reset, DCBAA, Command/Event rings, RUN/STOP) was uncommitted and referenced an XHCI_WAIT_FOR macro that was never defined, breaking the build. Wired all four wait sites to the existing xhci_wait_bit() helper instead, matching each register/bit/polarity needed (halt-before-reset waits for HCH set; HCRST, CNR, and post-RUN HCH waits all wait for their bit to clear). Also flipped g_doe_log_enabled's default from 1 to 0 -- the per-tick [HADES][DOE] CSV export was flooding every boot log and slowing interactive verification for no reason during ordinary acceptance runs; HB-ON still re-enables it at the REPL for anyone running an actual DoE campaign. Three-arch acceptance: amd64/aarch64/riscv64 all boot clean to ok>, zero DoE rows in any log. aarch64 and riscv64 both exited cleanly via BYE with no exception, confirming the earlier SMC->HVC PSCI fix still holds. Logs and DoE CSV artifacts from this run included. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5970c54912
commit
c2f1d94c97
@@ -59,7 +59,7 @@
|
||||
#include "freestanding/stdio.h"
|
||||
#include "word_registry.h"
|
||||
|
||||
int g_doe_log_enabled = 1;
|
||||
int g_doe_log_enabled = 0; /* off by default -- HB-ON to enable, per instruction */
|
||||
|
||||
#define DOE_PREFIX "\x1b[36m[HADES][DOE ]\x1b[0m "
|
||||
#define DOE_BUF_SIZE 512
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "starkernel/pci.h"
|
||||
#include "starkernel/xhci.h"
|
||||
#include "starkernel/xhci_driver.h"
|
||||
#include "starkernel/kmalloc.h"
|
||||
#include "starkernel/timer.h"
|
||||
#include "console.h"
|
||||
|
||||
/* Conservative fixed BAR0 mapping size. xHCI has no self-describing
|
||||
@@ -64,7 +66,162 @@ int xhci_find_and_map(xhci_dev_t *dev)
|
||||
dev->max_slots = XHCI_HCSPARAMS1_MAX_SLOTS(hcs1);
|
||||
dev->max_intrs = XHCI_HCSPARAMS1_MAX_INTRS(hcs1);
|
||||
dev->max_ports = XHCI_HCSPARAMS1_MAX_PORTS(hcs1);
|
||||
dev->max_scratchpad_bufs = XHCI_HCSPARAMS2_MAX_SCRATCHPAD_BUFS(dev->cap->hcs_params2);
|
||||
|
||||
console_println("xhci: controller found, BAR0 mapped");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Spin-count-bounded busy-wait, matching kernel_main.c's established
|
||||
* pattern (heartbeat_ticks() elapsed + a hard spin-count safety cap, not
|
||||
* just one or the other). Polls *reg for (val & mask) to equal want_set
|
||||
* (0 or 1), re-reading the register itself each iteration. */
|
||||
static int xhci_wait_bit(volatile uint32_t *reg, uint32_t mask, int want_set,
|
||||
uint64_t max_ticks)
|
||||
{
|
||||
uint64_t start = heartbeat_ticks();
|
||||
uint64_t spins = 0;
|
||||
for (;;) {
|
||||
uint32_t val = *reg;
|
||||
int is_set = (val & mask) != 0;
|
||||
if (is_set == want_set) return 0;
|
||||
spins++;
|
||||
if (heartbeat_ticks() - start >= max_ticks || spins >= 100000000ULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int xhci_bringup(xhci_dev_t *dev)
|
||||
{
|
||||
if (!dev || !dev->op) return -2;
|
||||
|
||||
/* 1. If running, stop first (Run/Stop must be cleared before HCRST is
|
||||
* guaranteed to behave per spec on some implementations). */
|
||||
if (dev->op->usb_cmd & XHCI_USBCMD_RUN) {
|
||||
dev->op->usb_cmd &= ~XHCI_USBCMD_RUN;
|
||||
if (xhci_wait_bit(&dev->op->usb_sts, XHCI_USBSTS_HCH, 1, 10000) != 0) {
|
||||
console_println("xhci: timeout waiting for halt before reset");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 2. Host Controller Reset. HCRST self-clears; CNR (Controller Not
|
||||
* Ready) must also clear before touching any other operational
|
||||
* register. */
|
||||
dev->op->usb_cmd |= XHCI_USBCMD_HCRST;
|
||||
if (xhci_wait_bit(&dev->op->usb_cmd, XHCI_USBCMD_HCRST, 0, 10000) != 0) {
|
||||
console_println("xhci: timeout waiting for HCRST to self-clear");
|
||||
return -1;
|
||||
}
|
||||
if (xhci_wait_bit(&dev->op->usb_sts, XHCI_USBSTS_CNR, 0, 10000) != 0) {
|
||||
console_println("xhci: timeout waiting for CNR to clear");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 3. Device Context Base Address Array — (max_slots+1) x 8-byte
|
||||
* pointers, 64-byte aligned, zeroed (DCBAAP requires 64-byte
|
||||
* alignment per spec; kmalloc_aligned enforces it). */
|
||||
size_t dcbaa_bytes = (size_t)(dev->max_slots + 1) * sizeof(uint64_t);
|
||||
dev->dcbaa = kmalloc_aligned(dcbaa_bytes, 64);
|
||||
if (!dev->dcbaa) {
|
||||
console_println("xhci: DCBAA allocation failed");
|
||||
return -2;
|
||||
}
|
||||
for (size_t i = 0; i < dcbaa_bytes / sizeof(uint64_t); i++) {
|
||||
((uint64_t *)dev->dcbaa)[i] = 0;
|
||||
}
|
||||
|
||||
/* 3b. Scratchpad buffers, only if the controller asks for them (slot 0
|
||||
* of the DCBAA points at the scratchpad buffer array, not a device
|
||||
* context, when max_scratchpad_bufs > 0). PAGESIZE register: bit N
|
||||
* set means 2^(N+12)-byte pages; use the lowest set bit found. */
|
||||
if (dev->max_scratchpad_bufs > 0) {
|
||||
uint32_t pagesize_bits = dev->op->page_size;
|
||||
uint32_t page_bytes = 4096u;
|
||||
for (uint32_t b = 0; b < 16; b++) {
|
||||
if (pagesize_bits & (1u << b)) { page_bytes = 1u << (b + 12); break; }
|
||||
}
|
||||
size_t arr_bytes = (size_t)dev->max_scratchpad_bufs * sizeof(uint64_t);
|
||||
dev->scratchpad_arr = kmalloc_aligned(arr_bytes, 64);
|
||||
if (!dev->scratchpad_arr) {
|
||||
console_println("xhci: scratchpad array allocation failed");
|
||||
return -2;
|
||||
}
|
||||
for (uint32_t i = 0; i < dev->max_scratchpad_bufs; i++) {
|
||||
void *buf = kmalloc_aligned(page_bytes, page_bytes);
|
||||
if (!buf) {
|
||||
console_println("xhci: scratchpad buffer allocation failed");
|
||||
return -2;
|
||||
}
|
||||
((uint64_t *)dev->scratchpad_arr)[i] = (uint64_t)(uintptr_t)buf;
|
||||
}
|
||||
((uint64_t *)dev->dcbaa)[0] = (uint64_t)(uintptr_t)dev->scratchpad_arr;
|
||||
}
|
||||
|
||||
dev->op->dcbaap = (uint64_t)(uintptr_t)dev->dcbaa;
|
||||
|
||||
/* 4. Command Ring — XHCI_RING_TRB_COUNT TRBs, 64-byte aligned, zeroed.
|
||||
* Initial Ring Cycle State = 1 (software convention; the ring is
|
||||
* "owned" by software until the first TRB with a matching cycle bit
|
||||
* is consumed). CRCR low bits carry RCS, not the TRBs themselves. */
|
||||
dev->cmd_ring = (xhci_trb_t *)kmalloc_aligned(XHCI_RING_BYTES, 64);
|
||||
if (!dev->cmd_ring) {
|
||||
console_println("xhci: command ring allocation failed");
|
||||
return -2;
|
||||
}
|
||||
for (uint32_t i = 0; i < XHCI_RING_TRB_COUNT; i++) {
|
||||
dev->cmd_ring[i].parameter = 0;
|
||||
dev->cmd_ring[i].status = 0;
|
||||
dev->cmd_ring[i].control = 0;
|
||||
}
|
||||
dev->cmd_ring_cycle = 1;
|
||||
dev->op->crcr = ((uint64_t)(uintptr_t)dev->cmd_ring & XHCI_CRCR_PTR_MASK) |
|
||||
XHCI_CRCR_RCS;
|
||||
|
||||
/* 5. Event Ring — one segment (Event Ring Segment Table with a single
|
||||
* 16-byte entry: base address + size), wired to Interrupter 0.
|
||||
* Interrupter Register Sets start at runtime_base + 0x20; each is
|
||||
* sizeof(xhci_intr_regs_t) apart, but only Interrupter 0 is used
|
||||
* (single-interrupter design decided in 2a). */
|
||||
dev->evt_ring = (xhci_trb_t *)kmalloc_aligned(XHCI_RING_BYTES, 64);
|
||||
if (!dev->evt_ring) {
|
||||
console_println("xhci: event ring allocation failed");
|
||||
return -2;
|
||||
}
|
||||
for (uint32_t i = 0; i < XHCI_RING_TRB_COUNT; i++) {
|
||||
dev->evt_ring[i].parameter = 0;
|
||||
dev->evt_ring[i].status = 0;
|
||||
dev->evt_ring[i].control = 0;
|
||||
}
|
||||
dev->evt_ring_cycle = 1;
|
||||
|
||||
/* Event Ring Segment Table entry layout: u64 base + u32 size + u32
|
||||
* reserved = 16 bytes. One segment is enough (ERST Max >= 1 always). */
|
||||
dev->evt_ring_seg_table = kmalloc_aligned(16, 64);
|
||||
if (!dev->evt_ring_seg_table) {
|
||||
console_println("xhci: event ring segment table allocation failed");
|
||||
return -2;
|
||||
}
|
||||
uint64_t *erst = (uint64_t *)dev->evt_ring_seg_table;
|
||||
erst[0] = (uint64_t)(uintptr_t)dev->evt_ring; /* base address */
|
||||
erst[1] = (uint64_t)XHCI_RING_TRB_COUNT; /* size, low 32 bits used */
|
||||
|
||||
xhci_intr_regs_t *intr0 = (xhci_intr_regs_t *)((uint8_t *)dev->runtime + 0x20);
|
||||
intr0->erstsz = 1;
|
||||
intr0->erstba = (uint64_t)(uintptr_t)dev->evt_ring_seg_table;
|
||||
intr0->erdp = ((uint64_t)(uintptr_t)dev->evt_ring & XHCI_ERDP_PTR_MASK);
|
||||
|
||||
/* 6. Enable device slots (all of them — no reason to restrict for a
|
||||
* single-drive-at-a-time driver) and start the controller. */
|
||||
dev->op->config = XHCI_CONFIG_MAX_SLOTS_EN(dev->max_slots);
|
||||
dev->op->usb_cmd |= XHCI_USBCMD_RUN;
|
||||
|
||||
if (xhci_wait_bit(&dev->op->usb_sts, XHCI_USBSTS_HCH, 0, 10000) != 0) {
|
||||
console_println("xhci: controller did not leave halted state after RUN");
|
||||
return -3;
|
||||
}
|
||||
|
||||
console_println("xhci: controller running");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user