MTD: Memory Technology Device

This article introduces the MTD (Memory Technology Devices).

Brief Introduction

Refer to General MTD documentation:

MTD subsystem (stands for Memory Technology Devices) provides an abstraction layer for raw flash devices. It makes it possible to use the same API when working with different flash types and technologies, e.g. NAND, OneNAND, NOR, AG-AND, ECC’d NOR, etc.

MTD subsystem does not deal with block devices like MMC, eMMC, SD, CompactFlash, etc. These devices are not raw flashes but they have a Flash Translation Layer (FTL) inside, which makes them look like block devices. These devices are the subject of the Linux block subsystem, not MTD. Refer to this FAQ section for a short list of the main differences between block and MTD devices:

Differences_between_flash_devices_and_block_drives

And the raw flash vs. FTL devices UBIFS section discusses this in more details.

MTD subsystem has the following interfaces:

  • MTD character devices - usually referred to as /dev/mtd0, /dev/mtd1, and so on. These character devices provide I/O access to the raw flash. They support a number of ioctl calls for erasing eraseblocks, marking them as bad or checking if an eraseblock is bad, getting information about MTD devices, etc.

  • The sysfs interface is relatively newer and it provides full information about each MTD device in the system. This interface is easily extensible and developers are encouraged to use the sysfs interface instead of older ioctl or /proc/mtd interfaces, when possible. The sysfs interface for the MTD subsystem is documentated in the kernel, and currently can be found at Documentation/ABI/testing/sysfs-class-mtd.

  • The /proc/mtd proc file system file provides general MTD information. This is a legacy interface and the sysfs interface provides more information.

MTD subsystem supports bare NAND flashes with software and hardware ECC, OneNAND flashes, CFI (Common Flash Interface) NOR flashes, and other flash types.

Additionally, MTD supports legacy FTL/NFTL translation layers, M-Systems’ DiskOnChip 2000 and Millennium chips, and PCMCIA flashes (pcmciamtd driver). But the corresponding drivers are very old and not maintained very much.

MTD Architecture

The following figure shows the MTD architecture under Linux system:

linux-mtd-architecture

MTD字符设备的主设备号是90,MTD块设备的主设备号是31,参见include/uapi/linux/major.h:

#define MTD_BLOCK_MAJOR		31
#define MTD_CHAR_MAJOR		90

MTD块设备的大小,可以通过查看分区信息获得:

~ # cat /proc/partitions
major   minor    #blocks name
   31       0       4096 mtdblock0
   31       1      20480 mtdblock1
   31       2     110592 mtdblock2

~ # cat /proc/mtd
 dev:     size erasesize name
mtd0: 00400000  00020000 "mtdram test device"
mtd1: 01400000  00020000 "kernel"
mtd2: 06c00000  00020000 "swap"

Note: 每个MTD字符设备都对应着一个MTD块设备。

MTD API

The MTD subsystem API is defined in include/linux/mtd/mtd.h. The methods and data structures in this file are used by higher layer kernel code such as flash file systems to access and control the MTD devices, and also by device driver authors to interface their device to the MTD subsystem. The various methods by which a driver provides access to the device are defined within struct mtd_info. Prior to kernel version 3.4, higher layers called the driver methods directly by way of a pointer to struct mtd_info. As of kernel 3.4, these methods are implemented within the MTD subsystem core code, which then calls the corresponding driver methods. Users of kernel 3.4 and later should not call the driver methods directly, but instead use those prototyped in include/linux/mtd/mtd.h outside of struct mtd_info. These methods include mtd_read(), mtd_write(), etc. The member flags in struct mtd_info takes the following values, refer to include/uapi/mtd/mtd-abi.h:

#define MTD_ABSENT		0
#define MTD_RAM			1
#define MTD_ROM			2
#define MTD_NORFLASH		3
#define MTD_NANDFLASH		4	/* SLC NAND */
#define MTD_DATAFLASH		6
#define MTD_UBIVOLUME		7
#define MTD_MLCNANDFLASH	8	/* MLC NAND (including TLC) */

Absent an error, the API methods will return zero, with two notable exceptions. mtd_read() and mtd_read_oob() may return -EUCLEAN in some circumstances. This return code is applicable mainly to NAND flash devices, and is used to indicate that some bit errors were corrected by the device’s ECC facility. Prior to kernel version 3.4, -EUCLEAN was returned if one or more bit errors were corrected during the read operation. As of kernel 3.4, the meaning is more nuanced, and can be broadly interpreted to mean a dangerously high number of bit errors were corrected. The -EUCLEAN return code is intended to help higher layers detect degradation of erase blocks. The conditions by which mtd_read() and mtd_read_oob() return -EUCLEAN can be tuned using the bitflip_threshold element of the sysfs interface. Please see the kernel documentation for the MTD sysfs interface (referenced above) before adjusting this value.

