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>
10 #include <asm/hypervisor.h>
11 #include <asm/mdesc.h>
13 #include <asm/oplib.h>
16 /* Unlike the OBP device tree, the machine description is a full-on
17 * DAG. An arbitrary number of ARCs are possible from one
18 * node to other nodes and thus we can't use the OBP device_node
19 * data structure to represent these nodes inside of the kernel.
21 * Actually, it isn't even a DAG, because there are back pointers
22 * which create cycles in the graph.
24 * mdesc_hdr and mdesc_elem describe the layout of the data structure
25 * we get from the Hypervisor.
28 u32 version
; /* Transport version */
29 u32 node_sz
; /* node block size */
30 u32 name_sz
; /* name block size */
31 u32 data_sz
; /* data block size */
36 #define MD_LIST_END 0x00
38 #define MD_NODE_END 0x45
40 #define MD_PROP_ARC 0x61
41 #define MD_PROP_VAL 0x76
42 #define MD_PROP_STR 0x73
43 #define MD_PROP_DATA 0x64
56 static struct mdesc_hdr
*main_mdesc
;
57 static struct mdesc_node
*allnodes
;
59 static struct mdesc_node
*allnodes_tail
;
60 static unsigned int unique_id
;
62 static struct mdesc_node
**mdesc_hash
;
63 static unsigned int mdesc_hash_size
;
65 static inline unsigned int node_hashfn(u64 node
)
67 return ((unsigned int) (node
^ (node
>> 8) ^ (node
>> 16)))
68 & (mdesc_hash_size
- 1);
71 static inline void hash_node(struct mdesc_node
*mp
)
73 struct mdesc_node
**head
= &mdesc_hash
[node_hashfn(mp
->node
)];
75 mp
->hash_next
= *head
;
79 allnodes_tail
->allnodes_next
= mp
;
82 allnodes
= allnodes_tail
= mp
;
86 static struct mdesc_node
*find_node(u64 node
)
88 struct mdesc_node
*mp
= mdesc_hash
[node_hashfn(node
)];
99 struct property
*md_find_property(const struct mdesc_node
*mp
,
105 for (pp
= mp
->properties
; pp
!= 0; pp
= pp
->next
) {
106 if (strcasecmp(pp
->name
, name
) == 0) {
114 EXPORT_SYMBOL(md_find_property
);
117 * Find a property with a given name for a given node
118 * and return the value.
120 const void *md_get_property(const struct mdesc_node
*mp
, const char *name
,
123 struct property
*pp
= md_find_property(mp
, name
, lenp
);
124 return pp
? pp
->value
: NULL
;
126 EXPORT_SYMBOL(md_get_property
);
128 struct mdesc_node
*md_find_node_by_name(struct mdesc_node
*from
,
131 struct mdesc_node
*mp
;
133 mp
= from
? from
->allnodes_next
: allnodes
;
134 for (; mp
!= NULL
; mp
= mp
->allnodes_next
) {
135 if (strcmp(mp
->name
, name
) == 0)
140 EXPORT_SYMBOL(md_find_node_by_name
);
142 static unsigned int mdesc_early_allocated
;
144 static void * __init
mdesc_early_alloc(unsigned long size
)
148 ret
= __alloc_bootmem(size
, SMP_CACHE_BYTES
, 0UL);
150 prom_printf("MDESC: alloc of %lu bytes failed.\n", size
);
154 memset(ret
, 0, size
);
156 mdesc_early_allocated
+= size
;
161 static unsigned int __init
count_arcs(struct mdesc_elem
*ep
)
163 unsigned int ret
= 0;
166 while (ep
->tag
!= MD_NODE_END
) {
167 if (ep
->tag
== MD_PROP_ARC
)
174 static void __init
mdesc_node_alloc(u64 node
, struct mdesc_elem
*ep
, const char *names
)
176 unsigned int num_arcs
= count_arcs(ep
);
177 struct mdesc_node
*mp
;
179 mp
= mdesc_early_alloc(sizeof(*mp
) +
180 (num_arcs
* sizeof(struct mdesc_arc
)));
181 mp
->name
= names
+ ep
->name_offset
;
183 mp
->unique_id
= unique_id
++;
184 mp
->num_arcs
= num_arcs
;
189 static inline struct mdesc_elem
*node_block(struct mdesc_hdr
*mdesc
)
191 return (struct mdesc_elem
*) (mdesc
+ 1);
194 static inline void *name_block(struct mdesc_hdr
*mdesc
)
196 return ((void *) node_block(mdesc
)) + mdesc
->node_sz
;
199 static inline void *data_block(struct mdesc_hdr
*mdesc
)
201 return ((void *) name_block(mdesc
)) + mdesc
->name_sz
;
204 /* In order to avoid recursion (the graph can be very deep) we use a
205 * two pass algorithm. First we allocate all the nodes and hash them.
206 * Then we iterate over each node, filling in the arcs and properties.
208 static void __init
build_all_nodes(struct mdesc_hdr
*mdesc
)
210 struct mdesc_elem
*start
, *ep
;
211 struct mdesc_node
*mp
;
216 start
= ep
= node_block(mdesc
);
217 last_node
= mdesc
->node_sz
/ 16;
219 names
= name_block(mdesc
);
222 u64 node
= ep
- start
;
224 if (ep
->tag
== MD_LIST_END
)
227 if (ep
->tag
!= MD_NODE
) {
228 prom_printf("MDESC: Inconsistent element list.\n");
232 mdesc_node_alloc(node
, ep
, names
);
234 if (ep
->d
.val
>= last_node
) {
235 printk("MDESC: Warning, early break out of node scan.\n");
236 printk("MDESC: Next node [%lu] last_node [%lu].\n",
241 ep
= start
+ ep
->d
.val
;
244 data
= data_block(mdesc
);
245 for (mp
= allnodes
; mp
; mp
= mp
->allnodes_next
) {
246 struct mdesc_elem
*ep
= start
+ mp
->node
;
247 struct property
**link
= &mp
->properties
;
248 unsigned int this_arc
= 0;
251 while (ep
->tag
!= MD_NODE_END
) {
254 struct mdesc_node
*target
;
256 if (this_arc
>= mp
->num_arcs
) {
257 prom_printf("MDESC: ARC overrun [%u:%u]\n",
258 this_arc
, mp
->num_arcs
);
261 target
= find_node(ep
->d
.val
);
263 printk("MDESC: Warning, arc points to "
264 "missing node, ignoring.\n");
267 mp
->arcs
[this_arc
].name
=
268 (names
+ ep
->name_offset
);
269 mp
->arcs
[this_arc
].arc
= target
;
277 struct property
*p
= mdesc_early_alloc(sizeof(*p
));
279 p
->unique_id
= unique_id
++;
280 p
->name
= (char *) names
+ ep
->name_offset
;
281 if (ep
->tag
== MD_PROP_VAL
) {
282 p
->value
= &ep
->d
.val
;
285 p
->value
= data
+ ep
->d
.data
.data_offset
;
286 p
->length
= ep
->d
.data
.data_len
;
297 printk("MDESC: Warning, ignoring unknown tag type %02x\n",
305 static unsigned int __init
count_nodes(struct mdesc_hdr
*mdesc
)
307 struct mdesc_elem
*ep
= node_block(mdesc
);
308 struct mdesc_elem
*end
;
309 unsigned int cnt
= 0;
311 end
= ((void *)ep
) + mdesc
->node_sz
;
313 if (ep
->tag
== MD_NODE
)
320 static void __init
report_platform_properties(void)
322 struct mdesc_node
*pn
= md_find_node_by_name(NULL
, "platform");
327 prom_printf("No platform node in machine-description.\n");
331 s
= md_get_property(pn
, "banner-name", NULL
);
332 printk("PLATFORM: banner-name [%s]\n", s
);
333 s
= md_get_property(pn
, "name", NULL
);
334 printk("PLATFORM: name [%s]\n", s
);
336 v
= md_get_property(pn
, "hostid", NULL
);
338 printk("PLATFORM: hostid [%08lx]\n", *v
);
339 v
= md_get_property(pn
, "serial#", NULL
);
341 printk("PLATFORM: serial# [%08lx]\n", *v
);
342 v
= md_get_property(pn
, "stick-frequency", NULL
);
343 printk("PLATFORM: stick-frequency [%08lx]\n", *v
);
344 v
= md_get_property(pn
, "mac-address", NULL
);
346 printk("PLATFORM: mac-address [%lx]\n", *v
);
347 v
= md_get_property(pn
, "watchdog-resolution", NULL
);
349 printk("PLATFORM: watchdog-resolution [%lu ms]\n", *v
);
350 v
= md_get_property(pn
, "watchdog-max-timeout", NULL
);
352 printk("PLATFORM: watchdog-max-timeout [%lu ms]\n", *v
);
353 v
= md_get_property(pn
, "max-cpus", NULL
);
355 printk("PLATFORM: max-cpus [%lu]\n", *v
);
358 static int inline find_in_proplist(const char *list
, const char *match
, int len
)
363 if (!strcmp(list
, match
))
365 l
= strlen(list
) + 1;
372 static void __init
fill_in_one_cache(cpuinfo_sparc
*c
, struct mdesc_node
*mp
)
374 const u64
*level
= md_get_property(mp
, "level", NULL
);
375 const u64
*size
= md_get_property(mp
, "size", NULL
);
376 const u64
*line_size
= md_get_property(mp
, "line-size", NULL
);
380 type
= md_get_property(mp
, "type", &type_len
);
384 if (find_in_proplist(type
, "instn", type_len
)) {
385 c
->icache_size
= *size
;
386 c
->icache_line_size
= *line_size
;
387 } else if (find_in_proplist(type
, "data", type_len
)) {
388 c
->dcache_size
= *size
;
389 c
->dcache_line_size
= *line_size
;
394 c
->ecache_size
= *size
;
395 c
->ecache_line_size
= *line_size
;
405 for (i
= 0; i
< mp
->num_arcs
; i
++) {
406 struct mdesc_node
*t
= mp
->arcs
[i
].arc
;
408 if (strcmp(mp
->arcs
[i
].name
, "fwd"))
411 if (!strcmp(t
->name
, "cache"))
412 fill_in_one_cache(c
, t
);
417 static void __init
mark_core_ids(struct mdesc_node
*mp
, int core_id
)
421 for (i
= 0; i
< mp
->num_arcs
; i
++) {
422 struct mdesc_node
*t
= mp
->arcs
[i
].arc
;
425 if (strcmp(mp
->arcs
[i
].name
, "back"))
428 if (!strcmp(t
->name
, "cpu")) {
429 id
= md_get_property(t
, "id", NULL
);
431 cpu_data(*id
).core_id
= core_id
;
435 for (j
= 0; j
< t
->num_arcs
; j
++) {
436 struct mdesc_node
*n
= t
->arcs
[j
].arc
;
438 if (strcmp(t
->arcs
[j
].name
, "back"))
441 if (strcmp(n
->name
, "cpu"))
444 id
= md_get_property(n
, "id", NULL
);
446 cpu_data(*id
).core_id
= core_id
;
452 static void __init
set_core_ids(void)
454 struct mdesc_node
*mp
;
458 md_for_each_node_by_name(mp
, "cache") {
459 const u64
*level
= md_get_property(mp
, "level", NULL
);
466 type
= md_get_property(mp
, "type", &len
);
467 if (!find_in_proplist(type
, "instn", len
))
470 mark_core_ids(mp
, idx
);
476 static void __init
mark_proc_ids(struct mdesc_node
*mp
, int proc_id
)
480 for (i
= 0; i
< mp
->num_arcs
; i
++) {
481 struct mdesc_node
*t
= mp
->arcs
[i
].arc
;
484 if (strcmp(mp
->arcs
[i
].name
, "back"))
487 if (strcmp(t
->name
, "cpu"))
490 id
= md_get_property(t
, "id", NULL
);
492 cpu_data(*id
).proc_id
= proc_id
;
496 static void __init
__set_proc_ids(const char *exec_unit_name
)
498 struct mdesc_node
*mp
;
502 md_for_each_node_by_name(mp
, exec_unit_name
) {
506 type
= md_get_property(mp
, "type", &len
);
507 if (!find_in_proplist(type
, "int", len
) &&
508 !find_in_proplist(type
, "integer", len
))
511 mark_proc_ids(mp
, idx
);
517 static void __init
set_proc_ids(void)
519 __set_proc_ids("exec_unit");
520 __set_proc_ids("exec-unit");
523 static void __init
get_one_mondo_bits(const u64
*p
, unsigned int *mask
, unsigned char def
)
531 if (!val
|| val
>= 64)
534 *mask
= ((1U << val
) * 64U) - 1U;
538 *mask
= ((1U << def
) * 64U) - 1U;
541 static void __init
get_mondo_data(struct mdesc_node
*mp
, struct trap_per_cpu
*tb
)
545 val
= md_get_property(mp
, "q-cpu-mondo-#bits", NULL
);
546 get_one_mondo_bits(val
, &tb
->cpu_mondo_qmask
, 7);
548 val
= md_get_property(mp
, "q-dev-mondo-#bits", NULL
);
549 get_one_mondo_bits(val
, &tb
->dev_mondo_qmask
, 7);
551 val
= md_get_property(mp
, "q-resumable-#bits", NULL
);
552 get_one_mondo_bits(val
, &tb
->resum_qmask
, 6);
554 val
= md_get_property(mp
, "q-nonresumable-#bits", NULL
);
555 get_one_mondo_bits(val
, &tb
->nonresum_qmask
, 2);
558 static void __init
mdesc_fill_in_cpu_data(void)
560 struct mdesc_node
*mp
;
563 md_for_each_node_by_name(mp
, "cpu") {
564 const u64
*id
= md_get_property(mp
, "id", NULL
);
565 const u64
*cfreq
= md_get_property(mp
, "clock-frequency", NULL
);
566 struct trap_per_cpu
*tb
;
576 if (cpuid
>= NR_CPUS
)
579 /* On uniprocessor we only want the values for the
580 * real physical cpu the kernel booted onto, however
581 * cpu_data() only has one entry at index 0.
583 if (cpuid
!= real_hard_smp_processor_id())
588 c
= &cpu_data(cpuid
);
589 c
->clock_tick
= *cfreq
;
591 tb
= &trap_block
[cpuid
];
592 get_mondo_data(mp
, tb
);
594 for (i
= 0; i
< mp
->num_arcs
; i
++) {
595 struct mdesc_node
*t
= mp
->arcs
[i
].arc
;
598 if (strcmp(mp
->arcs
[i
].name
, "fwd"))
601 if (!strcmp(t
->name
, "cache")) {
602 fill_in_one_cache(c
, t
);
606 for (j
= 0; j
< t
->num_arcs
; j
++) {
607 struct mdesc_node
*n
;
610 if (strcmp(t
->arcs
[j
].name
, "fwd"))
613 if (!strcmp(n
->name
, "cache"))
614 fill_in_one_cache(c
, n
);
619 cpu_set(cpuid
, cpu_present_map
);
620 cpu_set(cpuid
, phys_cpu_present_map
);
628 sparc64_multi_core
= 1;
634 smp_fill_in_sib_core_maps();
637 void __init
sun4v_mdesc_init(void)
639 unsigned long len
, real_len
, status
;
641 (void) sun4v_mach_desc(0UL, 0UL, &len
);
643 printk("MDESC: Size is %lu bytes.\n", len
);
645 main_mdesc
= mdesc_early_alloc(len
);
647 status
= sun4v_mach_desc(__pa(main_mdesc
), len
, &real_len
);
648 if (status
!= HV_EOK
|| real_len
> len
) {
649 prom_printf("sun4v_mach_desc fails, err(%lu), "
650 "len(%lu), real_len(%lu)\n",
651 status
, len
, real_len
);
655 len
= count_nodes(main_mdesc
);
656 printk("MDESC: %lu nodes.\n", len
);
658 len
= roundup_pow_of_two(len
);
660 mdesc_hash
= mdesc_early_alloc(len
* sizeof(struct mdesc_node
*));
661 mdesc_hash_size
= len
;
663 printk("MDESC: Hash size %lu entries.\n", len
);
665 build_all_nodes(main_mdesc
);
667 printk("MDESC: Built graph with %u bytes of memory.\n",
668 mdesc_early_allocated
);
670 report_platform_properties();
671 mdesc_fill_in_cpu_data();