For incoming ISO OUT packets it was possible to start
DMA from endpoint to RAM before transfer was started
resulting in unrelated memory corruption.
This is scenario that causes memory corruption:
- ISO OUT packet is received
- Packet is transferred by DMA to transfer buffer
- xfer->started is cleared and xfer->buffer is updated as
it is in every case
- Application takes to long to handle it (it happens when debugger
is connected breakpoint is hit slowing down software).
- Next ISO OUT packet arrives
At this point there was no check if transfer was started and packet
was copied by DMA to location beyond previous data, possibly overwriting
unrelated memory.
This solves the issue by checking that transfer was
started and there is buffer ready for incoming packet.
Ordering by element size prevents alignment holes, and as a consequence the
host mode version of the struct is the same size as device, as pad bytes at
the end are used instead.
Don't mark IN buffers as available during the last 200us of a full-speed
frame. This avoids a situation seen with the USB2.0 hub on a Raspberry
Pi 4 where a late IN token before the next full-speed SOF can cause port
babble and a corrupt ACK packet. The nature of the data corruption has a
chance to cause device lockup.
Use the next SOF to mark delayed buffers as available. This reduces
available Bulk IN bandwidth by approximately 20%, and requires that the
SOF interrupt is enabled while these transfers are ongoing.
Inherit the top-level enable from the corresponding Pico-SDK flag.
Applications that will not use the device in a situation where it could
be plugged into a Pi 4 or Pi 400 (for example, when directly connected
to a commodity hub or other host) can turn off the flag in the SDK.
v2: use a field in hw_endpoint to mark pending.
v3: Partial rewrite following review comments
- Stub functions out if the workaround is not required
- Only force-enable SOF while any vulnerable endpoints are active
- Respect dcd_sof_enable() functionality
- Get rid of all but necessary ifdef hackery
- Fix a bug where the "endpoint lock" was used with an uninitialised pointer.
The next change to the driver requires the export of these functions. Leave the
lock unimplemented for now.
Also move hw_set and hw_clear aliases into the top-level header file.