v4l2_pipeline_pm_use的知识点分析,错过后悔
退出while循环的条件是什么?
回帖(1)
2022-3-10 09:25:37
花了一个entity的链接简图,忽略了link
其中彩色线条是enable的,黑线是disable
使用上面的图来分析 v4l2_pipeline_pm_use,从stream_cif_mipi_id0这个entity开始
v4l2_pipeline_pm_use(&vnode->vdev.entity, 1);
v4l2_pipeline_pm_use()
int v4l2_pipeline_pm_use(struct media_entity *entity, int use)
{
/*
* 一切都是基于media的,所以要先找到media
* use传入的是1
*/
struct media_device *mdev = entity->graph_obj.mdev;
int change = use ? 1 : -1;
int ret;
mutex_lock(&mdev->graph_mutex);
/* Apply use count to node. */
/*
* 更新entity使用计数
*/
entity->use_count += change;
WARN_ON(entity->use_count < 0);
/* Apply power change to connected non-nodes. */
/*
* 上面这句话的意思是
* 将电源更改应用于连接的非节点
* 非节点是什么意思?非video节点?所以这里更改的事subdev节点?
*/
/*
* medv->pm_count_walk 这个变量实在media_device_register_entity中
* 被赋值的
* 该变量类型是 struct media_graph
* 可以看上一篇文章中的一个graph变量
*/
ret = pipeline_pm_power(entity, change, &mdev->pm_count_walk);
if (ret < 0)
entity->use_count -= change;
mutex_unlock(&mdev->graph_mutex);
return ret;
}
v4l2_pipeline_pm_use() -> pipeline_pm_power()
static int pipeline_pm_power(struct media_entity *entity, int change,
struct media_graph *graph)
{
struct media_entity *first = entity;
int ret = 0;
if (!change)
return 0;
media_graph_walk_start(graph, entity);
while (!ret && (entity = media_graph_walk_next(graph)))
if (is_media_entity_v4l2_subdev(entity))
ret = pipeline_pm_power_one(entity, change);
if (!ret)
return ret;
...
}
media_graph_walk_next 代码量有些大,会占用不少篇幅,所以还是看上一篇文章吧,这篇文章只会贴一些关键代码用于理解分析
这里贴一下log的部分打印
[ 77.491726] rkcif rkcif_mipi_lvds: begin graph walk at 'stream_cif_mipi_id0'
[ 77.491730] entity->name 0 is stream_cif_mipi_id0
[ 77.491743] is backlink!
[ 77.491757] entity->name 2 is rockchip-mipi-csi2
[ 77.491777] rkcif rkcif_mipi_lvds: walk: pushing 'rockchip-mipi-csi2' on stack
[ 77.491781] entity->name 0 is rockchip-mipi-csi2
[ 77.491794] is backlink!
[ 77.491808] entity->name 2 is rockchip-mipi-dphy-rx
[ 77.491828] rkcif rkcif_mipi_lvds: walk: pushing 'rockchip-mipi-dphy-rx' on stack
[ 77.491832] entity->name 0 is rockchip-mipi-dphy-rx
[ 77.491847] is link!
[ 77.491860] entity->name 1 is rockchip-mipi-csi2
[ 77.491880] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-csi2' (already seen)
[ 77.491884] entity->name 0 is rockchip-mipi-dphy-rx
[ 77.491898] is backlink!
[ 77.491912] entity->name 2 is m01_f_imx291 1-001a
[ 77.491931] rkcif rkcif_mipi_lvds: walk: pushing 'm01_f_imx291 1-001a' on stack
[ 77.491935] entity->name 0 is m01_f_imx291 1-001a
[ 77.491949] is link!
[ 77.491960] entity->name 1 is rockchip-mipi-dphy-rx
[ 77.491974] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-dphy-rx' (already seen)
[ 77.491982] rkcif rkcif_mipi_lvds: walk: returning entity 'm01_f_imx291 1-001a'
其中media_graph_walk_next中
#define link_top(en) ((en)->stack[(en)->top].link)
#define stack_top(en) ((en)->stack[(en)->top].entity)
struct media_entity *media_graph_walk_next(struct media_graph *graph)
{
struct media_entity *entity;
...
while (link_top(graph) != &stack_top(graph)->links)
media_graph_walk_iter(graph);
entity = stack_pop(graph);
dev_dbg(entity->graph_obj.mdev->dev,
"walk: returning entity '%s'n", entity->name);
return entity;
}
退出while循环的条件是什么?
&stack_top(graph) -> links 是链表头的地址,link_top(graph) 是links链表上的成员的地址
当两者相等的时候,也就是说links链表上的遍历完成的时候,就会退出while。
根据log,解释一下过程
/*
* media_graph_walk_start 中打印,top = 1
*/
[ 77.491726] rkcif rkcif_mipi_lvds: begin graph walk at 'stream_cif_mipi_id0'
/*
* 找到了stream_cif_mipi_id0的backlink
* 因为stream_cif_mipi_id0没有source pad,所以没有link只有backlink
* 通过backlink找到了source entity rockchip-mipi-csi2
*/
[ 77.491730] entity->name 0 is stream_cif_mipi_id0
[ 77.491743] is backlink!
[ 77.491757] entity->name 2 is rockchip-mipi-csi2
/*
* 简图中可以知道 stream_cif_mipi_id0:0 <---> rockchip-mipi-csi2:1
* 这2个pad是enable的
* 所以这里会入栈
* top = 2
*/
[ 77.491777] rkcif rkcif_mipi_lvds: walk: pushing 'rockchip-mipi-csi2' on stack
/*
* 由于执行了一次入栈操作,top的值发生了改变
* 所以这里不会在继续遍历stream_cif_mipi_id0的links
* 而是去遍历rockchip-mipi-csi2的links
* 首先遍历的是backlink
* 这就找到了source entity rockchip-mipi-dphy-rx
*/
[ 77.491781] entity->name 0 is rockchip-mipi-csi2
[ 77.491794] is backlink!
[ 77.491808] entity->name 2 is rockchip-mipi-dphy-rx
/*
* rockchip-mipi-csi2:0 <---> rockchip-mipi-dphy-rx:1
* top = 3
* 入栈操作
*/
[ 77.491828] rkcif rkcif_mipi_lvds: walk: pushing 'rockchip-mipi-dphy-rx' on stack
/*
* 于是遍历rockchip-mipi-dphy-rx的links
* 首先是link,对于是link还是backlink,还是看驱动中links挂载的顺序
* 使用link的时候,是向后走,这样就会找到sink entity rockchip-mipi-csi2
* 由于之前stream_cif_mipi_id0操作的时候,已经访问过rockchip-mipi-csi2了
* 所以会跳过rockchip-mipi-csi2
*/
[ 77.491832] entity->name 0 is rockchip-mipi-dphy-rx
[ 77.491847] is link!
[ 77.491860] entity->name 1 is rockchip-mipi-csi2
[ 77.491880] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-csi2' (already seen)
/*
* 因为没有执行入栈操作,所以这里会继续遍历rockchip-mipi-dphy-rx的links
* 这次找到了backlink
* 向前找到了 source entity m01_f_imx291 1-001a
*/
[ 77.491884] entity->name 0 is rockchip-mipi-dphy-rx
[ 77.491898] is backlink!
[ 77.491912] entity->name 2 is m01_f_imx291 1-001a
/*
* rockchip-mipi-dphy-rx:0 <----> m01_f_imx291 1-001a:1
* top = 4
* 入栈操作
*/
[ 77.491931] rkcif rkcif_mipi_lvds: walk: pushing 'm01_f_imx291 1-001a' on stack
/*
* 入栈操作导致top值改变
* 这里遍历m01_f_imx291 1-001a links
* 由于没有sink pad,所以只有link,没有backlink
*/
[ 77.491935] entity->name 0 is m01_f_imx291 1-001a
[ 77.491949] is link!
[ 77.491960] entity->name 1 is rockchip-mipi-dphy-rx
/*
* 通过link,向后找到了rockchip-mipi-dphy-rx
* 但是在rockchip-mipi-csi2操作中rockchip-mipi-dphy-rx已经访问过了
*/
[ 77.491974] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-dphy-rx' (already seen)
/*
* 由于没有入栈操作
* 所以继续遍历m01_f_imx291 1-001a links
* 由于只有一个link,所以就出现了满足上面分析的退出while的条件
*/
[ 77.491982] rkcif rkcif_mipi_lvds: walk: returning entity 'm01_f_imx291 1-001a'
此时对应的栈内数据如下
while (!ret && (entity = media_graph_walk_next(graph)))
if (is_media_entity_v4l2_subdev(entity))
ret = pipeline_pm_power_one(entity, change);
接着会判断返回的entity是不是subdev,是的话,会调core到s_power
这里和上一篇文章分析的get_remote_terminal_sensor不一样,这里不会判断是不是camera,而退出
继续通过log分析
/*
* 这里为什么会返回entity 'rockchip-mipi-dphy-rx'
* 因为media_greaph_walk_next有个出栈操作
* 之前top = 4 对应imx291
* 出栈后 top = 3 对应 rockchip-mipi-dphy-rx
* 所以这里会遍历rockchip-mipi-dphy-rx的links
* 之前已经遍历了其backlink及link。而且只有这2个link,之前已经遍历完了
* 所以满足while退出条件
*/
[ 193.566342] rkcif rkcif_mipi_lvds: walk: returning entity 'rockchip-mipi-dphy-rx'
/*
* 由于有进行了出栈操作
* top = 2
* 于是对应 entity rockchip-mipi-csi2
* 遍历rockchip-mipi-csi2的links
* 这里计算一下rockchip-mipi-csi2有几个link
* rockchip-mipi-csi2:0 ---- rockchip-mipi-dphy-rx:1 1个backlink enable
* rockchip-mipi-csi2:1 ---- stream_cif_mipi_id0:0 1个link enable
* rockchip-mipi-csi2:1 ---- stream_cif_mipi_id1:0 1个link disable
* rockchip-mipi-csi2:1 ---- stream_cif_mipi_id2:0 1个link disable
* rockchip-mipi-csi2:1 ---- stream_cif_mipi_id3:0 1个link disable
*
* rockchip-mipi-csi2:2 ---- stream_cif_mipi_id0:0 1个link disable
* rockchip-mipi-csi2:2 ---- stream_cif_mipi_id1:0 1个link enable
* rockchip-mipi-csi2:2 ---- stream_cif_mipi_id2:0 1个link disable
* rockchip-mipi-csi2:2 ---- stream_cif_mipi_id3:0 1个link disable
*
* rockchip-mipi-csi2:3 ---- stream_cif_mipi_id0:0 1个link disable
* rockchip-mipi-csi2:3 ---- stream_cif_mipi_id1:0 1个link disable
* rockchip-mipi-csi2:3 ---- stream_cif_mipi_id2:0 1个link enable
* rockchip-mipi-csi2:3 ---- stream_cif_mipi_id3:0 1个link disable
*
* rockchip-mipi-csi2:4 ---- stream_cif_mipi_id0:0 1个link disable
* rockchip-mipi-csi2:4 ---- stream_cif_mipi_id1:0 1个link disable
* rockchip-mipi-csi2:4 ---- stream_cif_mipi_id2:0 1个link disable
* rockchip-mipi-csi2:4 ---- stream_cif_mipi_id3:0 1个link enable
*
* 也就是17个links
* 上面的log分析中,知道backlink已经被遍历了,还有16个links
* 于是继续遍历links
*/
[ 193.566361] entity->name 0 is rockchip-mipi-csi2
[ 193.566375] is link!
[ 193.566388] entity->name 1 is stream_cif_mipi_id0
/*
* entity 'stream_cif_mipi_id0' 已经被访问过了,所以跳过
* 无入栈操作
*/
[ 193.566405] rkcif rkcif_mipi_lvds: walk: skipping entity 'stream_cif_mipi_id0' (already seen)
/*
* 遍历下一个link
* 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id1':0 disable
* 无入栈操作
*/
[ 193.566414] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id1':0
/*
* 遍历下一个link
* 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id2':0 disable
* 无入栈操作
*/
[ 193.566421] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id2':0
/*
* 遍历下一个link
* 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id3':0 disable
* 无入栈操作
*/
[ 193.566428] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id3':0
/*
* rockchip-mipi-csi2:1的links遍历完了
* 继续遍历rockchip-mipi-csi2:2的links
* rockchip-mipi-csi2:2 找到了 'stream_cif_mipi_id0':0
* 但是'stream_cif_mipi_id0':0之前已经访问过了
*/
[ 193.566436] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id0':0
/*
* rockchip-mipi-csi2:2 <---> stream_cif_mipi_id1:0 enable
* 找到了 entity stream_cif_mipi_id1
* 于是进行入栈操作
* top = 3
*/
[ 193.566439] entity->name 0 is rockchip-mipi-csi2
[ 193.566451] is link!
[ 193.566463] entity->name 1 is stream_cif_mipi_id1
[ 193.566479] rkcif rkcif_mipi_lvds: walk: pushing 'stream_cif_mipi_id1' on stack
/*
* 由于入栈操作
* 这里就找到了刚入栈的 entity stream_cif_mipi_id1
* 于是遍历其links
* 找到了 rockchip-mipi-csi2':1
* 但是 rockchip-mipi-csi2':1 --- 'stream_cif_mipi_id1':0 disable
*/
[ 193.566486] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id1':0
[ 193.566489] entity->name 0 is stream_cif_mipi_id1
[ 193.566498] is backlink!
[ 193.566508] entity->name 2 is rockchip-mipi-csi2
/*
* 继续遍历links
* 找到了entity 'rockchip-mipi-csi2':2
* 'rockchip-mipi-csi2':2 <---> 'stream_cif_mipi_id1':0 enable
* 但是 'rockchip-mipi-csi2':2 也访问过了
*/
[ 193.566525] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-csi2' (already seen)
/*
* 'rockchip-mipi-csi2':3 --- 'stream_cif_mipi_id1':0 disable
*/
[ 193.566532] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id1':0
/*
* 'rockchip-mipi-csi2':4 --- 'stream_cif_mipi_id1':0 disable
*/
[ 193.566540] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id1':0
/*
* stream_cif_mipi_id1 links遍历完了,出栈操作
* top = 2
* 对应 entity rockchip-mipi-csi2
*/
[ 193.566545] rkcif rkcif_mipi_lvds: walk: returning entity 'stream_cif_mipi_id1'
/*
* 继续遍历 entity rockchip-mipi-csi2:2的links
*
* 'rockchip-mipi-csi2':2 --- 'stream_cif_mipi_id2':0 disable
*/
[ 193.566552] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id2':0
/*
* 'rockchip-mipi-csi2':2 --- 'stream_cif_mipi_id3':0 disable
*/
[ 193.566560] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id3':0
/*
* 'rockchip-mipi-csi2':2 遍历完了
* 下面开始遍历 'rockchip-mipi-csi2':3
* 'rockchip-mipi-csi2':3 --- 'stream_cif_mipi_id0':0 disable
*/
[ 193.566568] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id0':0
/*
* 'rockchip-mipi-csi2':3 --- 'stream_cif_mipi_id1':0 disable
*/
[ 193.566575] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id1':0
/*
* 'rockchip-mipi-csi2':3 <---> 'stream_cif_mipi_id2':0 enable
*/
[ 193.566578] entity->name 0 is rockchip-mipi-csi2
[ 193.566591] is link!
[ 193.566603] entity->name 1 is stream_cif_mipi_id2
/*
* 入栈操作
* top = 3
*/
[ 193.566619] rkcif rkcif_mipi_lvds: walk: pushing 'stream_cif_mipi_id2' on stack
/*
* 遍历stream_cif_mipi_id2 的links
* 'rockchip-mipi-csi2':1 已经被访问过了
*/
[ 193.566626] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id2':0
/*
* 'rockchip-mipi-csi2':2 已经被访问过了
*/
[ 193.566633] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id2':0
/*
* 'rockchip-mipi-csi2':3 <---> 'stream_cif_mipi_id2':0 enable
* 但是'rockchip-mipi-csi2':3 也被访问过了
* 所以也不会出现入栈操作
*/
[ 193.566637] entity->name 0 is stream_cif_mipi_id2
[ 193.566648] is backlink!
[ 193.566663] entity->name 2 is rockchip-mipi-csi2
[ 193.566678] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-csi2' (already seen)
/*
* 'rockchip-mipi-csi2':4 --- 'stream_cif_mipi_id2':0 disable
*/
[ 193.566685] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id2':0
/*
* stream_cif_mipi_id2 遍历完成
* 进行出栈操作
* top = 2
*/
[ 193.566691] rkcif rkcif_mipi_lvds: walk: returning entity 'stream_cif_mipi_id2'
/*
* 由于出栈操作
* 现在又对应entity rockchip-mipi-csi2
* 继续遍历 'rockchip-mipi-csi2':3
* 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id3':0 disable
*/
[ 193.566698] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id3':0
/*
* 'rockchip-mipi-csi2':3 遍历完了,遍历'rockchip-mipi-csi2':4
* 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id0':0 disable
*/
[ 193.566705] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id0':0
/*
* * 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id1':0 disable
*/
[ 193.566720] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id1':0
/*
* * 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id2':0 disable
*/
[ 193.566734] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id2':0
/*
* 'rockchip-mipi-csi2':4 <---> 'stream_cif_mipi_id3':0 enable
*/
[ 193.566743] entity->name 0 is rockchip-mipi-csi2
[ 193.566764] is link!
[ 193.566783] entity->name 1 is stream_cif_mipi_id3
/*
* stream_cif_mipi_id3 入栈
* top = 3
*/
[ 193.566801] rkcif rkcif_mipi_lvds: walk: pushing 'stream_cif_mipi_id3' on stack
/*
* 遍历 stream_cif_mipi_id3的links
* 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id3':0 disable
*/
[ 193.566809] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id3':0
/*
* 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id3':0 disable
*/
[ 193.566817] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id3':0
/*
* 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id3':0 disable
*/
[ 193.566823] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id3':0
/*
* * 'rockchip-mipi-csi2':4 <---> 'stream_cif_mipi_id3':0 enable
*/
[ 193.566827] entity->name 0 is stream_cif_mipi_id3
[ 193.566838] is backlink!
[ 193.566851] entity->name 2 is rockchip-mipi-csi2
/*
* 由于* 'rockchip-mipi-csi2':4 已经访问过了
*/
[ 193.566866] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-csi2' (already seen)
/*
* stream_cif_mipi_id3 遍历完
* 出栈操作
* top = 2
*/
[ 193.566872] rkcif rkcif_mipi_lvds: walk: returning entity 'stream_cif_mipi_id3'
/*
* rockchip-mipi-csi2 遍历完
* 出栈操作
* top = 1
*/
[ 193.566877] rkcif rkcif_mipi_lvds: walk: returning entity 'rockchip-mipi-csi2'
/*
* 此时对应 entity stream_cif_mipi_id0
* 继续遍历 stream_cif_mipi_id0 的links
* 之前遍历了'rockchip-mipi-csi2':1
* 所以现在从 'rockchip-mipi-csi2':2开始
* 'rockchip-mipi-csi2':2 --- 'stream_cif_mipi_id0':0 disable
*/
[ 193.566887] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id0':0
/*
* 'rockchip-mipi-csi2':3 --- 'stream_cif_mipi_id0':0 disable
*/
[ 193.566894] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id0':0
/*
* 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id0':0 di***ale
*/
[ 193.566901] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id0':0
/*
* stream_cif_mipi_id0 遍历完成
* 出栈操作
* top = 0
*/
[ 193.566907] rkcif rkcif_mipi_lvds: walk: returning entity 'stream_cif_mipi_id0'
/*
* top = 0 已经没有数据了,退出。。
*/
花了一个entity的链接简图,忽略了link
其中彩色线条是enable的,黑线是disable
使用上面的图来分析 v4l2_pipeline_pm_use,从stream_cif_mipi_id0这个entity开始
v4l2_pipeline_pm_use(&vnode->vdev.entity, 1);
v4l2_pipeline_pm_use()
int v4l2_pipeline_pm_use(struct media_entity *entity, int use)
{
/*
* 一切都是基于media的,所以要先找到media
* use传入的是1
*/
struct media_device *mdev = entity->graph_obj.mdev;
int change = use ? 1 : -1;
int ret;
mutex_lock(&mdev->graph_mutex);
/* Apply use count to node. */
/*
* 更新entity使用计数
*/
entity->use_count += change;
WARN_ON(entity->use_count < 0);
/* Apply power change to connected non-nodes. */
/*
* 上面这句话的意思是
* 将电源更改应用于连接的非节点
* 非节点是什么意思?非video节点?所以这里更改的事subdev节点?
*/
/*
* medv->pm_count_walk 这个变量实在media_device_register_entity中
* 被赋值的
* 该变量类型是 struct media_graph
* 可以看上一篇文章中的一个graph变量
*/
ret = pipeline_pm_power(entity, change, &mdev->pm_count_walk);
if (ret < 0)
entity->use_count -= change;
mutex_unlock(&mdev->graph_mutex);
return ret;
}
v4l2_pipeline_pm_use() -> pipeline_pm_power()
static int pipeline_pm_power(struct media_entity *entity, int change,
struct media_graph *graph)
{
struct media_entity *first = entity;
int ret = 0;
if (!change)
return 0;
media_graph_walk_start(graph, entity);
while (!ret && (entity = media_graph_walk_next(graph)))
if (is_media_entity_v4l2_subdev(entity))
ret = pipeline_pm_power_one(entity, change);
if (!ret)
return ret;
...
}
media_graph_walk_next 代码量有些大,会占用不少篇幅,所以还是看上一篇文章吧,这篇文章只会贴一些关键代码用于理解分析
这里贴一下log的部分打印
[ 77.491726] rkcif rkcif_mipi_lvds: begin graph walk at 'stream_cif_mipi_id0'
[ 77.491730] entity->name 0 is stream_cif_mipi_id0
[ 77.491743] is backlink!
[ 77.491757] entity->name 2 is rockchip-mipi-csi2
[ 77.491777] rkcif rkcif_mipi_lvds: walk: pushing 'rockchip-mipi-csi2' on stack
[ 77.491781] entity->name 0 is rockchip-mipi-csi2
[ 77.491794] is backlink!
[ 77.491808] entity->name 2 is rockchip-mipi-dphy-rx
[ 77.491828] rkcif rkcif_mipi_lvds: walk: pushing 'rockchip-mipi-dphy-rx' on stack
[ 77.491832] entity->name 0 is rockchip-mipi-dphy-rx
[ 77.491847] is link!
[ 77.491860] entity->name 1 is rockchip-mipi-csi2
[ 77.491880] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-csi2' (already seen)
[ 77.491884] entity->name 0 is rockchip-mipi-dphy-rx
[ 77.491898] is backlink!
[ 77.491912] entity->name 2 is m01_f_imx291 1-001a
[ 77.491931] rkcif rkcif_mipi_lvds: walk: pushing 'm01_f_imx291 1-001a' on stack
[ 77.491935] entity->name 0 is m01_f_imx291 1-001a
[ 77.491949] is link!
[ 77.491960] entity->name 1 is rockchip-mipi-dphy-rx
[ 77.491974] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-dphy-rx' (already seen)
[ 77.491982] rkcif rkcif_mipi_lvds: walk: returning entity 'm01_f_imx291 1-001a'
其中media_graph_walk_next中
#define link_top(en) ((en)->stack[(en)->top].link)
#define stack_top(en) ((en)->stack[(en)->top].entity)
struct media_entity *media_graph_walk_next(struct media_graph *graph)
{
struct media_entity *entity;
...
while (link_top(graph) != &stack_top(graph)->links)
media_graph_walk_iter(graph);
entity = stack_pop(graph);
dev_dbg(entity->graph_obj.mdev->dev,
"walk: returning entity '%s'n", entity->name);
return entity;
}
退出while循环的条件是什么?
&stack_top(graph) -> links 是链表头的地址,link_top(graph) 是links链表上的成员的地址
当两者相等的时候,也就是说links链表上的遍历完成的时候,就会退出while。
根据log,解释一下过程
/*
* media_graph_walk_start 中打印,top = 1
*/
[ 77.491726] rkcif rkcif_mipi_lvds: begin graph walk at 'stream_cif_mipi_id0'
/*
* 找到了stream_cif_mipi_id0的backlink
* 因为stream_cif_mipi_id0没有source pad,所以没有link只有backlink
* 通过backlink找到了source entity rockchip-mipi-csi2
*/
[ 77.491730] entity->name 0 is stream_cif_mipi_id0
[ 77.491743] is backlink!
[ 77.491757] entity->name 2 is rockchip-mipi-csi2
/*
* 简图中可以知道 stream_cif_mipi_id0:0 <---> rockchip-mipi-csi2:1
* 这2个pad是enable的
* 所以这里会入栈
* top = 2
*/
[ 77.491777] rkcif rkcif_mipi_lvds: walk: pushing 'rockchip-mipi-csi2' on stack
/*
* 由于执行了一次入栈操作,top的值发生了改变
* 所以这里不会在继续遍历stream_cif_mipi_id0的links
* 而是去遍历rockchip-mipi-csi2的links
* 首先遍历的是backlink
* 这就找到了source entity rockchip-mipi-dphy-rx
*/
[ 77.491781] entity->name 0 is rockchip-mipi-csi2
[ 77.491794] is backlink!
[ 77.491808] entity->name 2 is rockchip-mipi-dphy-rx
/*
* rockchip-mipi-csi2:0 <---> rockchip-mipi-dphy-rx:1
* top = 3
* 入栈操作
*/
[ 77.491828] rkcif rkcif_mipi_lvds: walk: pushing 'rockchip-mipi-dphy-rx' on stack
/*
* 于是遍历rockchip-mipi-dphy-rx的links
* 首先是link,对于是link还是backlink,还是看驱动中links挂载的顺序
* 使用link的时候,是向后走,这样就会找到sink entity rockchip-mipi-csi2
* 由于之前stream_cif_mipi_id0操作的时候,已经访问过rockchip-mipi-csi2了
* 所以会跳过rockchip-mipi-csi2
*/
[ 77.491832] entity->name 0 is rockchip-mipi-dphy-rx
[ 77.491847] is link!
[ 77.491860] entity->name 1 is rockchip-mipi-csi2
[ 77.491880] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-csi2' (already seen)
/*
* 因为没有执行入栈操作,所以这里会继续遍历rockchip-mipi-dphy-rx的links
* 这次找到了backlink
* 向前找到了 source entity m01_f_imx291 1-001a
*/
[ 77.491884] entity->name 0 is rockchip-mipi-dphy-rx
[ 77.491898] is backlink!
[ 77.491912] entity->name 2 is m01_f_imx291 1-001a
/*
* rockchip-mipi-dphy-rx:0 <----> m01_f_imx291 1-001a:1
* top = 4
* 入栈操作
*/
[ 77.491931] rkcif rkcif_mipi_lvds: walk: pushing 'm01_f_imx291 1-001a' on stack
/*
* 入栈操作导致top值改变
* 这里遍历m01_f_imx291 1-001a links
* 由于没有sink pad,所以只有link,没有backlink
*/
[ 77.491935] entity->name 0 is m01_f_imx291 1-001a
[ 77.491949] is link!
[ 77.491960] entity->name 1 is rockchip-mipi-dphy-rx
/*
* 通过link,向后找到了rockchip-mipi-dphy-rx
* 但是在rockchip-mipi-csi2操作中rockchip-mipi-dphy-rx已经访问过了
*/
[ 77.491974] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-dphy-rx' (already seen)
/*
* 由于没有入栈操作
* 所以继续遍历m01_f_imx291 1-001a links
* 由于只有一个link,所以就出现了满足上面分析的退出while的条件
*/
[ 77.491982] rkcif rkcif_mipi_lvds: walk: returning entity 'm01_f_imx291 1-001a'
此时对应的栈内数据如下
while (!ret && (entity = media_graph_walk_next(graph)))
if (is_media_entity_v4l2_subdev(entity))
ret = pipeline_pm_power_one(entity, change);
接着会判断返回的entity是不是subdev,是的话,会调core到s_power
这里和上一篇文章分析的get_remote_terminal_sensor不一样,这里不会判断是不是camera,而退出
继续通过log分析
/*
* 这里为什么会返回entity 'rockchip-mipi-dphy-rx'
* 因为media_greaph_walk_next有个出栈操作
* 之前top = 4 对应imx291
* 出栈后 top = 3 对应 rockchip-mipi-dphy-rx
* 所以这里会遍历rockchip-mipi-dphy-rx的links
* 之前已经遍历了其backlink及link。而且只有这2个link,之前已经遍历完了
* 所以满足while退出条件
*/
[ 193.566342] rkcif rkcif_mipi_lvds: walk: returning entity 'rockchip-mipi-dphy-rx'
/*
* 由于有进行了出栈操作
* top = 2
* 于是对应 entity rockchip-mipi-csi2
* 遍历rockchip-mipi-csi2的links
* 这里计算一下rockchip-mipi-csi2有几个link
* rockchip-mipi-csi2:0 ---- rockchip-mipi-dphy-rx:1 1个backlink enable
* rockchip-mipi-csi2:1 ---- stream_cif_mipi_id0:0 1个link enable
* rockchip-mipi-csi2:1 ---- stream_cif_mipi_id1:0 1个link disable
* rockchip-mipi-csi2:1 ---- stream_cif_mipi_id2:0 1个link disable
* rockchip-mipi-csi2:1 ---- stream_cif_mipi_id3:0 1个link disable
*
* rockchip-mipi-csi2:2 ---- stream_cif_mipi_id0:0 1个link disable
* rockchip-mipi-csi2:2 ---- stream_cif_mipi_id1:0 1个link enable
* rockchip-mipi-csi2:2 ---- stream_cif_mipi_id2:0 1个link disable
* rockchip-mipi-csi2:2 ---- stream_cif_mipi_id3:0 1个link disable
*
* rockchip-mipi-csi2:3 ---- stream_cif_mipi_id0:0 1个link disable
* rockchip-mipi-csi2:3 ---- stream_cif_mipi_id1:0 1个link disable
* rockchip-mipi-csi2:3 ---- stream_cif_mipi_id2:0 1个link enable
* rockchip-mipi-csi2:3 ---- stream_cif_mipi_id3:0 1个link disable
*
* rockchip-mipi-csi2:4 ---- stream_cif_mipi_id0:0 1个link disable
* rockchip-mipi-csi2:4 ---- stream_cif_mipi_id1:0 1个link disable
* rockchip-mipi-csi2:4 ---- stream_cif_mipi_id2:0 1个link disable
* rockchip-mipi-csi2:4 ---- stream_cif_mipi_id3:0 1个link enable
*
* 也就是17个links
* 上面的log分析中,知道backlink已经被遍历了,还有16个links
* 于是继续遍历links
*/
[ 193.566361] entity->name 0 is rockchip-mipi-csi2
[ 193.566375] is link!
[ 193.566388] entity->name 1 is stream_cif_mipi_id0
/*
* entity 'stream_cif_mipi_id0' 已经被访问过了,所以跳过
* 无入栈操作
*/
[ 193.566405] rkcif rkcif_mipi_lvds: walk: skipping entity 'stream_cif_mipi_id0' (already seen)
/*
* 遍历下一个link
* 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id1':0 disable
* 无入栈操作
*/
[ 193.566414] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id1':0
/*
* 遍历下一个link
* 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id2':0 disable
* 无入栈操作
*/
[ 193.566421] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id2':0
/*
* 遍历下一个link
* 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id3':0 disable
* 无入栈操作
*/
[ 193.566428] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id3':0
/*
* rockchip-mipi-csi2:1的links遍历完了
* 继续遍历rockchip-mipi-csi2:2的links
* rockchip-mipi-csi2:2 找到了 'stream_cif_mipi_id0':0
* 但是'stream_cif_mipi_id0':0之前已经访问过了
*/
[ 193.566436] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id0':0
/*
* rockchip-mipi-csi2:2 <---> stream_cif_mipi_id1:0 enable
* 找到了 entity stream_cif_mipi_id1
* 于是进行入栈操作
* top = 3
*/
[ 193.566439] entity->name 0 is rockchip-mipi-csi2
[ 193.566451] is link!
[ 193.566463] entity->name 1 is stream_cif_mipi_id1
[ 193.566479] rkcif rkcif_mipi_lvds: walk: pushing 'stream_cif_mipi_id1' on stack
/*
* 由于入栈操作
* 这里就找到了刚入栈的 entity stream_cif_mipi_id1
* 于是遍历其links
* 找到了 rockchip-mipi-csi2':1
* 但是 rockchip-mipi-csi2':1 --- 'stream_cif_mipi_id1':0 disable
*/
[ 193.566486] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id1':0
[ 193.566489] entity->name 0 is stream_cif_mipi_id1
[ 193.566498] is backlink!
[ 193.566508] entity->name 2 is rockchip-mipi-csi2
/*
* 继续遍历links
* 找到了entity 'rockchip-mipi-csi2':2
* 'rockchip-mipi-csi2':2 <---> 'stream_cif_mipi_id1':0 enable
* 但是 'rockchip-mipi-csi2':2 也访问过了
*/
[ 193.566525] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-csi2' (already seen)
/*
* 'rockchip-mipi-csi2':3 --- 'stream_cif_mipi_id1':0 disable
*/
[ 193.566532] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id1':0
/*
* 'rockchip-mipi-csi2':4 --- 'stream_cif_mipi_id1':0 disable
*/
[ 193.566540] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id1':0
/*
* stream_cif_mipi_id1 links遍历完了,出栈操作
* top = 2
* 对应 entity rockchip-mipi-csi2
*/
[ 193.566545] rkcif rkcif_mipi_lvds: walk: returning entity 'stream_cif_mipi_id1'
/*
* 继续遍历 entity rockchip-mipi-csi2:2的links
*
* 'rockchip-mipi-csi2':2 --- 'stream_cif_mipi_id2':0 disable
*/
[ 193.566552] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id2':0
/*
* 'rockchip-mipi-csi2':2 --- 'stream_cif_mipi_id3':0 disable
*/
[ 193.566560] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id3':0
/*
* 'rockchip-mipi-csi2':2 遍历完了
* 下面开始遍历 'rockchip-mipi-csi2':3
* 'rockchip-mipi-csi2':3 --- 'stream_cif_mipi_id0':0 disable
*/
[ 193.566568] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id0':0
/*
* 'rockchip-mipi-csi2':3 --- 'stream_cif_mipi_id1':0 disable
*/
[ 193.566575] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id1':0
/*
* 'rockchip-mipi-csi2':3 <---> 'stream_cif_mipi_id2':0 enable
*/
[ 193.566578] entity->name 0 is rockchip-mipi-csi2
[ 193.566591] is link!
[ 193.566603] entity->name 1 is stream_cif_mipi_id2
/*
* 入栈操作
* top = 3
*/
[ 193.566619] rkcif rkcif_mipi_lvds: walk: pushing 'stream_cif_mipi_id2' on stack
/*
* 遍历stream_cif_mipi_id2 的links
* 'rockchip-mipi-csi2':1 已经被访问过了
*/
[ 193.566626] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id2':0
/*
* 'rockchip-mipi-csi2':2 已经被访问过了
*/
[ 193.566633] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id2':0
/*
* 'rockchip-mipi-csi2':3 <---> 'stream_cif_mipi_id2':0 enable
* 但是'rockchip-mipi-csi2':3 也被访问过了
* 所以也不会出现入栈操作
*/
[ 193.566637] entity->name 0 is stream_cif_mipi_id2
[ 193.566648] is backlink!
[ 193.566663] entity->name 2 is rockchip-mipi-csi2
[ 193.566678] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-csi2' (already seen)
/*
* 'rockchip-mipi-csi2':4 --- 'stream_cif_mipi_id2':0 disable
*/
[ 193.566685] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id2':0
/*
* stream_cif_mipi_id2 遍历完成
* 进行出栈操作
* top = 2
*/
[ 193.566691] rkcif rkcif_mipi_lvds: walk: returning entity 'stream_cif_mipi_id2'
/*
* 由于出栈操作
* 现在又对应entity rockchip-mipi-csi2
* 继续遍历 'rockchip-mipi-csi2':3
* 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id3':0 disable
*/
[ 193.566698] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id3':0
/*
* 'rockchip-mipi-csi2':3 遍历完了,遍历'rockchip-mipi-csi2':4
* 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id0':0 disable
*/
[ 193.566705] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id0':0
/*
* * 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id1':0 disable
*/
[ 193.566720] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id1':0
/*
* * 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id2':0 disable
*/
[ 193.566734] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id2':0
/*
* 'rockchip-mipi-csi2':4 <---> 'stream_cif_mipi_id3':0 enable
*/
[ 193.566743] entity->name 0 is rockchip-mipi-csi2
[ 193.566764] is link!
[ 193.566783] entity->name 1 is stream_cif_mipi_id3
/*
* stream_cif_mipi_id3 入栈
* top = 3
*/
[ 193.566801] rkcif rkcif_mipi_lvds: walk: pushing 'stream_cif_mipi_id3' on stack
/*
* 遍历 stream_cif_mipi_id3的links
* 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id3':0 disable
*/
[ 193.566809] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':1 -> 'stream_cif_mipi_id3':0
/*
* 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id3':0 disable
*/
[ 193.566817] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id3':0
/*
* 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id3':0 disable
*/
[ 193.566823] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id3':0
/*
* * 'rockchip-mipi-csi2':4 <---> 'stream_cif_mipi_id3':0 enable
*/
[ 193.566827] entity->name 0 is stream_cif_mipi_id3
[ 193.566838] is backlink!
[ 193.566851] entity->name 2 is rockchip-mipi-csi2
/*
* 由于* 'rockchip-mipi-csi2':4 已经访问过了
*/
[ 193.566866] rkcif rkcif_mipi_lvds: walk: skipping entity 'rockchip-mipi-csi2' (already seen)
/*
* stream_cif_mipi_id3 遍历完
* 出栈操作
* top = 2
*/
[ 193.566872] rkcif rkcif_mipi_lvds: walk: returning entity 'stream_cif_mipi_id3'
/*
* rockchip-mipi-csi2 遍历完
* 出栈操作
* top = 1
*/
[ 193.566877] rkcif rkcif_mipi_lvds: walk: returning entity 'rockchip-mipi-csi2'
/*
* 此时对应 entity stream_cif_mipi_id0
* 继续遍历 stream_cif_mipi_id0 的links
* 之前遍历了'rockchip-mipi-csi2':1
* 所以现在从 'rockchip-mipi-csi2':2开始
* 'rockchip-mipi-csi2':2 --- 'stream_cif_mipi_id0':0 disable
*/
[ 193.566887] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':2 -> 'stream_cif_mipi_id0':0
/*
* 'rockchip-mipi-csi2':3 --- 'stream_cif_mipi_id0':0 disable
*/
[ 193.566894] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':3 -> 'stream_cif_mipi_id0':0
/*
* 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id0':0 di***ale
*/
[ 193.566901] rkcif rkcif_mipi_lvds: walk: skipping disabled link 'rockchip-mipi-csi2':4 -> 'stream_cif_mipi_id0':0
/*
* stream_cif_mipi_id0 遍历完成
* 出栈操作
* top = 0
*/
[ 193.566907] rkcif rkcif_mipi_lvds: walk: returning entity 'stream_cif_mipi_id0'
/*
* top = 0 已经没有数据了,退出。。
*/
举报