Skip to content

Commit 660c8ca

Browse files
committed
host abort transfer on short packet in double buffer.
1 parent 31ec5a7 commit 660c8ca

File tree

1 file changed

+31
-34
lines changed

1 file changed

+31
-34
lines changed

src/portable/raspberrypi/rp2040/rp2040_usb.c

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ void rp2usb_init(void) {
102102

103103
void __tusb_irq_path_func(rp2usb_reset_transfer)(hw_endpoint_t *ep) {
104104
ep->active = false;
105+
ep->pending = 0;
105106
ep->remaining_len = 0;
106107
ep->xferred_len = 0;
107108
ep->user_buf = 0;
@@ -172,9 +173,8 @@ uint16_t __tusb_irq_path_func(bufctrl_prepare16)(hw_endpoint_t *ep, uint8_t *dpr
172173
buf_ctrl |= USB_BUF_CTRL_FULL;
173174
}
174175

175-
// Is this the last buffer? Only really matters for host mode. Will trigger
176-
// the trans complete irq but also stop it polling. We only really care about
177-
// trans complete for setup packets being sent
176+
// Is this the last buffer? Will trigger the trans complete irq but also stop it polling.
177+
// This is used to detect setup packets being sent in host mode
178178
if (ep->remaining_len == 0) {
179179
buf_ctrl |= USB_BUF_CTRL_LAST;
180180
}
@@ -349,7 +349,7 @@ bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_
349349
uint8_t *dpram_buf = ep->dpram_buf;
350350
if (buf_id) {
351351
#if CFG_TUSB_RP2_ERRATA_E4
352-
if (!(is_host && !is_double)) // incorrect buf_id, buffer data is still buf0
352+
if (!(is_host && !is_double)) // E4 bug: incorrect buf_id, buffer data is still buf0
353353
#endif
354354
{
355355
dpram_buf += 64; // buf1 offset
@@ -370,54 +370,51 @@ bool __tusb_irq_path_func(rp2usb_xfer_continue)(hw_endpoint_t *ep, io_rw_32 *ep_
370370
// Note: Host mode current does not save next transfer data due to shared epx --> potential issue. However, RP2040-E4
371371
// causes more or less of the same issue since it write to buf1 and next time it continues to transfer on buf0 (stale)
372372
if (is_short && is_double && is_rx && !is_last) {
373-
#if CFG_TUH_ENABLED
373+
const uint32_t abort_bit = TU_BIT(tu_edpt_number(ep->ep_addr) << 1); // abort is device only -> IN endpoint
374+
374375
if (is_host) {
375-
// stop current transfer
376-
uint32_t sie_ctrl = usb_hw->sie_ctrl & SIE_CTRL_BASE_MASK;
377-
sie_ctrl |= USB_SIE_CTRL_STOP_TRANS_BITS;
376+
// host stop current transfer, not safe, can be racing
377+
const uint32_t sie_ctrl = (usb_hw->sie_ctrl & SIE_CTRL_BASE_MASK) | USB_SIE_CTRL_STOP_TRANS_BITS;
378378
usb_hw->sie_ctrl = sie_ctrl;
379-
// maybe wait until STOP_TRANS bit is clear
380-
381-
*buf_reg = 0; // reset buffer control
382-
}
383-
#endif
384-
385-
#if CFG_TUD_ENABLED
386-
if (!is_host) {
387-
io_rw_16 *buf_reg16_other = buf_reg16 + (buf_id ^ 1);
388-
const uint32_t abort_bit = TU_BIT(tu_edpt_number(ep->ep_addr) << 1); // IN endpoint
389-
390-
#if CFG_TUSB_RP2_ERRATA_E2
379+
while (usb_hw->sie_ctrl & USB_SIE_CTRL_STOP_TRANS_BITS) {}
380+
} else {
381+
// device abort current transfer
382+
#if CFG_TUSB_RP2_ERRATA_E2
391383
if (rp2040_chipversion >= 2)
392-
#endif
384+
#endif
393385
{
394386
usb_hw_set->abort = abort_bit;
395387
while ((usb_hw->abort_done & abort_bit) != abort_bit) {}
396388
}
389+
}
397390

398-
// After abort, check if the other buffer received valid data
399-
const uint16_t buf_ctrl16_other = *buf_reg16_other;
400-
if (buf_ctrl16_other & USB_BUF_CTRL_FULL) {
401-
// Host already sent data into this buffer (e.g. write payload right after short CBW).
402-
// Save it for the next transfer.
403-
ep->future_len = (uint8_t)(buf_ctrl16_other & USB_BUF_CTRL_LEN_MASK);
404-
ep->future_bufid = buf_id ^ 1;
405-
// buff_status will be clear by the next run
391+
// After abort, check if the other buffer received valid data
392+
io_rw_16 *buf_reg16_other = buf_reg16 + (buf_id ^ 1);
393+
const uint16_t buf_ctrl16_other = *buf_reg16_other;
394+
if (buf_ctrl16_other & USB_BUF_CTRL_FULL) {
395+
// Data already sent into this buffer. Save it for the next transfer.
396+
// buff_status will be clear by the next run
397+
if (is_host) {
398+
// host put future_len pointer at end of epx_data
406399
} else {
407-
ep->next_pid ^= 1u; // roll back pid if aborted
400+
ep->future_len = (uint8_t)(buf_ctrl16_other & USB_BUF_CTRL_LEN_MASK);
408401
}
402+
ep->future_bufid = buf_id ^ 1;
403+
} else {
404+
ep->next_pid ^= 1u; // roll back pid if aborted
405+
}
409406

410-
*buf_reg = 0; // reset buffer control
407+
*buf_reg = 0; // reset buffer control
411408

412-
#if CFG_TUSB_RP2_ERRATA_E2
409+
if (!is_host) {
410+
#if CFG_TUSB_RP2_ERRATA_E2
413411
if (rp2040_chipversion >= 2)
414-
#endif
412+
#endif
415413
{
416414
usb_hw_clear->abort_done = abort_bit;
417415
usb_hw_clear->abort = abort_bit;
418416
}
419417
}
420-
#endif
421418

422419
hw_endpoint_lock_update(ep, -1);
423420
return true;

0 commit comments

Comments
 (0)