[RTEMS Project] #4981: Overwork Flashdev
RTEMS trac
trac at rtems.org
Thu Dec 28 16:01:07 UTC 2023
#4981: Overwork Flashdev
-----------------------------+--------------------
Reporter: Bernd Moessner | Owner: (none)
Type: defect | Status: new
Priority: normal | Milestone:
Component: admin | Version: 6
Severity: normal | Keywords:
Blocked By: | Blocking:
-----------------------------+--------------------
Hi, Aaron Nyholm has added a nice flashdev API this year. I wanted to put
LittleFS on top of this API and encountered some difficulties / found some
bugs / have some open questions / would like to make some breaking API
changes. Therefore, I hope that Aaron can comment.
1. C++ include guards are missing in flashdev.h
2. The switch case in flashdev.c => rtems_flashdev_ioctl is missing a
default case
3. Is there a guideline for naming IOCTLs? There are several defines and
functions which, I feel, could have a more descriptive name. For example,
there is the define RTEMS_FLASHDEV_IOCTL_PAGE_COUNT which is used to get
the number of pages within the flash. Could we have it called
RTEMS_FLASHDEV_IOCTL_GET_PAGE_COUNT so that it is immediately clear what
is good for? Basically, I would like to add "_GET" / "_get" at all
appropriate places (i.e. refactor the corresponding function names, too).
I guess there will be an issue with the 80 char per line limit, but I'd
provide a proposal for handling them at a final stage when all other
issues have been addressed.
4. I need to be able to create more than one flashdev. Therefore, the
mutex initializer in rtems_flashdev_do_init is a bit of a roadblocker as
it would use the same name for the mutex inside each flashdev instance.
From my point of view, the easiest way to deal with this is to have the
mutex name as an argument to the initializer. However, I'd prefer to
a. shorten the name - like FDEV_MTX_${Number}
b. loop over ${Number} until we can create the mutex
Is there an rtems_get_id_by_name? I've only found a function to get the
name of an id.
5. Some thoughts on the "regions". Regions behave much like paritions,
except that not every region / partition gets its own file handle, right?
a. Why not calling the regions partitions?
b. Do we really need to set them up "dynamically", or could we pass a
partition table to the flashdev initialisation?
c. There are the IOCTLs RTEMS_FLASHDEV_IOCTL_REGION_SET and
RTEMS_FLASHDEV_IOCTL_REGION_UNSET. Looking at the implementation I feel
they do more than I'd expect. For example, RTEMS_FLASHDEV_IOCTL_REGION_SET
creates the region, or even redefines a region if one has not called
unset, and then it activates the region. I'd like to refactor this into
four IOCTLs:
- RTEMS_FLASHDEV_IOCTL_ REGION or PARTITION _CREATE
- RTEMS_FLASHDEV_IOCTL_ REGION or PARTITION _DELETE
- RTEMS_FLASHDEV_IOCTL_ REGION or PARTITION _ACTIVATE
- RTEMS_FLASHDEV_IOCTL_ REGION or PARTITION _DEACTIVATE
For my use case, setting up a static partition table would be good enough.
We could spare the _CREATE, _DELETE, check the partitions more thoroughly
during initalisation (for example that they do not overlap), and would not
have to provide a mechanism to be able to resize them during runtime.
Flashdev shall work for NAND flashes, too. I am not an expert when it
comes to NAND flashes. Therefore, I would like to outline my basic
understanding and hope someone tells me if I am completely off.
Some parts I find often in designs:
NOR - MT25Q
https://www.micron.com/-/media/client/global/documents/products/data-sheet
/nor-flash/serial-nor/mt25q/die-rev-b/mt25q_qlkt_u_01g_bbb_0.pdf
NOR - S25FL512
https://www.infineon.com/dgdl/Infineon-S25FL512S_512_Mb_(64_MB)_3
.0_V_SPI_Flash_Memory-DataSheet-
v20_00-EN.pdf?fileId=8ac78c8c7d0d8da4017d0ed046ae4b53
NAND - W25N01
https://www.mouser.de/datasheet/2/949/w25n01gv_revl_050918_unsecured-1489588.pdf
**Memory layout**: bytes form pages, pages form sectors and sectors form
blocks. There is always some confusion as some vendors omit the term
sector
**Read operations**: can start at every address and have arbitrary length
**Write / Program operations**: work on single pages. Therefore, at max.
PAGE_SIZE Bytes can be written in one go. There is a wrap around in case
the configured address was not byte 0 in the current page. Usually, the
minimum write size is 1 byte. However, setting a minimum write size to a
different value might allow using additional features (such as ECC for the
s25fl when using 16 Byte writes to 16 byte aligned addresses).
**Erase operations**: work on sectors and they always erase the complete
sector. If an address is passed which points right in the middle of the
sector, also the sector memory before the address is erased.
6. Wrt. the write operations. I think
RTEMS_FLASHDEV_IOCTL_WRITE_BLOCK_SIZE is misleading as the term "block" is
already defined in the context of flash memories. The implementation /
comments / unit tests show that we are looking at the minimum write size.
a. Could we refactor this to RTEMS_FLASHDEV_IOCTL_GET_MIN_WRITE_SIZE?
b. Especially regarding the ECC features of some flashes. The addresses
need to be aligned to RTEMS_FLASHDEV_IOCTL_GET_MIN_WRITE_SIZE. I think we
should test the adress alignment on writes.
7. Wrt. the erase operations. The erase operations work on sectors!
a. I need an API extension to get the erase size
b. We should test that the address passed to the erase function is
aligned to the erase size.
c. The erase size puts constraints on the regions / partions. Their
addresses need to be aligned with the erase size and their length must be
a multiple of the erase size
8. Some unit tests (testsuite flashdev01) fail as expected, but not due to
expected reason. Take for example line 148 in
testsuites/libtests/flashdev01/init.c and change
read_data = fgets(buff, 2048, file);
to
read_data = fgets(buff, 1, file);
Actually, the test case is expected to fail as the sector size is only
512 bytes and we try to read 2048 bytes. Unfortunatelly, reading a single
byte doesnt work either. This is due to the fact that by default buffered
IO is used. On my side, each fgets translates to one or more read
operations of 1024 bytes length. I.e. this testcase will always succeed as
we expect the test to fail.
a. I like to propose that we initialise flashdev to operate in buffered
mode using RTEMS_FLASHDEV_IOCTL_GET_MIN_WRITE_SIZE.
b. I think we should add a raw_read and raw_write to be able to transfer
larger junks of data.
I can work on this and start providing patches for review.
--
Ticket URL: <http://devel.rtems.org/ticket/4981>
RTEMS Project <http://www.rtems.org/>
RTEMS Project
More information about the bugs
mailing list