【ARM64】【cpu_topology】

static int __init parse_dt_topology(void)
{
    struct device_node *cn, *map;
    int ret = 0;
    int cpu;

    /* (1) 找到dts中cpu topology的根节点"/cpus"" */
    cn = of_find_node_by_path("/cpus");
    if (!cn) {
        pr_err("No CPU information found in DT\n");
        return 0;
    }

    /*
     * When topology is provided cpu-map is essentially a root
     * cluster with restricted subnodes.
     */
    /* (2) 找到"cpu-map"节点 */
    map = of_get_child_by_name(cn, "cpu-map");
    if (!map)
        goto out;

    /* (3) 解析"cpu-map"中的cluster */
    ret = parse_cluster(map, 0);
    if (ret != 0)
        goto out_map;

    /*
     * Check that all cores are in the topology; the SMP code will
     * only mark cores described in the DT as possible.
     */
    for_each_possible_cpu(cpu)
        if (cpu_topology[cpu].cluster_id == -1)
            ret = -EINVAL;

out_map:
    of_node_put(map);
out:
    of_node_put(cn);
    return ret;
}

对应于dts中的文件如下:

    cpus {       
         #address-cells = <2>;
         #size-cells = <0>;
                  
         cpu-map {  
             cluster0 {
                 core0 {
                     cpu = <&CPU0>;
                 }; 
                 core1 {
                     cpu = <&CPU1>;
                 }; 
                 core2 {
                     cpu = <&CPU2>;
                 }; 
                 core3 {
                     cpu = <&CPU3>;
                 }; 
             };   
             cluster1 {
                 core0 {
                     cpu = <&CPU4>;
                 }; 
                 core1 {
                     cpu = <&CPU5>;
                 }; 
                 core2 {
                     cpu = <&CPU6>;
                 }; 
                 core3 {
                     cpu = <&CPU7>;
                 };
             };   
         };   
.....}	

搜索上面这个dts文件,先解析cluster--->core

static int __init parse_cluster(struct device_node *cluster, int depth)
{
    char name[10];
    bool leaf = true;
    bool has_cores = false;
    struct device_node *c;
    static int cluster_id __initdata;
    int core_id = 0;
    int i, ret;

    /*
     * First check for child clusters; we currently ignore any
     * information about the nesting of clusters and present the
     * scheduler with a flat list of them.
     */
    i = 0;
    /* (3.1) 如果有多级cluster,继续递归搜索 */
    do {
        snprintf(name, sizeof(name), "cluster%d", i);
        c = of_get_child_by_name(cluster, name);
        if (c) {
            leaf = false;
            ret = parse_cluster(c, depth + 1);
            of_node_put(c);
            if (ret != 0)
                return ret;
        }
        i++;
    } while (c);

    /* Now check for cores */
    i = 0;
    do {
        /* (3.2) 或者core层次的节点 */
        snprintf(name, sizeof(name), "core%d", i);
        c = of_get_child_by_name(cluster, name);
        if (c) {
            has_cores = true;

            if (depth == 0) {
                pr_err("%s: cpu-map children should be clusters\n",
                       c->full_name);
                of_node_put(c);
                return -EINVAL;
            }

            if (leaf) {
                /* (3.3) 如果是叶子cluster节点,继续遍历core中的cpu节点 */
                ret = parse_core(c, cluster_id, core_id++);
            } else {
                pr_err("%s: Non-leaf cluster with core %s\n",
                       cluster->full_name, name);
                ret = -EINVAL;
            }

            of_node_put(c);
            if (ret != 0)
                return ret;
        }
        i++;
    } while (c);

    if (leaf && !has_cores)
        pr_warn("%s: empty cluster\n", cluster->full_name);

    if (leaf)
        cluster_id++;

    return 0;
}

再从core解析到cpu

         CPU1: cpu@100 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x100>;
             enable-method = "psci";
             cpu-supply = <&fan53555_dcdc>;
             cpufreq-data-v1 = <&cpufreq_clus0>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
         };       
         CPU2: cpu@200 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x200>;
             enable-method = "psci";
             cpu-supply = <&fan53555_dcdc>;
             cpufreq-data-v1 = <&cpufreq_clus0>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
         };       
         CPU3: cpu@300 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x300>;
             enable-method = "psci";
             cpu-supply = <&fan53555_dcdc>;
             cpufreq-data-v1 = <&cpufreq_clus0>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
         };   
         CPU4: cpu@400 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x400>;
             enable-method = "psci";
             cpu-supply = <&vddcpu>;
             cpufreq-data-v1 = <&cpufreq_clus1>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
         };      
         CPU5: cpu@500 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x500>;
             enable-method = "psci";
             cpu-supply = <&vddcpu>;
             cpufreq-data-v1 = <&cpufreq_clus1>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
         };      
         CPU6: cpu@600 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x600>;
             enable-method = "psci";
             cpu-supply = <&vddcpu>;
             cpufreq-data-v1 = <&cpufreq_clus1>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
         };      
         CPU7: cpu@700 {
             device_type = "cpu";
             compatible = "arm,cortex-a55","arm,armv8";
             reg = <0x0 0x700>;
             enable-method = "psci";
             cpu-supply = <&vddcpu>;
             cpufreq-data-v1 = <&cpufreq_clus1>;
             cpu-idle-states = <&CORE_PD>;
             sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>;
         };      
     };   	 

继续解析cpu层级

