MTD driver code-Analysis of MTD device read/write marks

Source: Internet
Author: User
Tags configuration settings

This section describes the environment and tools:
VMware station + Debian + Samba + NFS + Source insignt
Linux-source-2.6.18 + XXXX. Patch
Problem description:
FD = open ("/dev/mtd4", o_rdwr) failed, while FD = open ("/dev/mtd4", o_rdonly) succeeded
Before the start, I found some information about MTD devices. Here, Jim Zeus's Linux MTD source code analysis is representative. I have not studied it very deeply. I mainly want to understand the MTD code Layer Structure and several important data structures. After all, my main task is to work with the middleware porting team to read and write MTD partitions, too much detail is a luxury for me.

MTD (memory technology device) is a Linux subsystem used to access memory devices (ROM, flash. The main purpose of MTD is to make the drive of the new memory device simpler. Therefore, MTD provides an abstract interface between the hardware and the upper layer. All source code of MTD is in the/Drivers/MTD subdirectory. I divide the MTD device of the CFI interface into four layers (from the device node to the underlying hardware driver). The four layers are as follows: device node, MTD device layer, MTD raw device layer, and hardware driver layer.

I. Flash hardware driver layer: the hardware driver layer drives flash hardware during init. The nor flash chip driver of Linux MTD follows the CFI interface standard, the driver is located in the drivers/MTD/chips subdirectory. The driver of NAND Flash is located in the/Drivers/MTD/NAND subdirectory.

2. MTD original device: the original device layer consists of two parts: the common code of the MTD original device and the data of each specific flash, such as partitioning. The data structure used to describe the original MTD device is mtd_info, which defines a large amount of MTD data and operation functions. Mtd_table (mtdcore. c) It is a list of all the original MTD devices. mtd_part (mtd_part.c) is a structure used to represent the partition of the original MTD device, including mtd_info, because each partition is regarded as an MTD original device added to mtd_table, most of the data in mtd_part.mtd_info is obtained from the primary partition mtd_part-> master. The drivers/MTD/maps/sub-directory stores specific flash data. Each file describes the flash on a board. Call add_mtd_device () and del_mtd_device () to create/Delete the mtd_info structure and add/Delete the mtd_table (or call add_mtd_partition () and del_mtd_partition () (mtdpart. c) Create/Delete the mtd_part structure and add mtd_part.mtd_info to/delete mtd_table ).

3. MTD device layer: based on the original MTD device, the Linux system can define MTD Block devices (master device number 31) and character devices (device Number 90 ). MTD character devices are defined in mtdchar. C by registering a series of file operation functions (lseek, open, close, read, write ). MTD block device defines a structure mtdblk_dev that describes MTD Block devices, and declares a pointer array named mtdblks. Each mtdblk_dev in the array corresponds to each mtd_info in mtd_table.

4. device node: Use mknod to create MTD character device nodes (primary device Number 90) and MTD block device nodes (primary device number 31) in the/dev subdirectory ), you can access MTD character devices and Block devices by accessing this device node.

5. root file system: in bootloader, The jffs (or jffs2) file system image is jffs. image (or jffs2.img) is burned into a flash partition, in/ARCH/ARM/Mach-Your/arch. the your_fixup function of file C mounts the partition as the root file system.

6. File System: After the kernel is started, the mount command can be used to mount the remaining partitions in flash as the file system to mountpoint.

I also want to know the CFI driver process. As follows:

1: Construct the map_info structure, specify the base address, bit width, size, and other information as well as the "cfi_probe" limitation, and then call do_map_probe ().

2: do_map_probe () Find the chip driver "cfi_probe.c" based on the name "cfi_probe" and call cfi_probe () directly ().

3: cfi_probe () directly calls mtd_do_chip_probe () and passes in the cfi_probe_chip () function pointer.

4: mtd_do_chip_probe () is divided into two steps. First, call genprobe_ident_chips () to detect the chip information, and then call check_cmd_set () to obtain and initialize the chip command set (Multi-partition Initialization is in it ).

5: If the genprobe_ident_chips () function does not consider multi-chip connection, you only need to check the previous genprobe_new_chip () call. After the call, CFI. chipshift = CFI. cfiq-> devsize, 2 ^ chipshift = flash size.

