内核如何解析 mtdparts 参数
网上搜素了 mtdparts 相关资料,没有一篇讲明白mtd_id 该怎么确认,于是自己从源码中找答案:
先看看 linux-4.14.63/Documentation 里面怎么说的
~/opt/linux-4.14.63/Documentation$ grep mtdparts . -rn
./admin-guide/kernel-parameters.txt:2408: mtdparts= [MTD]
./block/cmdline-partition.txt:10:The format for the command line is just like mtdparts:
./admin-guide/kernel-parameters.txt 里面写到
mtdparts= [MTD]
See drivers/mtd/cmdlinepart.c
好吧,没有一句废话,直接让看源码 drivers/mtd/cmdlinepart.c
先看看 Makefile ,确定什么时候会编译 cmdlinepart.c , 可知需要配置 CONFIG_MTD_CMDLINE_PARTS=y
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
好,现在开始看源码
首先是开头注释,这里面写了mtdparts 格式
* The format for the command line is as follows:
*
* mtdparts=<mtddef>[;<mtddef]
* <mtddef> := <mtd-id>:<partdef>[,<partdef>]
* <partdef> := <size>[@<offset>][<name>][ro][lk]
* <mtd-id> := unique name used in mapping driver/device (mtd->name)
* <size> := standard linux memsize OR "-" to denote all remaining space
* size is automatically truncated at end of device
* if specified or truncated size is 0 the part is skipped
* <offset> := standard linux memsize
* if omitted the part will immediately follow the previous part
* or 0 if the first part
* <name> := '(' NAME ')'
* NAME will appear in /proc/mtd
*
* <size> and <offset> can be specified such that the parts are out of order
* in physical memory and may even overlap.
这里面的东西都是跟网上能搜到的一样。
关键看 mtd-id
dts , spi_device 的创建,从 spi_register_controller 开始,
spi_register_controller
dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num); // spimaster 的名字形如 spi0
of_register_spi_devices
of_register_spi_device
struct spi_device *spi;
spi = spi_alloc_device(ctlr);
spi->dev.parent = &ctlr->dev;
spi_add_device(spi);
/* Set the bus ID string */
spi_dev_set_name(spi);
dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->controller->dev), spi->chip_select); //形如 spi0.0
mtd_device 的注册
m25p_probe
struct flash_platform_data *data;
data = dev_get_platdata(&spi->dev); // 如果有platdata 就用 platdata->name , dts 时代一般没有
nor->dev = &spi->dev; //
if (data && data->name)
nor->mtd.name = data->name;
-> spi_nor_scan
struct device *dev = nor->dev;
if (!mtd->name) // 如果 mtd.name 仍为空,则
mtd->name = dev_name(dev); // 使用 spi->dev 的名字,形如 spi0.0
-> mtd_device_register(&nor->mtd, data ? data->parts : NULL, data ? data->nr_parts : 0);
-> mtd_device_parse_register
-> mtd_set_dev_defaults(mtd); //
-> if (!mtd->name) // 如果 mtd.name 仍为空,则
mtd->name = dev_name(mtd->dev.parent); // 使用 mtd->dev.parent 的名字,即spi控制器的名字,形如 spi0
-> parse_mtd_partitions(mtd, types, parser_data)
-> types = mtd_is_partition(master) ? default_subpartition_types : default_mtd_part_types; // "cmdlinepart"
-> mtd_part_do_parse
-> ret = (*parser->parse_fn)(master, &pparts->parts, data); // cmdline_parser 里用mtd-id 与 mtd->name 匹配
cmdline_parser
static int __init mtdpart_setup(char *s)
{
cmdline = s;
return 1;
}
__setup("mtdparts=", mtdpart_setup);
static struct mtd_part_parser cmdline_parser = {
.parse_fn = parse_cmdline_partitions,
.name = "cmdlinepart",
};
真正的匹配过程:
parse_cmdline_partitions
const char *mtd_id = master->name; // master->name 其实就是 mtd->name ,
/*
* Search for the partition definition matching master->name.
* If master->name is not set, stop at first partition definition.
*/
for (part = partitions; part; part = part->next) {
if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id))) // part->mtd_id 是 mtdparts=<mtd-id>:.. 传进来的 mtd-id
break;
}
//....
小结:
CONFIG_MTD_CMDLINE_PARTS=y 开启内核对 mtdparts 参数的支持
dts 时代,mtd-id 写法一般为 spi0.0 , 也可以通过 sysfs 查看,如
/sys/devices/platform/soc/1c68000.spi/spi_master/spi0/spi0.0
举例:
mtdparts=spi0.0:512k(u-boot)ro,64k(env),64k(dtb),5M(kernel),8M(rootfs),-(data)
mtdparts=spi0.0:512k@0(u-boot)ro,64k@512k(env), 64k@576k(dtb) 5M@640k(kernel),8M@5760k(rootfs),-(data)
mtdparts=spi0.0:512k@0(u-boot)ro,64k@0x80000(env)ro,64k@0x90000(dtb),5M@a0000(kernel),8M@5a0000(rootfs),-(data)