我是靠谱客的博主 震动画笔,最近开发中收集的这篇文章主要介绍6-PSCI Power Domain Tree Structure,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

引流关键词: 中断、同步异常、异步异常、irq、fiq、BL1,BL2,BL3,BL31,BL32,BL33,AP_BL1,AP_BL2,AP_BL3,AP_BL31,AP_BL32,AP_BL33,SCP_BL1,SCP_BL2,BL0,BL30, optee、ATF、TF-A、Trustzone、optee3.14、MMU、VMSA、cache、TLB、arm、armv8、armv9、TEE、安全、内存管理、页表…

快速链接:
.
???????????? 个人博客笔记导读目录(全部) ????????????


[专栏目录]-ATF/FF-A/specification学习

请添加图片描述

6. PSCI 电源域树结构

6.1。要求

(1) 平台必须导出plat_get_aff_count()和 plat_get_aff_state()API 以使通用 PSCI 代码能够填充描述系统中电源域层次结构的树。这种方法不灵活,因为更改拓扑需要更改代码。

平台在数据结构中描述其电源域树会简单得多。

(2) 通用 PSCI 代码生成 MPIDR 以填充电源域树。它还使用 MPIDR 在树中查找节点。平台将使用与通用 PSCI 代码生成的完全相同的 MPIDR 的假设是不可扩展的。MPIDR 的使用还将电源域树中的级别数限制为四个。

因此,需要将 MPIDR 的分配与用于填充电源域拓扑树的机制分离。

(3) 电源域树的当前排列需要对特定级别的兄弟节点进行二进制搜索,以找到指定的电源域节点。在功率管理操作期间,树从“开始”到“结束”功率水平遍历。需要二分查找来查找每个级别的节点。执行这种遍历的自然方法是从叶节点开始,跟随父节点指针到达结束层。

因此,需要定义以促进这种遍历的方式实现树的数据结构。

(4) 核心电源域的属性不同于更高级别的电源域的属性。例如,只能使用 MPIDR 识别核心电源域。在核心电源域上执行电源管理操作时,不需要执行状态协调。

因此,需要以一种便于区分叶节点和非叶节点以及任何相关优化的方式来实现树。

6.2. 设计

6.2.1. 描述电源域树

为了满足要求 1.,现有的平台 API plat_get_aff_count()和plat_get_aff_state()已被删除。平台必须定义一个无符号字符数组,以便:

(1) 数组中的第一个条目指定平台中实现的最高功率级别的功率域数量。这适用于电源域树没有单个根节点的平台,例如,FVP 在最高级别 (1) 有两个集群电源域。

(2) 每个后续条目对应于一个电源域,并包含作为其直接子级的电源域的数量。

(3) 数组的大小减去第一个条目将等于非叶电源域的数量。

(4) 数组中每个条目中的值用于查找要在下一级考虑的条目数。一个级别的所有条目的值的总和(子项数)指定下一个级别的数组中的条目数。

以下示例电源域拓扑树将用于进一步描述上述文本。这棵树中的叶节点和非叶节点已分别编号。

                               +-+
                               |0|
                               +-+
                              /   
                             /     
                            /       
                           /         
                          /           
                         /             
                        /               
                       /                 
                      /                   
                     /                     
                  +-+                       +-+
                  |1|                       |2|
                  +-+                       +-+
                 /                        /   
                /                        /     
               /                        /       
              /                        /         
           +-+           +-+         +-+           +-+
           |3|           |4|         |5|           |6|
           +-+           +-+         +-+           +-+
  +---+-----+    +----+----|     +----+----+     +----+-----+-----+
  |   |     |    |    |    |     |    |    |     |    |     |     |
  |   |     |    |    |    |     |    |    |     |    |     |     |
  v   v     v    v    v    v     v    v    v     v    v     v     v
+-+  +-+   +-+  +-+  +-+  +-+   +-+  +-+  +-+   +-+  +--+  +--+  +--+
|0|  |1|   |2|  |3|  |4|  |5|   |6|  |7|  |8|   |9|  |10|  |11|  |12|
+-+  +-+   +-+  +-+  +-+  +-+   +-+  +-+  +-+   +-+  +--+  +--+  +--+

该树由平台定义为上述数组,如下所示:

#define PLAT_NUM_POWER_DOMAINS       20
#define PLATFORM_CORE_COUNT          13
#define PSCI_NUM_NON_CPU_PWR_DOMAINS 
                   (PLAT_NUM_POWER_DOMAINS - PLATFORM_CORE_COUNT)

unsigned char plat_power_domain_tree_desc[] = { 1, 2, 2, 2, 3, 3, 3, 4};

6.2.2. 删除有关平台中使用的 MPIDR 的假设

为了满足要求 2.,假设平台在每个核心电源域0之间分配一个唯一编号(核心索引)。MPIDR 可以以任何方式分配,不会用于填充树。PLAT_CORE_COUNT - 1

plat_core_pos_by_mpidr(mpidr)将返回与 MPIDR 对应的核心的核心索引。如果传递的 MPIDR 未分配或对应于不存在的核心,它将返回错误 (-1)。这个平台 API 的语义已经改变,因为它需要验证传递的 MPIDR。因此,它已成为强制性 API。

添加了另一个强制性 APIplat_my_core_pos()以返回调用核心的核​​心索引。该 API 提供了一种更轻量级的机制来获取索引,因为不需要验证调用核心的 MPIDR。

