Skip to content

Commit 635746e

Browse files
interrupts now arm and deliver
1 parent b6be0ed commit 635746e

File tree

2 files changed

+100
-141
lines changed

2 files changed

+100
-141
lines changed

include/usb_xhci.h

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,6 @@ struct usb_ep {
99
uint8_t dir_in; /* 1=in, 0=out (for non-ctrl) */
1010
};
1111

12-
/* Probe + bring-up a single xHCI controller on a given PCI function. */
13-
int xhci_probe_and_init(uint8_t bus, uint8_t dev, uint8_t func);
14-
15-
/* Submit a control transfer on EP0.
16-
setup must be 8 bytes (bmRequestType,bRequest,wValue,wIndex,wLength).
17-
If data_dir_in=1, data points to IN buffer; else it points to OUT buffer.
18-
Returns 0 on success; negative on error. */
19-
int xhci_ctrl_xfer(struct usb_dev *ud, const uint8_t *setup,
20-
void *data, uint16_t len, int data_dir_in);
21-
22-
/* Arm a persistent interrupt-IN transfer for HID (8-byte reports typical).
23-
The buffer must be DMA-safe and 64-byte aligned. On each completion,
24-
the host driver calls the provided callback with the filled data. */
25-
typedef void (*xhci_int_in_cb)(struct usb_dev *ud, const uint8_t *pkt, uint16_t len);
26-
int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb);
27-
28-
void init_usb_xhci(void);
29-
3012
/* ============================================================
3113
* xHCI — interrupt-driven (legacy INTx), single-controller v0
3214
* HID class runs without polling; commands are polled for v0.
@@ -120,9 +102,11 @@ void init_usb_xhci(void);
120102
#define XHCI_OP_USBCMD 0x00
121103
#define XHCI_OP_USBSTS 0x04
122104

123-
124105
#define XHCI_DNCTRL 0x14
125106

107+
/* Toggle Cycle (TC) for Link TRBs (matches xHCI spec & libpayload usage) */
108+
#define TRB_TOGGLE (1u << 1)
109+
126110
/* helper macros to build TRB fields */
127111
#define TRB_SET_TYPE(x) ((uint32_t)((x) & 0x3Fu) << 10)
128112

@@ -174,6 +158,11 @@ struct input_ctx {
174158
struct ep_ctx ep1_in;
175159
} __attribute__((packed, aligned(64)));
176160

161+
/* Arm a persistent interrupt-IN transfer for HID (8-byte reports typical).
162+
The buffer must be DMA-safe and 64-byte aligned. On each completion,
163+
the host driver calls the provided callback with the filled data. */
164+
typedef void (*xhci_int_in_cb)(struct usb_dev *ud, const uint8_t *pkt, uint16_t len);
165+
177166
struct xhci_hc {
178167
/* mmio bases */
179168
volatile uint8_t *cap;
@@ -235,3 +224,16 @@ struct xhci_hc {
235224
uint8_t irq_pin;
236225
};
237226

227+
228+
/* Probe + bring-up a single xHCI controller on a given PCI function. */
229+
int xhci_probe_and_init(uint8_t bus, uint8_t dev, uint8_t func);
230+
231+
/* Submit a control transfer on EP0.
232+
setup must be 8 bytes (bmRequestType,bRequest,wValue,wIndex,wLength).
233+
If data_dir_in=1, data points to IN buffer; else it points to OUT buffer.
234+
Returns 0 on success; negative on error. */
235+
int xhci_ctrl_xfer(struct usb_dev *ud, const uint8_t *setup, void *data, uint16_t len, int data_dir_in);
236+
237+
int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb);
238+
239+
void init_usb_xhci(void);

src/usb/xhci.c

Lines changed: 79 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
static struct xhci_hc* g_xhci; /* single controller */
77