static int __init parse_core(struct device_node *core, int cluster_id,
                 int core_id)
{
    char name[10];
    bool leaf = true;
    int i = 0;
    int cpu;
    struct device_node *t;

    do {
        /* (3.3.1) 如果存在thread层级,解析thread和cpu层级 */
        snprintf(name, sizeof(name), "thread%d", i);
        t = of_get_child_by_name(core, name);
        if (t) {
            leaf = false;
            cpu = get_cpu_for_node(t);
            if (cpu >= 0) {
                cpu_topology[cpu].cluster_id = cluster_id;
                cpu_topology[cpu].core_id = core_id;
                cpu_topology[cpu].thread_id = i;
            } else {
                pr_err("%s: Can't get CPU for thread\n",
                       t->full_name);
                of_node_put(t);
                return -EINVAL;
            }
            of_node_put(t);
        }
        i++;
    } while (t);

    /* (3.3.2) 否则直接解析cpu层级 */
    cpu = get_cpu_for_node(core);
    if (cpu >= 0) {
        if (!leaf) {
            pr_err("%s: Core has both threads and CPU\n",
                   core->full_name);
            return -EINVAL;
        }

        /* (3.3.3) 得到了cpu的cluster_id/core_id */
        cpu_topology[cpu].cluster_id = cluster_id;
        cpu_topology[cpu].core_id = core_id;
    } else if (leaf) {
        pr_err("%s: Can't get CPU for leaf core\n", core->full_name);
        return -EINVAL;
    }

    return 0;
}

这里没有thread层级,所以直接解析cpu层级

static int __init get_cpu_for_node(struct device_node *node)
{
    struct device_node *cpu_node;
    int cpu;

    cpu_node = of_parse_phandle(node, "cpu", 0);
    if (!cpu_node)
        return -1;

    for_each_possible_cpu(cpu) {
        if (of_get_cpu_node(cpu, NULL) == cpu_node) {
            of_node_put(cpu_node);
            return cpu;
        }
    }

    pr_crit("Unable to find CPU node for %s\n", cpu_node->full_name);

    of_node_put(cpu_node);
    return -1;
}

生成的外部节点信息

1) /sys/devices/system/cpu/cpuX/topology/physical_package_id:

    physical package id of cpuX. Typically corresponds to a physical
    socket number, but the actual value is architecture and platform
    dependent.

2) /sys/devices/system/cpu/cpuX/topology/core_id:

    the CPU core ID of cpuX. Typically it is the hardware platform's
    identifier (rather than the kernel's).  The actual value is
    architecture and platform dependent.

3) /sys/devices/system/cpu/cpuX/topology/book_id:

    the book ID of cpuX. Typically it is the hardware platform's
    identifier (rather than the kernel's).    The actual value is
    architecture and platform dependent.

4) /sys/devices/system/cpu/cpuX/topology/thread_siblings:

    internal kernel map of cpuX's hardware threads within the same
    core as cpuX.

5) /sys/devices/system/cpu/cpuX/topology/thread_siblings_list:

    human-readable list of cpuX's hardware threads within the same
    core as cpuX.

6) /sys/devices/system/cpu/cpuX/topology/core_siblings:

    internal kernel map of cpuX's hardware threads within the same
    physical_package_id.

7) /sys/devices/system/cpu/cpuX/topology/core_siblings_list:

    human-readable list of cpuX's hardware threads within the same
    physical_package_id.

8) /sys/devices/system/cpu/cpuX/topology/book_siblings:

    internal kernel map of cpuX's hardware threads within the same
    book_id.

9) /sys/devices/system/cpu/cpuX/topology/book_siblings_list:

    human-readable list of cpuX's hardware threads within the same
    book_id.

当前手机扫描出来的数据如下:

             core_id    0
       core_siblings    0f
  core_siblings_list    0-3
 physical_package_id    0
     thread_siblings    01
thread_siblings_list    0

             core_id    1
       core_siblings    0f
  core_siblings_list    0-3
 physical_package_id    0
     thread_siblings    02
thread_siblings_list    1

             core_id    2
       core_siblings    0f
  core_siblings_list    0-3
 physical_package_id    0
     thread_siblings    04
thread_siblings_list    2

             core_id    3
       core_siblings    0f
  core_siblings_list    0-3
 physical_package_id    0
     thread_siblings    08
thread_siblings_list    3

             core_id    0
       core_siblings    f0
  core_siblings_list    4-7
 physical_package_id    1
     thread_siblings    10
thread_siblings_list    4

             core_id    1
       core_siblings    f0
  core_siblings_list    4-7
 physical_package_id    1
     thread_siblings    20
thread_siblings_list    5

             core_id    2
       core_siblings    f0
  core_siblings_list    4-7
 physical_package_id    1
     thread_siblings    40
thread_siblings_list    6

             core_id    3
       core_siblings    f0
  core_siblings_list    4-7
 physical_package_id    1
     thread_siblings    80
thread_siblings_list    7

关于core_id\thread_sibling\core_sibling的解析如下:

static void update_siblings_masks(unsigned int cpuid)
{
	struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
	int cpu;

	/* update core and thread sibling masks */
	for_each_possible_cpu(cpu) {
		cpu_topo = &cpu_topology[cpu];

		if (cpuid_topo->cluster_id != cpu_topo->cluster_id)
			continue;
		// 关联的兄弟cpu
		cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
		if (cpu != cpuid)
			cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
		// 硬件plat的值
		if (cpuid_topo->core_id != cpu_topo->core_id)
			continue;
		// 关联硬件thread
		cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
		if (cpu != cpuid)
			cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
	}
}

一切感觉都是在填充topology这个结构体。

arm64架构的cpu拓扑结构存储在cpu_topology[]变量当中:

/*
 * cpu topology table
 */
struct cpu_topology cpu_topology[NR_CPUS];


struct cpu_topology {
    int thread_id;
    int core_id;
    int cluster_id;                 // 本cpu所在的cluster
    unsigned int partno;
    cpumask_t thread_sibling;
    cpumask_t core_sibling;         // 在MutiCore层次(即同一个cluster中),有哪些兄弟cpu
};

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值