summaryrefslogtreecommitdiffstats
path: root/drivers/base/node.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/node.c')
-rw-r--r--drivers/base/node.c151
1 files changed, 151 insertions, 0 deletions
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}