Linux component框架

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组件对象。

  1. device对象通过component_add()将自己的device结构和component_ops注册到component_list.

  2. 然后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;
}

猜你喜欢

转载自blog.csdn.net/hongyeying/article/details/128229155