diff options
| author | HiFiPHile <[email protected]> | 2026-08-19 05:06:04 +0200 |
|---|---|---|
| committer | HiFiPHile <[email protected]> | 2026-08-19 05:06:04 +0200 |
| commit | f065f280284a6f1b5b4c4d2849db4bff4a3ce70c (patch) | |
| tree | 7ca5519f9001b263dac05aab8b13228573f0c803 /src | |
| parent | 18bb2d650404432d0c6c61c26e98c7074f46ec6b (diff) | |
ohci: defer descriptor reclaim until next frame
Diffstat (limited to 'src')
| -rw-r--r-- | src/portable/ohci/ohci.c | 11 | ||||
| -rw-r--r-- | src/portable/ohci/ohci.h | 1 |
2 files changed, 9 insertions, 3 deletions
diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 7ede1ac72..2a174e46c 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -390,6 +390,9 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) { // Control endpoints (EP number 0) are statically allocated with the device which are only reused // after connection of another device long after HC has finished with them now, these can be freed immediately. if (ed->w0.ep_number != 0) { + // Wait until the next frame before reclaiming the ED and its TDs. Set the deadline before + // publishing is_reclaiming so a pending SOF IRQ cannot use an older deadline for this ED. + ohci_data.reclaim_frame = (uint16_t)(OHCI_REG->frame_number + 1); ed->w0.is_reclaiming = 1; // 5.2.7.1.2 Removing. Disable list processing for bulk @@ -397,7 +400,8 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr) { OHCI_REG->control &= ~OHCI_CONTROL_LIST_BULK_ENABLE_MASK; } - // Temporarily enable SOF IRQ. ED and TD Memory will be reclaimed in the SOF IRQ. + // Temporarily enable SOF IRQ. Clear any pending SOF first to wait for the next frame. + OHCI_REG->interrupt_status = OHCI_INT_SOF_MASK; OHCI_REG->interrupt_enable = OHCI_INT_SOF_MASK; } else { ed->w0.used = 0; @@ -665,8 +669,9 @@ void hcd_int_handler(uint8_t hostid, bool in_isr) { // Disable MIE as per OHCI spec 5.3 OHCI_REG->interrupt_disable = OHCI_INT_MASTER_ENABLE_MASK; - // Start of frame (SOF) - if (int_status & OHCI_INT_SOF_MASK) { + // Start of frame (SOF). Signed subtraction handles frame number rollover and delayed interrupts. + if ((int_status & OHCI_INT_SOF_MASK) && + ((int16_t)((uint16_t)OHCI_REG->frame_number - ohci_data.reclaim_frame) >= 0)) { OHCI_REG->interrupt_disable = OHCI_INT_SOF_MASK; bool re_enable_lists = false; diff --git a/src/portable/ohci/ohci.h b/src/portable/ohci/ohci.h index c66954502..e28c6404f 100644 --- a/src/portable/ohci/ohci.h +++ b/src/portable/ohci/ohci.h @@ -183,6 +183,7 @@ typedef struct TU_ATTR_ALIGNED(256) { gtd_extra_data_t gtd_extra[GTD_MAX]; volatile uint16_t frame_number_hi; + volatile uint16_t reclaim_frame; } ohci_data_t; //--------------------------------------------------------------------+ |
