aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/sysfs.c')
-rw-r--r--arch/powerpc/kernel/sysfs.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 156808086cac..56d172d16e56 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -22,6 +22,8 @@
22 22
23static DEFINE_PER_CPU(struct cpu, cpu_devices); 23static DEFINE_PER_CPU(struct cpu, cpu_devices);
24 24
25static DEFINE_PER_CPU(struct kobject *, cache_toplevel);
26
25/* SMT stuff */ 27/* SMT stuff */
26 28
27#ifdef CONFIG_PPC_MULTIPLATFORM 29#ifdef CONFIG_PPC_MULTIPLATFORM
@@ -297,6 +299,287 @@ static struct sysdev_attribute pa6t_attrs[] = {
297#endif /* CONFIG_DEBUG_KERNEL */ 299#endif /* CONFIG_DEBUG_KERNEL */
298}; 300};
299 301
302struct cache_desc {
303 struct kobject kobj;
304 struct cache_desc *next;
305 const char *type; /* Instruction, Data, or Unified */
306 u32 size; /* total cache size in KB */
307 u32 line_size; /* in bytes */
308 u32 nr_sets; /* number of sets */
309 u32 level; /* e.g. 1, 2, 3... */
310 u32 associativity; /* e.g. 8-way... 0 is fully associative */
311};
312
313DEFINE_PER_CPU(struct cache_desc *, cache_desc);
314
315static struct cache_desc *kobj_to_cache_desc(struct kobject *k)
316{
317 return container_of(k, struct cache_desc, kobj);
318}
319
320static void cache_desc_release(struct kobject *k)
321{
322 struct cache_desc *desc = kobj_to_cache_desc(k);
323
324 pr_debug("%s: releasing %s\n", __func__, kobject_name(k));
325
326 if (desc->next)
327 kobject_put(&desc->next->kobj);
328
329 kfree(kobj_to_cache_desc(k));
330}
331
332static ssize_t cache_desc_show(struct kobject *k, struct attribute *attr, char *buf)
333{
334 struct kobj_attribute *kobj_attr;
335
336 kobj_attr = container_of(attr, struct kobj_attribute, attr);
337
338 return kobj_attr->show(k, kobj_attr, buf);
339}
340
341static struct sysfs_ops cache_desc_sysfs_ops = {
342 .show = cache_desc_show,
343};
344
345static struct kobj_type cache_desc_type = {
346 .release = cache_desc_release,
347 .sysfs_ops = &cache_desc_sysfs_ops,
348};
349
350static ssize_t cache_size_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
351{
352 struct cache_desc *cache = kobj_to_cache_desc(k);
353
354 return sprintf(buf, "%uK\n", cache->size);
355}
356
357static struct kobj_attribute cache_size_attr =
358 __ATTR(size, 0444, cache_size_show, NULL);
359
360static ssize_t cache_line_size_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
361{
362 struct cache_desc *cache = kobj_to_cache_desc(k);
363
364 return sprintf(buf, "%u\n", cache->line_size);
365}
366
367static struct kobj_attribute cache_line_size_attr =
368 __ATTR(coherency_line_size, 0444, cache_line_size_show, NULL);
369
370static ssize_t cache_nr_sets_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
371{
372 struct cache_desc *cache = kobj_to_cache_desc(k);
373
374 return sprintf(buf, "%u\n", cache->nr_sets);
375}
376
377static struct kobj_attribute cache_nr_sets_attr =
378 __ATTR(number_of_sets, 0444, cache_nr_sets_show, NULL);
379
380static ssize_t cache_type_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
381{
382 struct cache_desc *cache = kobj_to_cache_desc(k);
383
384 return sprintf(buf, "%s\n", cache->type);
385}
386
387static struct kobj_attribute cache_type_attr =
388 __ATTR(type, 0444, cache_type_show, NULL);
389
390static ssize_t cache_level_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
391{
392 struct cache_desc *cache = kobj_to_cache_desc(k);
393
394 return sprintf(buf, "%u\n", cache->level);
395}
396
397static struct kobj_attribute cache_level_attr =
398 __ATTR(level, 0444, cache_level_show, NULL);
399
400static ssize_t cache_assoc_show(struct kobject *k, struct kobj_attribute *attr, char *buf)
401{
402 struct cache_desc *cache = kobj_to_cache_desc(k);
403
404 return sprintf(buf, "%u\n", cache->associativity);
405}
406
407static struct kobj_attribute cache_assoc_attr =
408 __ATTR(ways_of_associativity, 0444, cache_assoc_show, NULL);
409
410struct cache_desc_info {
411 const char *type;
412 const char *size_prop;
413 const char *line_size_prop;
414 const char *nr_sets_prop;
415};
416
417/* PowerPC Processor binding says the [di]-cache-* must be equal on
418 * unified caches, so just use d-cache properties. */
419static struct cache_desc_info ucache_info = {
420 .type = "Unified",
421 .size_prop = "d-cache-size",
422 .line_size_prop = "d-cache-line-size",
423 .nr_sets_prop = "d-cache-sets",
424};
425
426static struct cache_desc_info dcache_info = {
427 .type = "Data",
428 .size_prop = "d-cache-size",
429 .line_size_prop = "d-cache-line-size",
430 .nr_sets_prop = "d-cache-sets",
431};
432
433static struct cache_desc_info icache_info = {
434 .type = "Instruction",
435 .size_prop = "i-cache-size",
436 .line_size_prop = "i-cache-line-size",
437 .nr_sets_prop = "i-cache-sets",
438};
439
440static struct cache_desc * __cpuinit create_cache_desc(struct device_node *np, struct kobject *parent, int index, int level, struct cache_desc_info *info)
441{
442 const u32 *cache_line_size;
443 struct cache_desc *new;
444 const u32 *cache_size;
445 const u32 *nr_sets;
446 int rc;
447
448 new = kzalloc(sizeof(*new), GFP_KERNEL);
449 if (!new)
450 return NULL;
451
452 rc = kobject_init_and_add(&new->kobj, &cache_desc_type, parent,
453 "index%d", index);
454 if (rc)
455 goto err;
456
457 /* type */
458 new->type = info->type;
459 rc = sysfs_create_file(&new->kobj, &cache_type_attr.attr);
460 WARN_ON(rc);
461
462 /* level */
463 new->level = level;
464 rc = sysfs_create_file(&new->kobj, &cache_level_attr.attr);
465 WARN_ON(rc);
466
467 /* size */
468 cache_size = of_get_property(np, info->size_prop, NULL);
469 if (cache_size) {
470 new->size = *cache_size / 1024;
471 rc = sysfs_create_file(&new->kobj,
472 &cache_size_attr.attr);
473 WARN_ON(rc);
474 }
475
476 /* coherency_line_size */
477 cache_line_size = of_get_property(np, info->line_size_prop, NULL);
478 if (cache_line_size) {
479 new->line_size = *cache_line_size;
480 rc = sysfs_create_file(&new->kobj,
481 &cache_line_size_attr.attr);
482 WARN_ON(rc);
483 }
484
485 /* number_of_sets */
486 nr_sets = of_get_property(np, info->nr_sets_prop, NULL);
487 if (nr_sets) {
488 new->nr_sets = *nr_sets;
489 rc = sysfs_create_file(&new->kobj,
490 &cache_nr_sets_attr.attr);
491 WARN_ON(rc);
492 }
493
494 /* ways_of_associativity */
495 if (new->nr_sets == 1) {
496 /* fully associative */
497 new->associativity = 0;
498 goto create_assoc;
499 }
500
501 if (new->nr_sets && new->size && new->line_size) {
502 /* If we have values for all of these we can derive
503 * the associativity. */
504 new->associativity =
505 ((new->size * 1024) / new->nr_sets) / new->line_size;
506create_assoc:
507 rc = sysfs_create_file(&new->kobj,
508 &cache_assoc_attr.attr);
509 WARN_ON(rc);
510 }
511
512 return new;
513err:
514 kfree(new);
515 return NULL;
516}
517
518static bool cache_is_unified(struct device_node *np)
519{
520 return of_get_property(np, "cache-unified", NULL);
521}
522
523static struct cache_desc * __cpuinit create_cache_index_info(struct device_node *np, struct kobject *parent, int index, int level)
524{
525 const phandle *next_cache_phandle;
526 struct device_node *next_cache;
527 struct cache_desc *new, **end;
528
529 pr_debug("%s(node = %s, index = %d)\n", __func__, np->full_name, index);
530
531 if (cache_is_unified(np)) {
532 new = create_cache_desc(np, parent, index, level,
533 &ucache_info);
534 } else {
535 new = create_cache_desc(np, parent, index, level,
536 &dcache_info);
537 if (new) {
538 index++;
539 new->next = create_cache_desc(np, parent, index, level,
540 &icache_info);
541 }
542 }
543 if (!new)
544 return NULL;
545
546 end = &new->next;
547 while (*end)
548 end = &(*end)->next;
549
550 next_cache_phandle = of_get_property(np, "l2-cache", NULL);
551 if (!next_cache_phandle)
552 goto out;
553
554 next_cache = of_find_node_by_phandle(*next_cache_phandle);
555 if (!next_cache)
556 goto out;
557
558 *end = create_cache_index_info(next_cache, parent, ++index, ++level);
559
560 of_node_put(next_cache);
561out:
562 return new;
563}
564
565static void __cpuinit create_cache_info(struct sys_device *sysdev)
566{
567 struct kobject *cache_toplevel;
568 struct device_node *np = NULL;
569 int cpu = sysdev->id;
570
571 cache_toplevel = kobject_create_and_add("cache", &sysdev->kobj);
572 if (!cache_toplevel)
573 return;
574 per_cpu(cache_toplevel, cpu) = cache_toplevel;
575 np = of_get_cpu_node(cpu, NULL);
576 if (np != NULL) {
577 per_cpu(cache_desc, cpu) =
578 create_cache_index_info(np, cache_toplevel, 0, 1);
579 of_node_put(np);
580 }
581 return;
582}
300 583
301static void __cpuinit register_cpu_online(unsigned int cpu) 584static void __cpuinit register_cpu_online(unsigned int cpu)
302{ 585{
@@ -346,9 +629,33 @@ static void __cpuinit register_cpu_online(unsigned int cpu)
346 629
347 if (cpu_has_feature(CPU_FTR_DSCR)) 630 if (cpu_has_feature(CPU_FTR_DSCR))
348 sysdev_create_file(s, &attr_dscr); 631 sysdev_create_file(s, &attr_dscr);
632
633 create_cache_info(s);
349} 634}
350 635
351#ifdef CONFIG_HOTPLUG_CPU 636#ifdef CONFIG_HOTPLUG_CPU
637static void remove_cache_info(struct sys_device *sysdev)
638{
639 struct kobject *cache_toplevel;
640 struct cache_desc *cache_desc;
641 int cpu = sysdev->id;
642
643 cache_desc = per_cpu(cache_desc, cpu);
644 if (cache_desc != NULL) {
645 sysfs_remove_file(&cache_desc->kobj, &cache_size_attr.attr);
646 sysfs_remove_file(&cache_desc->kobj, &cache_line_size_attr.attr);
647 sysfs_remove_file(&cache_desc->kobj, &cache_type_attr.attr);
648 sysfs_remove_file(&cache_desc->kobj, &cache_level_attr.attr);
649 sysfs_remove_file(&cache_desc->kobj, &cache_nr_sets_attr.attr);
650 sysfs_remove_file(&cache_desc->kobj, &cache_assoc_attr.attr);
651
652 kobject_put(&cache_desc->kobj);
653 }
654 cache_toplevel = per_cpu(cache_toplevel, cpu);
655 if (cache_toplevel != NULL)
656 kobject_put(cache_toplevel);
657}
658
352static void unregister_cpu_online(unsigned int cpu) 659static void unregister_cpu_online(unsigned int cpu)
353{ 660{
354 struct cpu *c = &per_cpu(cpu_devices, cpu); 661 struct cpu *c = &per_cpu(cpu_devices, cpu);
@@ -399,6 +706,8 @@ static void unregister_cpu_online(unsigned int cpu)
399 706
400 if (cpu_has_feature(CPU_FTR_DSCR)) 707 if (cpu_has_feature(CPU_FTR_DSCR))
401 sysdev_remove_file(s, &attr_dscr); 708 sysdev_remove_file(s, &attr_dscr);
709
710 remove_cache_info(s);
402} 711}
403#endif /* CONFIG_HOTPLUG_CPU */ 712#endif /* CONFIG_HOTPLUG_CPU */
404 713