linux/arch/sparc/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/memblock.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#include <linux/bootmem.h>
  14#include <linux/export.h>
  15
  16#include <asm/cpudata.h>
  17#include <asm/hypervisor.h>
  18#include <asm/mdesc.h>
  19#include <asm/prom.h>
  20#include <linux/uaccess.h>
  21#include <asm/oplib.h>
  22#include <asm/smp.h>
  23
  24/* Unlike the OBP device tree, the machine description is a full-on
  25 * DAG.  An arbitrary number of ARCs are possible from one
  26 * node to other nodes and thus we can't use the OBP device_node
  27 * data structure to represent these nodes inside of the kernel.
  28 *
  29 * Actually, it isn't even a DAG, because there are back pointers
  30 * which create cycles in the graph.
  31 *
  32 * mdesc_hdr and mdesc_elem describe the layout of the data structure
  33 * we get from the Hypervisor.
  34 */
  35struct mdesc_hdr {
  36        u32     version; /* Transport version */
  37        u32     node_sz; /* node block size */
  38        u32     name_sz; /* name block size */
  39        u32     data_sz; /* data block size */
  40} __attribute__((aligned(16)));
  41
  42struct mdesc_elem {
  43        u8      tag;
  44#define MD_LIST_END     0x00
  45#define MD_NODE         0x4e
  46#define MD_NODE_END     0x45
  47#define MD_NOOP         0x20
  48#define MD_PROP_ARC     0x61
  49#define MD_PROP_VAL     0x76
  50#define MD_PROP_STR     0x73
  51#define MD_PROP_DATA    0x64
  52        u8      name_len;
  53        u16     resv;
  54        u32     name_offset;
  55        union {
  56                struct {
  57                        u32     data_len;
  58                        u32     data_offset;
  59                } data;
  60                u64     val;
  61        } d;
  62};
  63
  64struct mdesc_mem_ops {
  65        struct mdesc_handle *(*alloc)(unsigned int mdesc_size);
  66        void (*free)(struct mdesc_handle *handle);
  67};
  68
  69struct mdesc_handle {
  70        struct list_head        list;
  71        struct mdesc_mem_ops    *mops;
  72        void                    *self_base;
  73        atomic_t                refcnt;
  74        unsigned int            handle_size;
  75        struct mdesc_hdr        mdesc;
  76};
  77
  78typedef int (*mdesc_node_info_get_f)(struct mdesc_handle *, u64,
  79                                     union md_node_info *);
  80typedef void (*mdesc_node_info_rel_f)(union md_node_info *);
  81typedef bool (*mdesc_node_match_f)(union md_node_info *, union md_node_info *);
  82
  83struct md_node_ops {
  84        char                    *name;
  85        mdesc_node_info_get_f   get_info;
  86        mdesc_node_info_rel_f   rel_info;
  87        mdesc_node_match_f      node_match;
  88};
  89
  90static int get_vdev_port_node_info(struct mdesc_handle *md, u64 node,
  91                                   union md_node_info *node_info);
  92static void rel_vdev_port_node_info(union md_node_info *node_info);
  93static bool vdev_port_node_match(union md_node_info *a_node_info,
  94                                 union md_node_info *b_node_info);
  95
  96static int get_ds_port_node_info(struct mdesc_handle *md, u64 node,
  97                                 union md_node_info *node_info);
  98static void rel_ds_port_node_info(union md_node_info *node_info);
  99static bool ds_port_node_match(union md_node_info *a_node_info,
 100                               union md_node_info *b_node_info);
 101
 102/* supported node types which can be registered */
 103static struct md_node_ops md_node_ops_table[] = {
 104        {"virtual-device-port", get_vdev_port_node_info,
 105         rel_vdev_port_node_info, vdev_port_node_match},
 106        {"domain-services-port", get_ds_port_node_info,
 107         rel_ds_port_node_info, ds_port_node_match},
 108        {NULL, NULL, NULL, NULL}
 109};
 110
 111static void mdesc_get_node_ops(const char *node_name,
 112                               mdesc_node_info_get_f *get_info_f,
 113                               mdesc_node_info_rel_f *rel_info_f,
 114                               mdesc_node_match_f *match_f)
 115{
 116        int i;
 117
 118        if (get_info_f)
 119                *get_info_f = NULL;
 120
 121        if (rel_info_f)
 122                *rel_info_f = NULL;
 123
 124        if (match_f)
 125                *match_f = NULL;
 126
 127        if (!node_name)
 128                return;
 129
 130        for (i = 0; md_node_ops_table[i].name != NULL; i++) {
 131                if (strcmp(md_node_ops_table[i].name, node_name) == 0) {
 132                        if (get_info_f)
 133                                *get_info_f = md_node_ops_table[i].get_info;
 134
 135                        if (rel_info_f)
 136                                *rel_info_f = md_node_ops_table[i].rel_info;
 137
 138                        if (match_f)
 139                                *match_f = md_node_ops_table[i].node_match;
 140
 141                        break;
 142                }
 143        }
 144}
 145
 146static void mdesc_handle_init(struct mdesc_handle *hp,
 147                              unsigned int handle_size,
 148                              void *base)
 149{
 150        BUG_ON(((unsigned long)&hp->mdesc) & (16UL - 1));
 151
 152        memset(hp, 0, handle_size);
 153        INIT_LIST_HEAD(&hp->list);
 154        hp->self_base = base;
 155        atomic_set(&hp->refcnt, 1);
 156        hp->handle_size = handle_size;
 157}
 158
 159static struct mdesc_handle * __init mdesc_memblock_alloc(unsigned int mdesc_size)
 160{
 161        unsigned int handle_size, alloc_size;
 162        struct mdesc_handle *hp;
 163        unsigned long paddr;
 164
 165        handle_size = (sizeof(struct mdesc_handle) -
 166                       sizeof(struct mdesc_hdr) +
 167                       mdesc_size);
 168        alloc_size = PAGE_ALIGN(handle_size);
 169
 170        paddr = memblock_alloc(alloc_size, PAGE_SIZE);
 171
 172        hp = NULL;
 173        if (paddr) {
 174                hp = __va(paddr);
 175                mdesc_handle_init(hp, handle_size, hp);
 176        }
 177        return hp;
 178}
 179
 180static void __init mdesc_memblock_free(struct mdesc_handle *hp)
 181{
 182        unsigned int alloc_size;
 183        unsigned long start;
 184
 185        BUG_ON(atomic_read(&hp->refcnt) != 0);
 186        BUG_ON(!list_empty(&hp->list));
 187
 188        alloc_size = PAGE_ALIGN(hp->handle_size);
 189        start = __pa(hp);
 190        free_bootmem_late(start, alloc_size);
 191}
 192
 193static struct mdesc_mem_ops memblock_mdesc_ops = {
 194        .alloc = mdesc_memblock_alloc,
 195        .free  = mdesc_memblock_free,
 196};
 197
 198static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
 199{
 200        unsigned int handle_size;
 201        struct mdesc_handle *hp;
 202        unsigned long addr;
 203        void *base;
 204
 205        handle_size = (sizeof(struct mdesc_handle) -
 206                       sizeof(struct mdesc_hdr) +
 207                       mdesc_size);
 208        base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_RETRY_MAYFAIL);
 209        if (!base)
 210                return NULL;
 211
 212        addr = (unsigned long)base;
 213        addr = (addr + 15UL) & ~15UL;
 214        hp = (struct mdesc_handle *) addr;
 215
 216        mdesc_handle_init(hp, handle_size, base);
 217
 218        return hp;
 219}
 220
 221static void mdesc_kfree(struct mdesc_handle *hp)
 222{
 223        BUG_ON(atomic_read(&hp->refcnt) != 0);
 224        BUG_ON(!list_empty(&hp->list));
 225
 226        kfree(hp->self_base);
 227}
 228
 229static struct mdesc_mem_ops kmalloc_mdesc_memops = {
 230        .alloc = mdesc_kmalloc,
 231        .free  = mdesc_kfree,
 232};
 233
 234static struct mdesc_handle *mdesc_alloc(unsigned int mdesc_size,
 235                                        struct mdesc_mem_ops *mops)
 236{
 237        struct mdesc_handle *hp = mops->alloc(mdesc_size);
 238
 239        if (hp)
 240                hp->mops = mops;
 241
 242        return hp;
 243}
 244
 245static void mdesc_free(struct mdesc_handle *hp)
 246{
 247        hp->mops->free(hp);
 248}
 249
 250static struct mdesc_handle *cur_mdesc;
 251static LIST_HEAD(mdesc_zombie_list);
 252static DEFINE_SPINLOCK(mdesc_lock);
 253
 254struct mdesc_handle *mdesc_grab(void)
 255{
 256        struct mdesc_handle *hp;
 257        unsigned long flags;
 258
 259        spin_lock_irqsave(&mdesc_lock, flags);
 260        hp = cur_mdesc;
 261        if (hp)
 262                atomic_inc(&hp->refcnt);
 263        spin_unlock_irqrestore(&mdesc_lock, flags);
 264
 265        return hp;
 266}
 267EXPORT_SYMBOL(mdesc_grab);
 268
 269void mdesc_release(struct mdesc_handle *hp)
 270{
 271        unsigned long flags;
 272
 273        spin_lock_irqsave(&mdesc_lock, flags);
 274        if (atomic_dec_and_test(&hp->refcnt)) {
 275                list_del_init(&hp->list);
 276                hp->mops->free(hp);
 277        }
 278        spin_unlock_irqrestore(&mdesc_lock, flags);
 279}
 280EXPORT_SYMBOL(mdesc_release);
 281
 282static DEFINE_MUTEX(mdesc_mutex);
 283static struct mdesc_notifier_client *client_list;
 284
 285void mdesc_register_notifier(struct mdesc_notifier_client *client)
 286{
 287        bool supported = false;
 288        u64 node;
 289        int i;
 290
 291        mutex_lock(&mdesc_mutex);
 292
 293        /* check to see if the node is supported for registration */
 294        for (i = 0; md_node_ops_table[i].name != NULL; i++) {
 295                if (strcmp(md_node_ops_table[i].name, client->node_name) == 0) {
 296                        supported = true;
 297                        break;
 298                }
 299        }
 300
 301        if (!supported) {
 302                pr_err("MD: %s node not supported\n", client->node_name);
 303                mutex_unlock(&mdesc_mutex);
 304                return;
 305        }
 306
 307        client->next = client_list;
 308        client_list = client;
 309
 310        mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name)
 311                client->add(cur_mdesc, node, client->node_name);
 312
 313        mutex_unlock(&mdesc_mutex);
 314}
 315
 316static const u64 *parent_cfg_handle(struct mdesc_handle *hp, u64 node)
 317{
 318        const u64 *id;
 319        u64 a;
 320
 321        id = NULL;
 322        mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
 323                u64 target;
 324
 325                target = mdesc_arc_target(hp, a);
 326                id = mdesc_get_property(hp, target,
 327                                        "cfg-handle", NULL);
 328                if (id)
 329                        break;
 330        }
 331
 332        return id;
 333}
 334
 335static int get_vdev_port_node_info(struct mdesc_handle *md, u64 node,
 336                                   union md_node_info *node_info)
 337{
 338        const u64 *parent_cfg_hdlp;
 339        const char *name;
 340        const u64 *idp;
 341
 342        /*
 343         * Virtual device nodes are distinguished by:
 344         * 1. "id" property
 345         * 2. "name" property
 346         * 3. parent node "cfg-handle" property
 347         */
 348        idp = mdesc_get_property(md, node, "id", NULL);
 349        name = mdesc_get_property(md, node, "name", NULL);
 350        parent_cfg_hdlp = parent_cfg_handle(md, node);
 351
 352        if (!idp || !name || !parent_cfg_hdlp)
 353                return -1;
 354
 355        node_info->vdev_port.id = *idp;
 356        node_info->vdev_port.name = kstrdup_const(name, GFP_KERNEL);
 357        node_info->vdev_port.parent_cfg_hdl = *parent_cfg_hdlp;
 358
 359        return 0;
 360}
 361
 362static void rel_vdev_port_node_info(union md_node_info *node_info)
 363{
 364        if (node_info && node_info->vdev_port.name) {
 365                kfree_const(node_info->vdev_port.name);
 366                node_info->vdev_port.name = NULL;
 367        }
 368}
 369
 370static bool vdev_port_node_match(union md_node_info *a_node_info,
 371                                 union md_node_info *b_node_info)
 372{
 373        if (a_node_info->vdev_port.id != b_node_info->vdev_port.id)
 374                return false;
 375
 376        if (a_node_info->vdev_port.parent_cfg_hdl !=
 377            b_node_info->vdev_port.parent_cfg_hdl)
 378                return false;
 379
 380        if (strncmp(a_node_info->vdev_port.name,
 381                    b_node_info->vdev_port.name, MDESC_MAX_STR_LEN) != 0)
 382                return false;
 383
 384        return true;
 385}
 386
 387static int get_ds_port_node_info(struct mdesc_handle *md, u64 node,
 388                                 union md_node_info *node_info)
 389{
 390        const u64 *idp;
 391
 392        /* DS port nodes use the "id" property to distinguish them */
 393        idp = mdesc_get_property(md, node, "id", NULL);
 394        if (!idp)
 395                return -1;
 396
 397        node_info->ds_port.id = *idp;
 398
 399        return 0;
 400}
 401
 402static void rel_ds_port_node_info(union md_node_info *node_info)
 403{
 404}
 405
 406static bool ds_port_node_match(union md_node_info *a_node_info,
 407                               union md_node_info *b_node_info)
 408{
 409        if (a_node_info->ds_port.id != b_node_info->ds_port.id)
 410                return false;
 411
 412        return true;
 413}
 414
 415/* Run 'func' on nodes which are in A but not in B.  */
 416static void invoke_on_missing(const char *name,
 417                              struct mdesc_handle *a,
 418                              struct mdesc_handle *b,
 419                              void (*func)(struct mdesc_handle *, u64,
 420                                           const char *node_name))
 421{
 422        mdesc_node_info_get_f get_info_func;
 423        mdesc_node_info_rel_f rel_info_func;
 424        mdesc_node_match_f node_match_func;
 425        union md_node_info a_node_info;
 426        union md_node_info b_node_info;
 427        bool found;
 428        u64 a_node;
 429        u64 b_node;
 430        int rv;
 431
 432        /*
 433         * Find the get_info, rel_info and node_match ops for the given
 434         * node name
 435         */
 436        mdesc_get_node_ops(name, &get_info_func, &rel_info_func,
 437                           &node_match_func);
 438
 439        /* If we didn't find a match, the node type is not supported */
 440        if (!get_info_func || !rel_info_func || !node_match_func) {
 441                pr_err("MD: %s node type is not supported\n", name);
 442                return;
 443        }
 444
 445        mdesc_for_each_node_by_name(a, a_node, name) {
 446                found = false;
 447
 448                rv = get_info_func(a, a_node, &a_node_info);
 449                if (rv != 0) {
 450                        pr_err("MD: Cannot find 1 or more required match properties for %s node.\n",
 451                               name);
 452                        continue;
 453                }
 454
 455                /* Check each node in B for node matching a_node */
 456                mdesc_for_each_node_by_name(b, b_node, name) {
 457                        rv = get_info_func(b, b_node, &b_node_info);
 458                        if (rv != 0)
 459                                continue;
 460
 461                        if (node_match_func(&a_node_info, &b_node_info)) {
 462                                found = true;
 463                                rel_info_func(&b_node_info);
 464                                break;
 465                        }
 466
 467                        rel_info_func(&b_node_info);
 468                }
 469
 470                rel_info_func(&a_node_info);
 471
 472                if (!found)
 473                        func(a, a_node, name);
 474        }
 475}
 476
 477static void notify_one(struct mdesc_notifier_client *p,
 478                       struct mdesc_handle *old_hp,
 479                       struct mdesc_handle *new_hp)
 480{
 481        invoke_on_missing(p->node_name, old_hp, new_hp, p->remove);
 482        invoke_on_missing(p->node_name, new_hp, old_hp, p->add);
 483}
 484
 485static void mdesc_notify_clients(struct mdesc_handle *old_hp,
 486                                 struct mdesc_handle *new_hp)
 487{
 488        struct mdesc_notifier_client *p = client_list;
 489
 490        while (p) {
 491                notify_one(p, old_hp, new_hp);
 492                p = p->next;
 493        }
 494}
 495
 496void mdesc_update(void)
 497{
 498        unsigned long len, real_len, status;
 499        struct mdesc_handle *hp, *orig_hp;
 500        unsigned long flags;
 501
 502        mutex_lock(&mdesc_mutex);
 503
 504        (void) sun4v_mach_desc(0UL, 0UL, &len);
 505
 506        hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
 507        if (!hp) {
 508                printk(KERN_ERR "MD: mdesc alloc fails\n");
 509                goto out;
 510        }
 511
 512        status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
 513        if (status != HV_EOK || real_len > len) {
 514                printk(KERN_ERR "MD: mdesc reread fails with %lu\n",
 515                       status);
 516                atomic_dec(&hp->refcnt);
 517                mdesc_free(hp);
 518                goto out;
 519        }
 520
 521        spin_lock_irqsave(&mdesc_lock, flags);
 522        orig_hp = cur_mdesc;
 523        cur_mdesc = hp;
 524        spin_unlock_irqrestore(&mdesc_lock, flags);
 525
 526        mdesc_notify_clients(orig_hp, hp);
 527
 528        spin_lock_irqsave(&mdesc_lock, flags);
 529        if (atomic_dec_and_test(&orig_hp->refcnt))
 530                mdesc_free(orig_hp);
 531        else
 532                list_add(&orig_hp->list, &mdesc_zombie_list);
 533        spin_unlock_irqrestore(&mdesc_lock, flags);
 534
 535out:
 536        mutex_unlock(&mdesc_mutex);
 537}
 538
 539u64 mdesc_get_node(struct mdesc_handle *hp, const char *node_name,
 540                   union md_node_info *node_info)
 541{
 542        mdesc_node_info_get_f get_info_func;
 543        mdesc_node_info_rel_f rel_info_func;
 544        mdesc_node_match_f node_match_func;
 545        union md_node_info hp_node_info;
 546        u64 hp_node;
 547        int rv;
 548
 549        if (hp == NULL || node_name == NULL || node_info == NULL)
 550                return MDESC_NODE_NULL;
 551
 552        /* Find the ops for the given node name */
 553        mdesc_get_node_ops(node_name, &get_info_func, &rel_info_func,
 554                           &node_match_func);
 555
 556        /* If we didn't find ops for the given node name, it is not supported */
 557        if (!get_info_func || !rel_info_func || !node_match_func) {
 558                pr_err("MD: %s node is not supported\n", node_name);
 559                return -EINVAL;
 560        }
 561
 562        mdesc_for_each_node_by_name(hp, hp_node, node_name) {
 563                rv = get_info_func(hp, hp_node, &hp_node_info);
 564                if (rv != 0)
 565                        continue;
 566
 567                if (node_match_func(node_info, &hp_node_info))
 568                        break;
 569
 570                rel_info_func(&hp_node_info);
 571        }
 572
 573        rel_info_func(&hp_node_info);
 574
 575        return hp_node;
 576}
 577EXPORT_SYMBOL(mdesc_get_node);
 578
 579int mdesc_get_node_info(struct mdesc_handle *hp, u64 node,
 580                        const char *node_name, union md_node_info *node_info)
 581{
 582        mdesc_node_info_get_f get_info_func;
 583        int rv;
 584
 585        if (hp == NULL || node == MDESC_NODE_NULL ||
 586            node_name == NULL || node_info == NULL)
 587                return -EINVAL;
 588
 589        /* Find the get_info op for the given node name */
 590        mdesc_get_node_ops(node_name, &get_info_func, NULL, NULL);
 591
 592        /* If we didn't find a get_info_func, the node name is not supported */
 593        if (get_info_func == NULL) {
 594                pr_err("MD: %s node is not supported\n", node_name);
 595                return -EINVAL;
 596        }
 597
 598        rv = get_info_func(hp, node, node_info);
 599        if (rv != 0) {
 600                pr_err("MD: Cannot find 1 or more required match properties for %s node.\n",
 601                       node_name);
 602                return -1;
 603        }
 604
 605        return 0;
 606}
 607EXPORT_SYMBOL(mdesc_get_node_info);
 608
 609static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
 610{
 611        return (struct mdesc_elem *) (mdesc + 1);
 612}
 613
 614static void *name_block(struct mdesc_hdr *mdesc)
 615{
 616        return ((void *) node_block(mdesc)) + mdesc->node_sz;
 617}
 618
 619static void *data_block(struct mdesc_hdr *mdesc)
 620{
 621        return ((void *) name_block(mdesc)) + mdesc->name_sz;
 622}
 623
 624u64 mdesc_node_by_name(struct mdesc_handle *hp,
 625                       u64 from_node, const char *name)
 626{
 627        struct mdesc_elem *ep = node_block(&hp->mdesc);
 628        const char *names = name_block(&hp->mdesc);
 629        u64 last_node = hp->mdesc.node_sz / 16;
 630        u64 ret;
 631
 632        if (from_node == MDESC_NODE_NULL) {
 633                ret = from_node = 0;
 634        } else if (from_node >= last_node) {
 635                return MDESC_NODE_NULL;
 636        } else {
 637                ret = ep[from_node].d.val;
 638        }
 639
 640        while (ret < last_node) {
 641                if (ep[ret].tag != MD_NODE)
 642                        return MDESC_NODE_NULL;
 643                if (!strcmp(names + ep[ret].name_offset, name))
 644                        break;
 645                ret = ep[ret].d.val;
 646        }
 647        if (ret >= last_node)
 648                ret = MDESC_NODE_NULL;
 649        return ret;
 650}
 651EXPORT_SYMBOL(mdesc_node_by_name);
 652
 653const void *mdesc_get_property(struct mdesc_handle *hp, u64 node,
 654                               const char *name, int *lenp)
 655{
 656        const char *names = name_block(&hp->mdesc);
 657        u64 last_node = hp->mdesc.node_sz / 16;
 658        void *data = data_block(&hp->mdesc);
 659        struct mdesc_elem *ep;
 660
 661        if (node == MDESC_NODE_NULL || node >= last_node)
 662                return NULL;
 663
 664        ep = node_block(&hp->mdesc) + node;
 665        ep++;
 666        for (; ep->tag != MD_NODE_END; ep++) {
 667                void *val = NULL;
 668                int len = 0;
 669
 670                switch (ep->tag) {
 671                case MD_PROP_VAL:
 672                        val = &ep->d.val;
 673                        len = 8;
 674                        break;
 675
 676                case MD_PROP_STR:
 677                case MD_PROP_DATA:
 678                        val = data + ep->d.data.data_offset;
 679                        len = ep->d.data.data_len;
 680                        break;
 681
 682                default:
 683                        break;
 684                }
 685                if (!val)
 686                        continue;
 687
 688                if (!strcmp(names + ep->name_offset, name)) {
 689                        if (lenp)
 690                                *lenp = len;
 691                        return val;
 692                }
 693        }
 694
 695        return NULL;
 696}
 697EXPORT_SYMBOL(mdesc_get_property);
 698
 699u64 mdesc_next_arc(struct mdesc_handle *hp, u64 from, const char *arc_type)
 700{
 701        struct mdesc_elem *ep, *base = node_block(&hp->mdesc);
 702        const char *names = name_block(&hp->mdesc);
 703        u64 last_node = hp->mdesc.node_sz / 16;
 704
 705        if (from == MDESC_NODE_NULL || from >= last_node)
 706                return MDESC_NODE_NULL;
 707
 708        ep = base + from;
 709
 710        ep++;
 711        for (; ep->tag != MD_NODE_END; ep++) {
 712                if (ep->tag != MD_PROP_ARC)
 713                        continue;
 714
 715                if (strcmp(names + ep->name_offset, arc_type))
 716                        continue;
 717
 718                return ep - base;
 719        }
 720
 721        return MDESC_NODE_NULL;
 722}
 723EXPORT_SYMBOL(mdesc_next_arc);
 724
 725u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc)
 726{
 727        struct mdesc_elem *ep, *base = node_block(&hp->mdesc);
 728
 729        ep = base + arc;
 730
 731        return ep->d.val;
 732}
 733EXPORT_SYMBOL(mdesc_arc_target);
 734
 735const char *mdesc_node_name(struct mdesc_handle *hp, u64 node)
 736{
 737        struct mdesc_elem *ep, *base = node_block(&hp->mdesc);
 738        const char *names = name_block(&hp->mdesc);
 739        u64 last_node = hp->mdesc.node_sz / 16;
 740
 741        if (node == MDESC_NODE_NULL || node >= last_node)
 742                return NULL;
 743
 744        ep = base + node;
 745        if (ep->tag != MD_NODE)
 746                return NULL;
 747
 748        return names + ep->name_offset;
 749}
 750EXPORT_SYMBOL(mdesc_node_name);
 751
 752static u64 max_cpus = 64;
 753
 754static void __init report_platform_properties(void)
 755{
 756        struct mdesc_handle *hp = mdesc_grab();
 757        u64 pn = mdesc_node_by_name(hp, MDESC_NODE_NULL, "platform");
 758        const char *s;
 759        const u64 *v;
 760
 761        if (pn == MDESC_NODE_NULL) {
 762                prom_printf("No platform node in machine-description.\n");
 763                prom_halt();
 764        }
 765
 766        s = mdesc_get_property(hp, pn, "banner-name", NULL);
 767        printk("PLATFORM: banner-name [%s]\n", s);
 768        s = mdesc_get_property(hp, pn, "name", NULL);
 769        printk("PLATFORM: name [%s]\n", s);
 770
 771        v = mdesc_get_property(hp, pn, "hostid", NULL);
 772        if (v)
 773                printk("PLATFORM: hostid [%08llx]\n", *v);
 774        v = mdesc_get_property(hp, pn, "serial#", NULL);
 775        if (v)
 776                printk("PLATFORM: serial# [%08llx]\n", *v);
 777        v = mdesc_get_property(hp, pn, "stick-frequency", NULL);
 778        printk("PLATFORM: stick-frequency [%08llx]\n", *v);
 779        v = mdesc_get_property(hp, pn, "mac-address", NULL);
 780        if (v)
 781                printk("PLATFORM: mac-address [%llx]\n", *v);
 782        v = mdesc_get_property(hp, pn, "watchdog-resolution", NULL);
 783        if (v)
 784                printk("PLATFORM: watchdog-resolution [%llu ms]\n", *v);
 785        v = mdesc_get_property(hp, pn, "watchdog-max-timeout", NULL);
 786        if (v)
 787                printk("PLATFORM: watchdog-max-timeout [%llu ms]\n", *v);
 788        v = mdesc_get_property(hp, pn, "max-cpus", NULL);
 789        if (v) {
 790                max_cpus = *v;
 791                printk("PLATFORM: max-cpus [%llu]\n", max_cpus);
 792        }
 793
 794#ifdef CONFIG_SMP
 795        {
 796                int max_cpu, i;
 797
 798                if (v) {
 799                        max_cpu = *v;
 800                        if (max_cpu > NR_CPUS)
 801                                max_cpu = NR_CPUS;
 802                } else {
 803                        max_cpu = NR_CPUS;
 804                }
 805                for (i = 0; i < max_cpu; i++)
 806                        set_cpu_possible(i, true);
 807        }
 808#endif
 809
 810        mdesc_release(hp);
 811}
 812
 813static void fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_handle *hp, u64 mp)
 814{
 815        const u64 *level = mdesc_get_property(hp, mp, "level", NULL);
 816        const u64 *size = mdesc_get_property(hp, mp, "size", NULL);
 817        const u64 *line_size = mdesc_get_property(hp, mp, "line-size", NULL);
 818        const char *type;
 819        int type_len;
 820
 821        type = mdesc_get_property(hp, mp, "type", &type_len);
 822
 823        switch (*level) {
 824        case 1:
 825                if (of_find_in_proplist(type, "instn", type_len)) {
 826                        c->icache_size = *size;
 827                        c->icache_line_size = *line_size;
 828                } else if (of_find_in_proplist(type, "data", type_len)) {
 829                        c->dcache_size = *size;
 830                        c->dcache_line_size = *line_size;
 831                }
 832                break;
 833
 834        case 2:
 835                c->ecache_size = *size;
 836                c->ecache_line_size = *line_size;
 837                break;
 838
 839        default:
 840                break;
 841        }
 842
 843        if (*level == 1) {
 844                u64 a;
 845
 846                mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
 847                        u64 target = mdesc_arc_target(hp, a);
 848                        const char *name = mdesc_node_name(hp, target);
 849
 850                        if (!strcmp(name, "cache"))
 851                                fill_in_one_cache(c, hp, target);
 852                }
 853        }
 854}
 855
 856static void find_back_node_value(struct mdesc_handle *hp, u64 node,
 857                                 char *srch_val,
 858                                 void (*func)(struct mdesc_handle *, u64, int),
 859                                 u64 val, int depth)
 860{
 861        u64 arc;
 862
 863        /* Since we have an estimate of recursion depth, do a sanity check. */
 864        if (depth == 0)
 865                return;
 866
 867        mdesc_for_each_arc(arc, hp, node, MDESC_ARC_TYPE_BACK) {
 868                u64 n = mdesc_arc_target(hp, arc);
 869                const char *name = mdesc_node_name(hp, n);
 870
 871                if (!strcmp(srch_val, name))
 872                        (*func)(hp, n, val);
 873
 874                find_back_node_value(hp, n, srch_val, func, val, depth-1);
 875        }
 876}
 877
 878static void __mark_core_id(struct mdesc_handle *hp, u64 node,
 879                           int core_id)
 880{
 881        const u64 *id = mdesc_get_property(hp, node, "id", NULL);
 882
 883        if (*id < num_possible_cpus())
 884                cpu_data(*id).core_id = core_id;
 885}
 886
 887static void __mark_max_cache_id(struct mdesc_handle *hp, u64 node,
 888                                int max_cache_id)
 889{
 890        const u64 *id = mdesc_get_property(hp, node, "id", NULL);
 891
 892        if (*id < num_possible_cpus()) {
 893                cpu_data(*id).max_cache_id = max_cache_id;
 894
 895                /**
 896                 * On systems without explicit socket descriptions socket
 897                 * is max_cache_id
 898                 */
 899                cpu_data(*id).sock_id = max_cache_id;
 900        }
 901}
 902
 903static void mark_core_ids(struct mdesc_handle *hp, u64 mp,
 904                          int core_id)
 905{
 906        find_back_node_value(hp, mp, "cpu", __mark_core_id, core_id, 10);
 907}
 908
 909static void mark_max_cache_ids(struct mdesc_handle *hp, u64 mp,
 910                               int max_cache_id)
 911{
 912        find_back_node_value(hp, mp, "cpu", __mark_max_cache_id,
 913                             max_cache_id, 10);
 914}
 915
 916static void set_core_ids(struct mdesc_handle *hp)
 917{
 918        int idx;
 919        u64 mp;
 920
 921        idx = 1;
 922
 923        /* Identify unique cores by looking for cpus backpointed to by
 924         * level 1 instruction caches.
 925         */
 926        mdesc_for_each_node_by_name(hp, mp, "cache") {
 927                const u64 *level;
 928                const char *type;
 929                int len;
 930
 931                level = mdesc_get_property(hp, mp, "level", NULL);
 932                if (*level != 1)
 933                        continue;
 934
 935                type = mdesc_get_property(hp, mp, "type", &len);
 936                if (!of_find_in_proplist(type, "instn", len))
 937                        continue;
 938
 939                mark_core_ids(hp, mp, idx);
 940                idx++;
 941        }
 942}
 943
 944static int set_max_cache_ids_by_cache(struct mdesc_handle *hp, int level)
 945{
 946        u64 mp;
 947        int idx = 1;
 948        int fnd = 0;
 949
 950        /**
 951         * Identify unique highest level of shared cache by looking for cpus
 952         * backpointed to by shared level N caches.
 953         */
 954        mdesc_for_each_node_by_name(hp, mp, "cache") {
 955                const u64 *cur_lvl;
 956
 957                cur_lvl = mdesc_get_property(hp, mp, "level", NULL);
 958                if (*cur_lvl != level)
 959                        continue;
 960                mark_max_cache_ids(hp, mp, idx);
 961                idx++;
 962                fnd = 1;
 963        }
 964        return fnd;
 965}
 966
 967static void set_sock_ids_by_socket(struct mdesc_handle *hp, u64 mp)
 968{
 969        int idx = 1;
 970
 971        mdesc_for_each_node_by_name(hp, mp, "socket") {
 972                u64 a;
 973
 974                mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
 975                        u64 t = mdesc_arc_target(hp, a);
 976                        const char *name;
 977                        const u64 *id;
 978
 979                        name = mdesc_node_name(hp, t);
 980                        if (strcmp(name, "cpu"))
 981                                continue;
 982
 983                        id = mdesc_get_property(hp, t, "id", NULL);
 984                        if (*id < num_possible_cpus())
 985                                cpu_data(*id).sock_id = idx;
 986                }
 987                idx++;
 988        }
 989}
 990
 991static void set_sock_ids(struct mdesc_handle *hp)
 992{
 993        u64 mp;
 994
 995        /**
 996         * Find the highest level of shared cache which pre-T7 is also
 997         * the socket.
 998         */
 999        if (!set_max_cache_ids_by_cache(hp, 3))
1000                set_max_cache_ids_by_cache(hp, 2);
1001
1002        /* If machine description exposes sockets data use it.*/
1003        mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "sockets");
1004        if (mp != MDESC_NODE_NULL)
1005                set_sock_ids_by_socket(hp, mp);
1006}
1007
1008static void mark_proc_ids(struct mdesc_handle *hp, u64 mp, int proc_id)
1009{
1010        u64 a;
1011
1012        mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
1013                u64 t = mdesc_arc_target(hp, a);
1014                const char *name;
1015                const u64 *id;
1016
1017                name = mdesc_node_name(hp, t);
1018                if (strcmp(name, "cpu"))
1019                        continue;
1020
1021                id = mdesc_get_property(hp, t, "id", NULL);
1022                if (*id < NR_CPUS)
1023                        cpu_data(*id).proc_id = proc_id;
1024        }
1025}
1026
1027static void __set_proc_ids(struct mdesc_handle *hp, const char *exec_unit_name)
1028{
1029        int idx;
1030        u64 mp;
1031
1032        idx = 0;
1033        mdesc_for_each_node_by_name(hp, mp, exec_unit_name) {
1034                const char *type;
1035                int len;
1036
1037                type = mdesc_get_property(hp, mp, "type", &len);
1038                if (!of_find_in_proplist(type, "int", len) &&
1039                    !of_find_in_proplist(type, "integer", len))
1040                        continue;
1041
1042                mark_proc_ids(hp, mp, idx);
1043                idx++;
1044        }
1045}
1046
1047static void set_proc_ids(struct mdesc_handle *hp)
1048{
1049        __set_proc_ids(hp, "exec_unit");
1050        __set_proc_ids(hp, "exec-unit");
1051}
1052
1053static void get_one_mondo_bits(const u64 *p, unsigned int *mask,
1054                               unsigned long def, unsigned long max)
1055{
1056        u64 val;
1057
1058        if (!p)
1059                goto use_default;
1060        val = *p;
1061
1062        if (!val || val >= 64)
1063                goto use_default;
1064
1065        if (val > max)
1066                val = max;
1067
1068        *mask = ((1U << val) * 64U) - 1U;
1069        return;
1070
1071use_default:
1072        *mask = ((1U << def) * 64U) - 1U;
1073}
1074
1075static void get_mondo_data(struct mdesc_handle *hp, u64 mp,
1076                           struct trap_per_cpu *tb)
1077{
1078        static int printed;
1079        const u64 *val;
1080
1081        val = mdesc_get_property(hp, mp, "q-cpu-mondo-#bits", NULL);
1082        get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7, ilog2(max_cpus * 2));
1083
1084        val = mdesc_get_property(hp, mp, "q-dev-mondo-#bits", NULL);
1085        get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7, 8);
1086
1087        val = mdesc_get_property(hp, mp, "q-resumable-#bits", NULL);
1088        get_one_mondo_bits(val, &tb->resum_qmask, 6, 7);
1089
1090        val = mdesc_get_property(hp, mp, "q-nonresumable-#bits", NULL);
1091        get_one_mondo_bits(val, &tb->nonresum_qmask, 2, 2);
1092        if (!printed++) {
1093                pr_info("SUN4V: Mondo queue sizes "
1094                        "[cpu(%u) dev(%u) r(%u) nr(%u)]\n",
1095                        tb->cpu_mondo_qmask + 1,
1096                        tb->dev_mondo_qmask + 1,
1097                        tb->resum_qmask + 1,
1098                        tb->nonresum_qmask + 1);
1099        }
1100}
1101
1102static void *mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handle *, u64, int, void *), void *arg, cpumask_t *mask)
1103{
1104        struct mdesc_handle *hp = mdesc_grab();
1105        void *ret = NULL;
1106        u64 mp;
1107
1108        mdesc_for_each_node_by_name(hp, mp, "cpu") {
1109                const u64 *id = mdesc_get_property(hp, mp, "id", NULL);
1110                int cpuid = *id;
1111
1112#ifdef CONFIG_SMP
1113                if (cpuid >= NR_CPUS) {
1114                        printk(KERN_WARNING "Ignoring CPU %d which is "
1115                               ">= NR_CPUS (%d)\n",
1116                               cpuid, NR_CPUS);
1117                        continue;
1118                }
1119                if (!cpumask_test_cpu(cpuid, mask))
1120                        continue;
1121#endif
1122
1123                ret = func(hp, mp, cpuid, arg);
1124                if (ret)
1125                        goto out;
1126        }
1127out:
1128        mdesc_release(hp);
1129        return ret;
1130}
1131
1132static void *record_one_cpu(struct mdesc_handle *hp, u64 mp, int cpuid,
1133                            void *arg)
1134{
1135        ncpus_probed++;
1136#ifdef CONFIG_SMP
1137        set_cpu_present(cpuid, true);
1138#endif
1139        return NULL;
1140}
1141
1142void mdesc_populate_present_mask(cpumask_t *mask)
1143{
1144        if (tlb_type != hypervisor)
1145                return;
1146
1147        ncpus_probed = 0;
1148        mdesc_iterate_over_cpus(record_one_cpu, NULL, mask);
1149}
1150
1151static void * __init check_one_pgsz(struct mdesc_handle *hp, u64 mp, int cpuid, void *arg)
1152{
1153        const u64 *pgsz_prop = mdesc_get_property(hp, mp, "mmu-page-size-list", NULL);
1154        unsigned long *pgsz_mask = arg;
1155        u64 val;
1156
1157        val = (HV_PGSZ_MASK_8K | HV_PGSZ_MASK_64K |
1158               HV_PGSZ_MASK_512K | HV_PGSZ_MASK_4MB);
1159        if (pgsz_prop)
1160                val = *pgsz_prop;
1161
1162        if (!*pgsz_mask)
1163                *pgsz_mask = val;
1164        else
1165                *pgsz_mask &= val;
1166        return NULL;
1167}
1168
1169void __init mdesc_get_page_sizes(cpumask_t *mask, unsigned long *pgsz_mask)
1170{
1171        *pgsz_mask = 0;
1172        mdesc_iterate_over_cpus(check_one_pgsz, pgsz_mask, mask);
1173}
1174
1175static void *fill_in_one_cpu(struct mdesc_handle *hp, u64 mp, int cpuid,
1176                             void *arg)
1177{
1178        const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL);
1179        struct trap_per_cpu *tb;
1180        cpuinfo_sparc *c;
1181        u64 a;
1182
1183#ifndef CONFIG_SMP
1184        /* On uniprocessor we only want the values for the
1185         * real physical cpu the kernel booted onto, however
1186         * cpu_data() only has one entry at index 0.
1187         */
1188        if (cpuid != real_hard_smp_processor_id())
1189                return NULL;
1190        cpuid = 0;
1191#endif
1192
1193        c = &cpu_data(cpuid);
1194        c->clock_tick = *cfreq;
1195
1196        tb = &trap_block[cpuid];
1197        get_mondo_data(hp, mp, tb);
1198
1199        mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
1200                u64 j, t = mdesc_arc_target(hp, a);
1201                const char *t_name;
1202
1203                t_name = mdesc_node_name(hp, t);
1204                if (!strcmp(t_name, "cache")) {
1205                        fill_in_one_cache(c, hp, t);
1206                        continue;
1207                }
1208
1209                mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_FWD) {
1210                        u64 n = mdesc_arc_target(hp, j);
1211                        const char *n_name;
1212
1213                        n_name = mdesc_node_name(hp, n);
1214                        if (!strcmp(n_name, "cache"))
1215                                fill_in_one_cache(c, hp, n);
1216                }
1217        }
1218
1219        c->core_id = 0;
1220        c->proc_id = -1;
1221
1222        return NULL;
1223}
1224
1225void mdesc_fill_in_cpu_data(cpumask_t *mask)
1226{
1227        struct mdesc_handle *hp;
1228
1229        mdesc_iterate_over_cpus(fill_in_one_cpu, NULL, mask);
1230
1231        hp = mdesc_grab();
1232
1233        set_core_ids(hp);
1234        set_proc_ids(hp);
1235        set_sock_ids(hp);
1236
1237        mdesc_release(hp);
1238
1239        smp_fill_in_sib_core_maps();
1240}
1241
1242/* mdesc_open() - Grab a reference to mdesc_handle when /dev/mdesc is
1243 * opened. Hold this reference until /dev/mdesc is closed to ensure
1244 * mdesc data structure is not released underneath us. Store the
1245 * pointer to mdesc structure in private_data for read and seek to use
1246 */
1247static int mdesc_open(struct inode *inode, struct file *file)
1248{
1249        struct mdesc_handle *hp = mdesc_grab();
1250
1251        if (!hp)
1252                return -ENODEV;
1253
1254        file->private_data = hp;
1255
1256        return 0;
1257}
1258
1259static ssize_t mdesc_read(struct file *file, char __user *buf,
1260                          size_t len, loff_t *offp)
1261{
1262        struct mdesc_handle *hp = file->private_data;
1263        unsigned char *mdesc;
1264        int bytes_left, count = len;
1265
1266        if (*offp >= hp->handle_size)
1267                return 0;
1268
1269        bytes_left = hp->handle_size - *offp;
1270        if (count > bytes_left)
1271                count = bytes_left;
1272
1273        mdesc = (unsigned char *)&hp->mdesc;
1274        mdesc += *offp;
1275        if (!copy_to_user(buf, mdesc, count)) {
1276                *offp += count;
1277                return count;
1278        } else {
1279                return -EFAULT;
1280        }
1281}
1282
1283static loff_t mdesc_llseek(struct file *file, loff_t offset, int whence)
1284{
1285        struct mdesc_handle *hp = file->private_data;
1286
1287        return no_seek_end_llseek_size(file, offset, whence, hp->handle_size);
1288}
1289
1290/* mdesc_close() - /dev/mdesc is being closed, release the reference to
1291 * mdesc structure.
1292 */
1293static int mdesc_close(struct inode *inode, struct file *file)
1294{
1295        mdesc_release(file->private_data);
1296        return 0;
1297}
1298
1299static const struct file_operations mdesc_fops = {
1300        .open    = mdesc_open,
1301        .read    = mdesc_read,
1302        .llseek  = mdesc_llseek,
1303        .release = mdesc_close,
1304        .owner   = THIS_MODULE,
1305};
1306
1307static struct miscdevice mdesc_misc = {
1308        .minor  = MISC_DYNAMIC_MINOR,
1309        .name   = "mdesc",
1310        .fops   = &mdesc_fops,
1311};
1312
1313static int __init mdesc_misc_init(void)
1314{
1315        return misc_register(&mdesc_misc);
1316}
1317
1318__initcall(mdesc_misc_init);
1319
1320void __init sun4v_mdesc_init(void)
1321{
1322        struct mdesc_handle *hp;
1323        unsigned long len, real_len, status;
1324
1325        (void) sun4v_mach_desc(0UL, 0UL, &len);
1326
1327        printk("MDESC: Size is %lu bytes.\n", len);
1328
1329        hp = mdesc_alloc(len, &memblock_mdesc_ops);
1330        if (hp == NULL) {
1331                prom_printf("MDESC: alloc of %lu bytes failed.\n", len);
1332                prom_halt();
1333        }
1334
1335        status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
1336        if (status != HV_EOK || real_len > len) {
1337                prom_printf("sun4v_mach_desc fails, err(%lu), "
1338                            "len(%lu), real_len(%lu)\n",
1339                            status, len, real_len);
1340                mdesc_free(hp);
1341                prom_halt();
1342        }
1343
1344        cur_mdesc = hp;
1345
1346        report_platform_properties();
1347}
1348