summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeith Busch <keith.busch@intel.com>2019-03-11 16:56:02 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-04-04 12:41:21 -0400
commitacc02a109b0497e917c83f986a89c51e47d0022c (patch)
treed91c422777692d123a0f5d42b96b6e5c76fba566
parente1cf33aafb8462c7d0a0e6349925870316f040ee (diff)
node: Add memory-side caching attributes
System memory may have caches to help improve access speed to frequently requested address ranges. While the system provided cache is transparent to the software accessing these memory ranges, applications can optimize their own access based on cache attributes. Provide a new API for the kernel to register these memory-side caches under the memory node that provides it. The new sysfs representation is modeled from the existing cpu cacheinfo attributes, as seen from /sys/devices/system/cpu/<cpu>/cache/. Unlike CPU cacheinfo though, the node cache level is reported from the view of the memory. A higher level number is nearer to the CPU, while lower levels are closer to the last level memory. The exported attributes are the cache size, the line size, associativity indexing, and write back policy, and add the attributes for the system memory caches to sysfs stable documentation. Signed-off-by: Keith Busch <keith.busch@intel.com> Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Brice Goglin <Brice.Goglin@inria.fr> Tested-by: Brice Goglin <Brice.Goglin@inria.fr> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/ABI/stable/sysfs-devices-node34
-rw-r--r--drivers/base/node.c151
-rw-r--r--include/linux/node.h39
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>
142Description: 142Description:
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
146What: /sys/devices/system/node/nodeX/memory_side_cache/indexY/
147Date: December 2018
148Contact: Keith Busch <keith.busch@intel.com>
149Description:
150 The directory containing attributes for the memory-side cache
151 level 'Y'.
152
153What: /sys/devices/system/node/nodeX/memory_side_cache/indexY/indexing
154Date: December 2018
155Contact: Keith Busch <keith.busch@intel.com>
156Description:
157 The caches associativity indexing: 0 for direct mapped,
158 non-zero if indexed.
159
160What: /sys/devices/system/node/nodeX/memory_side_cache/indexY/line_size
161Date: December 2018
162Contact: Keith Busch <keith.busch@intel.com>
163Description:
164 The number of bytes accessed from the next cache level on a
165 cache miss.
166
167What: /sys/devices/system/node/nodeX/memory_side_cache/indexY/size
168Date: December 2018
169Contact: Keith Busch <keith.busch@intel.com>
170Description:
171 The size of this memory side cache in bytes.
172
173What: /sys/devices/system/node/nodeX/memory_side_cache/indexY/write_policy
174Date: December 2018
175Contact: Keith Busch <keith.busch@intel.com>
176Description:
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 */
215struct 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) \
223static 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} \
229DEVICE_ATTR_RO(name);
230
231CACHE_ATTR(size, "%llu")
232CACHE_ATTR(line_size, "%u")
233CACHE_ATTR(indexing, "%u")
234CACHE_ATTR(write_policy, "%u")
235
236static 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};
243ATTRIBUTE_GROUPS(cache);
244
245static void node_cache_release(struct device *dev)
246{
247 kfree(dev);
248}
249
250static void node_cacheinfo_release(struct device *dev)
251{
252 struct node_cache_info *info = to_cache_info(dev);
253 kfree(info);
254}
255
256static 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;
275free_name:
276 kfree_const(dev->kobj.name);
277free_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 */
286void 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;
330free_name:
331 kfree_const(dev->kobj.name);
332free_cache:
333 kfree(info);
334}
335
336static 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
350static void node_init_caches(unsigned int nid)
351{
352 INIT_LIST_HEAD(&node_devices[nid]->cache_attrs);
353}
354#else
355static void node_init_caches(unsigned int nid) { }
356static 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
38enum cache_indexing {
39 NODE_CACHE_DIRECT_MAP,
40 NODE_CACHE_INDEXED,
41 NODE_CACHE_OTHER,
42};
43
44enum 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 */
59struct 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
68void node_add_cache(unsigned int nid, struct node_cache_attrs *cache_attrs);
39void node_set_perf_attrs(unsigned int nid, struct node_hmem_attrs *hmem_attrs, 69void node_set_perf_attrs(unsigned int nid, struct node_hmem_attrs *hmem_attrs,
40 unsigned access); 70 unsigned access);
41#else 71#else
72static inline void node_add_cache(unsigned int nid,
73 struct node_cache_attrs *cache_attrs)
74{
75}
76
42static inline void node_set_perf_attrs(unsigned int nid, 77static 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
58struct memory_block; 97struct memory_block;