简介Component框架在qcom driver中的应用

1 架构目的

基于4.1.15内核,kernel中的component框架是为了subsystem能够按照一定的顺序初始化设备而提出的架构。subsystem中由较多设备模块组成,而内核加载每个模块时间不定。因此需要component框架来保证需最后初始化的设备加载前,所需设备全部加载完毕。

2 架构简介

在component中,包含两个基本概念,master和component。master是设备树中的“超级设备(superdevice)”,负责管理该超级设备下的普通设备,用于挂在全局链表masters上。component是由master管理的普通设备,所有的component都会挂在全局链表component_list链表上。看下两个结构体的定义:

struct master {
	struct list_head node;  // 用于添加自身到masters链表中
	bool bound; // 当所有component都执行完毕以后置true
	const struct component_master_ops *ops;
	struct device *dev;
	struct component_match *match;  // 旗下必需的component列表
	struct dentry *dentry;
};
struct component {
	struct list_head node;
	struct master *master;  // 决定挂在哪个master下
	bool bound;
	const struct component_ops *ops;
	int subcomponent;
	struct device *dev;
};

Component架构大致如下:

1.3 文件路径

/driver/base/component.c文件包含了主要逻辑。

1.4 qcom driver初始化

kmd主要由三个模块组成,分别是crm,cam sync以及子模块,umd层是控制kmd运转的大致框图如下。在provider初始化的时候会open video0,遍历所有的子设备节点,将所有子设备信息都放到CSL中,为之后的数据流转做好准备:

crm是qcom driver的核心,其注册为platform_driver后,会调用相应的probe方法:

static int cam_req_mgr_probe(struct platform_device *pdev) {
	int rc = 0;
	struct component_match *match_list = NULL;
	struct device *dev = &pdev->dev;
	rc = camera_component_match_add_drivers(dev, &match_list);
	if (rc) {
		CAM_ERR(CAM_CRM,
			"Unable to match components, probe failed rc: %d",
			rc);
		goto end;
	}

	/* Supply match_list to master for handing over control */
	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;
}

这里会调用camera_component_match_add_drivers方法将crm需要的子设备信息都收集到一个match_list结构体中:

int camera_component_match_add_drivers(struct device *master_dev,
	struct component_match **match_list) {
	int i, rc = 0;
	struct platform_device *pdev = NULL;
	struct device *start_dev = NULL, *match_dev = NULL;
	if (!master_dev || !match_list) {
		CAM_ERR(CAM_UTIL, "Invalid parameters for component match add");
		rc = -EINVAL;
		goto end;
	}
	for (i = 0; i < ARRAY_SIZE(cam_component_drivers); i++) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
		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
		start_dev = NULL;
		while ((match_dev = bus_find_device(&platform_bus_type,
			start_dev, drv_ptr, &camera_platform_compare_dev))) {
			put_device(start_dev);
            // 相当于是类型转换
			pdev = to_platform_device(match_dev);
			CAM_DBG(CAM_UTIL, "Adding matched component:%s", pdev->name);
			component_match_add(master_dev, match_list,
				camera_component_compare_dev, match_dev);
			start_dev = match_dev;
		}
		put_device(start_dev);
	}

end:
	return rc;
}

这里会遍历拿到crm下所有的子驱动列表,并且调用bus_find_device在bus总线上找到每个driver对应的device设备,然后调用component_match_add函数将设备信息收集到match_list列表中,这里的match_list非常重要,后面就是用match_list中收集的信息来进行component和从属master的配对

