Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/base/topology.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0+
2
/*
3
* driver/base/topology.c - Populate sysfs with cpu topology information
4
*
5
* Written by: Zhang Yanmin, Intel Corporation
6
*
7
* Copyright (C) 2006, Intel Corp.
8
*
9
* All rights reserved.
10
*/
11
#include <linux/mm.h>
12
#include <linux/cpu.h>
13
#include <linux/module.h>
14
#include <linux/hardirq.h>
15
#include <linux/topology.h>
16
17
#define define_id_show_func(name, fmt) \
18
static ssize_t name##_show(struct device *dev, \
19
struct device_attribute *attr, char *buf) \
20
{ \
21
return sysfs_emit(buf, fmt "\n", topology_##name(dev->id)); \
22
}
23
24
#define define_siblings_read_func(name, mask) \
25
static ssize_t name##_read(struct file *file, struct kobject *kobj, \
26
const struct bin_attribute *attr, char *buf, \
27
loff_t off, size_t count) \
28
{ \
29
struct device *dev = kobj_to_dev(kobj); \
30
cpumask_var_t mask; \
31
ssize_t n; \
32
\
33
if (!alloc_cpumask_var(&mask, GFP_KERNEL)) \
34
return -ENOMEM; \
35
\
36
cpumask_copy(mask, topology_##mask(dev->id)); \
37
n = cpumap_print_bitmask_to_buf(buf, mask, off, count); \
38
free_cpumask_var(mask); \
39
\
40
return n; \
41
} \
42
\
43
static ssize_t name##_list_read(struct file *file, struct kobject *kobj, \
44
const struct bin_attribute *attr, char *buf, \
45
loff_t off, size_t count) \
46
{ \
47
struct device *dev = kobj_to_dev(kobj); \
48
cpumask_var_t mask; \
49
ssize_t n; \
50
\
51
if (!alloc_cpumask_var(&mask, GFP_KERNEL)) \
52
return -ENOMEM; \
53
\
54
cpumask_copy(mask, topology_##mask(dev->id)); \
55
n = cpumap_print_list_to_buf(buf, mask, off, count); \
56
free_cpumask_var(mask); \
57
\
58
return n; \
59
}
60
61
define_id_show_func(physical_package_id, "%d");
62
static DEVICE_ATTR_RO(physical_package_id);
63
64
#ifdef TOPOLOGY_DIE_SYSFS
65
define_id_show_func(die_id, "%d");
66
static DEVICE_ATTR_RO(die_id);
67
#endif
68
69
#ifdef TOPOLOGY_CLUSTER_SYSFS
70
define_id_show_func(cluster_id, "%d");
71
static DEVICE_ATTR_RO(cluster_id);
72
#endif
73
74
define_id_show_func(core_id, "%d");
75
static DEVICE_ATTR_RO(core_id);
76
77
define_id_show_func(ppin, "0x%llx");
78
static DEVICE_ATTR_ADMIN_RO(ppin);
79
80
define_siblings_read_func(thread_siblings, sibling_cpumask);
81
static const BIN_ATTR_RO(thread_siblings, CPUMAP_FILE_MAX_BYTES);
82
static const BIN_ATTR_RO(thread_siblings_list, CPULIST_FILE_MAX_BYTES);
83
84
define_siblings_read_func(core_cpus, sibling_cpumask);
85
static const BIN_ATTR_RO(core_cpus, CPUMAP_FILE_MAX_BYTES);
86
static const BIN_ATTR_RO(core_cpus_list, CPULIST_FILE_MAX_BYTES);
87
88
define_siblings_read_func(core_siblings, core_cpumask);
89
static const BIN_ATTR_RO(core_siblings, CPUMAP_FILE_MAX_BYTES);
90
static const BIN_ATTR_RO(core_siblings_list, CPULIST_FILE_MAX_BYTES);
91
92
#ifdef TOPOLOGY_CLUSTER_SYSFS
93
define_siblings_read_func(cluster_cpus, cluster_cpumask);
94
static const BIN_ATTR_RO(cluster_cpus, CPUMAP_FILE_MAX_BYTES);
95
static const BIN_ATTR_RO(cluster_cpus_list, CPULIST_FILE_MAX_BYTES);
96
#endif
97
98
#ifdef TOPOLOGY_DIE_SYSFS
99
define_siblings_read_func(die_cpus, die_cpumask);
100
static const BIN_ATTR_RO(die_cpus, CPUMAP_FILE_MAX_BYTES);
101
static const BIN_ATTR_RO(die_cpus_list, CPULIST_FILE_MAX_BYTES);
102
#endif
103
104
define_siblings_read_func(package_cpus, core_cpumask);
105
static const BIN_ATTR_RO(package_cpus, CPUMAP_FILE_MAX_BYTES);
106
static const BIN_ATTR_RO(package_cpus_list, CPULIST_FILE_MAX_BYTES);
107
108
#ifdef TOPOLOGY_BOOK_SYSFS
109
define_id_show_func(book_id, "%d");
110
static DEVICE_ATTR_RO(book_id);
111
define_siblings_read_func(book_siblings, book_cpumask);
112
static const BIN_ATTR_RO(book_siblings, CPUMAP_FILE_MAX_BYTES);
113
static const BIN_ATTR_RO(book_siblings_list, CPULIST_FILE_MAX_BYTES);
114
#endif
115
116
#ifdef TOPOLOGY_DRAWER_SYSFS
117
define_id_show_func(drawer_id, "%d");
118
static DEVICE_ATTR_RO(drawer_id);
119
define_siblings_read_func(drawer_siblings, drawer_cpumask);
120
static const BIN_ATTR_RO(drawer_siblings, CPUMAP_FILE_MAX_BYTES);
121
static const BIN_ATTR_RO(drawer_siblings_list, CPULIST_FILE_MAX_BYTES);
122
#endif
123
124
static const struct bin_attribute *const bin_attrs[] = {
125
&bin_attr_core_cpus,
126
&bin_attr_core_cpus_list,
127
&bin_attr_thread_siblings,
128
&bin_attr_thread_siblings_list,
129
&bin_attr_core_siblings,
130
&bin_attr_core_siblings_list,
131
#ifdef TOPOLOGY_CLUSTER_SYSFS
132
&bin_attr_cluster_cpus,
133
&bin_attr_cluster_cpus_list,
134
#endif
135
#ifdef TOPOLOGY_DIE_SYSFS
136
&bin_attr_die_cpus,
137
&bin_attr_die_cpus_list,
138
#endif
139
&bin_attr_package_cpus,
140
&bin_attr_package_cpus_list,
141
#ifdef TOPOLOGY_BOOK_SYSFS
142
&bin_attr_book_siblings,
143
&bin_attr_book_siblings_list,
144
#endif
145
#ifdef TOPOLOGY_DRAWER_SYSFS
146
&bin_attr_drawer_siblings,
147
&bin_attr_drawer_siblings_list,
148
#endif
149
NULL
150
};
151
152
static struct attribute *default_attrs[] = {
153
&dev_attr_physical_package_id.attr,
154
#ifdef TOPOLOGY_DIE_SYSFS
155
&dev_attr_die_id.attr,
156
#endif
157
#ifdef TOPOLOGY_CLUSTER_SYSFS
158
&dev_attr_cluster_id.attr,
159
#endif
160
&dev_attr_core_id.attr,
161
#ifdef TOPOLOGY_BOOK_SYSFS
162
&dev_attr_book_id.attr,
163
#endif
164
#ifdef TOPOLOGY_DRAWER_SYSFS
165
&dev_attr_drawer_id.attr,
166
#endif
167
&dev_attr_ppin.attr,
168
NULL
169
};
170
171
static umode_t topology_is_visible(struct kobject *kobj,
172
struct attribute *attr, int unused)
173
{
174
if (attr == &dev_attr_ppin.attr && !topology_ppin(kobj_to_dev(kobj)->id))
175
return 0;
176
177
return attr->mode;
178
}
179
180
static const struct attribute_group topology_attr_group = {
181
.attrs = default_attrs,
182
.bin_attrs = bin_attrs,
183
.is_visible = topology_is_visible,
184
.name = "topology"
185
};
186
187
/* Add/Remove cpu_topology interface for CPU device */
188
static int topology_add_dev(unsigned int cpu)
189
{
190
struct device *dev = get_cpu_device(cpu);
191
192
return sysfs_create_group(&dev->kobj, &topology_attr_group);
193
}
194
195
static int topology_remove_dev(unsigned int cpu)
196
{
197
struct device *dev = get_cpu_device(cpu);
198
199
sysfs_remove_group(&dev->kobj, &topology_attr_group);
200
return 0;
201
}
202
203
static int __init topology_sysfs_init(void)
204
{
205
return cpuhp_setup_state(CPUHP_TOPOLOGY_PREPARE,
206
"base/topology:prepare", topology_add_dev,
207
topology_remove_dev);
208
}
209
210
device_initcall(topology_sysfs_init);
211
212
DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
213
EXPORT_PER_CPU_SYMBOL_GPL(cpu_scale);
214
215
void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity)
216
{
217
per_cpu(cpu_scale, cpu) = capacity;
218
}
219
220
static ssize_t cpu_capacity_show(struct device *dev,
221
struct device_attribute *attr,
222
char *buf)
223
{
224
struct cpu *cpu = container_of(dev, struct cpu, dev);
225
226
return sysfs_emit(buf, "%lu\n", topology_get_cpu_scale(cpu->dev.id));
227
}
228
229
static DEVICE_ATTR_RO(cpu_capacity);
230
231
static int cpu_capacity_sysctl_add(unsigned int cpu)
232
{
233
struct device *cpu_dev = get_cpu_device(cpu);
234
235
if (!cpu_dev)
236
return -ENOENT;
237
238
device_create_file(cpu_dev, &dev_attr_cpu_capacity);
239
240
return 0;
241
}
242
243
static int cpu_capacity_sysctl_remove(unsigned int cpu)
244
{
245
struct device *cpu_dev = get_cpu_device(cpu);
246
247
if (!cpu_dev)
248
return -ENOENT;
249
250
device_remove_file(cpu_dev, &dev_attr_cpu_capacity);
251
252
return 0;
253
}
254
255
static int register_cpu_capacity_sysctl(void)
256
{
257
cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "topology/cpu-capacity",
258
cpu_capacity_sysctl_add, cpu_capacity_sysctl_remove);
259
260
return 0;
261
}
262
subsys_initcall(register_cpu_capacity_sysctl);
263
264