6: genprobe_new_chip () enumeration of different chip Bit Width and back-to-back quantity, call the cfi_probe_chip () of step 3 in turn based on configuration settings. Note that CFI-> device_type = bankwidth/nr_chips, bankwidth indicates the bus bit width, and device_type indicates the chip bit width. Here we only need to pay attention to the limited complexity, the so-called limited complexity refers to the complex connection determined during compilation. In this way, cfi_probe_chip () is successful only after 1st calls. If the 32-bit flash is inserted on the 16bit bus, the 2nd calls are successful.

7: cfi_probe_chip (). For the reason of Step 6, the function returns directly in cfi_chip_setup (), and the subsequent Code does not need to be considered.

8: cfi_chip_setup () reads CFI information. You can pay attention to how to implement key 4 in Linux.

9: Return to the check_0000_set () stage in Step 4, enter the cfi_cmdset_0001 () function, first call read_pri_intelext () to read Intel's extension information, and then call cfi_intelext_setup () to initialize its own structure.

10: read_pri_intelext () function, you can pay attention to how to read the variable length structure, that is, the usage of "need_more. The following describes the meanings of some variables. For example, for a flash chip of the strataflash 128 MB bottom type, the block structure is 4*32 KB + 127 * kb = 16 MB, with a total of 16 partitions, 1 MB for each partition. Nb_parts = 2.

11: The cfi_intelext_setup () function first establishes mtd_erase_region_info Information Based on CFI, and then calls cfi_intelext_partition_fixup () to support partitions.

12: cfi_intelext_partition_fixup () is used to create a virtual chip. Each partition corresponds to one chip. However, it is not completely created based on the CFI extension information. Instead, it is assumed that the size of each partition is consistent. CFI-> chipshift is adjusted to partshift, and each virtual chip-> Start is adjusted to the base address of each partition. In the future, the function cfi_varsize_frob () will be used to access flash and obtain chipnum (chipnum = OFS> CFI-> chipshift) based on ofs. This is why we assume that the partition is consistent.

MTD several important data structures

 
 
  1. Struct mtd_info {
  2. U_char type;
  3. U_int32_t flags;
  4. U_int32_t size; // total size of the MTD
  5. /* "Major" erase size for the device. Na Mave users may take this
  6. * To be the only erase size available, or may use the more detailed
  7. * Information below if they desire
  8. */
  9. U_int32_t erasesize;
  10. /* Minimal writable flash unit size. In case of nor flash it is 1 (even
  11. * Though individual bits can be cleared), in case of NAND flash it is
  12. * One NAND page (or half, or one-fourths of it), in case of ECC-ed nor
  13. * It is of ECC block size, etc. It is illegal to have writesize = 0.
  14. * Any driver registering a struct mtd_info must ensure a writesize
  15. * 1 or larger.
  16. */
  17. U_int32_t writesize;
  18. U_int32_t oobsize; // amount of OOB data per block (e.g. 16)
  19. U_int32_t oobavail; // available OOB bytes per block
  20. // Kernel-only stuff starts here.
  21. Char * Name;
  22. Int index;
  23. /* ECC layout structure pointer-read only! */
  24. Struct nand_ecclayout * ecclayout;
  25. /* Data for variable erase regions. If numeraseregions is zero,
  26. * It means that the whole device has erasesize as given abve.
  27. */
  28. Int numeraseregions;
  29. Struct mtd_erase_region_info * eraseregions;
  30. ......
  31. };
  32. Struct erase_info {
  33. Struct mtd_info * MTD;
  34. U_int32_t ADDR;
  35. U_int32_t Len;
  36. U_int32_t fail_addr;
  37. U_long time;
  38. U_long retries;
  39. U_int dev;
  40. U_int cell;
  41. Void (* callback) (struct erase_info * Self );
  42. U_long priv;
  43. U_char state;
  44. Struct erase_info * next;
  45. };
  46. Struct mtd_erase_region_info {
  47. U_int32_t offset;/* at which this region starts, from the beginning of the MTD */
  48. U_int32_t erasesize;/* for this region */
  49. U_int32_t numblocks;/* number of blocks of erasesize in this region */
  50. Unsigned long * lockmap;/* If keeping bitmap of locks */
  51. };

If you want to know the process and details of a code driver, it is much faster to start with these important data structures.

I wanted to know MTD code because FD = open ("/dev/mtd4", o_rdwr) returned-1, while FD = open ("/dev/mtd4", o_rdonly) is successful. Mtd4 is not writable, but the middleware port needs to read and write the MTD partition, so it must be modified from the driver. The following procedures have been completed and are not so simple and organized at the beginning.