static struct platform_driver *const cam_component_drivers[] = {
/* BASE */
	&cam_sync_driver,
	&cam_smmu_driver,
	&cam_cpas_driver,
	&cam_cdm_intf_driver,
	&cam_hw_cdm_driver,
#ifdef CONFIG_SPECTRA_TFE
	&cam_csid_ppi100_driver,
	&cam_tfe_driver,
	&cam_tfe_csid_driver,
#endif
#ifdef CONFIG_SPECTRA_ISP
	&cam_ife_csid_driver,
	&cam_ife_csid_lite_driver,
	&cam_vfe_driver,
	&cam_sfe_driver,
	&isp_driver,
#endif
#ifdef CONFIG_SPECTRA_SENSOR
	&cam_res_mgr_driver,
	&cci_driver,
	&csiphy_driver,
	&cam_actuator_platform_driver,
	&cam_sensor_platform_driver,
	&cam_eeprom_platform_driver,
	&cam_ois_platform_driver,
	&cam_tpg_driver,
#if IS_REACHABLE(CONFIG_LEDS_QPNP_FLASH_V2) || \
	IS_REACHABLE(CONFIG_LEDS_QTI_FLASH)
	&cam_flash_platform_driver,
#endif
#endif
#ifdef CONFIG_SPECTRA_ICP
	&cam_a5_driver,
	&cam_lx7_driver,
	&cam_ipe_driver,
	&cam_bps_driver,
	&cam_icp_driver,
#endif
#ifdef CONFIG_SPECTRA_OPE
	&cam_ope_driver,
	&cam_ope_subdev_driver,
#endif
#ifdef CONFIG_SPECTRA_JPEG
	&cam_jpeg_enc_driver,
	&cam_jpeg_dma_driver,
	&jpeg_driver,
#endif
#ifdef CONFIG_SPECTRA_CRE
	&cam_cre_driver,
	&cam_cre_subdev_driver,
#endif
#ifdef CONFIG_SPECTRA_FD
	&cam_fd_hw_driver,
	&cam_fd_driver,
#endif
#ifdef CONFIG_SPECTRA_LRME
	&cam_lrme_hw_driver,
	&cam_lrme_driver,
#endif
};

看下component_match_add具体实现:

void component_match_add(struct device dev, struct component_match **matchptr, int (compare)(struct device *, void *), void *compare_data) {
    struct component_match *match = *matchptr;
    if (IS_ERR(match))
      return;
    
    if (!match || match->num == match->alloc) {
      size_t new_size = match ? match->alloc + 16 : 15;
      match = component_match_realloc(dev, match, new_size);
      *matchptr = match;    
      if (IS_ERR(match))
        return;
    }
    // match.compare是一个链状数组,可以使用[]一样访问里面的成员
    // 特别注意这里的compare_data,后面执行匹配的时候就是通过比较该变量来确定的
    match->compare[match->num].compare = compare;
	match->compare[match->num].compare_typed = compare_typed;
	match->compare[match->num].release = release;
	match->compare[match->num].data = compare_data;
	match->compare[match->num].component = NULL;
    match->num++; // 每添加一个成员到match中,相应的num+1
} 
// 顺便看下match-list是啥样的
struct component_match {
    size_t alloc;
    size_t num;
    // 也就是每个component包含的信息,下面称之为entry
    struct component_match_array *compare;
};
struct component_match_array {
    void *data;
    int (*compare)(struct device *, void *);
    int (*compare_typed)(struct device *, int, void *);
    void (*release)(struct device *, void *);
    struct component *component; // 主要就是管理这货
    bool duplicate;
};

(这里习惯将单个component_match.compare称为entry)

可以看出,上述camera_component_match_add_drivers方法就是将crm子设备对应的entry都放进match_list列表中,函数结束后,crm需要的match-list就被填充好(主要存放匹配信息)

特别注意,这里的compare_data对应于match_dev,后面将component-list中的component和match-list的entry中的component配对时,就是通过比较该变量来确定的。

回头继续看下component_master_add_with_match方法:

int component_master_add_with_match(struct device *dev,
	const struct component_master_ops *ops,
	struct component_match *match) {
	struct master *master;
	int ret;

	/* Reallocate the match array for its true size */
	ret = component_match_realloc(dev, match, match->num);
	if (ret)
		return ret;
	master = kzalloc(sizeof(*master), GFP_KERNEL);
	if (!master)
		return -ENOMEM;
    //  目前只确定了master的match-list,这里面有component的包装信息          
	master->dev = dev;
	master->ops = ops;
	master->match = match;
	component_master_debugfs_add(master);
	/* Add to the list of available masters. */
	mutex_lock(&component_mutex);
    // 封装master,然后将master添加到component架构中的masters链表中         
	list_add(&master->node, &masters);
    // 尝试初始化该master
	ret = try_to_bring_up_master(master, NULL);
	if (ret < 0)
		free_master(master);
	mutex_unlock(&component_mutex);
	return ret < 0 ? ret : 0;
}

这里主要做以下几个动作:

1、调用component_match_realloc,裁剪match内存为实际占用的内存(分配的时候数组大小为16,实际可能用不到那么多,因此裁剪一下);

2、封装master结构体,并且添加到全局链表master上,也就是crm将自己作为master注册进Component框架的masters链表中;

3、调用try_to_bring_up_master尝试初始化该master,因为crm中的子设备还没有集齐,所以这里不会初始化成功。

注意:目前尚未对match-list中的entry的component指针赋值,只赋值了匹配信息(用于找component)。

现在,component架构中的master已经创建好了,接下来自然要创建相应的component。crm中有很多的子设备,以sensor为例子,看子设备是如何添加到component架构中的。

