mmc subsystem系列(持续更新中):
[mmc subsystem] 概念与框架
[mmc subsystem] mmc core(第一章)——概述
[mmc subsystem] mmc core(第二章)——数据结构和宏定义说明
[mmc subsystem] mmc core(第三章)——bus模块说明
[mmc subsystem] mmc core(第四章)——host模块说明
[mmc subsystem] mmc core(第五章)——card相关模块(mmc type card)
[mmc subsystem] mmc core(第六章)——mmc core主模块
建议先参考《[mmc subsystem] 概念与框架》和《[mmc subsystem] mmc core(第一章)——概述》对整体有一个了解。
=========================================================================================================
一、说明
1、mmc core概述
mmc core主模块是mmc core的实现核心。也是本章的重点内容。
对应代码位置drivers/mmc/core/core.c。
其主要负责如下功能:
- mmc core初始化,包括注册mmc bus、mm host class等等
- mmc host的管理和维护,包括为其他模块提供mmc_host的操作接口,如下
- host的启动和停止
- host的占用和释放
- host电源状态的保存和恢复
- host总线操作集的绑定和解绑
- host上卡状态检测
- 为其他模块提供mmc_card的操作接口,如下
- card的唤醒和休眠
- card擦除
- card属性的获取
- 为其他模块提供总线io setting的接口
- 为其他模块提供mmc请求接口
- card检测接口
- bkops操作接口
- regulator操作接口
- clock操作接口
- mmc core电源管理操作接口
2、操作集说明
在mmc_host中有两个操作集成员,需要理解一下,以免在代码中产生误会:
- mmc_host->struct mmc_host_ops *ops,这个是host的操作集,由host controller驱动决定。对于sdhci类host来说,就是sdhci_ops(sdhci.c中设置)。
- mmc_host->struct mmc_bus_ops *bus_ops,这个是mmc总线的操作集(也可以理解为host的mmc bus handler,host的总线处理方法),由总线上的card type决定。对于mmc card type来说,就是mmc_ops_unsafe或者mmc_ops(mmc_attach_bus_ops中设置)。
二、API总览
1、mmc core初始化相关
- mmc_init & mmc_exit (模块内使用)
2、mmc host的管理和维护相关
- mmc_claim_host & mmc_try_claim_host & mmc_release_host (模块内使用)
- mmc_power_up & mmc_power_off
- mmc_start_host & mmc_stop_host
- mmc_power_save_host & mmc_power_restore_host
- mmc_resume_host & mmc_suspend_host
- mmc_pm_notify
3、mmc card的操作相关(包括card状态的获取)
- mmc_hw_reset & mmc_hw_reset_check &
- mmc_card_awake & mmc_card_sleep
- mmc_card_is_prog_state
- mmc_can_erase
- mmc_can_trim
- mmc_can_discard
- mmc_can_sanitize
- mmc_can_secure_erase_trim
- mmc_erase_group_aligned
4、总线io setting相关
- mmc_set_ios
- mmc_set_chip_select
- mmc_set_clock
- mmc_set_bus_mode
- mmc_set_bus_width
- mmc_select_voltage
- mmc_set_signal_voltage(特殊)
- mmc_set_timing
mmc_set_driver_type
mmc_get_max_frequency & mmc_get_min_frequency
5、host的mmc总线相关
- mmc_resume_bus
- mmc_attach_bus & mmc_detach_bus
6、mmc请求相关
- mmc_request_done
- mmc_wait_for_req
- mmc_wait_for_cmd
- mmc_set_data_timeout
- mmc_align_data_size
7、card检测相关
- mmc_detect_change
- mmc_rescan
- mmc_detect_card_removed
8、bkops操作相关
- mmc_blk_init_bkops_statistics
- mmc_start_delayed_bkops
- mmc_start_bkops & mmc_stop_bkops
- mmc_start_idle_time_bkops
- mmc_read_bkops_status
9、regulator操作相关
- mmc_regulator_get_ocrmask
- mmc_regulator_set_ocr
- mmc_regulator_get_supply
10、card擦除操作相关
- mmc_init_erase
- mmc_erase
11、clock操作接口
- mmc_init_clk_scaling & mmc_exit_clk_scaling
- mmc_can_scale_clk
- mmc_disable_clk_scaling
12、mmc core电源管理操作
- mmc_rpm_hold & mmc_rpm_release
二、接口代码说明——mmc core初始化相关
1、mmc_init实现
负责初始化整个mmc core。
主要工作:
- 分配一个workqueue,用于专门处理mmc core的执行的工作
- 注册mmc bus
- 注册mmc host class
代码如下:
static int __init mmc_init(void)
{
int ret;
/* 分配一个workqueue,用于专门处理mmc core的执行的工作 */
workqueue = alloc_ordered_workqueue("kmmcd", 0);
/* 注册mmc bus */
ret = mmc_register_bus(); // 调用mmc_register_bus注册mmc bus,具体参考《mmc core——bus模块说明》
// 会生成/sys/bus/mmc目录
/* 注册mmc host class */
ret = mmc_register_host_class(); // 调用mmc_register_host_class注册mmc host class,具体参考《mmc core——host模块说明》
// 会生成/sys/class/mmc_host目录
/* 注册sdio bus */
ret = sdio_register_bus();
return 0;
}
subsys_initcall(mmc_init);
三、接口代码说明——mmc host的管理和维护相关
1、mmc_claim_host & mmc_try_claim_host & mmc_release_host
host被使能之后就不能再次被使能,并且只能被某个进程独自占用。
可以简单地将host理解为一种资源,同时只能被一个进程获取,但是在占用进程里面可以重复占用。
在对host进行操作之前(包括发起mmc请求),必须使用mmc_claim_host和mmc_release_host来进行获取和释放。
变量说明
- mmc_host->claimed用来表示host是否被占用
- mmc_host->claimer用来表示host的占用者(进程)
- mmc_host->claim_cnt用来表示host的占用者的占用计数,为0时则会释放这个host
代码如下
static inline void mmc_claim_host(struct mmc_host *host)
{
__mmc_claim_host(host, NULL);·// 调用__mmc_claim_host来获取host
}
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
{
/只考虑abort为NULL的情况,在mmc core中的mmc_claim_host也是将其设置为NULL
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
int stop;
might_sleep(); // 说明这个函数可能导致进程休眠
add_wait_queue(&host->wq, &wait); // 把当前进程加入到等待队列中
spin_lock_irqsave(&host->lock, flags);
while (1) { // 以下尝试获取host,如果host正在被占用,会进入休眠
set_current_state(TASK_UNINTERRUPTIBLE); // 设置进程状态为TASK_UNINTERRUPTIBLE状态
stop = abort ? atomic_read(abort) : 0;
if (stop || !host->claimed || host->claimer == current) // 当host的占用标志claimed为0,或者占用者是当前进程的时候,说明可以占用了,退出
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule(); // 否则,进行调度进入休眠
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING); // 设置进程为运行状态
if (!stop) {
host->claimed = 1; // 设置占用标志claimed
host->claimer = current; // 设置占用者为当前进程
host->claim_cnt += 1; // 占用计数加1
} else
wake_up(&host->wq);
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait); // 将当前进程从等待队列中退出
if (host->ops->enable && !stop && host->claim_cnt == 1)
host->ops->enable(host); // 调用host操作集中的enable方法来占用该host,对应sdhci类host即为sdhci_enable
return stop;
}
void mmc_release_host(struct mmc_host *host)
{
unsigned long flags;
WARN_ON(!host->claimed);
if (host->ops->disable && host->claim_cnt == 1) // 当前claim_cnt为1(马上要变为0),调用释放host了
host->ops->disable(host); // 调用host操作集中的disable方法来释放该host,对应sdhci类host即为sdhci_disable
spin_lock_irqsave(&host->lock, flags);
if (--host->claim_cnt) {
/* Release for nested claim */
spin_unlock_irqrestore(&host->lock, flags); // 如果减一之后计数还不为0,说明当前进程需要继续占用该host,不做其他操作
} else { // 以下需要释放该host
host->claimed = 0; // 设置占用标志claimed为0
host->claimer = NULL; // 清空占用者(进程)
spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq); // 唤醒host的等待队列,让那些调用mmc_claim_host睡眠等待host资源的进程被唤醒
}
}
int mmc_try_claim_host(struct mmc_host *host)
{
// 和mmc_claim_host的主要区别在于进程不会休眠,获取失败直接返回
int claimed_host = 0;
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
if (!host->claimed || host->claimer == current) {
host->claimed = 1;
host->claimer = current;
host->claim_cnt += 1;
claimed_host = 1;
}
spin_unlock_irqrestore(&host->lock, flags);
if (host->ops->enable && claimed_host && host->