平台应分配核心索引(如上图所示),这样,如果核心节点从左到右编号,则核心域的索引将与该核心返回的索引 plat_core_pos_by_mpidr()相同plat_my_core_pos()。这种关系允许核心节点被分配到一个单独的数组中(要求 4.)psci_setup(),其顺序是核心在数组中的索引与这些 API 的返回值相同。

6.2.2.1。处理 MPIDR 分配中的漏洞

对于分配的 MPIDR 数量等于核心电源域数量的平台,例如 Juno 和 FVP,将 MPIDR 转换为核心索引的逻辑应保持不变。Juno 和 FVP 都使用简单的防碰撞哈希函数来执行此操作。

在某些平台上,MPIDR 的分配可能不连续或某些内核已被禁用。这实质上意味着 MPIDR 已被稀疏分配,即平台使用的 MPIDR 范围的大小不等于核心电源域的数量。

平台可以采用以下方法之一来处理这种情况:

(1) 实现更复杂的逻辑以将有效的 MPIDR 转换为核心索引,同时保持前面描述的关系。这意味着电源域树描述符不会描述任何被禁用或不存在的核心电源域。不会在树中为这些域分配条目。

(2) 将未分配的 MPIDR 和禁用的核心视为不存在,但仍在电源域描述符中描述它们,即描述的核心节点数等于分配的 MPIDR 范围的大小。这种方法将导致内存浪费,因为条目将在树中分配,但允许使用更简单的逻辑将 MPIDR 转换为核心索引。

6.2.3. 遍历和区分核心和非核心电源域

为了满足要求 3 和 4,已经定义了单独的数据结构来表示树中的叶和非叶功率域节点。

/*******************************************************************************
 * The following two data structures implement the power domain tree. The tree
 * is used to track the state of all the nodes i.e. power domain instances
 * described by the platform. The tree consists of nodes that describe CPU power
 * domains i.e. leaf nodes and all other power domains which are parents of a
 * CPU power domain i.e. non-leaf nodes.
 ******************************************************************************/
typedef struct non_cpu_pwr_domain_node {
    /*
     * Index of the first CPU power domain node level 0 which has this node
     * as its parent.
     */
    unsigned int cpu_start_idx;

    /*
     * Number of CPU power domains which are siblings of the domain indexed
     * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx
     * -> cpu_start_idx + ncpus' have this node as their parent.
     */
    unsigned int ncpus;

    /* Index of the parent power domain node */
    unsigned int parent_node;

    -----
} non_cpu_pd_node_t;

typedef struct cpu_pwr_domain_node {
    u_register_t mpidr;

    /* Index of the parent power domain node */
    unsigned int parent_node;

    -----
} cpu_pd_node_t;

功率域树被实现为以下数据结构的组合。

non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS];
cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT];

6.2.4. 填充电源域树

中的populate_power_domain_tree()函数psci_setup.c实现了解析平台导出的电源域描述符以填充两个数组的算法。它本质上是广度优先搜索。从根开始的每一层的节点在 psci_non_cpu_pd_nodes和psci_cpu_pd_nodes数组中依次排列如下:

psci_non_cpu_pd_nodes -> [[Level 3 nodes][Level 2 nodes][Level 1 nodes]]
psci_cpu_pd_nodes -> [Level 0 nodes]

对于上面所示的示例电源域树,psci_cpu_pd_nodes 将按如下方式填充。每个条目中的值是父节点的索引。为简单起见,其他字段已被忽略。


      +-------------+     ^
CPU0  |      3      |     |
      +-------------+     |
CPU1  |      3      |     |
      +-------------+     |
CPU2  |      3      |     |
      +-------------+     |
CPU3  |      4      |     |
      +-------------+     |
CPU4  |      4      |     |
      +-------------+     |
CPU5  |      4      |     | PLATFORM_CORE_COUNT
      +-------------+     |
CPU6  |      5      |     |
      +-------------+     |
CPU7  |      5      |     |
      +-------------+     |
CPU8  |      5      |     |
      +-------------+     |
CPU9  |      6      |     |
      +-------------+     |
CPU10 |      6      |     |
      +-------------+     |
CPU11 |      6      |     |
      +-------------+     |
CPU12 |      6      |     v
      +-------------+

该psci_non_cpu_pd_nodes数组将按如下方式填充。每个条目中的值是父节点的索引。


      +-------------+     ^
PD0   |      -1     |     |
      +-------------+     |
PD1   |      0      |     |
      +-------------+     |
PD2   |      0      |     |
      +-------------+     |
PD3   |      1      |     | PLAT_NUM_POWER_DOMAINS -
      +-------------+     | PLATFORM_CORE_COUNT
PD4   |      1      |     |
      +-------------+     |
PD5   |      2      |     |
      +-------------+     |
PD6   |      2      |     |
      +-------------+     v

每个核心都可以使用该函数在psci_cpu_pd_nodes数组 中找到它的节点。plat_my_core_pos()当一个核心打开时,普通世界提供一个 MPIDR。该plat_core_pos_by_mpidr()函数用于在使用 MPIDR 查找对应的核心节点之前验证 MPIDR。非核心功率域节点不需要被识别。

最后

以上就是震动画笔为你收集整理的6-PSCI Power Domain Tree Structure的全部内容,希望文章能够帮你解决6-PSCI Power Domain Tree Structure所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部