static int32_t cam_sensor_driver_platform_probe(
	struct platform_device *pdev) {
	int rc = 0;
	CAM_DBG(CAM_SENSOR, "Adding Sensor component");
    // cam_sensor_component_ops里装的就是该子设备初始化后执行的函数
	rc = component_add(&pdev->dev, &cam_sensor_component_ops);
	if (rc)
		CAM_ERR(CAM_SENSOR, "failed to add component rc: %d", rc);
	return rc;
}
static int __component_add(struct device *dev, const struct component_ops *ops,
	int subcomponent) {
	struct component *component;
	int ret;
	component = kzalloc(sizeof(*component), GFP_KERNEL);
	if (!component)
		return -ENOMEM;
    // 这里暂时未确定master
	component->ops = ops;
	component->dev = dev;
	component->subcomponent = subcomponent;
	dev_dbg(dev, "adding component (ops %ps)\n", ops);
	mutex_lock(&component_mutex)
    // 封装component结构体,并且放到component_list中          
	list_add_tail(&component->node, &component_list);
    // 这里竟然朝着总链masters动手了    
	ret = try_to_bring_up_masters(component);
	if (ret < 0) {
		if (component->master)
			remove_component(component->master, component);
		list_del(&component->node);
		kfree(component);
  	}
	mutex_unlock(&component_mutex);
	return ret < 0 ? ret : 0;
}

这里sensor将自己作为component注册进Component框架的component_list链表中,然后调用try_to_bring_up_masters试图将该component对应的master进行初始化(也就是查看masters中是否也有该component对应的master)。注意,每个子设备在注册为component时,并没有确定components->master,那是如何找到相应的master呢,继续往下看:

static int try_to_bring_up_masters(struct component *component) {
	struct master *m;
	int ret = 0;
	list_for_each_entry(m, &masters, node) {
		if (!m->bound) {
			ret = try_to_bring_up_master(m, component);
			if (ret != 0)
				break;
		}
	}
	return ret;
}

上述会去遍历链表,其中m就是链表中的一个master成员,如果该master没有绑定过(即没有收齐所有的component,相应的master-bound=false),则接下来通过执行try_to_bring_up_master函数来查看该master是否和conponent匹配,注意传入的参数:

static int try_to_bring_up_master(struct master *master,
	struct component *component) {
	int ret;
	dev_dbg(master->dev, "trying to bring up master\n");
	if (find_components(master)) {
		dev_dbg(master->dev, "master has incomplete components\n");
		return 0;
	}
    // 说明函数find_components会填充component->master
	if (component && component->master != master) {
		dev_dbg(master->dev, "master is not for this component (%s)\n",dev_name(component->dev));
		return 0;
	}
	if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
		return -ENOMEM;
    // 如果所有的component都收集好了,就会执行master对应的bind方法
	ret = master->ops->bind(master->dev);
	if (ret < 0) {
		devres_release_group(master->dev, NULL);
		if (ret != -EPROBE_DEFER)
			dev_info(master->dev, "master bind failed: %d\n", ret);
		return ret;
	}
    // 设置标记 
	master->bound = true;
	return 1;
}

try_to_bring_up_master函数中传入的形参component只做判断使用,没有其他用途。find_components中会确定components->master。这里先通过find_components来查看该master下所有的component是否集齐:

static int find_components(struct master *master) {
	struct component_match *match = master->match;
	size_t i;
	int ret = 0;
	for (i = 0; i < match->num; i++) {
        // 遍历match-list中的entry
		struct component_match_array *mc = &match->compare[i];
		struct component *c;
		dev_dbg(master->dev, "Looking for component %zu\n", i);
       // 不为空就跳过执行下一次循环,这里的目的是为空的entry找到相应的component
		if (match->compare[i].component)
			continue;
		c = find_component(master, mc);
		if (!c) {
			ret = -ENXIO;
			break;
		}
		dev_dbg(master->dev, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master);
		/* Attach this component to the master */
		match->compare[i].duplicate = !!c->master;
        // 确定关系
		match->compare[i].component = c;
        // 上面创建的component在此确定master属性
		c->master = master;
	}
	return ret;
}
static struct component *find_component(struct master *master,
	struct component_match_array *mc) {
	struct component *c;
	list_for_each_entry(c, &component_list, node) {
        // 遍历component-list,查看是否有和当前传入的master匹配的component
		if (c->master && c->master != master)
			continue;
        // 如果master匹配,且相应的比较函数也匹配,就说明找到了component
		if (mc->compare && mc->compare(c->dev, mc->data))
			return c;

		if (mc->compare_typed &&
		    mc->compare_typed(c->dev, c->subcomponent, mc->data))
			return c;
	}

	return NULL;
}

