瑞芯微Rockchip开发者社区
直播中

风尚男人

8年用户 945经验值
私信 关注
[问答]

v4l2_pipeline_pm_use的知识点分析,错过后悔

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 已经没有数据了,退出。。
*/


举报

更多回帖

发帖
×
20
完善资料,
赚取积分