Open fjtrujy opened 2 months ago
There is a hardware issue in the USB OHCI controller, which causes problems when a certain transfer size is used for outbound flows. The normal version will do some workaround, while the "aligned" version does not (assumption: you provide an aligned memory buffer, which will thus not meet the condition for the hardware bug). For more details, you may need to refer to the official documentation.
Actually, I did try using the normal function and I recall it somewhat worked. But as Sony remarked, the internal workaround might result in issues with some devices. I recall that writes resulted in corruption on my SanDisk.
Therefore, writes were left to use the aligned variant.
There is a hardware issue in the USB OHCI controller, which causes problems when a certain transfer size is used for outbound flows. The normal version will do some workaround, while the "aligned" version does not (assumption: you provide an aligned memory buffer, which will thus not meet the condition for the hardware bug). For more details, you may need to refer to the official documentation.
Actually, I did try using the normal function and I recall it somewhat worked. But as Sony remarked, the internal workaround might result in issues with some devices. I recall that writes resulted in corruption on my SanDisk.
Therefore, writes were left to use the aligned variant.
Thanks for the reply.
Yes, I was aware of the issue too. You mean the sceUsbdOpenPipeAligned
vs sceUsbdOpenPipe
, right?
I tried to use the sceUsbdOpenPipe
as well and it also generated corrupted data in the USB 😢 .
So this is why I was thinking that the only solution here is to align the buffer before starting the copy, but the thing is, how to align it without losing too much performance and the best function to do it...
Some additional useful info:
Initial implementation was done here
Which uses UsbOpenEndpointAligned
for both IN/OUT in the iop/usb/usbhdfsd/src/usb_driver.c
file.
We changed to UsbOpenEndpoint
for both IN/OUT here with the next commit message:
(USBHDFSD) Changed sceUsbdOpenPipeAligned() to sceUsbdOpenPipe(), and removed code that breaks up long transfers (since they're too long to exceed on the IOP).
The change to sceUsbdOpenPipe() is to avoid triggering the driver's checks when the address is misaligned.
3. We changed back to`sceUsbdOpenPipeAligned` [here](https://github.com/ps2dev/ps2sdk/commit/dc093db473ec8e673d1c4b97ce4acae8fbac9153) just for OUT with the next commit message
(USBHDFSD) Added workaround for not 100%-compliant USB devices and fixed faulty logic for writing.
This last commit is more or less the current status we are using for current drivers in terms of READ/WRITES aligned.
@sp193 Do you think it is possible to use `UsbOpenEndpoint` for writing having in mind the "hardware" error about rounding 63 and 64 sector byte to 62, with some workaround? or do you think is better to try align somehow buffer before producing the writes?
Cheers.
I will add some more debugging info...
newlib
split writes in slices of 1024 bytes, so fileXioWrite
is called with 1024 bytes length, but the buffer is still unaligned.fileXio RPC
function aligns it to 64 bytes. To do this, it creates one extra buffer aligned with a size of 64 bytes max, and copies into that extra buffer the unaligned 64 bytes part. In my example it is 58 bytes misaligned to 64 bytes, so this extra buffer has filled 58 bytes.fileXio_Write_RPC
), 2 write executions are produced, first using the extra buffer that contains 58 bytes, so it produces a write of 58 bytes, and everything goes well.FatFS
library. On the function f_write
from iop/fs/bdmfs_fatfs/src/ff.c
it performs some logic and sees that in order to write 966 bytes, it is going to execute 2 different write calls, 454 bytes + 512 bytes, (I suppose it tries to perform writes always with 512 bytes). Then it does first the 512-byte write calls, which means adding an offset of 454 bytes to the original aligned buffer (in my example, for instance, is 0x51b00
+ 454 it is 0x51cc6
) producing the unaligned buffer, the one that is always failing.From here I conclude that is possible to have also the same issue having an aligned buffer (even 64 bytes aligned) and producing concrete write length. I will check it...
The payload size restriction of 63 or 64 bytes, refers to the USB frame size (not your request length). Sony wrote that sceUsbdOpenPipe() will internally do some workaround to limit the frame size to 62 bytes. However, this workaround seems to cause corruption with certain USB disks. Therefore, I do not think you can do anything about this, as the only workarounds are already documented by Sony. Only the outbound flow is affected (inbound is not affected).
In my opinion, you could make some assumptions and declare some limitations. The PlayStation 2 was from an era where you needed to meet some requirements to get optimal performance, so having and living with documented limitations seems to be perfectly normal to me. Sony even split apart the I/O documentation for each device, rather than documenting I/O functions for general use.
Not all DMA channels could work with unaligned pointers, so this is probably not the only device that will require some copying.
If you want to have a middle-ground, I think you can attempt to design something like what you have found in the RPC code. If I recall right, it works something like this. Please check.
Where N is the amount needed to align the buffer.
Something like this strategy is also present in memcpy, if I remember right.
👋 I have been facing some issues with USB drivers when using
fwrite
from unaligned 4-byte buffers... Given the next example:It works as expected, however, if we replace
unsigned char *dummy_content_offset = dummy_content
withunsigned char *dummy_content_offset = dummy_content + 6
to force having an offset, it fails due to alignment issues on the USB driver.Compiling
PS2SDK
withDEBUG=1
we can have some extra information.Without
offset
:With
offset
:If you see, we start to suffer errors likes this one:
Where
bulk data transfer 262
262=0x106
which isfrom
iop/usb/usbd/include/usbd.h
Official documentation for FatFs - Generic FAT Filesystem Module mentioned in the
dread
anddwrite
information about possible alignment issues: http://elm-chan.org/fsw/ff/doc/dread.html http://elm-chan.org/fsw/ff/doc/dwrite.htmlThis is something that I actually see reflected on the execution... Let's follow the callback functions:
Buffer is aligned till it reaches the
iop/fs/bdmfs_fatfs/src/ff.c ==> f_write
function where it plays with buffer index, producing already an unaligned buffer. Is important to mention that code fromf_write
belong tofsw
library. So, why it is failing? It fails because on thesceUsbdTransferPipe
we have the next condition:If you see it check if data is aligned with
((u32)data & 3))
, but it only check it if theep->alignFlag
is different that0
.This flag is set when registering the endpoints
We generate 2 different endpoint, one for reading from USB (INPUT), and another one for writing (
OUTPUT
).If we see how this is done is through the function
usb_bulk_probeEndpoint
iniop/usb/usbmass_bd/src/usb_mass.c
If you take a look it uses
sceUsbdOpenPipeAligned
forUSB_DIR_OUT
. ThesceUsbdOpenPipeAligned
is the one that set thealignFlag = 1
, which triggers the condition that fails later on theiop/usb/usbd/src/interface.c ==> sceUsbdTransferPipe
.I don't know how to fix it as I don't have enough experience with drivers at that low level... however, I hope all this information is useful for you...
Pinging @sp193 @rickgaiser @davidgfnet @uyjulian as I know you have experience with these kinds of things.
Cheers.