Linux 2.6.11 MTD driver Scenario Analysis

Source: Internet
Author: User
Tags ranges
In recent days, I have made some research on the MTD driver to familiarize myself with Linux driver development. I think some of the articles I can find are not detailed enough, so I wrote some analysis on my own, hoping to help others and make my own memo ,. The blue text is excerpted from the Internet. An embedded system often uses nor flash or NAND Flash to store bootload, kernel, and file systems. The following is an analysis of the MTD driver in Linux found on the network: I. Flash Hardware driver layer: The hardware driver layer is responsible for driving the flash hardware during init. The nor flash chip driver of the Linux MTD device follows the CFI interface standard, and its driver is located in the drivers/MTD/chips subdirectory. The driver of NAND Flash is located in the/Drivers/MTD/NAND subdirectory. Ii. MTD Original DeviceThe original device layer consists of two parts: the common code of the MTD original device and the data of each specific flash, such as partition. 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 ). Iii. MTD Device layer: Based on the original MTD device, the Linux system can define MTD Block devices (primary 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. Iv. device nodes: 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. V. root file system: Jffs (or jffs2) file system image jffs in bootloader. 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. Vi. File System:After the kernel is started, the mount command can be used to mount the remaining partitions in flash to mountpoint as the file system. The nor flash chip driver and all the nor Flash Driver (PROBE) programs of the MTD original device are placed under Drivers/MTD/chips, an MTD source device can be composed of one or several identical flash chips. Assume that four flash devices with devicetype X8 are used, each block is 8 Mb, interleave is 2, and the starting address is 0x01000000. The address is connected to each other, and an original MTD device (0x0000000-0x03000000) is formed ), the two interleave blocks are converted into one chip. The IP address ranges from 0x0000000 to 0x02000000, and the other two interleave blocks are converted into one chip. The IP address ranges from 0x02000000 to 0x03000000. Note that all flash chips that constitute an MTD must be of the same type (whether interleave or address connection ), the data structure of the MTD raw device only uses the same structure to describe its flash chip. Each MTD original device has Mtd_infoStructure, in which the priv Pointer Points to Map_infoStructure. fldrv_priv in the map_info structure points to Cfi_privateStructure. The cfiq pointer of the cfi_private structure points to Cfi_identStructure. The chips Pointer Points to FlchipStructure array. The mtd_info, map_info, and cfi_private structures are used to describe the MTD original device. Because the nor flash is the same as the MTD original device, the cfi_ident structure is used to describe the flash chip information; the flchip structure is used to describe the proprietary information (such as the starting address) of each flash chip. In general, in embedded systems, one or more consecutive nor flash or NAND Flash spaces (each one may be composed of multiple identical chips) every space like this is regarded as an MTD original device (I don't know who the name is, so can I use it) according to the variable names used in some articles and code, I will refer to it as the primary partition. You can divide the primary partition into Several partitions according to your needs. The partition information for my Development Board is as follows: From alchemy_flash.c: static struct mtd_partition alchemy_partitions [] = {{. name = "User FS", // here to the root file system. size = board_flash_size-0x00400000 ,. offset = 0x0000000 },{. name = "yamon", // This piece is for Bootloader. size = 0x0100000 ,. offset = mtdpart_ofs_append, // indicates the next partition. mask_flags = mtd_writeable },{. name = "raw kernel ",. size = (0x300000-0x40000),/* Last 256kb is yamon E NV * /// this is the self-extracting compressed kernel. At last, it leaves the environment variable for booterloader, which is not used by the device driver, it is accessed by booterloader in its own way.. Offset = mtdpart_ofs_append,}; if you increase or decrease your flash space (by increasing or decreasing the flash chip) or you want to adjust the size of Several partitions, you only need to modify the table. If you have another NAND partition, you may have the following Partition Table (au1550nd. c): const static struct mtd_partition partition_info [] = {{. name = "nand fs 0 ",. offset = 0 ,. size = 8*1024*1024 },{. name = "nand fs 1 ",. offset = mtdpart_ofs_append ,. size = mtdpart_siz_full}; the entire alchemy_flash.c has two functions: alchemy_mtd_init (void) and alchemy_mtd_cleanup (). Int _ init alchemy_mtd_init (void) {struct mtd_partition * parts; int nb_parts = 0; unsigned long window_addr; unsigned long window_size;/* default flash buswidth */mask = board_flash_width; window_addr = 0x20000000-board_flash_size; window_size = board_flash_size; # ifdef config_mis_mirage_why/* boot Rom flash bank only; no user Bank */window_addr = 0x1c000000; window_size = 0x 04000000;/* userfs from 0x1c00 0000 to 0x1fc00000 */alchemy_partitions [0]. size = 0x03c00000; # endif/** static partition definition selection */parts = alchemy_partitions; nb_parts = nb_of (alchemy_partitions); alchemy_map.size = window_size; /** now let's probe for the actual flash. do it here since * specific machine settings might have been set above. */printk (kern_notice board_map_name ": Probing % d-bit flash bus/N ", route * 8); alchemy_map.virt = ioremap (window_addr, window_size); mymtd = do_map_probe (" cfi_probe ", & alchemy_map); If (! Mymtd) {iounmap (alchemy_map.virt); Return-enxio;} mymtd-> owner = this_module; add_mtd_partitions (mymtd, parts, nb_parts); Return 0;} Check the red area, do_map_probe returns an mtd_info structure pointer. It indicates that after finding your driver (CFI driver) correctly, this function will fill in the table and set the read/write functions to the correct values. The specific implementation will be analyzed in the future, one of the map_info parameters is not fully understood yet, because I have never studied the underlying Flash Driver before. You need to set the bankwidth and base address, and the driver name, I can only guess through some information that it is used to manage the primary partition and use it for the underlying driver. For example, the bad block information is saved here. Finally, call add_mtd_partitions to partition based on the partition table you set and the mtd_info of the primary partition. In fact, if you do not want to divide the primary partition into Several partitions, you can directly add the mtd_info to the mtd_table without processing in mtdpart. C. Next, let's take a look at this path: This function jumps to the file mtdpart. C. After you divide a primary partition into Several partitions, The mtd_info of these partitions is the same as that of your primary partition, except in terms of size and name. The add_mtd_partitions function is too big. It is not suitable to post all the functions. I 'd like to pick a few lines. Slave-> MTD. type = Master-> type; // copy the information of the master partition slave-> MTD. size = parts [I]. size; // changed the size slave-> MTD. oobblock = Master-> oobblock; // copy the information of the master partition slave-> MTD. name = parts [I]. name; // changed the name slave-> MTD. bank_size = Master-> bank_size; // copy the information of the primary partition, slave-> MTD. read = part_read; // This is your own. Let's look at the analysis below to see if (parts [I]. MTDP) hj6linux Alliance
{/* Store the Object Pointer (caller may or may not register it */hj6linux Alliance
* Parts [I]. MTDP = & slave-> MTD; hj6linux Alliance
Slave-> registered = 0; // you can also choose not to add hj6linux in mtd_table
} Hj6linux Alliance
Elsehj6linux Alliance
{Hj6linux Alliance
/* Register our partition */hj6linux Alliance
Add_mtd_device (& slave-> MTD); // Finally, add the mtd_table instead of the mtd_parthj6linux consortium containing the structure.
Slave-> registered = 1; hj6linux Alliance
} Hj6linux Alliance
Hj6linux Alliance
Static int part_read (struct mtd_info * MTD, loff_t from, size_t Len, size_t * retlen, u_char * BUF) {struct mtd_part * Part = part (MTD ); if (from> = MTD-> size) Len = 0; else if (from + Len> MTD-> size) Len = MTD-> size-from; if (Part-> master-> read_ecc = NULL) return part-> master-> Read (Part-> master, from + part-> offset, Len, retlen, buf); else return part-> master-> read_ecc (Part-> master, from + part -> Offset, Len, retlen, Buf, null, & MTD-> oobinfo);} it is clear that the offset is added when the READ function of the primary partition is called. Add_mtd_partitions is called at the end of add_mtd_device (& slave-> MTD). Each partition is added to mtd_table. In mtdcore. C, you can directly add the primary partition as a parameter to mtd_table without partitioning. Mtdcore. c, as its name is, is called core for a reason: it does not call any external function (except the registered callback function) of the MTD driver at all levels, but only outputs the function. It manages mtd_table. The underlying layer uses add_mtd_device and del_mtd_device to add and delete the original device (partition ). The upper-layer character devices and Block devices use get_mtd_device and put_mtd_device to apply for and release partitions. Int add_mtd_device (struct mtd_info * MTD) {int I; down (& mtd_table_mutex); for (I = 0; I <max_mtd_devices; I ++) if (! Mtd_table [I]) {struct list_head * This; mtd_table [I] = MTD; MTD-> Index = I; MTD-> usecount = 0; debug (0, "MTD: giving out device % d to % s/n ", I, MTD-> name);/* No Need To Get A refcount on the module containing the notifier, since we hold the mtd_table_mutex */list_for_each (this, & mtd_notifiers) {struct mtd_notifier * not = list_entry (this, struct mtd_notifier, list); Not-> Add (MTD ); // In my opinion, if you do not intend to dynamically add And delete the device. This // part is unnecessary. The linked list is empty when the system initializes the MTD device.} Up (& mtd_table_mutex);/* We _ know _ we aren't being removed, because our caller is still holding us here. so none of this try _ nonsense, and no bitching about it either. */_ module_get (this_module); Return 0 ;}up (& mtd_table_mutex); return 1 ;} the entire function is relatively simple, select an empty location in mtd_table to place the mtd_info of your partition. The red part is hard to understand: what is the role of the mtd_notifiers linked list? Let's see who has added something to this linked list. Register_mtd_user is the only member added to this linked list. Who called it? Check out the program void register_mtd_user (struct mtd_notifier * New) {int I; down (& mtd_table_mutex); list_add (& New-> list, & mtd_notifiers) in detail ); _ module_get (this_module); for (I = 0; I <max_mtd_devices; I ++) if (mtd_table [I]) New-> Add (mtd_table [I]); up (& mtd_table_mutex);} static inline void Merge (void) {devfs_mk_dir ("MTD"); register_mtd_user (& notifier);} int Merge (struct mtd_blktrans_ops * TR) {int ret, I;/* register the notifier if/when the first device type is registered, to prevent the link/init ordering from fucking us over. */If (! Blktrans_notifier.list.next) register_mtd_user (& blktrans_notifier );..... Omit n rows return 0;}. It seems that this linked list usually has only two members. The role is to notify the character device and block device driver on the MTD partition when it is deleted or added. What? When an MTD character device is created, mtdchar_devfs_init is called. Its notifier is like this: static struct mtd_notifier notifier = {. add = mtd_policy_add ,. remove = mtd_policy_remove,}; static void mtd_policy_add (struct mtd_info * MTD) {If (! MTD) return; devfs_mk_cdev (mkdev (mtd_char_major, MTD-> Index * 2), s_ifchr | s_irugo | s_iwugo, "MTD/% d", MTD-> index ); devfs_mk_cdev (mkdev (mtd_char_major, MTD-> Index * 2 + 1), s_ifchr | s_irugo, "MTD/% dro", MTD-> index );} this devfs_mk_cdev should be the automatically created devfs node, isn't it just a mknod? I am a newbie to Linux. If anyone knows this, please don't hesitate to give me some advice. I just guessed it by name. To sum up, my understanding is that the above MTD device driver architecture analysis is not especially important for porting, except for the partition table. But what should I do when you change the flash chip model? I roughly read the driver section and referred to the following link article. :Http:// OS .yesky.com/lin/233/3386733.shtml Advanced Linux MTD/CFI IN THE SYSTEM Driver introduction.I just learned a rough understanding of the so-called CFI (Common flash interface ). Is it true that this driver can solve all the problems? Trace the logs in another day, starting with do_map_probe.

 

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.