Skip to content

Commit 74137fc

Browse files
prevent double re-arm
1 parent 7e5f26e commit 74137fc

File tree

4 files changed

+92
-22
lines changed

4 files changed

+92
-22
lines changed

include/usb_xhci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ struct xhci_ring {
129129
uint32_t num_trbs; /* 256 for a 4K page */
130130
uint32_t enqueue; /* index */
131131
uint32_t cycle; /* 0/1 */
132+
132133
};
133134

134135
struct ep_ctx {

src/kernel.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ void kmain()
2323
preboot_fail("Failed to mount boot drive to VFS!");
2424
}
2525

26-
/*usb_core_init();
26+
usb_core_init();
2727
usb_hid_init();
28-
init_usb_xhci()*/
28+
init_usb_xhci();
2929

3030
init_process();
3131
}

src/usb/hid.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,14 @@ static void process_mod_changes(uint8_t prev_mod, uint8_t cur_mod)
149149
}
150150
}
151151

152+
static uint64_t ints;
153+
152154
static void hid_keyboard_report_cb(struct usb_dev *ud, const uint8_t *pkt, uint16_t len)
153155
{
154156
if (len < 8u) return;
155157

156-
dprintf("enter\n");
158+
dprintf("enter %lu\n", ints++);
159+
return;
157160

158161
/* disable HID’s built-in key repeat */
159162
if (memcmp(pkt, last_report, 8) == 0) {

src/usb/xhci.c

Lines changed: 85 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,41 @@ static inline uint8_t trb_get_slotid(const struct trb *e)
3535
return (uint8_t)(e->ctrl & 0xFF);
3636
}
3737

38+
/* === Event-ring consumer helpers (xHC produces; we only consume) === */
39+
40+
static inline struct trb *evt_cur(struct xhci_hc *hc)
41+
{
42+
return &hc->evt.base[hc->evt.enqueue];
43+
}
44+
45+
/* Is the next event TRB owned by software? (C-bit matches CCS/consumer cycle) */
46+
static inline int evt_has_ready(struct xhci_hc *hc)
47+
{
48+
const struct trb *e = evt_cur(hc);
49+
const uint32_t cbit = (e->ctrl & TRB_CYCLE) ? 1u : 0u;
50+
return (cbit == (hc->evt.cycle & 1u));
51+
}
52+
53+
/* Consume exactly one TRB and advance consumer cursor/cycle */
54+
static inline void evt_consume(struct xhci_hc *hc)
55+
{
56+
struct trb *e = evt_cur(hc);
57+
memset(e, 0, sizeof(*e)); /* optional but handy */
58+
hc->evt.enqueue++;
59+
if (hc->evt.enqueue == hc->evt.num_trbs) {
60+
hc->evt.enqueue = 0;
61+
hc->evt.cycle ^= 1u; /* toggle consumer cycle on wrap */
62+
}
63+
}
64+
65+
/* Program ERDP to the *next-to-consume* TRB, EHB clear (bit3=0) */
66+
static inline void evt_update_erdp(struct xhci_hc *hc)
67+
{
68+
volatile uint8_t *ir0 = hc->rt + XHCI_RT_IR0;
69+
uint64_t erdp = hc->evt.phys + ((uint64_t)hc->evt.enqueue * sizeof(struct trb));
70+
mmio_write64(ir0 + IR_ERDP, erdp); /* keep EHB clear in steady state */
71+
}
72+
3873
static void xhci_handle_unrelated_transfer_event(struct xhci_hc *hc, struct trb *e)
3974
{
4075
if (!hc || !e) return;
@@ -43,8 +78,7 @@ static void xhci_handle_unrelated_transfer_event(struct xhci_hc *hc, struct trb
4378
case TRB_TRANSFER_EVENT: {
4479
/* If this is our INT IN endpoint, deliver to HID and re-arm */
4580
uint8_t epid = trb_get_epid(e);
46-
if (epid == EPID_EP1_IN &&
47-
hc->dev.int_cb && hc->dev.int_buf && hc->dev.int_pkt_len) {
81+
if (epid == EPID_EP1_IN && hc->dev.int_cb && hc->dev.int_buf && hc->dev.int_pkt_len) {
4882
xhci_deliver_ep1in(hc, e, false);
4983
}
5084
break;
@@ -93,15 +127,45 @@ static void ring_init(struct xhci_ring *r, size_t bytes, uint64_t phys, void *vi
93127
dprintf("xhci.dbg: TRBs=%u link_trb@%u lo=%08x hi=%08x ctrl=%08x\n", r->num_trbs, r->num_trbs - 1, link->lo, link->hi, link->ctrl);
94128
}
95129

96-
/* ring_push with debug */
97-
static struct trb *ring_push(struct xhci_ring *r) {
98-
if (r->enqueue == r->num_trbs - 1) {
130+
// assumes: slot (last index) is pre-initialized as LINK TRB:
131+
// link->lo = ring_phys; // target
132+
// link->ctrl = TRB_SET_TYPE(TRB_LINK) | TRB_TOGGLE; // TC=1
133+
// r->cycle = 1; r->enqueue = 0;
134+
135+
static inline struct trb *ring_push(struct xhci_ring *r)
136+
{
137+
struct trb *cur = &r->base[r->enqueue];
138+
139+
// Ensure caller can set the C bit on the TRB they’re about to fill.
140+
// (Caller will set TRB_CYCLE according to r->cycle.)
141+
// Do NOT zero a LINK TRB.
142+
143+
// Advance the producer pointer
144+
r->enqueue++;
145+
dprintf("enqueue=%u num_trbs=%u\n", r->enqueue, r->num_trbs);
146+
147+
// If we landed on the LINK TRB, present it to HW and wrap
148+
if (r->enqueue == r->num_trbs) {
149+
dprintf("wrap LINK\n");
150+
struct trb *link = &r->base[r->num_trbs - 1];
151+
152+
// Set LINK’s C bit to current producer cycle
153+
link->ctrl = (link->ctrl & ~TRB_CYCLE) | (r->cycle ? TRB_CYCLE : 0);
154+
155+
// “Post” the LINK TRB by moving past it
99156
r->enqueue = 0;
100-
r->cycle ^= 1u;
157+
158+
// If LINK.TC=1, flip producer cycle bit
159+
if (link->ctrl & TRB_TOGGLE)
160+
r->cycle ^= 1u;
161+
162+
// Now cur becomes the first slot of the ring
163+
cur = &r->base[r->enqueue];
101164
}
102-
struct trb *t = &r->base[r->enqueue++];
103-
memset(t, 0, sizeof(*t));
104-
return t;
165+
166+
// Hand back the slot to be filled; clear only non-LINK slots
167+
memset(cur, 0, sizeof(*cur));
168+
return cur;
105169
}
106170

107171
static int xhci_cmd_submit_wait(struct xhci_hc *hc, struct trb *cmd_trb, uint64_t *out_cc_trb_lohi) {
@@ -340,10 +404,7 @@ static int xhci_reset_controller(struct xhci_hc *hc) {
340404
mmio_write32(ir0 + IR_IMOD, 0);
341405
mmio_write32(ir0 + IR_IMAN, IR_IMAN_IE);
342406

343-
dprintf("xhci.dbg: ERSTSZ=1 ERSTBA=%llx ERDP=%llx IMOD=64 IMAN=%08x\n",
344-
(unsigned long long)hc->erst_phys,
345-
(unsigned long long)(er_phys | (1ull << 3)),
346-
mmio_read32(ir0 + IR_IMAN));
407+
dprintf("xhci.dbg: ERSTSZ=1 ERSTBA=%lx ERDP=%lx IMOD=64 IMAN=%08x\n", hc->erst_phys, (uint64_t)(er_phys | (1ull << 3)), mmio_read32(ir0 + IR_IMAN));
347408

348409
/* CONFIG, RS+INTE */
349410
mmio_write32(hc->op + XHCI_CONFIG, hc->max_slots ? hc->max_slots : 8);
@@ -841,9 +902,11 @@ static void xhci_deliver_ep1in(struct xhci_hc *hc, const struct trb *e, bool del
841902
}
842903
}
843904

905+
static uint64_t xhci_ints;
906+
844907
static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
845908
{
846-
dprintf("xhci_isr\n");
909+
dprintf("xhci_isr %lu\n", xhci_ints++);
847910
struct xhci_hc *hc = (struct xhci_hc *)opaque;
848911
if (!hc || !hc->cap) return;
849912

@@ -873,11 +936,15 @@ static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
873936
/* Only deliver to HID for EP1-IN completions */
874937
if (epid == EPID_EP1_IN) {
875938
xhci_deliver_ep1in(hc, e, true);
939+
} else {
940+
/* Consume and advance ERDP by one TRB (leave EHB clear) */
941+
xhci_handle_unrelated_transfer_event(hc, e);
876942
}
943+
} else {
944+
/* Consume and advance ERDP by one TRB (leave EHB clear) */
945+
xhci_handle_unrelated_transfer_event(hc, e);
877946
}
878947

879-
/* Consume and advance ERDP by one TRB (leave EHB clear) */
880-
xhci_handle_unrelated_transfer_event(hc, e);
881948
memset(e, 0, sizeof(*e));
882949
erdp_cur = (erdp_cur + 16) & ~0x7ull;
883950
mmio_write64(ir0 + IR_ERDP, erdp_cur);
@@ -910,8 +977,7 @@ int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb) {
910977
/* Only EP1 IN is supported in this driver (EPID==3). */
911978
if (ep_num != 1) {
912979
uint8_t epid = (uint8_t)(2u * ep_num + 1u);
913-
dprintf("xhci.dbg: WARNING: device INT-IN at EP%u (EPID=%u), driver only supports EP1 IN; not arming.\n",
914-
ep_num, epid);
980+
dprintf("xhci.dbg: WARNING: device INT-IN at EP%u (EPID=%u), driver only supports EP1 IN; not arming.\n", ep_num, epid);
915981
return 0;
916982
}
917983

@@ -1059,7 +1125,7 @@ int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb) {
10591125
{
10601126
volatile uint8_t *ir0 = hc->rt + XHCI_RT_IR0;
10611127

1062-
mmio_write32(ir0 + IR_IMOD, 0);
1128+
mmio_write32(ir0 + IR_IMOD, 64);
10631129

10641130
uint32_t sts = mmio_read32(hc->op + XHCI_USBSTS);
10651131
if (sts & USBSTS_EINT) mmio_write32(hc->op + XHCI_USBSTS, USBSTS_EINT);

0 commit comments

Comments
 (0)