最近在解EMMC的一个bug,发现Linux EMMC有点小复杂,先整理个文档出来吧
用的是TI 平台,仅分析MMC,不分析SD和SDIO
mmc_init
2769 static int __init mmc_init(void)
2770 {
2774
2775 workqueue = alloc_ordered_workqueue("kmmcd", 0);
2776 if (!workqueue)
2777 return -ENOMEM;
2778
2779 ret = mmc_register_bus();
2780 if (ret)
2781 goto destroy_workqueue;
2782
2783 ret = mmc_register_host_class();
2784 if (ret)
2785 goto unregister_bus;;
2793
2802 }
2775分配一个workqueue,这个workqueue是专门用来处理card detect的,EMMC因为是unremovable的,所以不需要关注它
2779 注册mmc_bus_type,实现如下:
int mmc_register_bus(void)
{
return bus_register(&mmc_bus_type);
}
把mmc_bus_type注册到bus系统,后面调用device_add函数时,则会辗转调用到mmc_bus_type中的probe函数,不必太纠结在这个代码
mmc_init调用时间比较早,会在host驱动初始化之前执行完。
subsys_initcall(mmc_init);
host驱动初始化
kernel/drivers/mmc/host/omap_hsmmc.c
host驱动位置是kernel/drivers/mmc/host/,一般来说都是platform_driver,以omap hsmmc host驱动为例
<strong>.probe = omap_hsmmc_probe,</strong>
.remove = omap_hsmmc_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.pm = &omap_hsmmc_dev_pm_ops,
.of_match_table = of_match_ptr(omap_mmc_of_match),
},
};
module_platform_driver(omap_hsmmc_driver);
只需要关注omap_hsmmc_probe即可,当系统匹配到platform_device时,会调用omap_hsmmc_probe,好长的一个函数
2627 base = devm_ioremap_resource(&pdev->dev, res);
2628 if (IS_ERR(base))
2629 return PTR_ERR(base);
2630
2631 ret = omap_hsmmc_gpio_init(pdata);
2632 if (ret)
2633 goto err;
devm_ioremap_resource,实质就是ioremap,设备特定io资源到内核地址的映射,自行脑补一下ioremap。
omap_hsmmc_gpio_init是card detect和write protect gpio的初始化,Ignore it!!!
2635 mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev);
2636 if (!mmc) {
2637 ret = -ENOMEM;
2638 goto err_alloc;
2639 }
...............
mmc_alloc_host,分配一个omap_hsmmc_host结构(包含struct mmc_host),以供后面玩耍
2661 mmc->ops = &omap_hsmmc_ops;
2410 static const struct mmc_host_ops omap_hsmmc_ops = {
2411 .enable = omap_hsmmc_enable_fclk,
2412 .disable = omap_hsmmc_disable_fclk,
2413 .post_req = omap_hsmmc_post_req,
2414 .pre_req = omap_hsmmc_pre_req,
2415 .request = omap_hsmmc_request,
2416 .set_ios = omap_hsmmc_set_ios,
2417 .get_cd = omap_hsmmc_get_cd,
2418 .get_ro = omap_hsmmc_get_ro,
2419 .init_card = omap_hsmmc_init_card,
2420 .start_signal_voltage_switch = omap_start_signal_voltage_switch,
2421 .card_busy = omap_hsmmc_card_busy,
2422 .execute_tuning = omap_execute_tuning,
2423 /* NYET -- enable_sdio_irq */
2424 };
omap hsmmc host驱动和mmc子系统的所有接口都在这里了。
2663 mmc->f_min = OMAP_MMC_MIN_CLOCK;
2675 if (pdata->max_freq > 0) {
2676 mmc->f_max = pdata->max_freq;
2677 ret = clk_set_rate(host->fclk, pdata->max_freq);
2678 if (ret) {
2679 dev_err(dev, "failed to set clock to %d\n",
2680 pdata->max_freq);
2681 goto err1;
2682 }
2683 } else {
2684 mmc->f_max = OMAP_MMC_MAX_CLOCK;
2685 }
定义了最小时钟400K,在系统初始化阶段为了兼容的原因会使用这个时钟。最大时钟为52MHZ,后面还有机会再修改这个时钟频率。
2724 mmc->max_segs = 1024;
2725
2726 mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
2727 mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */
2728 mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
2729 mmc->max_seg_size = mmc->max_req_size;
mmc作为快设备,最主要的操作就是数据sectors读写,max_segs定义了block设备的request所支持的最大segment
max_blk_count 一个request中所包含的最大block数
其实多少都不重要,反正就是和request相关的一些上限。