find_component函数的作用是查看component-list链表中是的component成员与match-list的entry中包含的component是否相匹配,也就是查看前面赋值的dev是否一致,若匹配则将component-list中的component返回;

find_components函数的作用是遍历某master中的match-list,查找entry中的component是否和component-list上的一个具体的component匹配,如果匹配,则将component-list中的component放到match-list相应entry中保存(也就是保存在match_list.compare[i]中)。

比如crm在收集子设备的时候,已经将sensor放进match-list中。接着sensor在probe的时候将自己添加进了component-list列表,然后尝试在masters中试图找到和自身匹配的component成员。

上述函数的大致过程如下:

如果某master的match_list中的每个entry都有相应的component_list中的component成员与之匹配(也就是find_components函数返回值为0),就表示该master已经收集完旗下所有的component,此时就要调用该master对应的bind函数。这里看下crm相应的bind函数:

static int cam_req_mgr_component_master_bind(struct device *dev) {
	int rc = 0;
	// first: create v4l2-device node
	rc = cam_v4l2_device_setup(dev);
	if (rc)
		return rc;
    // second: create media node  
	rc = cam_media_device_setup(dev);
	if (rc)
		goto media_setup_fail;
    // third: create video0 node          
	rc = cam_video_device_setup();
	if (rc)
		goto video_setup_fail;
	g_dev.open_cnt = 0;
	g_dev.shutdown_state = false;
	mutex_init(&g_dev.cam_lock);
	spin_lock_init(&g_dev.cam_eventq_lock);
	mutex_init(&g_dev.dev_lock);
	rc = cam_req_mgr_util_init();
	if (rc) {
		CAM_ERR(CAM_CRM, "cam req mgr util init is failed");
		goto req_mgr_util_fail;
	}
	rc = cam_req_mgr_core_device_init();
	if (rc) {
		CAM_ERR(CAM_CRM, "core device setup failed");
		goto req_mgr_core_fail;
	}
	INIT_LIST_HEAD(&cam_req_mgr_ordered_sd_list);
    // 激活所有子设备的bind方法
	rc = component_bind_all(dev, NULL);
	if (rc) {
		CAM_ERR(CAM_CRM,
			"Error in binding all components rc: %d, Camera initialization failed!", rc);
		goto req_mgr_device_deinit;
	}

这里会注册v4l2-device设备、video0节点、media节点等,然后调用component_bind_all激活所有子设备的bind方法。

component_bind_all函数实现如下:

int component_bind_all(struct device *master_dev, void *data) {
	struct master *master;
	struct component *c;
	size_t i;
	int ret = 0;
	WARN_ON(!mutex_is_locked(&component_mutex));
	master = __master_find(master_dev, NULL);
	if (!master)
		return -EINVAL;
	/* Bind components in match order */
	for (i = 0; i < master->match->num; i++)
		if (!master->match->compare[i].duplicate) {
			c = master->match->compare[i].component;
            // 执行每个component对应的bind方法
			ret = component_bind(c, master, data);
			if (ret)
				break;
		}
        }

	return ret;
}
static int component_bind(struct component *component, 
       struct master *  master,void *data){
	int ret;
	if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
		return -ENOMEM;
	if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
		devres_release_group(master->dev, NULL);
		return -ENOMEM;
	}
	dev_dbg(master->dev, "binding %s (ops %ps)\n",
		dev_name(component->dev), component->ops);
     // 执行该component的相应bind方法,crm在前面注册为master时会赋值该ops方法
	ret = component->ops->bind(component->dev, master->dev, data);
	return ret;
}

1.5 总结

1.控制中枢(如crm)在probe函数里先创建一个master->match_list链表,将其下所有子设备信息记录在此链表中,然后将自己注册成master放到masters链表中;

2.所有的子驱动在初始化的时候,都会通过component_add方法把自己加入到component_list链表中,然后调用try_to_bring_up_masters尝试初始化masters中某个未绑定的master,实际上是查找masters链表中是否有master处于bound状态,如果有的话,则尝试初始化该master(执行完bind方法的master,需要做上标记master->bound == true);

3.当master中所有的component都收集完毕以后,调用相应的bind函数,在该bind方法中做一些初始化动作,如解析设备树、创建节点等,并激活该master下所有component对应的bind方法

注:上面是高通8550上的代码实现,8650上稍有改变,但是大体逻辑没变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值