component框架用来处理内核模块加载/卸载顺序,保证最后加载的模块在需要先加载的模块都加载后加载。
component有两个概念:master和component。master是超级设备,通过设备树管控多个component加载/卸载顺序,保证所有组件正常加载/卸载。
以高通相机系统"Spectra camera drivers"为例子,分析componet的概念与实现。
背景描述:
在阅读CSIPHY驱动代码时有如下的代码:
const static struct component_ops cam_csiphy_component_ops = {
.bind = cam_csiphy_component_bind,
.unbind = cam_csiphy_component_unbind,
};
static int32_t cam_csiphy_platform_probe(struct platform_device *pdev)
{
int rc = 0;
CAM_DBG(CAM_CSIPHY, "Adding CSIPHY component");
rc = component_add(&pdev->dev, &cam_csiphy_component_ops);
if (rc)
CAM_ERR(CAM_CSIPHY, "failed to add component rc: %d", rc);
return rc;
}
初见代码推测实现的内容大概是:component_add(&pdev->dev, &cam_csiphy_component_ops)将cam_csiphy_component_ops这组实现接口添加到哪里,以用于后续的使用。
内核中component实现
component通过维护两个全局的组件链表masters和component_list管理注册的master/component组件对象。
-
device对象通过component_add()将自己的device结构和component_ops注册到component_list.
-
然后component框架尝试bring up masters链表中的各master对象.如果master依赖的组件都已经加载完,这时的master可以加载了,会执行自己的bind()绑定自己的component。
component框架有三个处理流程:master/component add、component bind、component unbind。
1.master/component add
超级设备master设备调用component_master_add_with_match()将自己以组件形式添加到component框架。component设备调用component_add()将自己以组件形式添加到component框架。
master最终添加到component框架的masters链表,component最终添加到component_list链表。
下面以超级设备添加框架为例子,过程如下:
首先,component框架为超级设备分配一个master数据结构,装载要添加到框架中的设备。
然后,将这个超级设备的master对象添加到component框架的masters链表。
最后,这个master尝试bring up(详见接口:try_to_bring_up_master)。
2.component bind
有两种方式触发component框架进行bind流程:
-
一个master添加到component框架,同时这个master匹配的component都已经注册到component框架,这时master尝试bring up自己,触发bind处理流程.
-
一个component添加到component框架,同时这个component的加入使component框架中注册的一个或多个master的匹配条件得到满足,这时这些满足条件的master将逐个触发bind处理流程。
无论是master的注册还是component的注册触发bind流程,触发bind流程的条件都是:master的match条件得到满足。
master注册后调用try_to_bring_up_master()检查match条件,尝试启动bind流程;component注册后调用try_to_bring_up_masters()逐个检查注册到框架的master的match条件,尝试启动启动bind流程。
master match检查:
下面以一个有3个match要求的master注册后的首次尝试bind过程为例子,
这个master注册到masters链表,即将尝试bind。
master根据自己的match条件(几个match项;每个match项明确一个component match的要求,和一个指向满足该match的componet对象)对注册到component进行match检查。match失败,对注册的下一个component进行match;match成功时,更新对应match项,然后换下一个注册的component进行match,如下
直到master的所有match项都尝试match一次,即完成一次match条件检查。
master触发bind:
当master的match要求得到满足时,会触发bind流程。bind处理流程主要完成master和component顺序上的交互处理。component框架通过master注册的component_master_ops.bind()将bind流程交给master,后续master调用component_ops.bind()将bind()交给component,最终完成bind流程。
3.component unbind
master调用component_master_del()函数完成解绑。component调用component_del()函数解绑。
component_del()完成component的unbind和自己的注销。
component_master_del()完成和component的unbind,当master的所有component都unbind后,master注销。
使用举例-CameraSystem
CSIPHY作为component通过component_add()将自己的组件操作添加到component链表。
cam_req_mgr_dev作为master通过component_master_add_with_match()将自己添加到masters链表,并完成match。
代码介绍:
-
CSIPHY组件添加到component框架
-
CRM超级设备添加到componet框架
-
try_to_bing_up_master
-
CRM bind
-
CSIPHY bind
1.CSIPHY添加component
static int32_t cam_csiphy_platform_probe(struct platform_device *pdev)
{
int rc = 0;
CAM_DBG(CAM_CSIPHY, "Adding CSIPHY component");
//1.csiphy driver探测是通过component_add将自己的component_ops添加
rc = component_add(&pdev->dev, &cam_csiphy_component_ops);
if (rc)
CAM_ERR(CAM_CSIPHY, "failed to add component rc: %d", rc);
return rc;
}
component框架实现接口:
//drivers/base/component.c
int component_add(struct device *dev, const struct component_ops *ops)
{
return __component_add(dev, ops, 0); //继续添加component
}
EXPORT_SYMBOL_GPL(component_add);
static int __component_add(struct device *dev, const struct component_ops *ops,
int subcomponent)
{
struct component *component;
int ret;
//1.分配一个component结构
component = kzalloc(sizeof(*component), GFP_KERNEL);
if (!component)
return -ENOMEM;
//2.将添加的device和component_ops实例注册到这个component接口。
component->ops = ops;
component->dev = dev;
component->subcomponent = subcomponent;
//3.添加携带device和component_ops的component节点到component_list
list_add_tail(&component->node, &component_list);
//4.尝试bring up masters
ret = try_to_bring_up_masters(component);
return ret < 0 ? ret : 0;
}
component框架维护两个链表masters和component_list来管理注册到component框架的master设备和component设备。master注册到masters,component注册到component_list。
//drivers/base/component.c
static int try_to_bring_up_masters(struct component *component)
{
struct master *m;
int ret = 0;
//1.遍历masters中的master节点
list_for_each_entry(m, &masters, node) {
if (!m->bound) { //.bound是约束标志,表明master是不是还被束缚(依赖的component没全完成)
ret = try_to_bring_up_master(m, component); //继续bring up
if (ret != 0)
break;
}
}
return ret;
}
2.cam_req_mgr_dev添加master流程
//techpack/camera/drivers/cam_req_mgr/cam_req_mgr_dev.c
static const struct component_master_ops cam_req_mgr_component_master_ops = {
.bind = cam_req_mgr_component_master_bind,
.unbind = cam_req_mgr_component_master_unbind,
};
static int cam_req_mgr_probe(struct platform_device *pdev)
{
int rc = 0;
struct component_match *match_list = NULL;
struct device *dev = &pdev->dev;
//将camera component match添加到driver
rc = camera_component_match_add_drivers(dev, &match_list);
/* Supply match_list to master for handing over control */
//将自己作为master添加到component框架的masters链表
//同时根据match列表xx
rc = component_master_add_with_match(dev,
&cam_req_mgr_component_master_ops, match_list);
if (rc) {
CAM_ERR(CAM_CRM,
"Unable to add master, probe failed rc: %d",
rc);
goto end;
}
end:
return rc;
}
cam_req_mgr的match列表添加:
int camera_component_match_add_drivers(struct device *master_dev,
struct component_match **match_list)
{
int i, rc = 0;
struct platform_device *pdev = NULL;
//遍历cam_component_drivers
for (i = 0; i < ARRAY_SIZE(cam_component_drivers); i++) {
//1.组件设备驱动地址
#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE
struct device_driver const *drv =
&cam_component_drivers[i]->driver;
const void *drv_ptr = (const void *)drv;
#else
struct device_driver *drv = &cam_component_drivers[i]->driver;
void *drv_ptr = (void *)drv;
#endif
struct device *start_dev = NULL, *match_dev;
//2.bus从注册的设备中查找driver匹配的device
while ((match_dev = bus_find_device(&platform_bus_type,
start_dev, drv_ptr, &camera_platform_compare_dev))) {
//camera_platform_compare_dev()检查device和driver是不是match
put_device(start_dev);
pdev = to_platform_device(match_dev);
CAM_DBG(CAM_UTIL, "Adding matched component:%s",
pdev->name);
//3.收集匹配的device到match_list
component_match_add(master_dev, match_list, //match_list是收集到的匹配devices
camera_component_compare_dev, match_dev); //camera_component_compare_dev是添加component时用于match_list中device匹配比较的回调函数
//match_dev是注册到bus的device迭代变量
start_dev = match_dev;
}
put_device(start_dev);
}
end:
return rc;
}
3.master bring up流程
component添加到component_list或者master添加到masters,都会触发try_to_bring_up_master(),尝试bring up master。一个component的加入可能使某一个master达到bring up条件,所以需要对master链表遍历确定是不是已注册的master有可以bring up的,如果有要bring up哪个master。一个master的加入时,可能它需要的component都已经complete(一般也已经在component_list注册表),所以master加入时尝试一次bring up。
//drivers/base/component/c
static int try_to_bring_up_master(struct master *master, //masters链表中的一个master对象
struct component *component)//当前添加的component对象
{
int ret;
//1.检查master是不是有incomplete的components.
//如果有incomplete直接返回
if (find_components(master)) {
dev_dbg(master->dev, "master has incomplete components\n");
return 0;
}
//2.检查component的master是不是当前这个master对象,
//如果不是,说明要bring up的这个master对象需要的不是这个component对象,直接返回
if (component && component->master != master) {
dev_dbg(master->dev, "master is not for this component (%s)\n",
dev_name(component->dev));
return 0;
}
//3.为master表示的这个device打开资源group.(devres是设备资源管理用的)
if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
return -ENOMEM;
//走到这里表明master已经找到所有component
//4.master执行bind流程.绑定需要的component设备
ret = master->ops->bind(master->dev);
master->bound = true;
return 1;
}
到这里,master bring up要调用master dev注册的component_ops.bind()了。
CRM(master)bind流程
//techpack/camera/drivers/cam_req_mgr/cam_req_mgr_dev.c
struct kmem_cache *g_cam_reg_mgr_timer_cachep;
static int cam_req_mgr_component_master_bind(struct device *dev)
{
int rc = 0;
//1.v4l2_device setup(v4l2框架这部分的设置)
rc = cam_v4l2_device_setup(dev);
//2.media_device setup(media框架graph、pipeline、link这些的设置)
rc = cam_media_device_setup(dev);
//3.video_device setup(ctrl这部分设置)
rc = cam_video_device_setup();
//4.等CRM初始化完成
rc = cam_req_mgr_util_init();
//5.CRM核心device()初始化
rc = cam_req_mgr_core_device_init();
//6.更新g_dev。 g_dev是用于CRM设备全局管理的数据结构
g_dev.state = true;
//7.为crm_timer创建mem cache
if (g_cam_req_mgr_timer_cachep == NULL) {
g_cam_req_mgr_timer_cachep = kmem_cache_create("crm_timer",
sizeof(struct cam_req_mgr_timer), 64,
SLAB_CONSISTENCY_CHECKS | SLAB_RED_ZONE |
SLAB_POISON | SLAB_STORE_USER, NULL);
}
//8.调用match的component.binds
rc = component_bind_all(dev, NULL);
//9.sysfs系统节点文件的创建
rc = sysfs_create_file(&dev->kobj, &camera_debug_sysfs_attr.attr);
return rc;
}