Commit | Line | Data |
---|---|---|
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 |
18 | static 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) \ |
25 | static 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 | \ | |
43 | static 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 | 61 | define_id_show_func(physical_package_id, "%d"); |
d6ea8d01 | 62 | static DEVICE_ATTR_RO(physical_package_id); |
69dcc991 | 63 | |
2c4dcd7f | 64 | #ifdef TOPOLOGY_DIE_SYSFS |
182ecfaf | 65 | define_id_show_func(die_id, "%d"); |
0e344d8c | 66 | static DEVICE_ATTR_RO(die_id); |
2c4dcd7f | 67 | #endif |
0e344d8c | 68 | |
e7957077 | 69 | #ifdef TOPOLOGY_CLUSTER_SYSFS |
182ecfaf | 70 | define_id_show_func(cluster_id, "%d"); |
c5e22fef | 71 | static DEVICE_ATTR_RO(cluster_id); |
e7957077 | 72 | #endif |
c5e22fef | 73 | |
182ecfaf | 74 | define_id_show_func(core_id, "%d"); |
d6ea8d01 | 75 | static DEVICE_ATTR_RO(core_id); |
69dcc991 | 76 | |
ab28e944 TL |
77 | define_id_show_func(ppin, "0x%llx"); |
78 | static DEVICE_ATTR_ADMIN_RO(ppin); | |
79 | ||
bb9ec13d | 80 | define_siblings_read_func(thread_siblings, sibling_cpumask); |
5943c0dc TW |
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); | |
69dcc991 | 83 | |
bb9ec13d | 84 | define_siblings_read_func(core_cpus, sibling_cpumask); |
5943c0dc TW |
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); | |
2e4c54da | 87 | |
bb9ec13d | 88 | define_siblings_read_func(core_siblings, core_cpumask); |
5943c0dc TW |
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); | |
69dcc991 | 91 | |
e7957077 | 92 | #ifdef TOPOLOGY_CLUSTER_SYSFS |
c5e22fef | 93 | define_siblings_read_func(cluster_cpus, cluster_cpumask); |
5943c0dc TW |
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); | |
e7957077 | 96 | #endif |
c5e22fef | 97 | |
2c4dcd7f | 98 | #ifdef TOPOLOGY_DIE_SYSFS |
bb9ec13d | 99 | define_siblings_read_func(die_cpus, die_cpumask); |
5943c0dc TW |
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); | |
2c4dcd7f | 102 | #endif |
2e4c54da | 103 | |
bb9ec13d | 104 | define_siblings_read_func(package_cpus, core_cpumask); |
5943c0dc TW |
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); | |
b73ed8dc | 107 | |
f1045056 | 108 | #ifdef TOPOLOGY_BOOK_SYSFS |
182ecfaf | 109 | define_id_show_func(book_id, "%d"); |
d6ea8d01 | 110 | static DEVICE_ATTR_RO(book_id); |
bb9ec13d | 111 | define_siblings_read_func(book_siblings, book_cpumask); |
5943c0dc TW |
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); | |
b40d8ed4 HC |
114 | #endif |
115 | ||
f1045056 | 116 | #ifdef TOPOLOGY_DRAWER_SYSFS |
182ecfaf | 117 | define_id_show_func(drawer_id, "%d"); |
a62247e1 | 118 | static DEVICE_ATTR_RO(drawer_id); |
bb9ec13d | 119 | define_siblings_read_func(drawer_siblings, drawer_cpumask); |
5943c0dc TW |
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); | |
a62247e1 HC |
122 | #endif |
123 | ||
5943c0dc | 124 | static 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 | 152 | static 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 |
171 | static 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 | 180 | static 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 | 188 | static 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 | 195 | static 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 | 203 | static 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 | ||
210 | device_initcall(topology_sysfs_init); | |
6bceea7a RN |
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); |