1 /* mdesc.c: Sun4V machine description handling.
3 * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
5 #include <linux/kernel.h>
6 #include <linux/types.h>
7 #include <linux/bootmem.h>
8 #include <linux/log2.h>
9 #include <linux/list.h>
10 #include <linux/slab.h>
13 #include <asm/hypervisor.h>
14 #include <asm/mdesc.h>
16 #include <asm/oplib.h>
19 /* Unlike the OBP device tree, the machine description is a full-on
20 * DAG. An arbitrary number of ARCs are possible from one
21 * node to other nodes and thus we can't use the OBP device_node
22 * data structure to represent these nodes inside of the kernel.
24 * Actually, it isn't even a DAG, because there are back pointers
25 * which create cycles in the graph.
27 * mdesc_hdr and mdesc_elem describe the layout of the data structure
28 * we get from the Hypervisor.
31 u32 version
; /* Transport version */
32 u32 node_sz
; /* node block size */
33 u32 name_sz
; /* name block size */
34 u32 data_sz
; /* data block size */
35 } __attribute__((aligned(16)));
39 #define MD_LIST_END 0x00
41 #define MD_NODE_END 0x45
43 #define MD_PROP_ARC 0x61
44 #define MD_PROP_VAL 0x76
45 #define MD_PROP_STR 0x73
46 #define MD_PROP_DATA 0x64
59 struct mdesc_mem_ops
{
60 struct mdesc_handle
*(*alloc
)(unsigned int mdesc_size
);
61 void (*free
)(struct mdesc_handle
*handle
);
65 struct list_head list
;
66 struct mdesc_mem_ops
*mops
;
69 unsigned int handle_size
;
70 struct mdesc_hdr mdesc
;
73 static void mdesc_handle_init(struct mdesc_handle
*hp
,
74 unsigned int handle_size
,
77 BUG_ON(((unsigned long)&hp
->mdesc
) & (16UL - 1));
79 memset(hp
, 0, handle_size
);
80 INIT_LIST_HEAD(&hp
->list
);
82 atomic_set(&hp
->refcnt
, 1);
83 hp
->handle_size
= handle_size
;
86 static struct mdesc_handle
*mdesc_bootmem_alloc(unsigned int mdesc_size
)
88 struct mdesc_handle
*hp
;
89 unsigned int handle_size
, alloc_size
;
91 handle_size
= (sizeof(struct mdesc_handle
) -
92 sizeof(struct mdesc_hdr
) +
94 alloc_size
= PAGE_ALIGN(handle_size
);
96 hp
= __alloc_bootmem(alloc_size
, PAGE_SIZE
, 0UL);
98 mdesc_handle_init(hp
, handle_size
, hp
);
103 static void mdesc_bootmem_free(struct mdesc_handle
*hp
)
105 unsigned int alloc_size
, handle_size
= hp
->handle_size
;
106 unsigned long start
, end
;
108 BUG_ON(atomic_read(&hp
->refcnt
) != 0);
109 BUG_ON(!list_empty(&hp
->list
));
111 alloc_size
= PAGE_ALIGN(handle_size
);
113 start
= (unsigned long) hp
;
114 end
= start
+ alloc_size
;
116 while (start
< end
) {
119 p
= virt_to_page(start
);
120 ClearPageReserved(p
);
126 static struct mdesc_mem_ops bootmem_mdesc_memops
= {
127 .alloc
= mdesc_bootmem_alloc
,
128 .free
= mdesc_bootmem_free
,
131 static struct mdesc_handle
*mdesc_kmalloc(unsigned int mdesc_size
)
133 unsigned int handle_size
;
136 handle_size
= (sizeof(struct mdesc_handle
) -
137 sizeof(struct mdesc_hdr
) +
140 base
= kmalloc(handle_size
+ 15, GFP_KERNEL
| __GFP_NOFAIL
);
142 struct mdesc_handle
*hp
;
145 addr
= (unsigned long)base
;
146 addr
= (addr
+ 15UL) & ~15UL;
147 hp
= (struct mdesc_handle
*) addr
;
149 mdesc_handle_init(hp
, handle_size
, base
);
156 static void mdesc_kfree(struct mdesc_handle
*hp
)
158 BUG_ON(atomic_read(&hp
->refcnt
) != 0);
159 BUG_ON(!list_empty(&hp
->list
));
161 kfree(hp
->self_base
);
164 static struct mdesc_mem_ops kmalloc_mdesc_memops
= {
165 .alloc
= mdesc_kmalloc
,
169 static struct mdesc_handle
*mdesc_alloc(unsigned int mdesc_size
,
170 struct mdesc_mem_ops
*mops
)
172 struct mdesc_handle
*hp
= mops
->alloc(mdesc_size
);
180 static void mdesc_free(struct mdesc_handle
*hp
)
185 static struct mdesc_handle
*cur_mdesc
;
186 static LIST_HEAD(mdesc_zombie_list
);
187 static DEFINE_SPINLOCK(mdesc_lock
);
189 struct mdesc_handle
*mdesc_grab(void)
191 struct mdesc_handle
*hp
;
194 spin_lock_irqsave(&mdesc_lock
, flags
);
197 atomic_inc(&hp
->refcnt
);
198 spin_unlock_irqrestore(&mdesc_lock
, flags
);
202 EXPORT_SYMBOL(mdesc_grab
);
204 void mdesc_release(struct mdesc_handle
*hp
)
208 spin_lock_irqsave(&mdesc_lock
, flags
);
209 if (atomic_dec_and_test(&hp
->refcnt
)) {
210 list_del_init(&hp
->list
);
213 spin_unlock_irqrestore(&mdesc_lock
, flags
);
215 EXPORT_SYMBOL(mdesc_release
);
217 static DEFINE_MUTEX(mdesc_mutex
);
218 static struct mdesc_notifier_client
*client_list
;
220 void mdesc_register_notifier(struct mdesc_notifier_client
*client
)
224 mutex_lock(&mdesc_mutex
);
225 client
->next
= client_list
;
226 client_list
= client
;
228 mdesc_for_each_node_by_name(cur_mdesc
, node
, client
->node_name
)
229 client
->add(cur_mdesc
, node
);
231 mutex_unlock(&mdesc_mutex
);
234 /* Run 'func' on nodes which are in A but not in B. */
235 static void invoke_on_missing(const char *name
,
236 struct mdesc_handle
*a
,
237 struct mdesc_handle
*b
,
238 void (*func
)(struct mdesc_handle
*, u64
))
242 mdesc_for_each_node_by_name(a
, node
, name
) {
243 const u64
*id
= mdesc_get_property(a
, node
, "id", NULL
);
247 mdesc_for_each_node_by_name(b
, fnode
, name
) {
248 const u64
*fid
= mdesc_get_property(b
, fnode
,
261 static void notify_one(struct mdesc_notifier_client
*p
,
262 struct mdesc_handle
*old_hp
,
263 struct mdesc_handle
*new_hp
)
265 invoke_on_missing(p
->node_name
, old_hp
, new_hp
, p
->remove
);
266 invoke_on_missing(p
->node_name
, new_hp
, old_hp
, p
->add
);
269 static void mdesc_notify_clients(struct mdesc_handle
*old_hp
,
270 struct mdesc_handle
*new_hp
)
272 struct mdesc_notifier_client
*p
= client_list
;
275 notify_one(p
, old_hp
, new_hp
);
280 void mdesc_update(void)
282 unsigned long len
, real_len
, status
;
283 struct mdesc_handle
*hp
, *orig_hp
;
286 mutex_lock(&mdesc_mutex
);
288 (void) sun4v_mach_desc(0UL, 0UL, &len
);
290 hp
= mdesc_alloc(len
, &kmalloc_mdesc_memops
);
292 printk(KERN_ERR
"MD: mdesc alloc fails\n");
296 status
= sun4v_mach_desc(__pa(&hp
->mdesc
), len
, &real_len
);
297 if (status
!= HV_EOK
|| real_len
> len
) {
298 printk(KERN_ERR
"MD: mdesc reread fails with %lu\n",
300 atomic_dec(&hp
->refcnt
);
305 spin_lock_irqsave(&mdesc_lock
, flags
);
308 spin_unlock_irqrestore(&mdesc_lock
, flags
);
310 mdesc_notify_clients(orig_hp
, hp
);
312 spin_lock_irqsave(&mdesc_lock
, flags
);
313 if (atomic_dec_and_test(&orig_hp
->refcnt
))
316 list_add(&orig_hp
->list
, &mdesc_zombie_list
);
317 spin_unlock_irqrestore(&mdesc_lock
, flags
);
320 mutex_unlock(&mdesc_mutex
);
323 static struct mdesc_elem
*node_block(struct mdesc_hdr
*mdesc
)
325 return (struct mdesc_elem
*) (mdesc
+ 1);
328 static void *name_block(struct mdesc_hdr
*mdesc
)
330 return ((void *) node_block(mdesc
)) + mdesc
->node_sz
;
333 static void *data_block(struct mdesc_hdr
*mdesc
)
335 return ((void *) name_block(mdesc
)) + mdesc
->name_sz
;
338 u64
mdesc_node_by_name(struct mdesc_handle
*hp
,
339 u64 from_node
, const char *name
)
341 struct mdesc_elem
*ep
= node_block(&hp
->mdesc
);
342 const char *names
= name_block(&hp
->mdesc
);
343 u64 last_node
= hp
->mdesc
.node_sz
/ 16;
346 if (from_node
== MDESC_NODE_NULL
) {
348 } else if (from_node
>= last_node
) {
349 return MDESC_NODE_NULL
;
351 ret
= ep
[from_node
].d
.val
;
354 while (ret
< last_node
) {
355 if (ep
[ret
].tag
!= MD_NODE
)
356 return MDESC_NODE_NULL
;
357 if (!strcmp(names
+ ep
[ret
].name_offset
, name
))
361 if (ret
>= last_node
)
362 ret
= MDESC_NODE_NULL
;
365 EXPORT_SYMBOL(mdesc_node_by_name
);
367 const void *mdesc_get_property(struct mdesc_handle
*hp
, u64 node
,
368 const char *name
, int *lenp
)
370 const char *names
= name_block(&hp
->mdesc
);
371 u64 last_node
= hp
->mdesc
.node_sz
/ 16;
372 void *data
= data_block(&hp
->mdesc
);
373 struct mdesc_elem
*ep
;
375 if (node
== MDESC_NODE_NULL
|| node
>= last_node
)
378 ep
= node_block(&hp
->mdesc
) + node
;
380 for (; ep
->tag
!= MD_NODE_END
; ep
++) {
392 val
= data
+ ep
->d
.data
.data_offset
;
393 len
= ep
->d
.data
.data_len
;
402 if (!strcmp(names
+ ep
->name_offset
, name
)) {
411 EXPORT_SYMBOL(mdesc_get_property
);
413 u64
mdesc_next_arc(struct mdesc_handle
*hp
, u64 from
, const char *arc_type
)
415 struct mdesc_elem
*ep
, *base
= node_block(&hp
->mdesc
);
416 const char *names
= name_block(&hp
->mdesc
);
417 u64 last_node
= hp
->mdesc
.node_sz
/ 16;
419 if (from
== MDESC_NODE_NULL
|| from
>= last_node
)
420 return MDESC_NODE_NULL
;
425 for (; ep
->tag
!= MD_NODE_END
; ep
++) {
426 if (ep
->tag
!= MD_PROP_ARC
)
429 if (strcmp(names
+ ep
->name_offset
, arc_type
))
435 return MDESC_NODE_NULL
;
437 EXPORT_SYMBOL(mdesc_next_arc
);
439 u64
mdesc_arc_target(struct mdesc_handle
*hp
, u64 arc
)
441 struct mdesc_elem
*ep
, *base
= node_block(&hp
->mdesc
);
447 EXPORT_SYMBOL(mdesc_arc_target
);
449 const char *mdesc_node_name(struct mdesc_handle
*hp
, u64 node
)
451 struct mdesc_elem
*ep
, *base
= node_block(&hp
->mdesc
);
452 const char *names
= name_block(&hp
->mdesc
);
453 u64 last_node
= hp
->mdesc
.node_sz
/ 16;
455 if (node
== MDESC_NODE_NULL
|| node
>= last_node
)
459 if (ep
->tag
!= MD_NODE
)
462 return names
+ ep
->name_offset
;
464 EXPORT_SYMBOL(mdesc_node_name
);
466 static void __init
report_platform_properties(void)
468 struct mdesc_handle
*hp
= mdesc_grab();
469 u64 pn
= mdesc_node_by_name(hp
, MDESC_NODE_NULL
, "platform");
473 if (pn
== MDESC_NODE_NULL
) {
474 prom_printf("No platform node in machine-description.\n");
478 s
= mdesc_get_property(hp
, pn
, "banner-name", NULL
);
479 printk("PLATFORM: banner-name [%s]\n", s
);
480 s
= mdesc_get_property(hp
, pn
, "name", NULL
);
481 printk("PLATFORM: name [%s]\n", s
);
483 v
= mdesc_get_property(hp
, pn
, "hostid", NULL
);
485 printk("PLATFORM: hostid [%08lx]\n", *v
);
486 v
= mdesc_get_property(hp
, pn
, "serial#", NULL
);
488 printk("PLATFORM: serial# [%08lx]\n", *v
);
489 v
= mdesc_get_property(hp
, pn
, "stick-frequency", NULL
);
490 printk("PLATFORM: stick-frequency [%08lx]\n", *v
);
491 v
= mdesc_get_property(hp
, pn
, "mac-address", NULL
);
493 printk("PLATFORM: mac-address [%lx]\n", *v
);
494 v
= mdesc_get_property(hp
, pn
, "watchdog-resolution", NULL
);
496 printk("PLATFORM: watchdog-resolution [%lu ms]\n", *v
);
497 v
= mdesc_get_property(hp
, pn
, "watchdog-max-timeout", NULL
);
499 printk("PLATFORM: watchdog-max-timeout [%lu ms]\n", *v
);
500 v
= mdesc_get_property(hp
, pn
, "max-cpus", NULL
);
502 printk("PLATFORM: max-cpus [%lu]\n", *v
);
510 if (max_cpu
> NR_CPUS
)
515 for (i
= 0; i
< max_cpu
; i
++)
516 cpu_set(i
, cpu_possible_map
);
523 static int inline find_in_proplist(const char *list
, const char *match
, int len
)
528 if (!strcmp(list
, match
))
530 l
= strlen(list
) + 1;
537 static void __devinit
fill_in_one_cache(cpuinfo_sparc
*c
,
538 struct mdesc_handle
*hp
,
541 const u64
*level
= mdesc_get_property(hp
, mp
, "level", NULL
);
542 const u64
*size
= mdesc_get_property(hp
, mp
, "size", NULL
);
543 const u64
*line_size
= mdesc_get_property(hp
, mp
, "line-size", NULL
);
547 type
= mdesc_get_property(hp
, mp
, "type", &type_len
);
551 if (find_in_proplist(type
, "instn", type_len
)) {
552 c
->icache_size
= *size
;
553 c
->icache_line_size
= *line_size
;
554 } else if (find_in_proplist(type
, "data", type_len
)) {
555 c
->dcache_size
= *size
;
556 c
->dcache_line_size
= *line_size
;
561 c
->ecache_size
= *size
;
562 c
->ecache_line_size
= *line_size
;
572 mdesc_for_each_arc(a
, hp
, mp
, MDESC_ARC_TYPE_FWD
) {
573 u64 target
= mdesc_arc_target(hp
, a
);
574 const char *name
= mdesc_node_name(hp
, target
);
576 if (!strcmp(name
, "cache"))
577 fill_in_one_cache(c
, hp
, target
);
582 static void __devinit
mark_core_ids(struct mdesc_handle
*hp
, u64 mp
,
587 mdesc_for_each_arc(a
, hp
, mp
, MDESC_ARC_TYPE_BACK
) {
588 u64 t
= mdesc_arc_target(hp
, a
);
592 name
= mdesc_node_name(hp
, t
);
593 if (!strcmp(name
, "cpu")) {
594 id
= mdesc_get_property(hp
, t
, "id", NULL
);
596 cpu_data(*id
).core_id
= core_id
;
600 mdesc_for_each_arc(j
, hp
, t
, MDESC_ARC_TYPE_BACK
) {
601 u64 n
= mdesc_arc_target(hp
, j
);
604 n_name
= mdesc_node_name(hp
, n
);
605 if (strcmp(n_name
, "cpu"))
608 id
= mdesc_get_property(hp
, n
, "id", NULL
);
610 cpu_data(*id
).core_id
= core_id
;
616 static void __devinit
set_core_ids(struct mdesc_handle
*hp
)
622 mdesc_for_each_node_by_name(hp
, mp
, "cache") {
627 level
= mdesc_get_property(hp
, mp
, "level", NULL
);
631 type
= mdesc_get_property(hp
, mp
, "type", &len
);
632 if (!find_in_proplist(type
, "instn", len
))
635 mark_core_ids(hp
, mp
, idx
);
641 static void __devinit
mark_proc_ids(struct mdesc_handle
*hp
, u64 mp
,
646 mdesc_for_each_arc(a
, hp
, mp
, MDESC_ARC_TYPE_BACK
) {
647 u64 t
= mdesc_arc_target(hp
, a
);
651 name
= mdesc_node_name(hp
, t
);
652 if (strcmp(name
, "cpu"))
655 id
= mdesc_get_property(hp
, t
, "id", NULL
);
657 cpu_data(*id
).proc_id
= proc_id
;
661 static void __devinit
__set_proc_ids(struct mdesc_handle
*hp
,
662 const char *exec_unit_name
)
668 mdesc_for_each_node_by_name(hp
, mp
, exec_unit_name
) {
672 type
= mdesc_get_property(hp
, mp
, "type", &len
);
673 if (!find_in_proplist(type
, "int", len
) &&
674 !find_in_proplist(type
, "integer", len
))
677 mark_proc_ids(hp
, mp
, idx
);
683 static void __devinit
set_proc_ids(struct mdesc_handle
*hp
)
685 __set_proc_ids(hp
, "exec_unit");
686 __set_proc_ids(hp
, "exec-unit");
689 static void __devinit
get_one_mondo_bits(const u64
*p
, unsigned int *mask
,
698 if (!val
|| val
>= 64)
701 *mask
= ((1U << val
) * 64U) - 1U;
705 *mask
= ((1U << def
) * 64U) - 1U;
708 static void __devinit
get_mondo_data(struct mdesc_handle
*hp
, u64 mp
,
709 struct trap_per_cpu
*tb
)
713 val
= mdesc_get_property(hp
, mp
, "q-cpu-mondo-#bits", NULL
);
714 get_one_mondo_bits(val
, &tb
->cpu_mondo_qmask
, 7);
716 val
= mdesc_get_property(hp
, mp
, "q-dev-mondo-#bits", NULL
);
717 get_one_mondo_bits(val
, &tb
->dev_mondo_qmask
, 7);
719 val
= mdesc_get_property(hp
, mp
, "q-resumable-#bits", NULL
);
720 get_one_mondo_bits(val
, &tb
->resum_qmask
, 6);
722 val
= mdesc_get_property(hp
, mp
, "q-nonresumable-#bits", NULL
);
723 get_one_mondo_bits(val
, &tb
->nonresum_qmask
, 2);
726 void __devinit
mdesc_fill_in_cpu_data(cpumask_t mask
)
728 struct mdesc_handle
*hp
= mdesc_grab();
732 mdesc_for_each_node_by_name(hp
, mp
, "cpu") {
733 const u64
*id
= mdesc_get_property(hp
, mp
, "id", NULL
);
734 const u64
*cfreq
= mdesc_get_property(hp
, mp
, "clock-frequency", NULL
);
735 struct trap_per_cpu
*tb
;
745 if (cpuid
>= NR_CPUS
)
747 if (!cpu_isset(cpuid
, mask
))
750 /* On uniprocessor we only want the values for the
751 * real physical cpu the kernel booted onto, however
752 * cpu_data() only has one entry at index 0.
754 if (cpuid
!= real_hard_smp_processor_id())
759 c
= &cpu_data(cpuid
);
760 c
->clock_tick
= *cfreq
;
762 tb
= &trap_block
[cpuid
];
763 get_mondo_data(hp
, mp
, tb
);
765 mdesc_for_each_arc(a
, hp
, mp
, MDESC_ARC_TYPE_FWD
) {
766 u64 j
, t
= mdesc_arc_target(hp
, a
);
769 t_name
= mdesc_node_name(hp
, t
);
770 if (!strcmp(t_name
, "cache")) {
771 fill_in_one_cache(c
, hp
, t
);
775 mdesc_for_each_arc(j
, hp
, t
, MDESC_ARC_TYPE_FWD
) {
776 u64 n
= mdesc_arc_target(hp
, j
);
779 n_name
= mdesc_node_name(hp
, n
);
780 if (!strcmp(n_name
, "cache"))
781 fill_in_one_cache(c
, hp
, n
);
786 cpu_set(cpuid
, cpu_present_map
);
794 sparc64_multi_core
= 1;
800 smp_fill_in_sib_core_maps();
805 void __init
sun4v_mdesc_init(void)
807 struct mdesc_handle
*hp
;
808 unsigned long len
, real_len
, status
;
811 (void) sun4v_mach_desc(0UL, 0UL, &len
);
813 printk("MDESC: Size is %lu bytes.\n", len
);
815 hp
= mdesc_alloc(len
, &bootmem_mdesc_memops
);
817 prom_printf("MDESC: alloc of %lu bytes failed.\n", len
);
821 status
= sun4v_mach_desc(__pa(&hp
->mdesc
), len
, &real_len
);
822 if (status
!= HV_EOK
|| real_len
> len
) {
823 prom_printf("sun4v_mach_desc fails, err(%lu), "
824 "len(%lu), real_len(%lu)\n",
825 status
, len
, real_len
);
832 report_platform_properties();
835 mdesc_fill_in_cpu_data(mask
);