Merge tag 'net-6.16-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-block.git] / drivers / base / topology.c
CommitLineData
989d42e8 1// SPDX-License-Identifier: GPL-2.0+
69dcc991
ZY
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.
69dcc991 10 */
69dcc991
ZY
11#include <linux/mm.h>
12#include <linux/cpu.h>
13#include <linux/module.h>
b13d3720 14#include <linux/hardirq.h>
69dcc991
ZY
15#include <linux/topology.h>
16
182ecfaf 17#define define_id_show_func(name, fmt) \
948b3edb
JP
18static ssize_t name##_show(struct device *dev, \
19 struct device_attribute *attr, char *buf) \
20{ \
182ecfaf 21 return sysfs_emit(buf, fmt "\n", topology_##name(dev->id)); \
69dcc991
ZY
22}
23
bb9ec13d
TT
24#define define_siblings_read_func(name, mask) \
25static ssize_t name##_read(struct file *file, struct kobject *kobj, \
562e932a 26 const struct bin_attribute *attr, char *buf, \
bb9ec13d
TT
27 loff_t off, size_t count) \
28{ \
29 struct device *dev = kobj_to_dev(kobj); \
cbd399f7
LH
30 cpumask_var_t mask; \
31 ssize_t n; \
bb9ec13d 32 \
cbd399f7
LH
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; \
bb9ec13d
TT
41} \
42 \
43static ssize_t name##_list_read(struct file *file, struct kobject *kobj, \
562e932a 44 const struct bin_attribute *attr, char *buf, \
bb9ec13d
TT
45 loff_t off, size_t count) \
46{ \
47 struct device *dev = kobj_to_dev(kobj); \
cbd399f7
LH
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); \
bb9ec13d 57 \
cbd399f7 58 return n; \
23ca4bba
MT
59}
60
182ecfaf 61define_id_show_func(physical_package_id, "%d");
d6ea8d01 62static DEVICE_ATTR_RO(physical_package_id);
69dcc991 63
2c4dcd7f 64#ifdef TOPOLOGY_DIE_SYSFS
182ecfaf 65define_id_show_func(die_id, "%d");
0e344d8c 66static DEVICE_ATTR_RO(die_id);
2c4dcd7f 67#endif
0e344d8c 68
e7957077 69#ifdef TOPOLOGY_CLUSTER_SYSFS
182ecfaf 70define_id_show_func(cluster_id, "%d");
c5e22fef 71static DEVICE_ATTR_RO(cluster_id);
e7957077 72#endif
c5e22fef 73
182ecfaf 74define_id_show_func(core_id, "%d");
d6ea8d01 75static DEVICE_ATTR_RO(core_id);
69dcc991 76
ab28e944
TL
77define_id_show_func(ppin, "0x%llx");
78static DEVICE_ATTR_ADMIN_RO(ppin);
79
bb9ec13d 80define_siblings_read_func(thread_siblings, sibling_cpumask);
5943c0dc
TW
81static const BIN_ATTR_RO(thread_siblings, CPUMAP_FILE_MAX_BYTES);
82static const BIN_ATTR_RO(thread_siblings_list, CPULIST_FILE_MAX_BYTES);
69dcc991 83
bb9ec13d 84define_siblings_read_func(core_cpus, sibling_cpumask);
5943c0dc
TW
85static const BIN_ATTR_RO(core_cpus, CPUMAP_FILE_MAX_BYTES);
86static const BIN_ATTR_RO(core_cpus_list, CPULIST_FILE_MAX_BYTES);
2e4c54da 87
bb9ec13d 88define_siblings_read_func(core_siblings, core_cpumask);
5943c0dc
TW
89static const BIN_ATTR_RO(core_siblings, CPUMAP_FILE_MAX_BYTES);
90static const BIN_ATTR_RO(core_siblings_list, CPULIST_FILE_MAX_BYTES);
69dcc991 91
e7957077 92#ifdef TOPOLOGY_CLUSTER_SYSFS
c5e22fef 93define_siblings_read_func(cluster_cpus, cluster_cpumask);
5943c0dc
TW
94static const BIN_ATTR_RO(cluster_cpus, CPUMAP_FILE_MAX_BYTES);
95static const BIN_ATTR_RO(cluster_cpus_list, CPULIST_FILE_MAX_BYTES);
e7957077 96#endif
c5e22fef 97
2c4dcd7f 98#ifdef TOPOLOGY_DIE_SYSFS
bb9ec13d 99define_siblings_read_func(die_cpus, die_cpumask);
5943c0dc
TW
100static const BIN_ATTR_RO(die_cpus, CPUMAP_FILE_MAX_BYTES);
101static const BIN_ATTR_RO(die_cpus_list, CPULIST_FILE_MAX_BYTES);
2c4dcd7f 102#endif
2e4c54da 103
bb9ec13d 104define_siblings_read_func(package_cpus, core_cpumask);
5943c0dc
TW
105static const BIN_ATTR_RO(package_cpus, CPUMAP_FILE_MAX_BYTES);
106static const BIN_ATTR_RO(package_cpus_list, CPULIST_FILE_MAX_BYTES);
b73ed8dc 107
f1045056 108#ifdef TOPOLOGY_BOOK_SYSFS
182ecfaf 109define_id_show_func(book_id, "%d");
d6ea8d01 110static DEVICE_ATTR_RO(book_id);
bb9ec13d 111define_siblings_read_func(book_siblings, book_cpumask);
5943c0dc
TW
112static const BIN_ATTR_RO(book_siblings, CPUMAP_FILE_MAX_BYTES);
113static const BIN_ATTR_RO(book_siblings_list, CPULIST_FILE_MAX_BYTES);
b40d8ed4
HC
114#endif
115
f1045056 116#ifdef TOPOLOGY_DRAWER_SYSFS
182ecfaf 117define_id_show_func(drawer_id, "%d");
a62247e1 118static DEVICE_ATTR_RO(drawer_id);
bb9ec13d 119define_siblings_read_func(drawer_siblings, drawer_cpumask);
5943c0dc
TW
120static const BIN_ATTR_RO(drawer_siblings, CPUMAP_FILE_MAX_BYTES);
121static const BIN_ATTR_RO(drawer_siblings_list, CPULIST_FILE_MAX_BYTES);
a62247e1
HC
122#endif
123
5943c0dc 124static const struct bin_attribute *const bin_attrs[] = {
bb9ec13d
TT
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,
e7957077 131#ifdef TOPOLOGY_CLUSTER_SYSFS
c5e22fef
JC
132 &bin_attr_cluster_cpus,
133 &bin_attr_cluster_cpus_list,
e7957077 134#endif
2c4dcd7f 135#ifdef TOPOLOGY_DIE_SYSFS
bb9ec13d
TT
136 &bin_attr_die_cpus,
137 &bin_attr_die_cpus_list,
2c4dcd7f 138#endif
bb9ec13d
TT
139 &bin_attr_package_cpus,
140 &bin_attr_package_cpus_list,
f1045056 141#ifdef TOPOLOGY_BOOK_SYSFS
bb9ec13d
TT
142 &bin_attr_book_siblings,
143 &bin_attr_book_siblings_list,
144#endif
f1045056 145#ifdef TOPOLOGY_DRAWER_SYSFS
bb9ec13d
TT
146 &bin_attr_drawer_siblings,
147 &bin_attr_drawer_siblings_list,
148#endif
149 NULL
150};
151
69dcc991 152static struct attribute *default_attrs[] = {
8a25a2fd 153 &dev_attr_physical_package_id.attr,
2c4dcd7f 154#ifdef TOPOLOGY_DIE_SYSFS
0e344d8c 155 &dev_attr_die_id.attr,
2c4dcd7f 156#endif
e7957077 157#ifdef TOPOLOGY_CLUSTER_SYSFS
c5e22fef 158 &dev_attr_cluster_id.attr,
e7957077 159#endif
8a25a2fd 160 &dev_attr_core_id.attr,
f1045056 161#ifdef TOPOLOGY_BOOK_SYSFS
8a25a2fd 162 &dev_attr_book_id.attr,
a62247e1 163#endif
f1045056 164#ifdef TOPOLOGY_DRAWER_SYSFS
a62247e1 165 &dev_attr_drawer_id.attr,
b40d8ed4 166#endif
ab28e944 167 &dev_attr_ppin.attr,
69dcc991
ZY
168 NULL
169};
170
aa63a74d
TL
171static umode_t topology_is_visible(struct kobject *kobj,
172 struct attribute *attr, int unused)
173{
c95ce3a2 174 if (attr == &dev_attr_ppin.attr && !topology_ppin(kobj_to_dev(kobj)->id))
aa63a74d
TL
175 return 0;
176
177 return attr->mode;
178}
179
df44d30d 180static const struct attribute_group topology_attr_group = {
69dcc991 181 .attrs = default_attrs,
5943c0dc 182 .bin_attrs_new = bin_attrs,
aa63a74d 183 .is_visible = topology_is_visible,
69dcc991
ZY
184 .name = "topology"
185};
186
187/* Add/Remove cpu_topology interface for CPU device */
a83048eb 188static int topology_add_dev(unsigned int cpu)
69dcc991 189{
8a25a2fd 190 struct device *dev = get_cpu_device(cpu);
06a4bcae 191
8a25a2fd 192 return sysfs_create_group(&dev->kobj, &topology_attr_group);
69dcc991
ZY
193}
194
38643a0e 195static int topology_remove_dev(unsigned int cpu)
69dcc991 196{
8a25a2fd 197 struct device *dev = get_cpu_device(cpu);
06a4bcae 198
8a25a2fd 199 sysfs_remove_group(&dev->kobj, &topology_attr_group);
38643a0e 200 return 0;
69dcc991 201}
69dcc991 202
0d989da3 203static int __init topology_sysfs_init(void)
69dcc991 204{
38643a0e
SAS
205 return cpuhp_setup_state(CPUHP_TOPOLOGY_PREPARE,
206 "base/topology:prepare", topology_add_dev,
207 topology_remove_dev);
69dcc991
ZY
208}
209
210device_initcall(topology_sysfs_init);
6bceea7a
RN
211
212DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
213EXPORT_PER_CPU_SYMBOL_GPL(cpu_scale);
214
215void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity)
216{
217 per_cpu(cpu_scale, cpu) = capacity;
218}
219
220static 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
229static DEVICE_ATTR_RO(cpu_capacity);
230
231static 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
243static 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
255static 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}
262subsys_initcall(register_cpu_capacity_sysctl);