Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
015b2693
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
015b2693
编写于
8月 30, 2019
作者:
P
Paul Walmsley
浏览文件
操作
浏览文件
下载
差异文件
Merge tag 'common/for-v5.4-rc1/cpu-topology' into for-v5.4-rc1-branch
上级
a256f2e3
f51edcec
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
514 addition
and
486 deletion
+514
-486
Documentation/devicetree/bindings/cpu/cpu-topology.txt
Documentation/devicetree/bindings/cpu/cpu-topology.txt
+167
-89
MAINTAINERS
MAINTAINERS
+7
-0
arch/arm/include/asm/topology.h
arch/arm/include/asm/topology.h
+0
-20
arch/arm/kernel/topology.c
arch/arm/kernel/topology.c
+6
-54
arch/arm64/include/asm/topology.h
arch/arm64/include/asm/topology.h
+0
-23
arch/arm64/kernel/topology.c
arch/arm64/kernel/topology.c
+4
-299
arch/riscv/Kconfig
arch/riscv/Kconfig
+1
-0
arch/riscv/kernel/smpboot.c
arch/riscv/kernel/smpboot.c
+3
-0
drivers/base/Kconfig
drivers/base/Kconfig
+1
-1
drivers/base/arch_topology.c
drivers/base/arch_topology.c
+298
-0
include/linux/arch_topology.h
include/linux/arch_topology.h
+26
-0
include/linux/topology.h
include/linux/topology.h
+1
-0
未找到文件。
Documentation/devicetree/bindings/
arm/
topology.txt
→
Documentation/devicetree/bindings/
cpu/cpu-
topology.txt
浏览文件 @
015b2693
===========================================
ARM
topology binding description
CPU
topology binding description
===========================================
===========================================
1 - Introduction
===========================================
In a
n ARM
system, the hierarchy of CPUs is defined through three entities that
In a
SMP
system, the hierarchy of CPUs is defined through three entities that
are used to describe the layout of physical CPUs in the system:
- socket
- cluster
- core
- thread
The cpu nodes (bindings defined in [1]) represent the devices that
correspond to physical CPUs and are to be mapped to the hierarchy levels.
The bottom hierarchy level sits at core or thread level depending on whether
symmetric multi-threading (SMT) is supported or not.
...
...
@@ -24,33 +22,31 @@ threads existing in the system and map to the hierarchy level "thread" above.
In systems where SMT is not supported "cpu" nodes represent all cores present
in the system and map to the hierarchy level "core" above.
ARM
topology bindings allow one to associate cpu nodes with hierarchical groups
CPU
topology bindings allow one to associate cpu nodes with hierarchical groups
corresponding to the system hierarchy; syntactically they are defined as device
tree nodes.
The remainder of this document provides the topology bindings for ARM, based
on the Devicetree Specification, available from:
Currently, only ARM/RISC-V intend to use this cpu topology binding but it may be
used for any other architecture as well.
https://www.devicetree.org/specifications/
The cpu nodes, as per bindings defined in [4], represent the devices that
correspond to physical CPUs and are to be mapped to the hierarchy levels.
If not stated otherwise, whenever a reference to a cpu node phandle is made its
value must point to a cpu node compliant with the cpu node bindings as
documented in [1].
A topology description containing phandles to cpu nodes that are not compliant
with bindings standardized in [
1
] is therefore considered invalid.
with bindings standardized in [
4
] is therefore considered invalid.
===========================================
2 - cpu-map node
===========================================
The ARM CPU topology is defined within the cpu-map node, which is a direct
The ARM
/RISC-V
CPU topology is defined within the cpu-map node, which is a direct
child of the cpus node and provides a container where the actual topology
nodes are listed.
- cpu-map node
Usage: Optional - On
ARM
SMP systems provide CPUs topology to the OS.
ARM u
niprocessor systems do not require a topology
Usage: Optional - On SMP systems provide CPUs topology to the OS.
U
niprocessor systems do not require a topology
description and therefore should not define a
cpu-map node.
...
...
@@ -63,21 +59,23 @@ nodes are listed.
The cpu-map node's child nodes can be:
- one or more cluster nodes
- one or more cluster nodes or
- one or more socket nodes in a multi-socket system
Any other configuration is considered invalid.
The cpu-map node can only contain
three
types of child nodes:
The cpu-map node can only contain
4
types of child nodes:
- socket node
- cluster node
- core node
- thread node
whose bindings are described in paragraph 3.
The nodes describing the CPU topology (
cluster/core/thread) can only
be defined within the cpu-map node and every core/thread in the system
must be defined within the topology. Any other configuration is
The nodes describing the CPU topology (
socket/cluster/core/thread) can
only be defined within the cpu-map node and every core/thread in the
system
must be defined within the topology. Any other configuration is
invalid and therefore must be ignored.
===========================================
...
...
@@ -85,26 +83,44 @@ invalid and therefore must be ignored.
===========================================
cpu-map child nodes must follow a naming convention where the node name
must be "
clusterN", "coreN", "threadN" depending on the node type (i
e
cluster/core/thread) (where N = {0, 1, ...} is the node number; nodes which
are siblings within a single common parent node must be given a unique and
must be "
socketN", "clusterN", "coreN", "threadN" depending on the node typ
e
(ie socket/cluster/core/thread) (where N = {0, 1, ...} is the node number; nodes
which
are siblings within a single common parent node must be given a unique and
sequential N value, starting from 0).
cpu-map child nodes which do not share a common parent node can have the same
name (ie same number N as other cpu-map child nodes at different device tree
levels) since name uniqueness will be guaranteed by the device tree hierarchy.
===========================================
3 - cluster/core/thread node bindings
3 -
socket/
cluster/core/thread node bindings
===========================================
Bindings for cluster/cpu/thread nodes are defined as follows:
Bindings for socket/cluster/cpu/thread nodes are defined as follows:
- socket node
Description: must be declared within a cpu-map node, one node
per physical socket in the system. A system can
contain single or multiple physical socket.
The association of sockets and NUMA nodes is beyond
the scope of this bindings, please refer [2] for
NUMA bindings.
This node is optional for a single socket system.
The socket node name must be "socketN" as described in 2.1 above.
A socket node can not be a leaf node.
A socket node's child nodes must be one or more cluster nodes.
Any other configuration is considered invalid.
- cluster node
Description: must be declared within a cpu-map node, one node
per cluster. A system can contain several layers of
clustering
and cluster nodes can be contained in parent
cluster nodes.
clustering
within a single physical socket and cluster
nodes can be contained in parent
cluster nodes.
The cluster node name must be "clusterN" as described in 2.1 above.
A cluster node can not be a leaf node.
...
...
@@ -164,90 +180,93 @@ Bindings for cluster/cpu/thread nodes are defined as follows:
4 - Example dts
===========================================
Example 1 (ARM 64-bit, 16-cpu system, two clusters of clusters):
Example 1 (ARM 64-bit, 16-cpu system, two clusters of clusters in a single
physical socket):
cpus {
#size-cells = <0>;
#address-cells = <2>;
cpu-map {
cluster
0 {
socket
0 {
cluster0 {
core0 {
thread0 {
cpu = <&CPU0>;
cluster0 {
core0 {
thread0 {
cpu = <&CPU0>;
};
thread1 {
cpu = <&CPU1>;
};
};
thread1 {
cpu = <&CPU1>;
};
};
core1 {
thread0 {
cpu = <&CPU2>;
};
thread1 {
cpu = <&CPU3>;
core1 {
thread0 {
cpu = <&CPU2>;
};
thread1 {
cpu = <&CPU3>;
};
};
};
};
cluster1 {
core0 {
thread0 {
cpu = <&CPU4>;
};
thread1 {
cpu = <&CPU5>;
cluster1 {
core0 {
thread0 {
cpu = <&CPU4>;
};
thread1 {
cpu = <&CPU5>;
};
};
};
core1 {
thread0 {
cpu = <&CPU6>;
};
thread1 {
cpu = <&CPU7>;
};
};
};
};
cluster1 {
cluster0 {
core0 {
thread0 {
cpu = <&CPU8>;
};
thread1 {
cpu = <&CPU9>;
};
};
core1 {
thread0 {
cpu = <&CPU10>;
};
thread1 {
cpu = <&CPU11>;
core1 {
thread0 {
cpu = <&CPU6>;
};
thread1 {
cpu = <&CPU7>;
};
};
};
};
cluster1 {
core0 {
thread0 {
cpu = <&CPU12>;
cluster0 {
core0 {
thread0 {
cpu = <&CPU8>;
};
thread1 {
cpu = <&CPU9>;
};
};
thread1 {
cpu = <&CPU13>;
core1 {
thread0 {
cpu = <&CPU10>;
};
thread1 {
cpu = <&CPU11>;
};
};
};
core1 {
thread0 {
cpu = <&CPU14>;
cluster1 {
core0 {
thread0 {
cpu = <&CPU12>;
};
thread1 {
cpu = <&CPU13>;
};
};
thread1 {
cpu = <&CPU15>;
core1 {
thread0 {
cpu = <&CPU14>;
};
thread1 {
cpu = <&CPU15>;
};
};
};
};
...
...
@@ -470,6 +489,65 @@ cpus {
};
};
Example 3: HiFive Unleashed (RISC-V 64 bit, 4 core system)
{
#address-cells = <2>;
#size-cells = <2>;
compatible = "sifive,fu540g", "sifive,fu500";
model = "sifive,hifive-unleashed-a00";
...
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu-map {
socket0 {
cluster0 {
core0 {
cpu = <&CPU1>;
};
core1 {
cpu = <&CPU2>;
};
core2 {
cpu0 = <&CPU2>;
};
core3 {
cpu0 = <&CPU3>;
};
};
};
};
CPU1: cpu@1 {
device_type = "cpu";
compatible = "sifive,rocket0", "riscv";
reg = <0x1>;
}
CPU2: cpu@2 {
device_type = "cpu";
compatible = "sifive,rocket0", "riscv";
reg = <0x2>;
}
CPU3: cpu@3 {
device_type = "cpu";
compatible = "sifive,rocket0", "riscv";
reg = <0x3>;
}
CPU4: cpu@4 {
device_type = "cpu";
compatible = "sifive,rocket0", "riscv";
reg = <0x4>;
}
}
};
===============================================================================
[1] ARM Linux kernel documentation
Documentation/devicetree/bindings/arm/cpus.yaml
[2] Devicetree NUMA binding description
Documentation/devicetree/bindings/numa.txt
[3] RISC-V Linux kernel documentation
Documentation/devicetree/bindings/riscv/cpus.txt
[4] https://www.devicetree.org/specifications/
MAINTAINERS
浏览文件 @
015b2693
...
...
@@ -6732,6 +6732,13 @@ W: https://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-gemtek*
GENERIC ARCHITECTURE TOPOLOGY
M: Sudeep Holla <sudeep.holla@arm.com>
L: linux-kernel@vger.kernel.org
S: Maintained
F: drivers/base/arch_topology.c
F: include/linux/arch_topology.h
GENERIC GPIO I2C DRIVER
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
S: Supported
...
...
arch/arm/include/asm/topology.h
浏览文件 @
015b2693
...
...
@@ -5,26 +5,6 @@
#ifdef CONFIG_ARM_CPU_TOPOLOGY
#include <linux/cpumask.h>
struct
cputopo_arm
{
int
thread_id
;
int
core_id
;
int
socket_id
;
cpumask_t
thread_sibling
;
cpumask_t
core_sibling
;
};
extern
struct
cputopo_arm
cpu_topology
[
NR_CPUS
];
#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
void
init_cpu_topology
(
void
);
void
store_cpu_topology
(
unsigned
int
cpuid
);
const
struct
cpumask
*
cpu_coregroup_mask
(
int
cpu
);
#include <linux/arch_topology.h>
/* Replace task scheduler's default frequency-invariant accounting */
...
...
arch/arm/kernel/topology.c
浏览文件 @
015b2693
...
...
@@ -177,17 +177,6 @@ static inline void parse_dt_topology(void) {}
static
inline
void
update_cpu_capacity
(
unsigned
int
cpuid
)
{}
#endif
/*
* cpu topology table
*/
struct
cputopo_arm
cpu_topology
[
NR_CPUS
];
EXPORT_SYMBOL_GPL
(
cpu_topology
);
const
struct
cpumask
*
cpu_coregroup_mask
(
int
cpu
)
{
return
&
cpu_topology
[
cpu
].
core_sibling
;
}
/*
* The current assumption is that we can power gate each core independently.
* This will be superseded by DT binding once available.
...
...
@@ -197,32 +186,6 @@ const struct cpumask *cpu_corepower_mask(int cpu)
return
&
cpu_topology
[
cpu
].
thread_sibling
;
}
static
void
update_siblings_masks
(
unsigned
int
cpuid
)
{
struct
cputopo_arm
*
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
->
socket_id
!=
cpu_topo
->
socket_id
)
continue
;
cpumask_set_cpu
(
cpuid
,
&
cpu_topo
->
core_sibling
);
if
(
cpu
!=
cpuid
)
cpumask_set_cpu
(
cpu
,
&
cpuid_topo
->
core_sibling
);
if
(
cpuid_topo
->
core_id
!=
cpu_topo
->
core_id
)
continue
;
cpumask_set_cpu
(
cpuid
,
&
cpu_topo
->
thread_sibling
);
if
(
cpu
!=
cpuid
)
cpumask_set_cpu
(
cpu
,
&
cpuid_topo
->
thread_sibling
);
}
smp_wmb
();
}
/*
* store_cpu_topology is called at boot when only one cpu is running
* and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
...
...
@@ -230,7 +193,7 @@ static void update_siblings_masks(unsigned int cpuid)
*/
void
store_cpu_topology
(
unsigned
int
cpuid
)
{
struct
cpu
topo_arm
*
cpuid_topo
=
&
cpu_topology
[
cpuid
];
struct
cpu
_topology
*
cpuid_topo
=
&
cpu_topology
[
cpuid
];
unsigned
int
mpidr
;
/* If the cpu topology has been already set, just return */
...
...
@@ -250,12 +213,12 @@ void store_cpu_topology(unsigned int cpuid)
/* core performance interdependency */
cpuid_topo
->
thread_id
=
MPIDR_AFFINITY_LEVEL
(
mpidr
,
0
);
cpuid_topo
->
core_id
=
MPIDR_AFFINITY_LEVEL
(
mpidr
,
1
);
cpuid_topo
->
socket
_id
=
MPIDR_AFFINITY_LEVEL
(
mpidr
,
2
);
cpuid_topo
->
package
_id
=
MPIDR_AFFINITY_LEVEL
(
mpidr
,
2
);
}
else
{
/* largely independent cores */
cpuid_topo
->
thread_id
=
-
1
;
cpuid_topo
->
core_id
=
MPIDR_AFFINITY_LEVEL
(
mpidr
,
0
);
cpuid_topo
->
socket
_id
=
MPIDR_AFFINITY_LEVEL
(
mpidr
,
1
);
cpuid_topo
->
package
_id
=
MPIDR_AFFINITY_LEVEL
(
mpidr
,
1
);
}
}
else
{
/*
...
...
@@ -265,7 +228,7 @@ void store_cpu_topology(unsigned int cpuid)
*/
cpuid_topo
->
thread_id
=
-
1
;
cpuid_topo
->
core_id
=
0
;
cpuid_topo
->
socket
_id
=
-
1
;
cpuid_topo
->
package
_id
=
-
1
;
}
update_siblings_masks
(
cpuid
);
...
...
@@ -275,7 +238,7 @@ void store_cpu_topology(unsigned int cpuid)
pr_info
(
"CPU%u: thread %d, cpu %d, socket %d, mpidr %x
\n
"
,
cpuid
,
cpu_topology
[
cpuid
].
thread_id
,
cpu_topology
[
cpuid
].
core_id
,
cpu_topology
[
cpuid
].
socket
_id
,
mpidr
);
cpu_topology
[
cpuid
].
package
_id
,
mpidr
);
}
static
inline
int
cpu_corepower_flags
(
void
)
...
...
@@ -298,18 +261,7 @@ static struct sched_domain_topology_level arm_topology[] = {
*/
void
__init
init_cpu_topology
(
void
)
{
unsigned
int
cpu
;
/* init core mask and capacity */
for_each_possible_cpu
(
cpu
)
{
struct
cputopo_arm
*
cpu_topo
=
&
(
cpu_topology
[
cpu
]);
cpu_topo
->
thread_id
=
-
1
;
cpu_topo
->
core_id
=
-
1
;
cpu_topo
->
socket_id
=
-
1
;
cpumask_clear
(
&
cpu_topo
->
core_sibling
);
cpumask_clear
(
&
cpu_topo
->
thread_sibling
);
}
reset_cpu_topology
();
smp_wmb
();
parse_dt_topology
();
...
...
arch/arm64/include/asm/topology.h
浏览文件 @
015b2693
...
...
@@ -4,29 +4,6 @@
#include <linux/cpumask.h>
struct
cpu_topology
{
int
thread_id
;
int
core_id
;
int
package_id
;
int
llc_id
;
cpumask_t
thread_sibling
;
cpumask_t
core_sibling
;
cpumask_t
llc_sibling
;
};
extern
struct
cpu_topology
cpu_topology
[
NR_CPUS
];
#define topology_physical_package_id(cpu) (cpu_topology[cpu].package_id)
#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
#define topology_llc_cpumask(cpu) (&cpu_topology[cpu].llc_sibling)
void
init_cpu_topology
(
void
);
void
store_cpu_topology
(
unsigned
int
cpuid
);
void
remove_cpu_topology
(
unsigned
int
cpuid
);
const
struct
cpumask
*
cpu_coregroup_mask
(
int
cpu
);
#ifdef CONFIG_NUMA
struct
pci_bus
;
...
...
arch/arm64/kernel/topology.c
浏览文件 @
015b2693
...
...
@@ -14,250 +14,13 @@
#include <linux/acpi.h>
#include <linux/arch_topology.h>
#include <linux/cacheinfo.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/init.h>
#include <linux/percpu.h>
#include <linux/node.h>
#include <linux/nodemask.h>
#include <linux/of.h>
#include <linux/sched.h>
#include <linux/sched/topology.h>
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/string.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
#include <asm/topology.h>
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
;
cpu
=
of_cpu_node_to_id
(
cpu_node
);
if
(
cpu
>=
0
)
topology_parse_cpu_capacity
(
cpu_node
,
cpu
);
else
pr_crit
(
"Unable to find CPU node for %pOF
\n
"
,
cpu_node
);
of_node_put
(
cpu_node
);
return
cpu
;
}
static
int
__init
parse_core
(
struct
device_node
*
core
,
int
package_id
,
int
core_id
)
{
char
name
[
10
];
bool
leaf
=
true
;
int
i
=
0
;
int
cpu
;
struct
device_node
*
t
;
do
{
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
].
package_id
=
package_id
;
cpu_topology
[
cpu
].
core_id
=
core_id
;
cpu_topology
[
cpu
].
thread_id
=
i
;
}
else
{
pr_err
(
"%pOF: Can't get CPU for thread
\n
"
,
t
);
of_node_put
(
t
);
return
-
EINVAL
;
}
of_node_put
(
t
);
}
i
++
;
}
while
(
t
);
cpu
=
get_cpu_for_node
(
core
);
if
(
cpu
>=
0
)
{
if
(
!
leaf
)
{
pr_err
(
"%pOF: Core has both threads and CPU
\n
"
,
core
);
return
-
EINVAL
;
}
cpu_topology
[
cpu
].
package_id
=
package_id
;
cpu_topology
[
cpu
].
core_id
=
core_id
;
}
else
if
(
leaf
)
{
pr_err
(
"%pOF: Can't get CPU for leaf core
\n
"
,
core
);
return
-
EINVAL
;
}
return
0
;
}
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
package_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
;
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
{
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
(
"%pOF: cpu-map children should be clusters
\n
"
,
c
);
of_node_put
(
c
);
return
-
EINVAL
;
}
if
(
leaf
)
{
ret
=
parse_core
(
c
,
package_id
,
core_id
++
);
}
else
{
pr_err
(
"%pOF: Non-leaf cluster with core %s
\n
"
,
cluster
,
name
);
ret
=
-
EINVAL
;
}
of_node_put
(
c
);
if
(
ret
!=
0
)
return
ret
;
}
i
++
;
}
while
(
c
);
if
(
leaf
&&
!
has_cores
)
pr_warn
(
"%pOF: empty cluster
\n
"
,
cluster
);
if
(
leaf
)
package_id
++
;
return
0
;
}
static
int
__init
parse_dt_topology
(
void
)
{
struct
device_node
*
cn
,
*
map
;
int
ret
=
0
;
int
cpu
;
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.
*/
map
=
of_get_child_by_name
(
cn
,
"cpu-map"
);
if
(
!
map
)
goto
out
;
ret
=
parse_cluster
(
map
,
0
);
if
(
ret
!=
0
)
goto
out_map
;
topology_normalize_cpu_scale
();
/*
* 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
].
package_id
==
-
1
)
ret
=
-
EINVAL
;
out_map:
of_node_put
(
map
);
out:
of_node_put
(
cn
);
return
ret
;
}
/*
* cpu topology table
*/
struct
cpu_topology
cpu_topology
[
NR_CPUS
];
EXPORT_SYMBOL_GPL
(
cpu_topology
);
const
struct
cpumask
*
cpu_coregroup_mask
(
int
cpu
)
{
const
cpumask_t
*
core_mask
=
cpumask_of_node
(
cpu_to_node
(
cpu
));
/* Find the smaller of NUMA, core or LLC siblings */
if
(
cpumask_subset
(
&
cpu_topology
[
cpu
].
core_sibling
,
core_mask
))
{
/* not numa in package, lets use the package siblings */
core_mask
=
&
cpu_topology
[
cpu
].
core_sibling
;
}
if
(
cpu_topology
[
cpu
].
llc_id
!=
-
1
)
{
if
(
cpumask_subset
(
&
cpu_topology
[
cpu
].
llc_sibling
,
core_mask
))
core_mask
=
&
cpu_topology
[
cpu
].
llc_sibling
;
}
return
core_mask
;
}
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_online_cpu
(
cpu
)
{
cpu_topo
=
&
cpu_topology
[
cpu
];
if
(
cpuid_topo
->
llc_id
==
cpu_topo
->
llc_id
)
{
cpumask_set_cpu
(
cpu
,
&
cpuid_topo
->
llc_sibling
);
cpumask_set_cpu
(
cpuid
,
&
cpu_topo
->
llc_sibling
);
}
if
(
cpuid_topo
->
package_id
!=
cpu_topo
->
package_id
)
continue
;
cpumask_set_cpu
(
cpuid
,
&
cpu_topo
->
core_sibling
);
cpumask_set_cpu
(
cpu
,
&
cpuid_topo
->
core_sibling
);
if
(
cpuid_topo
->
core_id
!=
cpu_topo
->
core_id
)
continue
;
cpumask_set_cpu
(
cpuid
,
&
cpu_topo
->
thread_sibling
);
cpumask_set_cpu
(
cpu
,
&
cpuid_topo
->
thread_sibling
);
}
}
void
store_cpu_topology
(
unsigned
int
cpuid
)
{
struct
cpu_topology
*
cpuid_topo
=
&
cpu_topology
[
cpuid
];
...
...
@@ -296,59 +59,19 @@ void store_cpu_topology(unsigned int cpuid)
update_siblings_masks
(
cpuid
);
}
static
void
clear_cpu_topology
(
int
cpu
)
{
struct
cpu_topology
*
cpu_topo
=
&
cpu_topology
[
cpu
];
cpumask_clear
(
&
cpu_topo
->
llc_sibling
);
cpumask_set_cpu
(
cpu
,
&
cpu_topo
->
llc_sibling
);
cpumask_clear
(
&
cpu_topo
->
core_sibling
);
cpumask_set_cpu
(
cpu
,
&
cpu_topo
->
core_sibling
);
cpumask_clear
(
&
cpu_topo
->
thread_sibling
);
cpumask_set_cpu
(
cpu
,
&
cpu_topo
->
thread_sibling
);
}
static
void
__init
reset_cpu_topology
(
void
)
{
unsigned
int
cpu
;
for_each_possible_cpu
(
cpu
)
{
struct
cpu_topology
*
cpu_topo
=
&
cpu_topology
[
cpu
];
cpu_topo
->
thread_id
=
-
1
;
cpu_topo
->
core_id
=
0
;
cpu_topo
->
package_id
=
-
1
;
cpu_topo
->
llc_id
=
-
1
;
clear_cpu_topology
(
cpu
);
}
}
void
remove_cpu_topology
(
unsigned
int
cpu
)
{
int
sibling
;
for_each_cpu
(
sibling
,
topology_core_cpumask
(
cpu
))
cpumask_clear_cpu
(
cpu
,
topology_core_cpumask
(
sibling
));
for_each_cpu
(
sibling
,
topology_sibling_cpumask
(
cpu
))
cpumask_clear_cpu
(
cpu
,
topology_sibling_cpumask
(
sibling
));
for_each_cpu
(
sibling
,
topology_llc_cpumask
(
cpu
))
cpumask_clear_cpu
(
cpu
,
topology_llc_cpumask
(
sibling
));
clear_cpu_topology
(
cpu
);
}
#ifdef CONFIG_ACPI
/*
* Propagate the topology information of the processor_topology_node tree to the
* cpu_topology array.
*/
static
int
__init
parse_acpi_topology
(
void
)
int
__init
parse_acpi_topology
(
void
)
{
bool
is_threaded
;
int
cpu
,
topology_id
;
if
(
acpi_disabled
)
return
0
;
is_threaded
=
read_cpuid_mpidr
()
&
MPIDR_MT_BITMASK
;
for_each_possible_cpu
(
cpu
)
{
...
...
@@ -384,24 +107,6 @@ static int __init parse_acpi_topology(void)
return
0
;
}
#else
static
inline
int
__init
parse_acpi_topology
(
void
)
{
return
-
EINVAL
;
}
#endif
void
__init
init_cpu_topology
(
void
)
{
reset_cpu_topology
();
/*
* Discard anything that was parsed if we hit an error so we
* don't use partial information.
*/
if
(
!
acpi_disabled
&&
parse_acpi_topology
())
reset_cpu_topology
();
else
if
(
of_have_populated_dt
()
&&
parse_dt_topology
())
reset_cpu_topology
();
}
arch/riscv/Kconfig
浏览文件 @
015b2693
...
...
@@ -48,6 +48,7 @@ config RISCV
select PCI_MSI if PCI
select RISCV_TIMER
select GENERIC_IRQ_MULTI_HANDLER
select GENERIC_ARCH_TOPOLOGY if SMP
select ARCH_HAS_PTE_SPECIAL
select ARCH_HAS_MMIOWB
select HAVE_EBPF_JIT if 64BIT
...
...
arch/riscv/kernel/smpboot.c
浏览文件 @
015b2693
...
...
@@ -8,6 +8,7 @@
* Copyright (C) 2017 SiFive
*/
#include <linux/arch_topology.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
...
...
@@ -35,6 +36,7 @@ static DECLARE_COMPLETION(cpu_running);
void
__init
smp_prepare_boot_cpu
(
void
)
{
init_cpu_topology
();
}
void
__init
smp_prepare_cpus
(
unsigned
int
max_cpus
)
...
...
@@ -138,6 +140,7 @@ asmlinkage void __init smp_callin(void)
trap_init
();
notify_cpu_starting
(
smp_processor_id
());
update_siblings_masks
(
smp_processor_id
());
set_cpu_online
(
smp_processor_id
(),
1
);
/*
* Remote TLB flushes are ignored while the CPU is offline, so emit
...
...
drivers/base/Kconfig
浏览文件 @
015b2693
...
...
@@ -202,7 +202,7 @@ config GENERIC_ARCH_TOPOLOGY
help
Enable support for architectures common topology code: e.g., parsing
CPU capacity information from DT, usage of such information for
appropriate scaling, sysfs interface for
chang
ing capacity values at
appropriate scaling, sysfs interface for
read
ing capacity values at
runtime.
endmenu
drivers/base/arch_topology.c
浏览文件 @
015b2693
...
...
@@ -15,6 +15,11 @@
#include <linux/string.h>
#include <linux/sched/topology.h>
#include <linux/cpuset.h>
#include <linux/cpumask.h>
#include <linux/init.h>
#include <linux/percpu.h>
#include <linux/sched.h>
#include <linux/smp.h>
DEFINE_PER_CPU
(
unsigned
long
,
freq_scale
)
=
SCHED_CAPACITY_SCALE
;
...
...
@@ -241,3 +246,296 @@ static void parsing_done_workfn(struct work_struct *work)
#else
core_initcall
(
free_raw_capacity
);
#endif
#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
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
;
cpu
=
of_cpu_node_to_id
(
cpu_node
);
if
(
cpu
>=
0
)
topology_parse_cpu_capacity
(
cpu_node
,
cpu
);
else
pr_crit
(
"Unable to find CPU node for %pOF
\n
"
,
cpu_node
);
of_node_put
(
cpu_node
);
return
cpu
;
}
static
int
__init
parse_core
(
struct
device_node
*
core
,
int
package_id
,
int
core_id
)
{
char
name
[
10
];
bool
leaf
=
true
;
int
i
=
0
;
int
cpu
;
struct
device_node
*
t
;
do
{
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
].
package_id
=
package_id
;
cpu_topology
[
cpu
].
core_id
=
core_id
;
cpu_topology
[
cpu
].
thread_id
=
i
;
}
else
{
pr_err
(
"%pOF: Can't get CPU for thread
\n
"
,
t
);
of_node_put
(
t
);
return
-
EINVAL
;
}
of_node_put
(
t
);
}
i
++
;
}
while
(
t
);
cpu
=
get_cpu_for_node
(
core
);
if
(
cpu
>=
0
)
{
if
(
!
leaf
)
{
pr_err
(
"%pOF: Core has both threads and CPU
\n
"
,
core
);
return
-
EINVAL
;
}
cpu_topology
[
cpu
].
package_id
=
package_id
;
cpu_topology
[
cpu
].
core_id
=
core_id
;
}
else
if
(
leaf
)
{
pr_err
(
"%pOF: Can't get CPU for leaf core
\n
"
,
core
);
return
-
EINVAL
;
}
return
0
;
}
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
package_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
;
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
{
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
(
"%pOF: cpu-map children should be clusters
\n
"
,
c
);
of_node_put
(
c
);
return
-
EINVAL
;
}
if
(
leaf
)
{
ret
=
parse_core
(
c
,
package_id
,
core_id
++
);
}
else
{
pr_err
(
"%pOF: Non-leaf cluster with core %s
\n
"
,
cluster
,
name
);
ret
=
-
EINVAL
;
}
of_node_put
(
c
);
if
(
ret
!=
0
)
return
ret
;
}
i
++
;
}
while
(
c
);
if
(
leaf
&&
!
has_cores
)
pr_warn
(
"%pOF: empty cluster
\n
"
,
cluster
);
if
(
leaf
)
package_id
++
;
return
0
;
}
static
int
__init
parse_dt_topology
(
void
)
{
struct
device_node
*
cn
,
*
map
;
int
ret
=
0
;
int
cpu
;
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.
*/
map
=
of_get_child_by_name
(
cn
,
"cpu-map"
);
if
(
!
map
)
goto
out
;
ret
=
parse_cluster
(
map
,
0
);
if
(
ret
!=
0
)
goto
out_map
;
topology_normalize_cpu_scale
();
/*
* 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
].
package_id
==
-
1
)
ret
=
-
EINVAL
;
out_map:
of_node_put
(
map
);
out:
of_node_put
(
cn
);
return
ret
;
}
#endif
/*
* cpu topology table
*/
struct
cpu_topology
cpu_topology
[
NR_CPUS
];
EXPORT_SYMBOL_GPL
(
cpu_topology
);
const
struct
cpumask
*
cpu_coregroup_mask
(
int
cpu
)
{
const
cpumask_t
*
core_mask
=
cpumask_of_node
(
cpu_to_node
(
cpu
));
/* Find the smaller of NUMA, core or LLC siblings */
if
(
cpumask_subset
(
&
cpu_topology
[
cpu
].
core_sibling
,
core_mask
))
{
/* not numa in package, lets use the package siblings */
core_mask
=
&
cpu_topology
[
cpu
].
core_sibling
;
}
if
(
cpu_topology
[
cpu
].
llc_id
!=
-
1
)
{
if
(
cpumask_subset
(
&
cpu_topology
[
cpu
].
llc_sibling
,
core_mask
))
core_mask
=
&
cpu_topology
[
cpu
].
llc_sibling
;
}
return
core_mask
;
}
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_online_cpu
(
cpu
)
{
cpu_topo
=
&
cpu_topology
[
cpu
];
if
(
cpuid_topo
->
llc_id
==
cpu_topo
->
llc_id
)
{
cpumask_set_cpu
(
cpu
,
&
cpuid_topo
->
llc_sibling
);
cpumask_set_cpu
(
cpuid
,
&
cpu_topo
->
llc_sibling
);
}
if
(
cpuid_topo
->
package_id
!=
cpu_topo
->
package_id
)
continue
;
cpumask_set_cpu
(
cpuid
,
&
cpu_topo
->
core_sibling
);
cpumask_set_cpu
(
cpu
,
&
cpuid_topo
->
core_sibling
);
if
(
cpuid_topo
->
core_id
!=
cpu_topo
->
core_id
)
continue
;
cpumask_set_cpu
(
cpuid
,
&
cpu_topo
->
thread_sibling
);
cpumask_set_cpu
(
cpu
,
&
cpuid_topo
->
thread_sibling
);
}
}
static
void
clear_cpu_topology
(
int
cpu
)
{
struct
cpu_topology
*
cpu_topo
=
&
cpu_topology
[
cpu
];
cpumask_clear
(
&
cpu_topo
->
llc_sibling
);
cpumask_set_cpu
(
cpu
,
&
cpu_topo
->
llc_sibling
);
cpumask_clear
(
&
cpu_topo
->
core_sibling
);
cpumask_set_cpu
(
cpu
,
&
cpu_topo
->
core_sibling
);
cpumask_clear
(
&
cpu_topo
->
thread_sibling
);
cpumask_set_cpu
(
cpu
,
&
cpu_topo
->
thread_sibling
);
}
void
__init
reset_cpu_topology
(
void
)
{
unsigned
int
cpu
;
for_each_possible_cpu
(
cpu
)
{
struct
cpu_topology
*
cpu_topo
=
&
cpu_topology
[
cpu
];
cpu_topo
->
thread_id
=
-
1
;
cpu_topo
->
core_id
=
-
1
;
cpu_topo
->
package_id
=
-
1
;
cpu_topo
->
llc_id
=
-
1
;
clear_cpu_topology
(
cpu
);
}
}
void
remove_cpu_topology
(
unsigned
int
cpu
)
{
int
sibling
;
for_each_cpu
(
sibling
,
topology_core_cpumask
(
cpu
))
cpumask_clear_cpu
(
cpu
,
topology_core_cpumask
(
sibling
));
for_each_cpu
(
sibling
,
topology_sibling_cpumask
(
cpu
))
cpumask_clear_cpu
(
cpu
,
topology_sibling_cpumask
(
sibling
));
for_each_cpu
(
sibling
,
topology_llc_cpumask
(
cpu
))
cpumask_clear_cpu
(
cpu
,
topology_llc_cpumask
(
sibling
));
clear_cpu_topology
(
cpu
);
}
__weak
int
__init
parse_acpi_topology
(
void
)
{
return
0
;
}
#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
void
__init
init_cpu_topology
(
void
)
{
reset_cpu_topology
();
/*
* Discard anything that was parsed if we hit an error so we
* don't use partial information.
*/
if
(
parse_acpi_topology
())
reset_cpu_topology
();
else
if
(
of_have_populated_dt
()
&&
parse_dt_topology
())
reset_cpu_topology
();
}
#endif
include/linux/arch_topology.h
浏览文件 @
015b2693
...
...
@@ -33,4 +33,30 @@ unsigned long topology_get_freq_scale(int cpu)
return
per_cpu
(
freq_scale
,
cpu
);
}
struct
cpu_topology
{
int
thread_id
;
int
core_id
;
int
package_id
;
int
llc_id
;
cpumask_t
thread_sibling
;
cpumask_t
core_sibling
;
cpumask_t
llc_sibling
;
};
#ifdef CONFIG_GENERIC_ARCH_TOPOLOGY
extern
struct
cpu_topology
cpu_topology
[
NR_CPUS
];
#define topology_physical_package_id(cpu) (cpu_topology[cpu].package_id)
#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
#define topology_llc_cpumask(cpu) (&cpu_topology[cpu].llc_sibling)
void
init_cpu_topology
(
void
);
void
store_cpu_topology
(
unsigned
int
cpuid
);
const
struct
cpumask
*
cpu_coregroup_mask
(
int
cpu
);
void
update_siblings_masks
(
unsigned
int
cpu
);
void
remove_cpu_topology
(
unsigned
int
cpuid
);
void
reset_cpu_topology
(
void
);
#endif
#endif
/* _LINUX_ARCH_TOPOLOGY_H_ */
include/linux/topology.h
浏览文件 @
015b2693
...
...
@@ -27,6 +27,7 @@
#ifndef _LINUX_TOPOLOGY_H
#define _LINUX_TOPOLOGY_H
#include <linux/arch_topology.h>
#include <linux/cpumask.h>
#include <linux/bitops.h>
#include <linux/mmzone.h>
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录