I am working on upgrading the firmware on a legacy board running a modified 2.6.12.1 with the at91rm9200 processor and at45db642D dataflash to using a at45db641E dataflash. The characteristics of the 641E are:

  • 32768 pages
  • page size of 264 bytes
  • flexible erase options to erase a page (264 bytes), a block (2 KB), a sector (256 KB), or the whole chip (64 Mbits).

The kernel memory manager page size is the standard 4096 bytes, I believe.

I want to put an appropriate jffs2 image on the device. The mkfs.jffs2 options I'm wondering about are (from man page):

  • --pagesize: Use page size SIZE. The default is 4 KiB. This size is the maximum size of a data node. Set according to target system's memory management page size (NOTE: this is NOT related to NAND page size).
  • --eraseblock: Use erase block size SIZE. The default is 64 KiB. If you use a erase block size different than the erase block size of the target MTD device, JFFS2 may not perform optimally. If the SIZE specified is below 4096, the units are assumed to be KiB.

The man says pagesize is related to kernel memory manage page size (4096 in my case, same as the default) and NOT the device's page of 264 bytes. So I would need to specify --pagesize=4096 and NOT --pagesize=264, is this correct?

The man also says --eraseblock must be the same size as the erase block of the MTD device. I'm confused about several things.

  1. The 641E has several different erase options. Which must be selected for mkfs.jffs2 --eraseblock option?
  2. If the correct option is either the 641E's page size or block size, how can I specify that to mkfs.jffs2 given the fact that values below 4096 are assumed to be in KB and not bytes?
  3. This link (referenced by this related but insufficient SO question) says that jffs2 nodes must fit entirely within an erase block. Since their size is 4+ KB, larger than the "erase block" size of the device, the link says "You should join several erasblock into one virtual eraseblock of 64 or 128 KiB and use it - this will be more optiomal" followed by "You need to make your driver report 128KiB eraseblock size and emulate it, then it'll work. It won't work out of the box." How do I set up such a "virtual eraseblock"?
  4. Within the at91 dataflash driver, device->erasesize=pagesize. So it seems like there are a few similarly named but different concepts: driver erasesize, device erase block size, and jffs2 eraseblock size. What are the relationships and differences between these? How does the jffs2 specified eraseblock size eventually affect the operations executed by the drivers?

Thank you for any help.

1

There are 1 answers

0
fluffynukeit On

I've managed to inspect the various source files in the kernel to figure out what is going on, at least well enough to get it working. Please note that this applies to 2.6.12.1 and not necessarily later kernel versions.

There are four terms that are similarly named, related, but not necessarily equal. From highest level to lowest...

  1. mkfs.jffs2 eraseblock - this determines where nodes are laid out in in the resulting filesystem binary image.
  2. mounted jffs2 virtual blocksize - this determines how the nodes are laid out when reading and writing to the jffs2 file system.
  3. mtd core erasesize - this is the smallest eraseable unit that is reported to the jffs2 file system code by the dataflash driver implementation.
  4. device erase page/block/sector - these are the hardware erase opcodes options available to the device driver implementer to erase data from the flash.

Here are the constraints as I understand them.

  • Some option in #4 must be less than or equal to #3. In the at91_dataflash.c file, they are equal, and both equal to the page size of 264 bytes (i.e. mtd core erasesize = flash page size = 264 bytes). Generally, some combination of opcodes available in #4 must add up to exactly the erasesize, and the driver must execute the right opcodes accordingly to erase data of erasesize.
  • Nominally, the jffs2 virtual blocksize in #2 equals the mtd core erasesize in #3. However, there is a case in which the jffs2 code will alter the virtual block size automatically. The jffs2 code keeps track of dirty and clean areas on the flash disk using a set of linked lists that require the existence of one list node per virtual block. There is a 128KB limit on the total size of all such list nodes. If the virtual block size is very small, as it is in both the AT45DB642D and AT45DB641E cases in which virtual block size = mtd core erasesize = flash device page size, then this would create a large number of nodes and exceed the 128KB limit on nodes. In this case, the jffs2 fs code will automatically increase the virtual block size and decrease the virtual block count by factors of 2 until the 128KB constraint is met. The kernel will output a message saying "jffs2: Erase block size too small (0KiB). Using virtual blocks size (4KiB) instead." (Note the precision truncation). Let's call this the adjusted virtual block size.
  • The adjusted virtual block size is used for mounting the jffs2 fs stored on the flash. The adjusted virtual block size must be equal to the jffs2 image eraseblock size of #1 (although this textbook suggests that #1 eraseblock must be no greater than the #2' adjusted virtual block size. I haven't tested it.)

So in my case, the virtual block size was adjusted from 264 bytes to 4224 bytes by the kernel. My jffs2 file system thus worked by using -e 4224 option for mkfs.jffs2. The driver erases each 4224-byte long virtual block one page at a time.

Other considerations:

  • The -s pagesize option is related to the kernel page size according to the man page. I used my kernel page size using -s 4096.
  • It is very likely that the adjusted virtual block size will never be less than the size required for a full jffs2 node, so using a -e parameter less than 4096 bytes is unlikely, making my problem with the units moot.
  • I expect all the above bytecounts for #1 and #2 must be clean multiples of the mtd core eraseblock size.
  • The automatic virtual block size adjustment can be disabled/enabled in the kernel configuration.