MTD Tests

The MTD subsystem includes a set of tests which you may run to verify your flash hardware and drivers. The tests are available in the mainline kernels starting from kernel version 2.6.29 and they live in the drivers/mtd/tests directory of the linux kernel source codes. You may compile the tests as kernel modules by enabling them in the kernel configuration menu by marking: Device Drivers -> Memory Technology Device (MTD) support -> MTD tests support (or the MTD_TESTS symbol in the .config file).

If you have a pre-2.6.29 kernel, you may find the tests here git://git.infradead.org/users/ahunter/nand-tests.git

The MTD test-suite contains the following tests:

  • mtd_speedtest: measures and reports read/write/erase speed of the MTD device.
  • mtd_stresstest: performs random read/write/erase operations and validates the MTD device I/O capabilities.
  • mtd_readtest: this tests reads whole MTD device, one NAND page at a time including OOB (or 512 bytes at a time in case of flashes like NOR) and checks that reading works properly.
  • mtd_pagetest: relevant only for NAND flashes, tests NAND page writing and reading in different sizes and order; this test was originally developed for testing the OneNAND driver, so it might be a little OneNAND-oriented, but must work on any NAND flash.
  • mtd_oobtest: relevant only for NAND flashes, tests that the OOB area I/O works properly by writing data to different offsets and verifying it.
  • mtd_subpagetest: relevant only for NAND flashes, tests sub-page I/O.
  • mtd_torturetest: this test is designed to wear out flash eraseblocks. It repeatedly writes and erases the same group of eraseblocks until an I/O error happens, so be careful! The test supports a number of options (see modinfo mtd_torturetest) which allow you to set the amount of eraseblocks to torture and how the torturing is done. You may limit the amount of torturing cycles using the cycles_count module parameter. It may be very god idea to run this test for some time and validate your flash driver and HW, providing you have a spare device. For example, we caught rather rare and nasty DMA issues on an OMAP2 board with OneNAND flash, just by running this tests for few hours.
  • mtd_nandecctest: a simple test that checks correctness of the built-in software ECC for 256 and 512-byte buffers; this test is not driver-specific but tests general NAND support code.

mtdblock driver

The mtdblock driver available in the MTD is an archaic tool which emulates block devices on top of MTD devices. It does not even have bad eraseblock handling, so it is not really usable with NAND flashes. And it works by caching a whole flash erase block in RAM, modifying it as requested, then erasing the whole block and writing back the modified. This means that mtdblock does not try to do any optimizations, and that you will lose lots of data in case of power cuts. And last, but not least, mtdblock does not do any wear-leveling or bit-flips handling.

Often people consider mtdblock as general FTL layer and try to use block-based file systems on top of bare flashes using mtdblock. This is wrong in most cases. In other words, please, do not use mtdblock unless you know exactly what you are doing.

There is also a read-only version of this driver, mainly for use with uCLinux where the extra RAM requirement was considered too large. However, just like the R/W version of the driver, there is no wear-levelling and bit-flips handling.

Instead of using this old driver, you may check the R/O block device emulation provided by UBI useful. Please refer to the UBI section for more details.

mtd-utils

The mtd-utils repository is git://git.infradead.org/mtd-utils.git, refer to Compiling MTD Utils.

The MTD Utilities are a collection of tools that allow the user to interact with the MTD subsystem in the kernel to perform operations on Flash devices. The most commonly used utilities are:

mtd-utils Description
mtd_debug Debug MTD
flash_info Displays information about Flash devices
flashcp Copies data into NOR flash
flash_erase Erases an erase block of flash
flash_eraseall Erases the entire flash device
flash_lock Lock flash pages to prevent writing
flash_unlock Unlock flash pages to allow writing
mkfs.jffs2 Create a JFFS2 file system image from an existing file system
nandwrite Write an input file (i.e. JFFS2 or YAFFS2 image) to the NAND Flash device

These utilities are often used to write file system images to the Flash device on an embedded system.

Repository

Tree Name GIT URL Gitweb URL
MTD git://git.infradead.org/linux-mtd.git http://git.infradead.org/linux-mtd.git
MTD (next) git://git.infradead.org/l2-mtd.git http://git.infradead.org/l2-mtd.git
UBI / UBIFS git://git.infradead.org/linux-ubifs.git http://git.infradead.org/linux-ubifs.git
MTD user-space tools git://git.infradead.org/mtd-utils.git http://git.infradead.org/mtd-utils.git
linux-mtd.infradead.org git://git.infradead.org/mtd-www.git http://git.infradead.org/mtd-www.git

References