diff options
-rw-r--r-- | Documentation/ABI/stable/sysfs-devices-node | 34 | ||||
-rw-r--r-- | drivers/base/node.c | 151 | ||||
-rw-r--r-- | include/linux/node.h | 39 |
3 files changed, 224 insertions, 0 deletions
diff --git a/Documentation/ABI/stable/sysfs-devices-node b/Documentation/ABI/stable/sysfs-devices-node index 735a40a3f9b2..f7ce68fbd4b9 100644 --- a/Documentation/ABI/stable/sysfs-devices-node +++ b/Documentation/ABI/stable/sysfs-devices-node | |||
@@ -142,3 +142,37 @@ Contact: Keith Busch <keith.busch@intel.com> | |||
142 | Description: | 142 | Description: |
143 | This node's write latency in nanoseconds when access | 143 | This node's write latency in nanoseconds when access |
144 | from nodes found in this class's linked initiators. | 144 | from nodes found in this class's linked initiators. |
145 | |||
146 | What: /sys/devices/system/node/nodeX/memory_side_cache/indexY/ | ||
147 | Date: December 2018 | ||
148 | Contact: Keith Busch <keith.busch@intel.com> | ||
149 | Description: | ||
150 | The directory containing attributes for the memory-side cache | ||
151 | level 'Y'. | ||
152 | |||
153 | What: /sys/devices/system/node/nodeX/memory_side_cache/indexY/indexing | ||
154 | Date: December 2018 | ||
155 | Contact: Keith Busch <keith.busch@intel.com> | ||
156 | Description: | ||
157 | The caches associativity indexing: 0 for direct mapped, | ||
158 | non-zero if indexed. | ||
159 | |||
160 | What: /sys/devices/system/node/nodeX/memory_side_cache/indexY/line_size | ||
161 | Date: December 2018 | ||
162 | Contact: Keith Busch <keith.busch@intel.com> | ||
163 | Description: | ||
164 | The number of bytes accessed from the next cache level on a | ||
165 | cache miss. | ||
166 | |||
167 | What: /sys/devices/system/node/nodeX/memory_side_cache/indexY/size | ||
168 | Date: December 2018 | ||
169 | Contact: Keith Busch <keith.busch@intel.com> | ||
170 | Description: | ||
171 | The size of this memory side cache in bytes. | ||
172 | |||
173 | What: /sys/devices/system/node/nodeX/memory_side_cache/indexY/write_policy | ||
174 | Date: December 2018 | ||
175 | Contact: Keith Busch <keith.busch@intel.com> | ||
176 | Description: | ||
177 | The cache write policy: 0 for write-back, 1 for write-through, | ||
178 | other or unknown. | ||
diff --git a/drivers/base/node.c b/drivers/base/node.c index 2de546a040a5..8598fcbd2a17 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c | |||
@@ -205,6 +205,155 @@ void node_set_perf_attrs(unsigned int nid, struct node_hmem_attrs *hmem_attrs, | |||
205 | } | 205 | } |
206 | } | 206 | } |
207 | } | 207 | } |
208 | |||
209 | /** | ||
210 | * struct node_cache_info - Internal tracking for memory node caches | ||
211 | * @dev: Device represeting the cache level | ||
212 | * @node: List element for tracking in the node | ||
213 | * @cache_attrs:Attributes for this cache level | ||
214 | */ | ||
215 | struct node_cache_info { | ||
216 | struct device dev; | ||
217 | struct list_head node; | ||
218 | struct node_cache_attrs cache_attrs; | ||
219 | }; | ||
220 | #define to_cache_info(device) container_of(device, struct node_cache_info, dev) | ||
221 | |||
222 | #define CACHE_ATTR(name, fmt) \ | ||
223 | static ssize_t name##_show(struct device *dev, \ | ||
224 | struct device_attribute *attr, \ | ||
225 | char *buf) \ | ||
226 | { \ | ||
227 | return sprintf(buf, fmt "\n", to_cache_info(dev)->cache_attrs.name);\ | ||
228 | } \ | ||
229 | DEVICE_ATTR_RO(name); | ||
230 | |||
231 | CACHE_ATTR(size, "%llu") | ||
232 | CACHE_ATTR(line_size, "%u") | ||
233 | CACHE_ATTR(indexing, "%u") | ||
234 | CACHE_ATTR(write_policy, "%u") | ||
235 | |||
236 | static struct attribute *cache_attrs[] = { | ||
237 | &dev_attr_indexing.attr, | ||
238 | &dev_attr_size.attr, | ||
239 | &dev_attr_line_size.attr, | ||
240 | &dev_attr_write_policy.attr, | ||
241 | NULL, | ||
242 | }; | ||
243 | ATTRIBUTE_GROUPS(cache); | ||
244 | |||
245 | static void node_cache_release(struct device *dev) | ||
246 | { | ||
247 | kfree(dev); | ||
248 | } | ||
249 | |||
250 | static void node_cacheinfo_release(struct device *dev) | ||
251 | { | ||
252 | struct node_cache_info *info = to_cache_info(dev); | ||
253 | kfree(info); | ||
254 | } | ||
255 | |||
256 | static void node_init_cache_dev(struct node *node) | ||
257 | { | ||
258 | struct device *dev; | ||
259 | |||
260 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
261 | if (!dev) | ||
262 | return; | ||
263 | |||
264 | dev->parent = &node->dev; | ||
265 | dev->release = node_cache_release; | ||
266 | if (dev_set_name(dev, "memory_side_cache")) | ||
267 | goto free_dev; | ||
268 | |||
269 | if (device_register(dev)) | ||
270 | goto free_name; | ||
271 | |||
272 | pm_runtime_no_callbacks(dev); | ||
273 | node->cache_dev = dev; | ||
274 | return; | ||
275 | free_name: | ||
276 | kfree_const(dev->kobj.name); | ||
277 | free_dev: | ||
278 | kfree(dev); | ||
279 | } | ||
280 | |||
281 | /** | ||
282 | * node_add_cache() - add cache attribute to a memory node | ||
283 | * @nid: Node identifier that has new cache attributes | ||
284 | * @cache_attrs: Attributes for the cache being added | ||
285 | */ | ||
286 | void node_add_cache(unsigned int nid, struct node_cache_attrs *cache_attrs) | ||
287 | { | ||
288 | struct node_cache_info *info; | ||
289 | struct device *dev; | ||
290 | struct node *node; | ||
291 | |||
292 | if (!node_online(nid) || !node_devices[nid]) | ||
293 | return; | ||
294 | |||
295 | node = node_devices[nid]; | ||
296 | list_for_each_entry(info, &node->cache_attrs, node) { | ||
297 | if (info->cache_attrs.level == cache_attrs->level) { | ||
298 | dev_warn(&node->dev, | ||
299 | "attempt to add duplicate cache level:%d\n", | ||
300 | cache_attrs->level); | ||
301 | return; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | if (!node->cache_dev) | ||
306 | node_init_cache_dev(node); | ||
307 | if (!node->cache_dev) | ||
308 | return; | ||
309 | |||
310 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
311 | if (!info) | ||
312 | return; | ||
313 | |||
314 | dev = &info->dev; | ||
315 | dev->parent = node->cache_dev; | ||
316 | dev->release = node_cacheinfo_release; | ||
317 | dev->groups = cache_groups; | ||
318 | if (dev_set_name(dev, "index%d", cache_attrs->level)) | ||
319 | goto free_cache; | ||
320 | |||
321 | info->cache_attrs = *cache_attrs; | ||
322 | if (device_register(dev)) { | ||
323 | dev_warn(&node->dev, "failed to add cache level:%d\n", | ||
324 | cache_attrs->level); | ||
325 | goto free_name; | ||
326 | } | ||
327 | pm_runtime_no_callbacks(dev); | ||
328 | list_add_tail(&info->node, &node->cache_attrs); | ||
329 | return; | ||
330 | free_name: | ||
331 | kfree_const(dev->kobj.name); | ||
332 | free_cache: | ||
333 | kfree(info); | ||
334 | } | ||
335 | |||
336 | static void node_remove_caches(struct node *node) | ||
337 | { | ||
338 | struct node_cache_info *info, *next; | ||
339 | |||
340 | if (!node->cache_dev) | ||
341 | return; | ||
342 | |||
343 | list_for_each_entry_safe(info, next, &node->cache_attrs, node) { | ||
344 | list_del(&info->node); | ||
345 | device_unregister(&info->dev); | ||
346 | } | ||
347 | device_unregister(node->cache_dev); | ||
348 | } | ||
349 | |||
350 | static void node_init_caches(unsigned int nid) | ||
351 | { | ||
352 | INIT_LIST_HEAD(&node_devices[nid]->cache_attrs); | ||
353 | } | ||
354 | #else | ||
355 | static void node_init_caches(unsigned int nid) { } | ||
356 | static void node_remove_caches(struct node *node) { } | ||
208 | #endif | 357 | #endif |
209 | 358 | ||
210 | #define K(x) ((x) << (PAGE_SHIFT - 10)) | 359 | #define K(x) ((x) << (PAGE_SHIFT - 10)) |
@@ -489,6 +638,7 @@ void unregister_node(struct node *node) | |||
489 | { | 638 | { |
490 | hugetlb_unregister_node(node); /* no-op, if memoryless node */ | 639 | hugetlb_unregister_node(node); /* no-op, if memoryless node */ |
491 | node_remove_accesses(node); | 640 | node_remove_accesses(node); |
641 | node_remove_caches(node); | ||
492 | device_unregister(&node->dev); | 642 | device_unregister(&node->dev); |
493 | } | 643 | } |
494 | 644 | ||
@@ -781,6 +931,7 @@ int __register_one_node(int nid) | |||
781 | INIT_LIST_HEAD(&node_devices[nid]->access_list); | 931 | INIT_LIST_HEAD(&node_devices[nid]->access_list); |
782 | /* initialize work queue for memory hot plug */ | 932 | /* initialize work queue for memory hot plug */ |
783 | init_node_hugetlb_work(nid); | 933 | init_node_hugetlb_work(nid); |
934 | node_init_caches(nid); | ||
784 | 935 | ||
785 | return error; | 936 | return error; |
786 | } | 937 | } |
diff --git a/include/linux/node.h b/include/linux/node.h index 4139d728f8b3..1a557c589ecb 100644 --- a/include/linux/node.h +++ b/include/linux/node.h | |||
@@ -35,10 +35,45 @@ struct node_hmem_attrs { | |||
35 | unsigned int write_latency; | 35 | unsigned int write_latency; |
36 | }; | 36 | }; |
37 | 37 | ||
38 | enum cache_indexing { | ||
39 | NODE_CACHE_DIRECT_MAP, | ||
40 | NODE_CACHE_INDEXED, | ||
41 | NODE_CACHE_OTHER, | ||
42 | }; | ||
43 | |||
44 | enum cache_write_policy { | ||
45 | NODE_CACHE_WRITE_BACK, | ||
46 | NODE_CACHE_WRITE_THROUGH, | ||
47 | NODE_CACHE_WRITE_OTHER, | ||
48 | }; | ||
49 | |||
50 | /** | ||
51 | * struct node_cache_attrs - system memory caching attributes | ||
52 | * | ||
53 | * @indexing: The ways memory blocks may be placed in cache | ||
54 | * @write_policy: Write back or write through policy | ||
55 | * @size: Total size of cache in bytes | ||
56 | * @line_size: Number of bytes fetched on a cache miss | ||
57 | * @level: The cache hierarchy level | ||
58 | */ | ||
59 | struct node_cache_attrs { | ||
60 | enum cache_indexing indexing; | ||
61 | enum cache_write_policy write_policy; | ||
62 | u64 size; | ||
63 | u16 line_size; | ||
64 | u8 level; | ||
65 | }; | ||
66 | |||
38 | #ifdef CONFIG_HMEM_REPORTING | 67 | #ifdef CONFIG_HMEM_REPORTING |
68 | void node_add_cache(unsigned int nid, struct node_cache_attrs *cache_attrs); | ||
39 | void node_set_perf_attrs(unsigned int nid, struct node_hmem_attrs *hmem_attrs, | 69 | void node_set_perf_attrs(unsigned int nid, struct node_hmem_attrs *hmem_attrs, |
40 | unsigned access); | 70 | unsigned access); |
41 | #else | 71 | #else |
72 | static inline void node_add_cache(unsigned int nid, | ||
73 | struct node_cache_attrs *cache_attrs) | ||
74 | { | ||
75 | } | ||
76 | |||
42 | static inline void node_set_perf_attrs(unsigned int nid, | 77 | static inline void node_set_perf_attrs(unsigned int nid, |
43 | struct node_hmem_attrs *hmem_attrs, | 78 | struct node_hmem_attrs *hmem_attrs, |
44 | unsigned access) | 79 | unsigned access) |
@@ -53,6 +88,10 @@ struct node { | |||
53 | #if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_HUGETLBFS) | 88 | #if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_HUGETLBFS) |
54 | struct work_struct node_work; | 89 | struct work_struct node_work; |
55 | #endif | 90 | #endif |
91 | #ifdef CONFIG_HMEM_REPORTING | ||
92 | struct list_head cache_attrs; | ||
93 | struct device *cache_dev; | ||
94 | #endif | ||
56 | }; | 95 | }; |
57 | 96 | ||
58 | struct memory_block; | 97 | struct memory_block; |