First, start with the MTD device layer, because file operation functions such as open, close, read, write, and IOCTL are defined here. In the implementation of the mtdopen function, we can quickly see the trend. Note that the font in the following code box is bold:

 
 
  1. DE>/* You can't open the RO devices RW */
  2. if ((file->f_mode & 2) && (minor & 1))
  3. return -EACCES;
  4. mtd = get_mtd_device(NULL, devnum);
  5. if (!mtd)
  6. return -ENODEV;
  7. if (MTD_ABSENT == mtd->type) {
  8. put_mtd_device(mtd);
  9. return -ENODEV;
  10. }
  11. /* You can't open it RW if it's not a writeable device */
  12. if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) {
  13. put_mtd_device(mtd);
  14. return -EACCES;
  15. }DE>

Also defined in FS. h

De> # define fmode_read 1

# Define fmode_write 2de>

Obviously, if the open file mark has a write mark, it will determine whether the device allows write operations when it is open. At the beginning, I used the IF (file-> f_mode & 2) & (minor & 1) method to track whether the second device number and Phase 1 of mtd4 are not 0. Execute LS-L/dev/mtd4 on the target board system and find that the next device Number of mtd4 is 8, so that the system does not return this step.

The rest is only if (file-> f_mode & 2 )&&! (MTD-> flags & mtd_writeable), MTD-> flags may be set! Mtd_writeable flag. The subsequent work is located on MTD-> flags.

Mtd_info initialization should be performed on the flash hardware driver layer. With this idea, I would like to know the probe process of CFI. It turns out that it is unnecessary. Now return to the Flash hardware driver layer and find the drive path of the flash chip of our project. The definition of init_xxxx_map () is as follows:

De>

 
 
  1. // Set the offset and size of each MTD area.
  2. Xxxx_mtd = do_map_probe ("cfi_probe", & xxxx_map );
  3. If (! Xxxx_mtd ){
  4. Iounmap (void *) xxxx_map.virt );
  5. Return-enxio;
  6. }
  7. Add_mtd_partitions (xxxx_mtd, xxxx_parts, numparts );
  8. Xxxx_mtd-> owner = this_module;
  9. Return 0;

De>

The initial initialization of mtd_info is completed in do_map_probe (). In fact, it is done by calling cfi_probe (). From there, we can trace MTD-> flags = mtd_cap_norflash, mtd_cap_norflash is equal to mtd_writeable | mtd_bit_writeable. Add_mtd_partitions () is the loading implementation of MTD partitions. In general, information such as mtd_info will also be set here to enter this function, and we can find the part we care about:

De>

 
 
  1. if ((slave->mtd.flags & MTD_WRITEABLE) &&
  2. (slave->offset % slave->mtd.erasesize)) {
  3. /* Doesn't start on a boundary of major erase size */
  4. /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
  5. slave->mtd.flags &= ~MTD_WRITEABLE;
  6. printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
  7. parts[i].name);
  8. }
  9. if ((slave->mtd.flags & MTD_WRITEABLE) &&
  10. (slave->mtd.size % slave->mtd.erasesize)) {
  11. slave->mtd.flags &= ~MTD_WRITEABLE;
  12. printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
  13. parts[i].name);
  14. }

De>

If the two if conditions are determined, if the offset of the partition cannot be divisible by erasesize or the partition size cannot be divisible by erasesize, The MTD. flags of the partition will be set to a non-writable flag. According to the printk information, offset and size must meet the boundary conditions of erasesize before they can be written.

I found the reason and verified it. IOCTL (FD, memgetinfo, & mtd_info) Get mtd_info.erasesize = 0x20000, The xxxx-flash.c defines the MTD partition information:

De>

{Name: "rootfs", offset: 0, size: 28*1024*1024 },

{Name: "bootloader", offset: 0x01c00000, size: 512*1024 },

{Name: "zimage", offset: 0x01c80000, size: 3582*1024 },

{Name: "macadr", offset: 0x01fff800, size: 144 },

{Name: "Config", offset: 0x01fff890, size: 1904 },

De>

The offset and size of the rootfs and bootloader partitions can be calculated to conform to the erasesize boundary conditions. The zimage, config, and macadr partitions do not conform to the erasesize boundary conditions. O_rdwr indicates that both open/dev/mtd0 and/dev/mtd1 are successful, and the devices in the last three MTD areas fail, basically verifying the previous analysis.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.