aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/mdesc.c
diff options
context:
space:
mode:
authorSam Ravnborg <sam@ravnborg.org>2008-12-03 06:11:52 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-04 12:17:21 -0500
commita88b5ba8bd8ac18aad65ee6c6a254e2e74876db3 (patch)
treeeb3d0ffaf53c3f7ec6083752c2097cecd1cb892a /arch/sparc64/kernel/mdesc.c
parentd670bd4f803c8b646acd20f3ba21e65458293faf (diff)
sparc,sparc64: unify kernel/
o Move all files from sparc64/kernel/ to sparc/kernel - rename as appropriate o Update sparc/Makefile to the changes o Update sparc/kernel/Makefile to include the sparc64 files NOTE: This commit changes link order on sparc64! Link order had to change for either of sparc32 and sparc64. And assuming sparc64 see more testing than sparc32 change link order on sparc64 where issues will be caught faster. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/mdesc.c')
-rw-r--r--arch/sparc64/kernel/mdesc.c916
1 files changed, 0 insertions, 916 deletions
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
deleted file mode 100644
index dde52bcf5c6..00000000000
--- a/arch/sparc64/kernel/mdesc.c
+++ /dev/null
@@ -1,916 +0,0 @@
1/* mdesc.c: Sun4V machine description handling.
2 *
3 * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
4 */
5#include <linux/kernel.h>
6#include <linux/types.h>
7#include <linux/lmb.h>
8#include <linux/log2.h>
9#include <linux/list.h>
10#include <linux/slab.h>
11#include <linux/mm.h>
12#include <linux/miscdevice.h>
13
14#include <asm/hypervisor.h>
15#include <asm/mdesc.h>
16#include <asm/prom.h>
17#include <asm/oplib.h>
18#include <asm/smp.h>
19
20/* Unlike the OBP device tree, the machine description is a full-on
21 * DAG. An arbitrary number of ARCs are possible from one
22 * node to other nodes and thus we can't use the OBP device_node
23 * data structure to represent these nodes inside of the kernel.
24 *
25 * Actually, it isn't even a DAG, because there are back pointers
26 * which create cycles in the graph.
27 *
28 * mdesc_hdr and mdesc_elem describe the layout of the data structure
29 * we get from the Hypervisor.
30 */
31struct mdesc_hdr {
32 u32 version; /* Transport version */
33 u32 node_sz; /* node block size */
34 u32 name_sz; /* name block size */
35 u32 data_sz; /* data block size */
36} __attribute__((aligned(16)));
37
38struct mdesc_elem {
39 u8 tag;
40#define MD_LIST_END 0x00
41#define MD_NODE 0x4e
42#define MD_NODE_END 0x45
43#define MD_NOOP 0x20
44#define MD_PROP_ARC 0x61
45#define MD_PROP_VAL 0x76
46#define MD_PROP_STR 0x73
47#define MD_PROP_DATA 0x64
48 u8 name_len;
49 u16 resv;
50 u32 name_offset;
51 union {
52 struct {
53 u32 data_len;
54 u32 data_offset;
55 } data;
56 u64 val;
57 } d;
58};
59
60struct mdesc_mem_ops {
61 struct mdesc_handle *(*alloc)(unsigned int mdesc_size);
62 void (*free)(struct mdesc_handle *handle);
63};
64
65struct mdesc_handle {
66 struct list_head list;
67 struct mdesc_mem_ops *mops;
68 void *self_base;
69 atomic_t refcnt;
70 unsigned int handle_size;
71 struct mdesc_hdr mdesc;
72};
73
74static void mdesc_handle_init(struct mdesc_handle *hp,
75 unsigned int handle_size,
76 void *base)
77{
78 BUG_ON(((unsigned long)&hp->mdesc) & (16UL - 1));
79
80 memset(hp, 0, handle_size);
81 INIT_LIST_HEAD(&hp->list);
82 hp->self_base = base;
83 atomic_set(&hp->refcnt, 1);
84 hp->handle_size = handle_size;
85}
86
87static struct mdesc_handle * __init mdesc_lmb_alloc(unsigned int mdesc_size)
88{
89 unsigned int handle_size, alloc_size;
90 struct mdesc_handle *hp;
91 unsigned long paddr;
92
93 handle_size = (sizeof(struct mdesc_handle) -
94 sizeof(struct mdesc_hdr) +
95 mdesc_size);
96 alloc_size = PAGE_ALIGN(handle_size);
97
98 paddr = lmb_alloc(alloc_size, PAGE_SIZE);
99
100 hp = NULL;
101 if (paddr) {
102 hp = __va(paddr);
103 mdesc_handle_init(hp, handle_size, hp);
104 }
105 return hp;
106}
107
108static void mdesc_lmb_free(struct mdesc_handle *hp)
109{
110 unsigned int alloc_size, handle_size = hp->handle_size;
111 unsigned long start, end;
112
113 BUG_ON(atomic_read(&hp->refcnt) != 0);
114 BUG_ON(!list_empty(&hp->list));
115
116 alloc_size = PAGE_ALIGN(handle_size);
117
118 start = (unsigned long) hp;
119 end = start + alloc_size;
120
121 while (start < end) {
122 struct page *p;
123
124 p = virt_to_page(start);
125 ClearPageReserved(p);
126 __free_page(p);
127 start += PAGE_SIZE;
128 }
129}
130
131static struct mdesc_mem_ops lmb_mdesc_ops = {
132 .alloc = mdesc_lmb_alloc,
133 .free = mdesc_lmb_free,
134};
135
136static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
137{
138 unsigned int handle_size;
139 void *base;
140
141 handle_size = (sizeof(struct mdesc_handle) -
142 sizeof(struct mdesc_hdr) +
143 mdesc_size);
144
145 base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
146 if (base) {
147 struct mdesc_handle *hp;
148 unsigned long addr;
149
150 addr = (unsigned long)base;
151 addr = (addr + 15UL) & ~15UL;
152 hp = (struct mdesc_handle *) addr;
153
154 mdesc_handle_init(hp, handle_size, base);
155 return hp;
156 }
157
158 return NULL;
159}
160
161static void mdesc_kfree(struct mdesc_handle *hp)
162{
163 BUG_ON(atomic_read(&hp->refcnt) != 0);
164 BUG_ON(!list_empty(&hp->list));
165
166 kfree(hp->self_base);
167}
168
169static struct mdesc_mem_ops kmalloc_mdesc_memops = {
170 .alloc = mdesc_kmalloc,
171 .free = mdesc_kfree,
172};
173
174static struct mdesc_handle *mdesc_alloc(unsigned int mdesc_size,
175 struct mdesc_mem_ops *mops)
176{
177 struct mdesc_handle *hp = mops->alloc(mdesc_size);
178
179 if (hp)
180 hp->mops = mops;
181
182 return hp;
183}
184
185static void mdesc_free(struct mdesc_handle *hp)
186{
187 hp->mops->free(hp);
188}
189
190static struct mdesc_handle *cur_mdesc;
191static LIST_HEAD(mdesc_zombie_list);
192static DEFINE_SPINLOCK(mdesc_lock);
193
194struct mdesc_handle *mdesc_grab(void)
195{
196 struct mdesc_handle *hp;
197 unsigned long flags;
198
199 spin_lock_irqsave(&mdesc_lock, flags);
200 hp = cur_mdesc;
201 if (hp)
202 atomic_inc(&hp->refcnt);
203 spin_unlock_irqrestore(&mdesc_lock, flags);
204
205 return hp;
206}
207EXPORT_SYMBOL(mdesc_grab);
208
209void mdesc_release(struct mdesc_handle *hp)
210{
211 unsigned long flags;
212
213 spin_lock_irqsave(&mdesc_lock, flags);
214 if (atomic_dec_and_test(&hp->refcnt)) {
215 list_del_init(&hp->list);
216 hp->mops->free(hp);
217 }
218 spin_unlock_irqrestore(&mdesc_lock, flags);
219}
220EXPORT_SYMBOL(mdesc_release);
221
222static DEFINE_MUTEX(mdesc_mutex);
223static struct mdesc_notifier_client *client_list;
224
225void mdesc_register_notifier(struct mdesc_notifier_client *client)
226{
227 u64 node;
228
229 mutex_lock(&mdesc_mutex);
230 client->next = client_list;
231 client_list = client;
232
233 mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name)
234 client->add(cur_mdesc, node);
235
236 mutex_unlock(&mdesc_mutex);
237}
238
239static const u64 *parent_cfg_handle(struct mdesc_handle *hp, u64 node)
240{
241 const u64 *id;
242 u64 a;
243
244 id = NULL;
245 mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
246 u64 target;
247
248 target = mdesc_arc_target(hp, a);
249 id = mdesc_get_property(hp, target,
250 "cfg-handle", NULL);
251 if (id)
252 break;
253 }
254
255 return id;
256}
257
258/* Run 'func' on nodes which are in A but not in B. */
259static void invoke_on_missing(const char *name,
260 struct mdesc_handle *a,
261 struct mdesc_handle *b,
262 void (*func)(struct mdesc_handle *, u64))
263{
264 u64 node;
265
266 mdesc_for_each_node_by_name(a, node, name) {
267 int found = 0, is_vdc_port = 0;
268 const char *name_prop;
269 const u64 *id;
270 u64 fnode;
271
272 name_prop = mdesc_get_property(a, node, "name", NULL);
273 if (name_prop && !strcmp(name_prop, "vdc-port")) {
274 is_vdc_port = 1;
275 id = parent_cfg_handle(a, node);
276 } else
277 id = mdesc_get_property(a, node, "id", NULL);
278
279 if (!id) {
280 printk(KERN_ERR "MD: Cannot find ID for %s node.\n",
281 (name_prop ? name_prop : name));
282 continue;
283 }
284
285 mdesc_for_each_node_by_name(b, fnode, name) {
286 const u64 *fid;
287
288 if (is_vdc_port) {
289 name_prop = mdesc_get_property(b, fnode,
290 "name", NULL);
291 if (!name_prop ||
292 strcmp(name_prop, "vdc-port"))
293 continue;
294 fid = parent_cfg_handle(b, fnode);
295 if (!fid) {
296 printk(KERN_ERR "MD: Cannot find ID "
297 "for vdc-port node.\n");
298 continue;
299 }
300 } else
301 fid = mdesc_get_property(b, fnode,
302 "id", NULL);
303
304 if (*id == *fid) {
305 found = 1;
306 break;
307 }
308 }
309 if (!found)
310 func(a, node);
311 }
312}
313
314static void notify_one(struct mdesc_notifier_client *p,
315 struct mdesc_handle *old_hp,
316 struct mdesc_handle *new_hp)
317{
318 invoke_on_missing(p->node_name, old_hp, new_hp, p->remove);
319 invoke_on_missing(p->node_name, new_hp, old_hp, p->add);
320}
321
322static void mdesc_notify_clients(struct mdesc_handle *old_hp,
323 struct mdesc_handle *new_hp)
324{
325 struct mdesc_notifier_client *p = client_list;
326
327 while (p) {
328 notify_one(p, old_hp, new_hp);
329 p = p->next;
330 }
331}
332
333void mdesc_update(void)
334{
335 unsigned long len, real_len, status;
336 struct mdesc_handle *hp, *orig_hp;
337 unsigned long flags;
338
339 mutex_lock(&mdesc_mutex);
340
341 (void) sun4v_mach_desc(0UL, 0UL, &len);
342
343 hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
344 if (!hp) {
345 printk(KERN_ERR "MD: mdesc alloc fails\n");
346 goto out;
347 }
348
349 status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
350 if (status != HV_EOK || real_len > len) {
351 printk(KERN_ERR "MD: mdesc reread fails with %lu\n",
352 status);
353 atomic_dec(&hp->refcnt);
354 mdesc_free(hp);
355 goto out;
356 }
357
358 spin_lock_irqsave(&mdesc_lock, flags);
359 orig_hp = cur_mdesc;
360 cur_mdesc = hp;
361 spin_unlock_irqrestore(&mdesc_lock, flags);
362
363 mdesc_notify_clients(orig_hp, hp);
364
365 spin_lock_irqsave(&mdesc_lock, flags);
366 if (atomic_dec_and_test(&orig_hp->refcnt))
367 mdesc_free(orig_hp);
368 else
369 list_add(&orig_hp->list, &mdesc_zombie_list);
370 spin_unlock_irqrestore(&mdesc_lock, flags);
371
372out:
373 mutex_unlock(&mdesc_mutex);
374}
375
376static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
377{
378 return (struct mdesc_elem *) (mdesc + 1);
379}
380
381static void *name_block(struct mdesc_hdr *mdesc)
382{
383 return ((void *) node_block(mdesc)) + mdesc->node_sz;
384}
385
386static void *data_block(struct mdesc_hdr *mdesc)
387{
388 return ((void *) name_block(mdesc)) + mdesc->name_sz;
389}
390
391u64 mdesc_node_by_name(struct mdesc_handle *hp,
392 u64 from_node, const char *name)
393{
394 struct mdesc_elem *ep = node_block(&hp->mdesc);
395 const char *names = name_block(&hp->mdesc);
396 u64 last_node = hp->mdesc.node_sz / 16;
397 u64 ret;
398
399 if (from_node == MDESC_NODE_NULL) {
400 ret = from_node = 0;
401 } else if (from_node >= last_node) {
402 return MDESC_NODE_NULL;
403 } else {
404 ret = ep[from_node].d.val;
405 }
406
407 while (ret < last_node) {
408 if (ep[ret].tag != MD_NODE)
409 return MDESC_NODE_NULL;
410 if (!strcmp(names + ep[ret].name_offset, name))
411 break;
412 ret = ep[ret].d.val;
413 }
414 if (ret >= last_node)
415 ret = MDESC_NODE_NULL;
416 return ret;
417}
418EXPORT_SYMBOL(mdesc_node_by_name);
419
420const void *mdesc_get_property(struct mdesc_handle *hp, u64 node,
421 const char *name, int *lenp)
422{
423 const char *names = name_block(&hp->mdesc);
424 u64 last_node = hp->mdesc.node_sz / 16;
425 void *data = data_block(&hp->mdesc);
426 struct mdesc_elem *ep;
427
428 if (node == MDESC_NODE_NULL || node >= last_node)
429 return NULL;
430
431 ep = node_block(&hp->mdesc) + node;
432 ep++;
433 for (; ep->tag != MD_NODE_END; ep++) {
434 void *val = NULL;
435 int len = 0;
436
437 switch (ep->tag) {
438 case MD_PROP_VAL:
439 val = &ep->d.val;
440 len = 8;
441 break;
442
443 case MD_PROP_STR:
444 case MD_PROP_DATA:
445 val = data + ep->d.data.data_offset;
446 len = ep->d.data.data_len;
447 break;
448
449 default:
450 break;
451 }
452 if (!val)
453 continue;
454
455 if (!strcmp(names + ep->name_offset, name)) {
456 if (lenp)
457 *lenp = len;
458 return val;
459 }
460 }
461
462 return NULL;
463}
464EXPORT_SYMBOL(mdesc_get_property);
465
466u64 mdesc_next_arc(struct mdesc_handle *hp, u64 from, const char *arc_type)
467{
468 struct mdesc_elem *ep, *base = node_block(&hp->mdesc);
469 const char *names = name_block(&hp->mdesc);
470 u64 last_node = hp->mdesc.node_sz / 16;
471
472 if (from == MDESC_NODE_NULL || from >= last_node)
473 return MDESC_NODE_NULL;
474
475 ep = base + from;
476
477 ep++;
478 for (; ep->tag != MD_NODE_END; ep++) {
479 if (ep->tag != MD_PROP_ARC)
480 continue;
481
482 if (strcmp(names + ep->name_offset, arc_type))
483 continue;
484
485 return ep - base;
486 }
487
488 return MDESC_NODE_NULL;
489}
490EXPORT_SYMBOL(mdesc_next_arc);
491
492u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc)
493{
494 struct mdesc_elem *ep, *base = node_block(&hp->mdesc);
495
496 ep = base + arc;
497
498 return ep->d.val;
499}
500EXPORT_SYMBOL(mdesc_arc_target);
501
502const char *mdesc_node_name(struct mdesc_handle *hp, u64 node)
503{
504 struct mdesc_elem *ep, *base = node_block(&hp->mdesc);
505 const char *names = name_block(&hp->mdesc);
506 u64 last_node = hp->mdesc.node_sz / 16;
507
508 if (node == MDESC_NODE_NULL || node >= last_node)
509 return NULL;
510
511 ep = base + node;
512 if (ep->tag != MD_NODE)
513 return NULL;
514
515 return names + ep->name_offset;
516}
517EXPORT_SYMBOL(mdesc_node_name);
518
519static void __init report_platform_properties(void)
520{
521 struct mdesc_handle *hp = mdesc_grab();
522 u64 pn = mdesc_node_by_name(hp, MDESC_NODE_NULL, "platform");
523 const char *s;
524 const u64 *v;
525
526 if (pn == MDESC_NODE_NULL) {
527 prom_printf("No platform node in machine-description.\n");
528 prom_halt();
529 }
530
531 s = mdesc_get_property(hp, pn, "banner-name", NULL);
532 printk("PLATFORM: banner-name [%s]\n", s);
533 s = mdesc_get_property(hp, pn, "name", NULL);
534 printk("PLATFORM: name [%s]\n", s);
535
536 v = mdesc_get_property(hp, pn, "hostid", NULL);
537 if (v)
538 printk("PLATFORM: hostid [%08lx]\n", *v);
539 v = mdesc_get_property(hp, pn, "serial#", NULL);
540 if (v)
541 printk("PLATFORM: serial# [%08lx]\n", *v);
542 v = mdesc_get_property(hp, pn, "stick-frequency", NULL);
543 printk("PLATFORM: stick-frequency [%08lx]\n", *v);
544 v = mdesc_get_property(hp, pn, "mac-address", NULL);
545 if (v)
546 printk("PLATFORM: mac-address [%lx]\n", *v);
547 v = mdesc_get_property(hp, pn, "watchdog-resolution", NULL);
548 if (v)
549 printk("PLATFORM: watchdog-resolution [%lu ms]\n", *v);
550 v = mdesc_get_property(hp, pn, "watchdog-max-timeout", NULL);
551 if (v)
552 printk("PLATFORM: watchdog-max-timeout [%lu ms]\n", *v);
553 v = mdesc_get_property(hp, pn, "max-cpus", NULL);
554 if (v)
555 printk("PLATFORM: max-cpus [%lu]\n", *v);
556
557#ifdef CONFIG_SMP
558 {
559 int max_cpu, i;
560
561 if (v) {
562 max_cpu = *v;
563 if (max_cpu > NR_CPUS)
564 max_cpu = NR_CPUS;
565 } else {
566 max_cpu = NR_CPUS;
567 }
568 for (i = 0; i < max_cpu; i++)
569 cpu_set(i, cpu_possible_map);
570 }
571#endif
572
573 mdesc_release(hp);
574}
575
576static void __devinit fill_in_one_cache(cpuinfo_sparc *c,
577 struct mdesc_handle *hp,
578 u64 mp)
579{
580 const u64 *level = mdesc_get_property(hp, mp, "level", NULL);
581 const u64 *size = mdesc_get_property(hp, mp, "size", NULL);
582 const u64 *line_size = mdesc_get_property(hp, mp, "line-size", NULL);
583 const char *type;
584 int type_len;
585
586 type = mdesc_get_property(hp, mp, "type", &type_len);
587
588 switch (*level) {
589 case 1:
590 if (of_find_in_proplist(type, "instn", type_len)) {
591 c->icache_size = *size;
592 c->icache_line_size = *line_size;
593 } else if (of_find_in_proplist(type, "data", type_len)) {
594 c->dcache_size = *size;
595 c->dcache_line_size = *line_size;
596 }
597 break;
598
599 case 2:
600 c->ecache_size = *size;
601 c->ecache_line_size = *line_size;
602 break;
603
604 default:
605 break;
606 }
607
608 if (*level == 1) {
609 u64 a;
610
611 mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
612 u64 target = mdesc_arc_target(hp, a);
613 const char *name = mdesc_node_name(hp, target);
614
615 if (!strcmp(name, "cache"))
616 fill_in_one_cache(c, hp, target);
617 }
618 }
619}
620
621static void __devinit mark_core_ids(struct mdesc_handle *hp, u64 mp,
622 int core_id)
623{
624 u64 a;
625
626 mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
627 u64 t = mdesc_arc_target(hp, a);
628 const char *name;
629 const u64 *id;
630
631 name = mdesc_node_name(hp, t);
632 if (!strcmp(name, "cpu")) {
633 id = mdesc_get_property(hp, t, "id", NULL);
634 if (*id < NR_CPUS)
635 cpu_data(*id).core_id = core_id;
636 } else {
637 u64 j;
638
639 mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_BACK) {
640 u64 n = mdesc_arc_target(hp, j);
641 const char *n_name;
642
643 n_name = mdesc_node_name(hp, n);
644 if (strcmp(n_name, "cpu"))
645 continue;
646
647 id = mdesc_get_property(hp, n, "id", NULL);
648 if (*id < NR_CPUS)
649 cpu_data(*id).core_id = core_id;
650 }
651 }
652 }
653}
654
655static void __devinit set_core_ids(struct mdesc_handle *hp)
656{
657 int idx;
658 u64 mp;
659
660 idx = 1;
661 mdesc_for_each_node_by_name(hp, mp, "cache") {
662 const u64 *level;
663 const char *type;
664 int len;
665
666 level = mdesc_get_property(hp, mp, "level", NULL);
667 if (*level != 1)
668 continue;
669
670 type = mdesc_get_property(hp, mp, "type", &len);
671 if (!of_find_in_proplist(type, "instn", len))
672 continue;
673
674 mark_core_ids(hp, mp, idx);
675
676 idx++;
677 }
678}
679
680static void __devinit mark_proc_ids(struct mdesc_handle *hp, u64 mp,
681 int proc_id)
682{
683 u64 a;
684
685 mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
686 u64 t = mdesc_arc_target(hp, a);
687 const char *name;
688 const u64 *id;
689
690 name = mdesc_node_name(hp, t);
691 if (strcmp(name, "cpu"))
692 continue;
693
694 id = mdesc_get_property(hp, t, "id", NULL);
695 if (*id < NR_CPUS)
696 cpu_data(*id).proc_id = proc_id;
697 }
698}
699
700static void __devinit __set_proc_ids(struct mdesc_handle *hp,
701 const char *exec_unit_name)
702{
703 int idx;
704 u64 mp;
705
706 idx = 0;
707 mdesc_for_each_node_by_name(hp, mp, exec_unit_name) {
708 const char *type;
709 int len;
710
711 type = mdesc_get_property(hp, mp, "type", &len);
712 if (!of_find_in_proplist(type, "int", len) &&
713 !of_find_in_proplist(type, "integer", len))
714 continue;
715
716 mark_proc_ids(hp, mp, idx);
717
718 idx++;
719 }
720}
721
722static void __devinit set_proc_ids(struct mdesc_handle *hp)
723{
724 __set_proc_ids(hp, "exec_unit");
725 __set_proc_ids(hp, "exec-unit");
726}
727
728static void __devinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
729 unsigned char def)
730{
731 u64 val;
732
733 if (!p)
734 goto use_default;
735 val = *p;
736
737 if (!val || val >= 64)
738 goto use_default;
739
740 *mask = ((1U << val) * 64U) - 1U;
741 return;
742
743use_default:
744 *mask = ((1U << def) * 64U) - 1U;
745}
746
747static void __devinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
748 struct trap_per_cpu *tb)
749{
750 const u64 *val;
751
752 val = mdesc_get_property(hp, mp, "q-cpu-mondo-#bits", NULL);
753 get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7);
754
755 val = mdesc_get_property(hp, mp, "q-dev-mondo-#bits", NULL);
756 get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7);
757
758 val = mdesc_get_property(hp, mp, "q-resumable-#bits", NULL);
759 get_one_mondo_bits(val, &tb->resum_qmask, 6);
760
761 val = mdesc_get_property(hp, mp, "q-nonresumable-#bits", NULL);
762 get_one_mondo_bits(val, &tb->nonresum_qmask, 2);
763}
764
765void __cpuinit mdesc_fill_in_cpu_data(cpumask_t mask)
766{
767 struct mdesc_handle *hp = mdesc_grab();
768 u64 mp;
769
770 ncpus_probed = 0;
771 mdesc_for_each_node_by_name(hp, mp, "cpu") {
772 const u64 *id = mdesc_get_property(hp, mp, "id", NULL);
773 const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL);
774 struct trap_per_cpu *tb;
775 cpuinfo_sparc *c;
776 int cpuid;
777 u64 a;
778
779 ncpus_probed++;
780
781 cpuid = *id;
782
783#ifdef CONFIG_SMP
784 if (cpuid >= NR_CPUS) {
785 printk(KERN_WARNING "Ignoring CPU %d which is "
786 ">= NR_CPUS (%d)\n",
787 cpuid, NR_CPUS);
788 continue;
789 }
790 if (!cpu_isset(cpuid, mask))
791 continue;
792#else
793 /* On uniprocessor we only want the values for the
794 * real physical cpu the kernel booted onto, however
795 * cpu_data() only has one entry at index 0.
796 */
797 if (cpuid != real_hard_smp_processor_id())
798 continue;
799 cpuid = 0;
800#endif
801
802 c = &cpu_data(cpuid);
803 c->clock_tick = *cfreq;
804
805 tb = &trap_block[cpuid];
806 get_mondo_data(hp, mp, tb);
807
808 mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
809 u64 j, t = mdesc_arc_target(hp, a);
810 const char *t_name;
811
812 t_name = mdesc_node_name(hp, t);
813 if (!strcmp(t_name, "cache")) {
814 fill_in_one_cache(c, hp, t);
815 continue;
816 }
817
818 mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_FWD) {
819 u64 n = mdesc_arc_target(hp, j);
820 const char *n_name;
821
822 n_name = mdesc_node_name(hp, n);
823 if (!strcmp(n_name, "cache"))
824 fill_in_one_cache(c, hp, n);
825 }
826 }
827
828#ifdef CONFIG_SMP
829 cpu_set(cpuid, cpu_present_map);
830#endif
831
832 c->core_id = 0;
833 c->proc_id = -1;
834 }
835
836#ifdef CONFIG_SMP
837 sparc64_multi_core = 1;
838#endif
839
840 set_core_ids(hp);
841 set_proc_ids(hp);
842
843 smp_fill_in_sib_core_maps();
844
845 mdesc_release(hp);
846}
847
848static ssize_t mdesc_read(struct file *file, char __user *buf,
849 size_t len, loff_t *offp)
850{
851 struct mdesc_handle *hp = mdesc_grab();
852 int err;
853
854 if (!hp)
855 return -ENODEV;
856
857 err = hp->handle_size;
858 if (len < hp->handle_size)
859 err = -EMSGSIZE;
860 else if (copy_to_user(buf, &hp->mdesc, hp->handle_size))
861 err = -EFAULT;
862 mdesc_release(hp);
863
864 return err;
865}
866
867static const struct file_operations mdesc_fops = {
868 .read = mdesc_read,
869 .owner = THIS_MODULE,
870};
871
872static struct miscdevice mdesc_misc = {
873 .minor = MISC_DYNAMIC_MINOR,
874 .name = "mdesc",
875 .fops = &mdesc_fops,
876};
877
878static int __init mdesc_misc_init(void)
879{
880 return misc_register(&mdesc_misc);
881}
882
883__initcall(mdesc_misc_init);
884
885void __init sun4v_mdesc_init(void)
886{
887 struct mdesc_handle *hp;
888 unsigned long len, real_len, status;
889 cpumask_t mask;
890
891 (void) sun4v_mach_desc(0UL, 0UL, &len);
892
893 printk("MDESC: Size is %lu bytes.\n", len);
894
895 hp = mdesc_alloc(len, &lmb_mdesc_ops);
896 if (hp == NULL) {
897 prom_printf("MDESC: alloc of %lu bytes failed.\n", len);
898 prom_halt();
899 }
900
901 status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
902 if (status != HV_EOK || real_len > len) {
903 prom_printf("sun4v_mach_desc fails, err(%lu), "
904 "len(%lu), real_len(%lu)\n",
905 status, len, real_len);
906 mdesc_free(hp);
907 prom_halt();
908 }
909
910 cur_mdesc = hp;
911
912 report_platform_properties();
913
914 cpus_setall(mask);
915 mdesc_fill_in_cpu_data(mask);
916}