linux/arch/sparc64/kernel/mdesc.c
<<
>>
Prefs
   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}
 917
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.