Line data Source code
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 : struct bin_attribute *attr, char *buf, \
27 : loff_t off, size_t count) \
28 : { \
29 : struct device *dev = kobj_to_dev(kobj); \
30 : \
31 : return cpumap_print_bitmask_to_buf(buf, topology_##mask(dev->id), \
32 : off, count); \
33 : } \
34 : \
35 : static ssize_t name##_list_read(struct file *file, struct kobject *kobj, \
36 : struct bin_attribute *attr, char *buf, \
37 : loff_t off, size_t count) \
38 : { \
39 : struct device *dev = kobj_to_dev(kobj); \
40 : \
41 : return cpumap_print_list_to_buf(buf, topology_##mask(dev->id), \
42 : off, count); \
43 : }
44 :
45 0 : define_id_show_func(physical_package_id, "%d");
46 : static DEVICE_ATTR_RO(physical_package_id);
47 :
48 : #ifdef TOPOLOGY_DIE_SYSFS
49 : define_id_show_func(die_id, "%d");
50 : static DEVICE_ATTR_RO(die_id);
51 : #endif
52 :
53 : #ifdef TOPOLOGY_CLUSTER_SYSFS
54 : define_id_show_func(cluster_id, "%d");
55 : static DEVICE_ATTR_RO(cluster_id);
56 : #endif
57 :
58 0 : define_id_show_func(core_id, "%d");
59 : static DEVICE_ATTR_RO(core_id);
60 :
61 0 : define_id_show_func(ppin, "0x%llx");
62 : static DEVICE_ATTR_ADMIN_RO(ppin);
63 :
64 0 : define_siblings_read_func(thread_siblings, sibling_cpumask);
65 : static BIN_ATTR_RO(thread_siblings, CPUMAP_FILE_MAX_BYTES);
66 : static BIN_ATTR_RO(thread_siblings_list, CPULIST_FILE_MAX_BYTES);
67 :
68 0 : define_siblings_read_func(core_cpus, sibling_cpumask);
69 : static BIN_ATTR_RO(core_cpus, CPUMAP_FILE_MAX_BYTES);
70 : static BIN_ATTR_RO(core_cpus_list, CPULIST_FILE_MAX_BYTES);
71 :
72 0 : define_siblings_read_func(core_siblings, core_cpumask);
73 : static BIN_ATTR_RO(core_siblings, CPUMAP_FILE_MAX_BYTES);
74 : static BIN_ATTR_RO(core_siblings_list, CPULIST_FILE_MAX_BYTES);
75 :
76 : #ifdef TOPOLOGY_CLUSTER_SYSFS
77 : define_siblings_read_func(cluster_cpus, cluster_cpumask);
78 : static BIN_ATTR_RO(cluster_cpus, CPUMAP_FILE_MAX_BYTES);
79 : static BIN_ATTR_RO(cluster_cpus_list, CPULIST_FILE_MAX_BYTES);
80 : #endif
81 :
82 : #ifdef TOPOLOGY_DIE_SYSFS
83 : define_siblings_read_func(die_cpus, die_cpumask);
84 : static BIN_ATTR_RO(die_cpus, CPUMAP_FILE_MAX_BYTES);
85 : static BIN_ATTR_RO(die_cpus_list, CPULIST_FILE_MAX_BYTES);
86 : #endif
87 :
88 0 : define_siblings_read_func(package_cpus, core_cpumask);
89 : static BIN_ATTR_RO(package_cpus, CPUMAP_FILE_MAX_BYTES);
90 : static BIN_ATTR_RO(package_cpus_list, CPULIST_FILE_MAX_BYTES);
91 :
92 : #ifdef TOPOLOGY_BOOK_SYSFS
93 : define_id_show_func(book_id, "%d");
94 : static DEVICE_ATTR_RO(book_id);
95 : define_siblings_read_func(book_siblings, book_cpumask);
96 : static BIN_ATTR_RO(book_siblings, CPUMAP_FILE_MAX_BYTES);
97 : static BIN_ATTR_RO(book_siblings_list, CPULIST_FILE_MAX_BYTES);
98 : #endif
99 :
100 : #ifdef TOPOLOGY_DRAWER_SYSFS
101 : define_id_show_func(drawer_id, "%d");
102 : static DEVICE_ATTR_RO(drawer_id);
103 : define_siblings_read_func(drawer_siblings, drawer_cpumask);
104 : static BIN_ATTR_RO(drawer_siblings, CPUMAP_FILE_MAX_BYTES);
105 : static BIN_ATTR_RO(drawer_siblings_list, CPULIST_FILE_MAX_BYTES);
106 : #endif
107 :
108 : static struct bin_attribute *bin_attrs[] = {
109 : &bin_attr_core_cpus,
110 : &bin_attr_core_cpus_list,
111 : &bin_attr_thread_siblings,
112 : &bin_attr_thread_siblings_list,
113 : &bin_attr_core_siblings,
114 : &bin_attr_core_siblings_list,
115 : #ifdef TOPOLOGY_CLUSTER_SYSFS
116 : &bin_attr_cluster_cpus,
117 : &bin_attr_cluster_cpus_list,
118 : #endif
119 : #ifdef TOPOLOGY_DIE_SYSFS
120 : &bin_attr_die_cpus,
121 : &bin_attr_die_cpus_list,
122 : #endif
123 : &bin_attr_package_cpus,
124 : &bin_attr_package_cpus_list,
125 : #ifdef TOPOLOGY_BOOK_SYSFS
126 : &bin_attr_book_siblings,
127 : &bin_attr_book_siblings_list,
128 : #endif
129 : #ifdef TOPOLOGY_DRAWER_SYSFS
130 : &bin_attr_drawer_siblings,
131 : &bin_attr_drawer_siblings_list,
132 : #endif
133 : NULL
134 : };
135 :
136 : static struct attribute *default_attrs[] = {
137 : &dev_attr_physical_package_id.attr,
138 : #ifdef TOPOLOGY_DIE_SYSFS
139 : &dev_attr_die_id.attr,
140 : #endif
141 : #ifdef TOPOLOGY_CLUSTER_SYSFS
142 : &dev_attr_cluster_id.attr,
143 : #endif
144 : &dev_attr_core_id.attr,
145 : #ifdef TOPOLOGY_BOOK_SYSFS
146 : &dev_attr_book_id.attr,
147 : #endif
148 : #ifdef TOPOLOGY_DRAWER_SYSFS
149 : &dev_attr_drawer_id.attr,
150 : #endif
151 : &dev_attr_ppin.attr,
152 : NULL
153 : };
154 :
155 3 : static umode_t topology_is_visible(struct kobject *kobj,
156 : struct attribute *attr, int unused)
157 : {
158 3 : if (attr == &dev_attr_ppin.attr && !topology_ppin(kobj_to_dev(kobj)->id))
159 : return 0;
160 :
161 2 : return attr->mode;
162 : }
163 :
164 : static const struct attribute_group topology_attr_group = {
165 : .attrs = default_attrs,
166 : .bin_attrs = bin_attrs,
167 : .is_visible = topology_is_visible,
168 : .name = "topology"
169 : };
170 :
171 : /* Add/Remove cpu_topology interface for CPU device */
172 1 : static int topology_add_dev(unsigned int cpu)
173 : {
174 1 : struct device *dev = get_cpu_device(cpu);
175 :
176 1 : return sysfs_create_group(&dev->kobj, &topology_attr_group);
177 : }
178 :
179 0 : static int topology_remove_dev(unsigned int cpu)
180 : {
181 0 : struct device *dev = get_cpu_device(cpu);
182 :
183 0 : sysfs_remove_group(&dev->kobj, &topology_attr_group);
184 0 : return 0;
185 : }
186 :
187 1 : static int __init topology_sysfs_init(void)
188 : {
189 1 : return cpuhp_setup_state(CPUHP_TOPOLOGY_PREPARE,
190 : "base/topology:prepare", topology_add_dev,
191 : topology_remove_dev);
192 : }
193 :
194 : device_initcall(topology_sysfs_init);
|