8-
/* ring_init with debug */
8+
/* ring_init with debug — set Toggle Cycle (TC) like libpayload */
99
static void ring_init(struct xhci_ring *r, size_t bytes, uint64_t phys, void *virt) {
1010
dprintf("xhci.dbg: ring_init bytes=%u phys=%llx virt=%llx\n",
1111
(unsigned)bytes, (unsigned long long)phys, (unsigned long long)(uintptr_t)virt);
@@ -17,12 +17,12 @@ static void ring_init(struct xhci_ring *r, size_t bytes, uint64_t phys, void *vi
1717
r->cycle = 1;
1818
memset(r->base, 0, bytes);
1919

20-
/* terminal link TRB */
20+
/* terminal link TRB: point to start, set TC=1, set C=1 (producer PCS) */
2121
struct trb *link = &r->base[r->num_trbs - 1];
2222
link->lo = (uint32_t) (r->phys & 0xFFFFFFFFu);
2323
link->hi = (uint32_t) (r->phys >> 32);
2424
link->sts = 0;
25-
link->ctrl = TRB_SET_TYPE(TRB_LINK) | TRB_CYCLE;
25+
link->ctrl = TRB_SET_TYPE(TRB_LINK) | TRB_TOGGLE | TRB_CYCLE;
2626

2727
dprintf("xhci.dbg: TRBs=%u link_trb@%u lo=%08x hi=%08x ctrl=%08x\n",
2828
r->num_trbs, r->num_trbs - 1, link->lo, link->hi, link->ctrl);
@@ -765,7 +765,7 @@ static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
765765
volatile uint8_t *ir0 = hc->rt + XHCI_RT_IR0;
766766
dprintf("xhci int\n");
767767

768-
/* Service all posted events. DO NOT set EHB here; keep it clear on exit. */
768+
/* Service all posted events. Keep EHB clear on exit. */
769769
uint64_t erdp_cur = mmio_read64(ir0 + IR_ERDP) & ~0x7ull;
770770

771771
for (uint32_t i = 0; i < hc->evt.num_trbs; i++) {
@@ -777,19 +777,29 @@ static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
777777
i, type, e->lo, e->hi, e->sts);
778778

779779
if (type == TRB_TRANSFER_EVENT) {
780-
/* Asynchronous: INT-IN only in this driver */
781-
if (hc->dev.int_cb && hc->dev.int_buf && hc->dev.int_pkt_len) {
780+
/* Identify our EP1-IN transfer by TRB pointer range (robust & simple) */
781+
uint64_t trb_ptr = ((uint64_t)e->hi << 32) | e->lo;
782+
uint64_t ring_lo = hc->dev.int_in_tr.phys;
783+
uint64_t ring_hi = ring_lo + 4096; /* one 4K segment */
784+
785+
if (hc->dev.int_buf && hc->dev.int_pkt_len &&
786+
trb_ptr >= ring_lo && trb_ptr < ring_hi) {
787+
788+
/* Length actually transferred is in EVTL (DW2[23:0]) */
789+
uint32_t evtl = (e->sts & 0x00FFFFFFu);
790+
782791
struct usb_dev ud = {0};
783792
ud.hc = hc;
784793
ud.slot_id = hc->dev.slot_id;
785-
hc->dev.int_cb(&ud, hc->dev.int_buf, hc->dev.int_pkt_len);
786794

787-
/* Re-arm EP1 IN (IOC|ISP) */
795+
hc->dev.int_cb(&ud, hc->dev.int_buf, (uint16_t)evtl);
796+
797+
/* Re-arm exactly one INT-IN TRB (IOC|ISP) */
788798
struct trb *n = ring_push(&hc->dev.int_in_tr);
789-
n->lo = (uint32_t)(hc->dev.int_buf_phys & 0xFFFFFFFFu);
790-
n->hi = (uint32_t)(hc->dev.int_buf_phys >> 32);
791-
n->sts = hc->dev.int_pkt_len;
792-
n->ctrl = TRB_SET_TYPE(TRB_NORMAL) | TRB_IOC | TRB_ISP |
799+
n->lo = (uint32_t)(hc->dev.int_buf_phys & 0xFFFFFFFFu);
800+
n->hi = (uint32_t)(hc->dev.int_buf_phys >> 32);
801+
n->sts = hc->dev.int_pkt_len;
802+
n->ctrl = TRB_SET_TYPE(TRB_NORMAL) | TRB_ISP | TRB_IOC |
793803
(hc->dev.int_in_tr.cycle ? TRB_CYCLE : 0);
794804

795805
mmio_write32(hc->db + 4u * hc->dev.slot_id, EPID_EP1_IN);
@@ -823,13 +833,13 @@ int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb) {
823833
struct xhci_hc *hc = (struct xhci_hc *) ud->hc;
824834

825835
/* Use discovered INT-IN from config (fallbacks retained). */
826-
uint8_t ep_num = hc->dev.int_ep_num ? hc->dev.int_ep_num : 1;
827-
uint16_t ep_mps = hc->dev.int_ep_mps ? hc->dev.int_ep_mps : 8;
828-
uint8_t ep_bInterval= hc->dev.int_ep_interval ? hc->dev.int_ep_interval : 1;
836+
uint8_t ep_num = hc->dev.int_ep_num ? hc->dev.int_ep_num : 1;
837+
uint16_t ep_mps = hc->dev.int_ep_mps ? hc->dev.int_ep_mps : 8;
838+
uint8_t ep_bInterval = hc->dev.int_ep_interval ? hc->dev.int_ep_interval : 1;
829839

830-
/* We currently only carry an input context slot for EP1 IN. Bail if not EP1 IN. */
840+
/* Only EP1 IN is supported in this driver (EPID==3). */
831841
if (ep_num != 1) {
832-
uint8_t epid = (uint8_t)(2u * ep_num + 1u); /* IN => odd EPID */
842+
uint8_t epid = (uint8_t)(2u * ep_num + 1u);
833843
dprintf("xhci.dbg: WARNING: device INT-IN at EP%u (EPID=%u), driver only supports EP1 IN; not arming.\n",
834844
ep_num, epid);
835845
return 0;
@@ -838,12 +848,12 @@ int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb) {
838848
/* Ensure TR for EP1 IN */
839849
if (!hc->dev.int_in_tr.base) {
840850
void *v = kmalloc_aligned(4096, 4096);
841-
uint64_t p = (uint64_t)(uintptr_t) v;
842-
dprintf("xhci.dbg: INT-IN TR alloc v=%p phys=%lx\n", v, p);
843851
if (!v) {
844852
dprintf("xhci.dbg: INT-IN TR alloc fail\n");
845853
return 0;
846854
}
855+
uint64_t p = (uint64_t)(uintptr_t)v;
856+
dprintf("xhci.dbg: INT-IN TR alloc v=%p phys=%lx\n", v, p);
847857
ring_init(&hc->dev.int_in_tr, 4096, p, v);
848858
dprintf("xhci.dbg: INT-IN TR init base=%p phys=%lx cycle=%u\n",
849859
hc->dev.int_in_tr.base, hc->dev.int_in_tr.phys,
@@ -880,70 +890,75 @@ int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb) {
880890
/* Copy current Device Slot Context -> Input Slot Context; set CE=3. */
881891
{
882892
uint64_t dphys = hc->dcbaa[ud->slot_id];
883-
volatile uint32_t *dcs = (volatile uint32_t *)(uintptr_t)dphys; /* device slot ctx (8 dwords) */
884-
volatile uint32_t *isc = (volatile uint32_t *)&hc->dev.ic->slot; /* input slot ctx (8 dwords) */
885-
for (int k = 0; k < 8; k++) {
886-
isc[k] = dcs[k];
887-
}
893+
volatile uint32_t *dcs = (volatile uint32_t *)(uintptr_t)dphys; /* device slot ctx (8 dwords) */
894+
volatile uint32_t *isc = (volatile uint32_t *)&hc->dev.ic->slot; /* input slot ctx (8 dwords) */
895+
for (int k = 0; k < 8; k++) isc[k] = dcs[k];
888896
/* CE = highest context ID present (3 => EP1 IN included) */
889897
isc[0] = (isc[0] & ~(0x1Fu << 27)) | (3u << 27);
890898
dprintf("xhci.dbg: slot.dword0(copy+CE)=%08x (CE=%u)\n",
891899
isc[0], (unsigned)((isc[0] >> 27) & 0x1F));
892900
}
893901

894-
/* -------- Interval encoding per xHCI --------
895-
* For SS and HS Interrupt endpoints, the Endpoint Context 'Interval' is (bInterval - 1)
896-
* in 125us units (exponent encoding). For FS/LS Interrupt endpoints, 'Interval' is
897-
* the bInterval in frames (no -1).
902+
/* -------- Interval encoding per xHCI (libpayload semantics) --------
903+
* HS/SS: INTVAL = bInterval - 1 (units: 125 µs exponent)
904+
* FS/LS: INTVAL = bInterval (units: frames)
905+
* Bound the value like libpayload for FS/LS interrupt endpoints.
898906
*/
899-
uint32_t interval_field = 1;
907+
uint32_t intval = 1;
900908
{
901-
/* speed was recorded in Slot Context dword2[3:0] by your enumerate path */
902-
uint32_t s0 = hc->dev.ic->slot.dword2 & 0xF;
903-
/* 1: Full, 2: Low, 3: High, 4: SuperSpeed (values vary by impl; you logged 'speed=3' earlier for SS) */
904-
uint8_t speed_code = (uint8_t)s0;
909+
/* speed code was captured in Slot Context dword2[3:0] during enumerate */
910+
uint8_t speed_code = (uint8_t)(hc->dev.ic->slot.dword2 & 0xF);
905911

906912
if (speed_code >= 3) {
907-
/* HS/SS: exponent encoding. Guard against bInterval==0. */
908-
uint8_t bI = (ep_bInterval ? ep_bInterval : 1);
909-
interval_field = (bI > 0 ? (uint32_t)(bI - 1) : 0u);
913+
/* High/Super speed */
914+
uint8_t bI = ep_bInterval ? ep_bInterval : 1;
915+
intval = (bI > 0) ? (uint32_t)(bI - 1) : 0u;
910916
} else {
911-
/* FS/LS: frames; program as-is (minimum 1). */
912-
interval_field = (ep_bInterval ? ep_bInterval : 1);
917+
/* Full/Low speed */
918+
intval = ep_bInterval ? ep_bInterval : 1;
919+
if (intval < 3) intval = 3;
920+
else if (intval > 11) intval = 11;
913921
}
922+
if (intval > 15) intval = 15;
914923
}
915924

916-
/* Program EP1 IN context */
925+
/* Program EP1 IN context — field placement matches libpayload:
926+
* DW0: CErr=3
927+
* DW1: [31:16] MaxPacketSize, [15:8] Interval, [5:3] EPType (=7 Interrupt IN)
928+
* TR Dequeue: ring phys | DCS
929+
* DW4: AvgTRB Length (31:16), Max ESIT Payload (15:0)
930+
*/
917931
memset(&hc->dev.ic->ep1_in, 0, sizeof(hc->dev.ic->ep1_in));
918-
919-
/* dword0: EP State=0 (Disabled), CErr=3 */
920932
hc->dev.ic->ep1_in.dword0 = (3u << 1);
921933

922-
/* dword1: Max Packet Size (31:16) | EP Type (10:8 = 7 Interrupt IN) | Interval (7:0) */
923-
hc->dev.ic->ep1_in.dword1 = ((uint32_t)ep_mps << 16) | (7u << 8) | (interval_field & 0xFFu);
934+
hc->dev.ic->ep1_in.dword1 =
935+
((uint32_t)ep_mps << 16) |
936+
((intval & 0xFFu) << 8) |
937+
(7u << 3); /* EPType = 7 (Interrupt IN) in bits [5:3] */
924938

925-
/* TR Dequeue (DCS=1) */
926-
hc->dev.ic->ep1_in.deq = (hc->dev.int_in_tr.phys | 1u);
939+
hc->dev.ic->ep1_in.deq = (hc->dev.int_in_tr.phys | 1u);
927940

928-
/* dword4: Avg TRB Len (31:16) | Max ESIT Payload (15:0) — use pkt_len as both (8 for boot kbd) */
929-
hc->dev.ic->ep1_in.dword4 = ((uint32_t)pkt_len << 16) | (uint32_t)pkt_len;
941+
{
942+
uint32_t avg_trb_len = 1024; /* libpayload uses 1024 for INT */
943+
uint32_t max_esit = ep_mps; /* MPS * MBS (MBS defaults to 1 for HID) */
944+
hc->dev.ic->ep1_in.dword4 = (avg_trb_len << 16) | max_esit;
945+
}
930946

931947
{
932948
const uint32_t *epd = (const uint32_t *)&hc->dev.ic->ep1_in;
933-
dprintf("xhci.dbg: EP1 IN ctx dwords: %08x %08x %08x %08x | %08x %08x %08x %08x (mps=%u bInterval=%u -> interval=%u)\n",
949+
dprintf("xhci.dbg: EP1 IN ctx dwords: %08x %08x %08x %08x | %08x %08x %08x %08x (mps=%u bInterval=%u -> intval=%u)\n",
934950
epd[0], epd[1], epd[2], epd[3], epd[4], epd[5], epd[6], epd[7],
935-
ep_mps, ep_bInterval, (unsigned)interval_field);
951+
ep_mps, ep_bInterval, (unsigned)intval);
936952
}
937953

938954
dprintf("xhci.dbg: CONFIGURE_EP add_flags=%08x slot.dword0=%08x (CE=%u)\n",
939-
hc->dev.ic->add_flags,
940-
hc->dev.ic->slot.dword0,
955+
hc->dev.ic->add_flags, hc->dev.ic->slot.dword0,
941956
(hc->dev.ic->slot.dword0 >> 27) & 0x1F);
942957

943958
/* Issue Configure Endpoint (add EP1 IN) */
944959
struct trb *ce = xhci_cmd_begin(hc);
945-
ce->lo = (uint32_t)(hc->dev.ic_phys & 0xFFFFFFFFu);
946-
ce->hi = (uint32_t)(hc->dev.ic_phys >> 32);
960+
ce->lo = (uint32_t)(hc->dev.ic_phys & 0xFFFFFFFFu);
961+
ce->hi = (uint32_t)(hc->dev.ic_phys >> 32);
947962
ce->ctrl |= TRB_SET_TYPE(TRB_CONFIGURE_EP) | ((uint32_t)ud->slot_id << 24);
948963
dprintf("xhci.dbg: ring_push for CONFIGURE_EP trb=%08x ic_phys_lo=%08x ic_phys_hi=%08x ctrl=%08x slot=%u\n",
949964
(uint32_t)(uintptr_t)ce,
@@ -957,99 +972,41 @@ int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb) {
957972
}
958973
dprintf("xhci.dbg: CONFIGURE_EP success\n");
959974

960-
/* Post first INT-IN Normal TRB and doorbell EP1 IN.
961-
Use TRB_ISP so short reports complete reliably. */
962-
struct trb *n = ring_push(&hc->dev.int_in_tr);
963-
n->lo = (uint32_t)(hc->dev.int_buf_phys & 0xFFFFFFFFu);
964-
n->hi = (uint32_t)(hc->dev.int_buf_phys >> 32);
965-
n->sts = hc->dev.int_pkt_len;
966-
n->ctrl = TRB_SET_TYPE(TRB_NORMAL) | TRB_IOC | TRB_ISP |
967-
(hc->dev.int_in_tr.cycle ? TRB_CYCLE : 0);
968-
dprintf("xhci.dbg: INT-IN normal TRB @%08x lo=%08x hi=%08x len=%u ctrl=%08x cycle=%u\n",
969-
(uint32_t)(uintptr_t)n, n->lo, n->hi, n->sts, n->ctrl,
970-
(unsigned)hc->dev.int_in_tr.cycle);
971-
972-
mmio_write32(hc->db + 4u * ud->slot_id, EPID_EP1_IN);
973-
dprintf("xhci.dbg: doorbell EP1 IN (slot=%u) tr.phys=%lx buf.phys=%lx\n",
974-
ud->slot_id, hc->dev.int_in_tr.phys, hc->dev.int_buf_phys);
975-
976-
{
977-
uint64_t dphys = hc->dcbaa[ud->slot_id];
978-
volatile uint32_t *dc = (volatile uint32_t *)(uintptr_t)dphys;
979-
980-
/* 32-byte contexts => 8 dwords per context */
981-
const size_t stride = 8;
982-
983-
volatile uint32_t *d_slot = dc + 0*stride; /* Slot Context */
984-
volatile uint32_t *d_ep1in = dc + 3*stride; /* EP1 IN (ID 3) */
985-
986-
uint32_t ep_state = d_ep1in[0] & 0x7; /* Endpoint State */
987-
uint32_t ep_type = (d_ep1in[1] >> 3) & 0x7; /* 7 = Intr IN */
988-
uint32_t ep_mps = (d_ep1in[1] >> 16) & 0xFFFF; /* Max Packet Size */
989-
uint32_t ep_intvl = d_ep1in[1] & 0xFF; /* Interval (xHCI-encoded) */
990-
uint32_t avg_len = (d_ep1in[4] >> 16) & 0xFFFF;
991-
uint32_t max_esit = d_ep1in[4] & 0xFFFF;
992-
993-
dprintf("xhci.dbg: DEV CTX @%lx\n", (unsigned long)dphys);
994-
dprintf("xhci.dbg: D-SLOT ctx: %08x %08x %08x %08x | %08x %08x %08x %08x\n",
995-
d_slot[0], d_slot[1], d_slot[2], d_slot[3], d_slot[4], d_slot[5], d_slot[6], d_slot[7]);
996-
dprintf("xhci.dbg: D-EP1IN ctx: %08x %08x %08x %08x | %08x %08x %08x %08x\n",
997-
d_ep1in[0], d_ep1in[1], d_ep1in[2], d_ep1in[3],
998-
d_ep1in[4], d_ep1in[5], d_ep1in[6], d_ep1in[7]);
999-
dprintf("xhci.dbg: EP1-IN decoded: state=%u (0=Disabled,1=Running,2=Halted,3=Stopped,4=Error) "
1000-
"type=%u mps=%u interval=%u TRDP=%08x%08x avg=%u max_esit=%u\n",
1001-
ep_state, ep_type, ep_mps, ep_intvl, d_ep1in[3], (d_ep1in[2] & ~1u), avg_len, max_esit);
1002-
}
1003-
1004-
/* after ringing EP1 IN doorbell */
1005-
{
1006-
/* read the EP1-IN dequeue pointer back */
1007-
uint64_t dphys = hc->dcbaa[ud->slot_id];
1008-
volatile uint32_t *dc = (volatile uint32_t *)(uintptr_t)dphys;
1009-
volatile uint32_t *d_ep1in = dc + 3*8; /* 32B contexts -> 8 dwords stride */
1010-
1011-
dprintf("xhci.dbg: EP1-IN TRDP now=%08x%08x (expect ~%08x%08x while first TD outstanding)\n",
1012-
d_ep1in[3], (d_ep1in[2] & ~1u),
1013-
(uint32_t)((hc->dev.int_in_tr.phys + 0) >> 32),
1014-
(uint32_t)(hc->dev.int_in_tr.phys & ~1u));
975+
/* Pre-post two INT-IN TRBs (IOC|ISP) and ring once (libpayload style) */
976+
for (int k = 0; k < 2; ++k) {
977+
struct trb *n = ring_push(&hc->dev.int_in_tr);
978+
n->lo = (uint32_t)(hc->dev.int_buf_phys & 0xFFFFFFFFu);
979+
n->hi = (uint32_t)(hc->dev.int_buf_phys >> 32);
980+
n->sts = hc->dev.int_pkt_len;
981+
n->ctrl = TRB_SET_TYPE(TRB_NORMAL) | TRB_ISP | TRB_IOC |
982+
(hc->dev.int_in_tr.cycle ? TRB_CYCLE : 0);
1015983
}
1016-
1017984
mmio_write32(hc->db + 4u * ud->slot_id, EPID_EP1_IN);
1018-
dprintf("xhci.dbg: doorbell EP1 IN (slot=%u) tr.phys=%lx buf.phys=%lx\n",
985+
dprintf("xhci.dbg: doorbell EP1 IN (slot=%u) tr.phys=%lx buf.phys=%lx (prepost=2)\n",
1019986
ud->slot_id, hc->dev.int_in_tr.phys, hc->dev.int_buf_phys);
1020987

988+
/* Steady-state: moderation 0, clear EHB & IP, enable IE and INTE */
1021989
{
1022990
volatile uint8_t *ir0 = hc->rt + XHCI_RT_IR0;
1023991

1024-
/* 1) Make moderation a non-issue (fire immediately) */
1025992
mmio_write32(ir0 + IR_IMOD, 0);
1026993

1027-
/* 2) Clear any stale summary bit and IP, then (re)enable IE */
1028994
uint32_t sts = mmio_read32(hc->op + XHCI_USBSTS);
1029995
if (sts & USBSTS_EINT) mmio_write32(hc->op + XHCI_USBSTS, USBSTS_EINT);
1030996

1031997
uint32_t iman = mmio_read32(ir0 + IR_IMAN);
1032998
if (iman & IR_IMAN_IP) mmio_write32(ir0 + IR_IMAN, IR_IMAN_IP); /* W1C IP */
1033999
mmio_write32(ir0 + IR_IMAN, (mmio_read32(ir0 + IR_IMAN) | IR_IMAN_IE));
10341000

1035-
/* 3) Ensure EHB is CLEAR in steady state */
10361001
uint64_t erdp = mmio_read64(ir0 + IR_ERDP) & ~0x7ull;
1037-
mmio_write64(ir0 + IR_ERDP, erdp); /* bit3=0 => EHB clear */
1002+
mmio_write64(ir0 + IR_ERDP, erdp); /* EHB clear */
10381003

1039-
/* 4) Also ensure global INTE is on */
10401004
uint32_t cmd = mmio_read32(hc->op + XHCI_USBCMD) | USBCMD_INTE;
10411005
mmio_write32(hc->op + XHCI_USBCMD, cmd);
10421006

10431007
xhci_irq_sanity_dump(hc, "post-arm");
10441008
}
10451009

1046-
/*
1047-
mmio_write32(hc->db + 4u * ud->slot_id, EPID_EP1_IN);
1048-
dprintf("xhci.dbg: doorbell EP1 IN (slot=%u) tr.phys=%lx buf.phys=%lx\n",
1049-
ud->slot_id, hc->dev.int_in_tr.phys, hc->dev.int_buf_phys);
1050-
xhci_wait_for_any_transfer_event(hc, 60000, "ep1-in verify");
1051-
*/
1052-
10531010
return 1;
10541011
}
10551012

0 commit comments

Comments
 (0)