linux/drivers/platform/x86/uv_sysfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * This file supports the /sys/firmware/sgi_uv topology tree on HPE UV.
   4 *
   5 *  Copyright (c) 2020 Hewlett Packard Enterprise.  All Rights Reserved.
   6 *  Copyright (c) Justin Ernst
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/kernel.h>
  11#include <linux/device.h>
  12#include <linux/slab.h>
  13#include <linux/kobject.h>
  14#include <asm/uv/bios.h>
  15#include <asm/uv/uv.h>
  16#include <asm/uv/uv_hub.h>
  17#include <asm/uv/uv_geo.h>
  18
  19#define INVALID_CNODE -1
  20
  21struct kobject *sgi_uv_kobj;
  22static struct kset *uv_pcibus_kset;
  23static struct kset *uv_hubs_kset;
  24static struct uv_bios_hub_info *hub_buf;
  25static struct uv_bios_port_info **port_buf;
  26static struct uv_hub **uv_hubs;
  27static struct uv_pci_top_obj **uv_pci_objs;
  28static int num_pci_lines;
  29static int num_cnodes;
  30static int *prev_obj_to_cnode;
  31static int uv_bios_obj_cnt;
  32static signed short uv_master_nasid = -1;
  33static void *uv_biosheap;
  34
  35static const char *uv_type_string(void)
  36{
  37        if (is_uv5_hub())
  38                return "9.0";
  39        else if (is_uv4a_hub())
  40                return "7.1";
  41        else if (is_uv4_hub())
  42                return "7.0";
  43        else if (is_uv3_hub())
  44                return "5.0";
  45        else if (is_uv2_hub())
  46                return "3.0";
  47        else if (uv_get_hubless_system())
  48                return "0.1";
  49        else
  50                return "unknown";
  51}
  52
  53static int ordinal_to_nasid(int ordinal)
  54{
  55        if (ordinal < num_cnodes && ordinal >= 0)
  56                return UV_PNODE_TO_NASID(uv_blade_to_pnode(ordinal));
  57        else
  58                return -1;
  59}
  60
  61static union geoid_u cnode_to_geoid(int cnode)
  62{
  63        union geoid_u geoid;
  64
  65        uv_bios_get_geoinfo(ordinal_to_nasid(cnode), (u64)sizeof(union geoid_u), (u64 *)&geoid);
  66        return geoid;
  67}
  68
  69static int location_to_bpos(char *location, int *rack, int *slot, int *blade)
  70{
  71        char type, r, b, h;
  72        int idb, idh;
  73
  74        if (sscanf(location, "%c%03d%c%02d%c%2d%c%d",
  75                         &r, rack, &type, slot, &b, &idb, &h, &idh) != 8)
  76                return -1;
  77        *blade = idb * 2 + idh;
  78
  79        return 0;
  80}
  81
  82static int cache_obj_to_cnode(struct uv_bios_hub_info *obj)
  83{
  84        int cnode;
  85        union geoid_u geoid;
  86        int obj_rack, obj_slot, obj_blade;
  87        int rack, slot, blade;
  88
  89        if (!obj->f.fields.this_part && !obj->f.fields.is_shared)
  90                return 0;
  91
  92        if (location_to_bpos(obj->location, &obj_rack, &obj_slot, &obj_blade))
  93                return -1;
  94
  95        for (cnode = 0; cnode < num_cnodes; cnode++) {
  96                geoid = cnode_to_geoid(cnode);
  97                rack = geo_rack(geoid);
  98                slot = geo_slot(geoid);
  99                blade = geo_blade(geoid);
 100                if (obj_rack == rack && obj_slot == slot && obj_blade == blade)
 101                        prev_obj_to_cnode[obj->id] = cnode;
 102        }
 103
 104        return 0;
 105}
 106
 107static int get_obj_to_cnode(int obj_id)
 108{
 109        return prev_obj_to_cnode[obj_id];
 110}
 111
 112struct uv_hub {
 113        struct kobject kobj;
 114        struct uv_bios_hub_info *hub_info;
 115        struct uv_port **ports;
 116};
 117
 118#define to_uv_hub(kobj_ptr) container_of(kobj_ptr, struct uv_hub, kobj)
 119
 120static ssize_t hub_name_show(struct uv_bios_hub_info *hub_info, char *buf)
 121{
 122        return scnprintf(buf, PAGE_SIZE, "%s\n", hub_info->name);
 123}
 124
 125static ssize_t hub_location_show(struct uv_bios_hub_info *hub_info, char *buf)
 126{
 127        return scnprintf(buf, PAGE_SIZE, "%s\n", hub_info->location);
 128}
 129
 130static ssize_t hub_partition_show(struct uv_bios_hub_info *hub_info, char *buf)
 131{
 132        return sprintf(buf, "%d\n", hub_info->f.fields.this_part);
 133}
 134
 135static ssize_t hub_shared_show(struct uv_bios_hub_info *hub_info, char *buf)
 136{
 137        return sprintf(buf, "%d\n", hub_info->f.fields.is_shared);
 138}
 139static ssize_t hub_nasid_show(struct uv_bios_hub_info *hub_info, char *buf)
 140{
 141        int cnode = get_obj_to_cnode(hub_info->id);
 142
 143        return sprintf(buf, "%d\n", ordinal_to_nasid(cnode));
 144}
 145static ssize_t hub_cnode_show(struct uv_bios_hub_info *hub_info, char *buf)
 146{
 147        return sprintf(buf, "%d\n", get_obj_to_cnode(hub_info->id));
 148}
 149
 150struct hub_sysfs_entry {
 151        struct attribute attr;
 152        ssize_t (*show)(struct uv_bios_hub_info *hub_info, char *buf);
 153        ssize_t (*store)(struct uv_bios_hub_info *hub_info, const char *buf, size_t sz);
 154};
 155
 156static struct hub_sysfs_entry name_attribute =
 157        __ATTR(name, 0444, hub_name_show, NULL);
 158static struct hub_sysfs_entry location_attribute =
 159        __ATTR(location, 0444, hub_location_show, NULL);
 160static struct hub_sysfs_entry partition_attribute =
 161        __ATTR(this_partition, 0444, hub_partition_show, NULL);
 162static struct hub_sysfs_entry shared_attribute =
 163        __ATTR(shared, 0444, hub_shared_show, NULL);
 164static struct hub_sysfs_entry nasid_attribute =
 165        __ATTR(nasid, 0444, hub_nasid_show, NULL);
 166static struct hub_sysfs_entry cnode_attribute =
 167        __ATTR(cnode, 0444, hub_cnode_show, NULL);
 168
 169static struct attribute *uv_hub_attrs[] = {
 170        &name_attribute.attr,
 171        &location_attribute.attr,
 172        &partition_attribute.attr,
 173        &shared_attribute.attr,
 174        &nasid_attribute.attr,
 175        &cnode_attribute.attr,
 176        NULL,
 177};
 178
 179static void hub_release(struct kobject *kobj)
 180{
 181        struct uv_hub *hub = to_uv_hub(kobj);
 182
 183        kfree(hub);
 184}
 185
 186static ssize_t hub_type_show(struct kobject *kobj, struct attribute *attr,
 187                                char *buf)
 188{
 189        struct uv_hub *hub = to_uv_hub(kobj);
 190        struct uv_bios_hub_info *bios_hub_info = hub->hub_info;
 191        struct hub_sysfs_entry *entry;
 192
 193        entry = container_of(attr, struct hub_sysfs_entry, attr);
 194
 195        if (!entry->show)
 196                return -EIO;
 197
 198        return entry->show(bios_hub_info, buf);
 199}
 200
 201static const struct sysfs_ops hub_sysfs_ops = {
 202        .show = hub_type_show,
 203};
 204
 205static struct kobj_type hub_attr_type = {
 206        .release        = hub_release,
 207        .sysfs_ops      = &hub_sysfs_ops,
 208        .default_attrs  = uv_hub_attrs,
 209};
 210
 211static int uv_hubs_init(void)
 212{
 213        s64 biosr;
 214        u64 sz;
 215        int i, ret;
 216
 217        prev_obj_to_cnode = kmalloc_array(uv_bios_obj_cnt, sizeof(*prev_obj_to_cnode),
 218                                         GFP_KERNEL);
 219        if (!prev_obj_to_cnode)
 220                return -ENOMEM;
 221
 222        for (i = 0; i < uv_bios_obj_cnt; i++)
 223                prev_obj_to_cnode[i] = INVALID_CNODE;
 224
 225        uv_hubs_kset = kset_create_and_add("hubs", NULL, sgi_uv_kobj);
 226        if (!uv_hubs_kset) {
 227                ret = -ENOMEM;
 228                goto err_hubs_kset;
 229        }
 230        sz = uv_bios_obj_cnt * sizeof(*hub_buf);
 231        hub_buf = kzalloc(sz, GFP_KERNEL);
 232        if (!hub_buf) {
 233                ret = -ENOMEM;
 234                goto err_hub_buf;
 235        }
 236
 237        biosr = uv_bios_enum_objs((u64)uv_master_nasid, sz, (u64 *)hub_buf);
 238        if (biosr) {
 239                ret = -EINVAL;
 240                goto err_enum_objs;
 241        }
 242
 243        uv_hubs = kcalloc(uv_bios_obj_cnt, sizeof(*uv_hubs), GFP_KERNEL);
 244        if (!uv_hubs) {
 245                ret = -ENOMEM;
 246                goto err_enum_objs;
 247        }
 248
 249        for (i = 0; i < uv_bios_obj_cnt; i++) {
 250                uv_hubs[i] = kzalloc(sizeof(*uv_hubs[i]), GFP_KERNEL);
 251                if (!uv_hubs[i]) {
 252                        i--;
 253                        ret = -ENOMEM;
 254                        goto err_hubs;
 255                }
 256
 257                uv_hubs[i]->hub_info = &hub_buf[i];
 258                cache_obj_to_cnode(uv_hubs[i]->hub_info);
 259
 260                uv_hubs[i]->kobj.kset = uv_hubs_kset;
 261
 262                ret = kobject_init_and_add(&uv_hubs[i]->kobj, &hub_attr_type,
 263                                          NULL, "hub_%u", hub_buf[i].id);
 264                if (ret)
 265                        goto err_hubs;
 266                kobject_uevent(&uv_hubs[i]->kobj, KOBJ_ADD);
 267        }
 268        return 0;
 269
 270err_hubs:
 271        for (; i >= 0; i--)
 272                kobject_put(&uv_hubs[i]->kobj);
 273        kfree(uv_hubs);
 274err_enum_objs:
 275        kfree(hub_buf);
 276err_hub_buf:
 277        kset_unregister(uv_hubs_kset);
 278err_hubs_kset:
 279        kfree(prev_obj_to_cnode);
 280        return ret;
 281
 282}
 283
 284static void uv_hubs_exit(void)
 285{
 286        int i;
 287
 288        for (i = 0; i < uv_bios_obj_cnt; i++)
 289                kobject_put(&uv_hubs[i]->kobj);
 290
 291        kfree(uv_hubs);
 292        kfree(hub_buf);
 293        kset_unregister(uv_hubs_kset);
 294        kfree(prev_obj_to_cnode);
 295}
 296
 297struct uv_port {
 298        struct kobject kobj;
 299        struct uv_bios_port_info *port_info;
 300};
 301
 302#define to_uv_port(kobj_ptr) container_of(kobj_ptr, struct uv_port, kobj)
 303
 304static ssize_t uv_port_conn_hub_show(struct uv_bios_port_info *port, char *buf)
 305{
 306        return sprintf(buf, "%d\n", port->conn_id);
 307}
 308
 309static ssize_t uv_port_conn_port_show(struct uv_bios_port_info *port, char *buf)
 310{
 311        return sprintf(buf, "%d\n", port->conn_port);
 312}
 313
 314struct uv_port_sysfs_entry {
 315        struct attribute attr;
 316        ssize_t (*show)(struct uv_bios_port_info *port_info, char *buf);
 317        ssize_t (*store)(struct uv_bios_port_info *port_info, const char *buf, size_t size);
 318};
 319
 320static struct uv_port_sysfs_entry uv_port_conn_hub_attribute =
 321        __ATTR(conn_hub, 0444, uv_port_conn_hub_show, NULL);
 322static struct uv_port_sysfs_entry uv_port_conn_port_attribute =
 323        __ATTR(conn_port, 0444, uv_port_conn_port_show, NULL);
 324
 325static struct attribute *uv_port_attrs[] = {
 326        &uv_port_conn_hub_attribute.attr,
 327        &uv_port_conn_port_attribute.attr,
 328        NULL,
 329};
 330
 331static void uv_port_release(struct kobject *kobj)
 332{
 333        struct uv_port *port = to_uv_port(kobj);
 334
 335        kfree(port);
 336}
 337
 338static ssize_t uv_port_type_show(struct kobject *kobj, struct attribute *attr,
 339                                char *buf)
 340{
 341        struct uv_port *port = to_uv_port(kobj);
 342        struct uv_bios_port_info *port_info = port->port_info;
 343        struct uv_port_sysfs_entry *entry;
 344
 345        entry = container_of(attr, struct uv_port_sysfs_entry, attr);
 346
 347        if (!entry->show)
 348                return -EIO;
 349
 350        return entry->show(port_info, buf);
 351}
 352
 353static const struct sysfs_ops uv_port_sysfs_ops = {
 354        .show = uv_port_type_show,
 355};
 356
 357static struct kobj_type uv_port_attr_type = {
 358        .release        = uv_port_release,
 359        .sysfs_ops      = &uv_port_sysfs_ops,
 360        .default_attrs  = uv_port_attrs,
 361};
 362
 363static int uv_ports_init(void)
 364{
 365        s64 biosr;
 366        int j = 0, k = 0, ret, sz;
 367
 368        port_buf = kcalloc(uv_bios_obj_cnt, sizeof(*port_buf), GFP_KERNEL);
 369        if (!port_buf)
 370                return -ENOMEM;
 371
 372        for (j = 0; j < uv_bios_obj_cnt; j++) {
 373                sz = hub_buf[j].ports * sizeof(*port_buf[j]);
 374                port_buf[j] = kzalloc(sz, GFP_KERNEL);
 375                if (!port_buf[j]) {
 376                        ret = -ENOMEM;
 377                        j--;
 378                        goto err_port_info;
 379                }
 380                biosr = uv_bios_enum_ports((u64)uv_master_nasid, (u64)hub_buf[j].id, sz,
 381                                        (u64 *)port_buf[j]);
 382                if (biosr) {
 383                        ret = -EINVAL;
 384                        goto err_port_info;
 385                }
 386        }
 387        for (j = 0; j < uv_bios_obj_cnt; j++) {
 388                uv_hubs[j]->ports = kcalloc(hub_buf[j].ports,
 389                                           sizeof(*uv_hubs[j]->ports), GFP_KERNEL);
 390                if (!uv_hubs[j]->ports) {
 391                        ret = -ENOMEM;
 392                        j--;
 393                        goto err_ports;
 394                }
 395        }
 396        for (j = 0; j < uv_bios_obj_cnt; j++) {
 397                for (k = 0; k < hub_buf[j].ports; k++) {
 398                        uv_hubs[j]->ports[k] = kzalloc(sizeof(*uv_hubs[j]->ports[k]), GFP_KERNEL);
 399                        if (!uv_hubs[j]->ports[k]) {
 400                                ret = -ENOMEM;
 401                                k--;
 402                                goto err_kobj_ports;
 403                        }
 404                        uv_hubs[j]->ports[k]->port_info = &port_buf[j][k];
 405                        ret = kobject_init_and_add(&uv_hubs[j]->ports[k]->kobj, &uv_port_attr_type,
 406                                        &uv_hubs[j]->kobj, "port_%d", port_buf[j][k].port);
 407                        if (ret)
 408                                goto err_kobj_ports;
 409                        kobject_uevent(&uv_hubs[j]->ports[k]->kobj, KOBJ_ADD);
 410                }
 411        }
 412        return 0;
 413
 414err_kobj_ports:
 415        for (; j >= 0; j--) {
 416                for (; k >= 0; k--)
 417                        kobject_put(&uv_hubs[j]->ports[k]->kobj);
 418                if (j > 0)
 419                        k = hub_buf[j-1].ports - 1;
 420        }
 421        j = uv_bios_obj_cnt - 1;
 422err_ports:
 423        for (; j >= 0; j--)
 424                kfree(uv_hubs[j]->ports);
 425        j = uv_bios_obj_cnt - 1;
 426err_port_info:
 427        for (; j >= 0; j--)
 428                kfree(port_buf[j]);
 429        kfree(port_buf);
 430        return ret;
 431}
 432
 433static void uv_ports_exit(void)
 434{
 435        int j, k;
 436
 437        for (j = 0; j < uv_bios_obj_cnt; j++) {
 438                for (k = hub_buf[j].ports - 1; k >= 0; k--)
 439                        kobject_put(&uv_hubs[j]->ports[k]->kobj);
 440        }
 441        for (j = 0; j < uv_bios_obj_cnt; j++) {
 442                kfree(uv_hubs[j]->ports);
 443                kfree(port_buf[j]);
 444        }
 445        kfree(port_buf);
 446}
 447
 448struct uv_pci_top_obj {
 449        struct kobject kobj;
 450        char *type;
 451        char *location;
 452        int iio_stack;
 453        char *ppb_addr;
 454        int slot;
 455};
 456
 457#define to_uv_pci_top_obj(kobj_ptr) container_of(kobj_ptr, struct uv_pci_top_obj, kobj)
 458
 459static ssize_t uv_pci_type_show(struct uv_pci_top_obj *top_obj, char *buf)
 460{
 461        return scnprintf(buf, PAGE_SIZE, "%s\n", top_obj->type);
 462}
 463
 464static ssize_t uv_pci_location_show(struct uv_pci_top_obj *top_obj, char *buf)
 465{
 466        return scnprintf(buf, PAGE_SIZE, "%s\n", top_obj->location);
 467}
 468
 469static ssize_t uv_pci_iio_stack_show(struct uv_pci_top_obj *top_obj, char *buf)
 470{
 471        return sprintf(buf, "%d\n", top_obj->iio_stack);
 472}
 473
 474static ssize_t uv_pci_ppb_addr_show(struct uv_pci_top_obj *top_obj, char *buf)
 475{
 476        return scnprintf(buf, PAGE_SIZE, "%s\n", top_obj->ppb_addr);
 477}
 478
 479static ssize_t uv_pci_slot_show(struct uv_pci_top_obj *top_obj, char *buf)
 480{
 481        return sprintf(buf, "%d\n", top_obj->slot);
 482}
 483
 484struct uv_pci_top_sysfs_entry {
 485        struct attribute attr;
 486        ssize_t (*show)(struct uv_pci_top_obj *top_obj, char *buf);
 487        ssize_t (*store)(struct uv_pci_top_obj *top_obj, const char *buf, size_t size);
 488};
 489
 490static struct uv_pci_top_sysfs_entry uv_pci_type_attribute =
 491        __ATTR(type, 0444, uv_pci_type_show, NULL);
 492static struct uv_pci_top_sysfs_entry uv_pci_location_attribute =
 493        __ATTR(location, 0444, uv_pci_location_show, NULL);
 494static struct uv_pci_top_sysfs_entry uv_pci_iio_stack_attribute =
 495        __ATTR(iio_stack, 0444, uv_pci_iio_stack_show, NULL);
 496static struct uv_pci_top_sysfs_entry uv_pci_ppb_addr_attribute =
 497        __ATTR(ppb_addr, 0444, uv_pci_ppb_addr_show, NULL);
 498static struct uv_pci_top_sysfs_entry uv_pci_slot_attribute =
 499        __ATTR(slot, 0444, uv_pci_slot_show, NULL);
 500
 501static void uv_pci_top_release(struct kobject *kobj)
 502{
 503        struct uv_pci_top_obj *top_obj = to_uv_pci_top_obj(kobj);
 504
 505        kfree(top_obj->type);
 506        kfree(top_obj->location);
 507        kfree(top_obj->ppb_addr);
 508        kfree(top_obj);
 509}
 510
 511static ssize_t pci_top_type_show(struct kobject *kobj,
 512                        struct attribute *attr, char *buf)
 513{
 514        struct uv_pci_top_obj *top_obj = to_uv_pci_top_obj(kobj);
 515        struct uv_pci_top_sysfs_entry *entry;
 516
 517        entry = container_of(attr, struct uv_pci_top_sysfs_entry, attr);
 518
 519        if (!entry->show)
 520                return -EIO;
 521
 522        return entry->show(top_obj, buf);
 523}
 524
 525static const struct sysfs_ops uv_pci_top_sysfs_ops = {
 526        .show = pci_top_type_show,
 527};
 528
 529static struct kobj_type uv_pci_top_attr_type = {
 530        .release        = uv_pci_top_release,
 531        .sysfs_ops      = &uv_pci_top_sysfs_ops,
 532};
 533
 534static int init_pci_top_obj(struct uv_pci_top_obj *top_obj, char *line)
 535{
 536        char *start;
 537        char type[11], location[14], ppb_addr[15];
 538        int str_cnt, ret;
 539        unsigned int tmp_match[2];
 540
 541        // Minimum line length
 542        if (strlen(line) < 36)
 543                return -EINVAL;
 544
 545        //Line must match format "pcibus %4x:%2x" to be valid
 546        str_cnt = sscanf(line, "pcibus %4x:%2x", &tmp_match[0], &tmp_match[1]);
 547        if (str_cnt < 2)
 548                return -EINVAL;
 549
 550        /* Connect pcibus to segment:bus number with '_'
 551         * to concatenate name tokens.
 552         * pcibus 0000:00 ... -> pcibus_0000:00 ...
 553         */
 554        line[6] = '_';
 555
 556        /* Null terminate after the concatencated name tokens
 557         * to produce kobj name string.
 558         */
 559        line[14] = '\0';
 560
 561        // Use start to index after name tokens string for remainder of line info.
 562        start = &line[15];
 563
 564        top_obj->iio_stack = -1;
 565        top_obj->slot = -1;
 566
 567        /* r001i01b00h0 BASE IO (IIO Stack 0)
 568         * r001i01b00h1 PCIe IO (IIO Stack 1)
 569         * r001i01b03h1 PCIe SLOT
 570         * r001i01b00h0 NODE IO
 571         * r001i01b00h0 Riser
 572         * (IIO Stack #) may not be present.
 573         */
 574        if (start[0] == 'r') {
 575                str_cnt = sscanf(start, "%13s %10[^(] %*s %*s %d)",
 576                                location, type, &top_obj->iio_stack);
 577                if (str_cnt < 2)
 578                        return -EINVAL;
 579                top_obj->type = kstrdup(type, GFP_KERNEL);
 580                if (!top_obj->type)
 581                        return -ENOMEM;
 582                top_obj->location = kstrdup(location, GFP_KERNEL);
 583                if (!top_obj->location) {
 584                        kfree(top_obj->type);
 585                        return -ENOMEM;
 586                }
 587        }
 588        /* PPB at 0000:80:00.00 (slot 3)
 589         * (slot #) may not be present.
 590         */
 591        else if (start[0] == 'P') {
 592                str_cnt = sscanf(start, "%10s %*s %14s %*s %d)",
 593                                type, ppb_addr, &top_obj->slot);
 594                if (str_cnt < 2)
 595                        return -EINVAL;
 596                top_obj->type = kstrdup(type, GFP_KERNEL);
 597                if (!top_obj->type)
 598                        return -ENOMEM;
 599                top_obj->ppb_addr = kstrdup(ppb_addr, GFP_KERNEL);
 600                if (!top_obj->ppb_addr) {
 601                        kfree(top_obj->type);
 602                        return -ENOMEM;
 603                }
 604        } else
 605                return -EINVAL;
 606
 607        top_obj->kobj.kset = uv_pcibus_kset;
 608
 609        ret = kobject_init_and_add(&top_obj->kobj, &uv_pci_top_attr_type, NULL, "%s", line);
 610        if (ret)
 611                goto err_add_sysfs;
 612
 613        if (top_obj->type) {
 614                ret = sysfs_create_file(&top_obj->kobj, &uv_pci_type_attribute.attr);
 615                if (ret)
 616                        goto err_add_sysfs;
 617        }
 618        if (top_obj->location) {
 619                ret = sysfs_create_file(&top_obj->kobj, &uv_pci_location_attribute.attr);
 620                if (ret)
 621                        goto err_add_sysfs;
 622        }
 623        if (top_obj->iio_stack >= 0) {
 624                ret = sysfs_create_file(&top_obj->kobj, &uv_pci_iio_stack_attribute.attr);
 625                if (ret)
 626                        goto err_add_sysfs;
 627        }
 628        if (top_obj->ppb_addr) {
 629                ret = sysfs_create_file(&top_obj->kobj, &uv_pci_ppb_addr_attribute.attr);
 630                if (ret)
 631                        goto err_add_sysfs;
 632        }
 633        if (top_obj->slot >= 0) {
 634                ret = sysfs_create_file(&top_obj->kobj, &uv_pci_slot_attribute.attr);
 635                if (ret)
 636                        goto err_add_sysfs;
 637        }
 638
 639        kobject_uevent(&top_obj->kobj, KOBJ_ADD);
 640        return 0;
 641
 642err_add_sysfs:
 643        kobject_put(&top_obj->kobj);
 644        return ret;
 645}
 646
 647static int pci_topology_init(void)
 648{
 649        char *pci_top_str, *start, *found, *count;
 650        size_t sz;
 651        s64 biosr;
 652        int l = 0, k = 0;
 653        int len, ret;
 654
 655        uv_pcibus_kset = kset_create_and_add("pcibuses", NULL, sgi_uv_kobj);
 656        if (!uv_pcibus_kset)
 657                return -ENOMEM;
 658
 659        for (sz = PAGE_SIZE; sz < 16 * PAGE_SIZE; sz += PAGE_SIZE) {
 660                pci_top_str = kmalloc(sz, GFP_KERNEL);
 661                if (!pci_top_str) {
 662                        ret = -ENOMEM;
 663                        goto err_pci_top_str;
 664                }
 665                biosr = uv_bios_get_pci_topology((u64)sz, (u64 *)pci_top_str);
 666                if (biosr == BIOS_STATUS_SUCCESS) {
 667                        len = strnlen(pci_top_str, sz);
 668                        for (count = pci_top_str; count < pci_top_str + len; count++) {
 669                                if (*count == '\n')
 670                                        l++;
 671                        }
 672                        num_pci_lines = l;
 673
 674                        uv_pci_objs = kcalloc(num_pci_lines,
 675                                             sizeof(*uv_pci_objs), GFP_KERNEL);
 676                        if (!uv_pci_objs) {
 677                                kfree(pci_top_str);
 678                                ret = -ENOMEM;
 679                                goto err_pci_top_str;
 680                        }
 681                        start = pci_top_str;
 682                        while ((found = strsep(&start, "\n")) != NULL) {
 683                                uv_pci_objs[k] = kzalloc(sizeof(*uv_pci_objs[k]), GFP_KERNEL);
 684                                if (!uv_pci_objs[k]) {
 685                                        ret = -ENOMEM;
 686                                        goto err_pci_obj;
 687                                }
 688                                ret = init_pci_top_obj(uv_pci_objs[k], found);
 689                                if (ret)
 690                                        goto err_pci_obj;
 691                                k++;
 692                                if (k == num_pci_lines)
 693                                        break;
 694                        }
 695                }
 696                kfree(pci_top_str);
 697                if (biosr == BIOS_STATUS_SUCCESS || biosr == BIOS_STATUS_UNIMPLEMENTED)
 698                        break;
 699        }
 700
 701        return 0;
 702err_pci_obj:
 703        k--;
 704        for (; k >= 0; k--)
 705                kobject_put(&uv_pci_objs[k]->kobj);
 706        kfree(uv_pci_objs);
 707        kfree(pci_top_str);
 708err_pci_top_str:
 709        kset_unregister(uv_pcibus_kset);
 710        return ret;
 711}
 712
 713static void pci_topology_exit(void)
 714{
 715        int k;
 716
 717        for (k = 0; k < num_pci_lines; k++)
 718                kobject_put(&uv_pci_objs[k]->kobj);
 719        kset_unregister(uv_pcibus_kset);
 720        kfree(uv_pci_objs);
 721}
 722
 723static ssize_t partition_id_show(struct kobject *kobj,
 724                        struct kobj_attribute *attr, char *buf)
 725{
 726        return sprintf(buf, "%ld\n", sn_partition_id);
 727}
 728
 729static ssize_t coherence_id_show(struct kobject *kobj,
 730                        struct kobj_attribute *attr, char *buf)
 731{
 732        return sprintf(buf, "%ld\n", sn_coherency_id);
 733}
 734
 735static ssize_t uv_type_show(struct kobject *kobj,
 736                        struct kobj_attribute *attr, char *buf)
 737{
 738        return scnprintf(buf, PAGE_SIZE, "%s\n", uv_type_string());
 739}
 740
 741static ssize_t uv_archtype_show(struct kobject *kobj,
 742                        struct kobj_attribute *attr, char *buf)
 743{
 744        return uv_get_archtype(buf, PAGE_SIZE);
 745}
 746
 747static ssize_t uv_hub_type_show(struct kobject *kobj,
 748                        struct kobj_attribute *attr, char *buf)
 749{
 750        return scnprintf(buf, PAGE_SIZE, "0x%x\n", uv_hub_type());
 751}
 752
 753static ssize_t uv_hubless_show(struct kobject *kobj,
 754                        struct kobj_attribute *attr, char *buf)
 755{
 756        return scnprintf(buf, PAGE_SIZE, "0x%x\n", uv_get_hubless_system());
 757}
 758
 759static struct kobj_attribute partition_id_attr =
 760        __ATTR(partition_id, 0444, partition_id_show, NULL);
 761static struct kobj_attribute coherence_id_attr =
 762        __ATTR(coherence_id, 0444, coherence_id_show, NULL);
 763static struct kobj_attribute uv_type_attr =
 764        __ATTR(uv_type, 0444, uv_type_show, NULL);
 765static struct kobj_attribute uv_archtype_attr =
 766        __ATTR(archtype, 0444, uv_archtype_show, NULL);
 767static struct kobj_attribute uv_hub_type_attr =
 768        __ATTR(hub_type, 0444, uv_hub_type_show, NULL);
 769static struct kobj_attribute uv_hubless_attr =
 770        __ATTR(hubless, 0444, uv_hubless_show, NULL);
 771
 772static struct attribute *base_attrs[] = {
 773        &partition_id_attr.attr,
 774        &coherence_id_attr.attr,
 775        &uv_type_attr.attr,
 776        &uv_archtype_attr.attr,
 777        &uv_hub_type_attr.attr,
 778        NULL,
 779};
 780
 781static const struct attribute_group base_attr_group = {
 782        .attrs = base_attrs
 783};
 784
 785static int initial_bios_setup(void)
 786{
 787        u64 v;
 788        s64 biosr;
 789
 790        biosr = uv_bios_get_master_nasid((u64)sizeof(uv_master_nasid), (u64 *)&uv_master_nasid);
 791        if (biosr)
 792                return -EINVAL;
 793
 794        biosr = uv_bios_get_heapsize((u64)uv_master_nasid, (u64)sizeof(u64), &v);
 795        if (biosr)
 796                return -EINVAL;
 797
 798        uv_biosheap = vmalloc(v);
 799        if (!uv_biosheap)
 800                return -ENOMEM;
 801
 802        biosr = uv_bios_install_heap((u64)uv_master_nasid, v, (u64 *)uv_biosheap);
 803        if (biosr) {
 804                vfree(uv_biosheap);
 805                return -EINVAL;
 806        }
 807
 808        biosr = uv_bios_obj_count((u64)uv_master_nasid, sizeof(u64), &v);
 809        if (biosr) {
 810                vfree(uv_biosheap);
 811                return -EINVAL;
 812        }
 813        uv_bios_obj_cnt = (int)v;
 814
 815        return 0;
 816}
 817
 818static struct attribute *hubless_base_attrs[] = {
 819        &partition_id_attr.attr,
 820        &uv_type_attr.attr,
 821        &uv_archtype_attr.attr,
 822        &uv_hubless_attr.attr,
 823        NULL,
 824};
 825
 826static const struct attribute_group hubless_base_attr_group = {
 827        .attrs = hubless_base_attrs
 828};
 829
 830
 831static int __init uv_sysfs_hubless_init(void)
 832{
 833        int ret;
 834
 835        ret = sysfs_create_group(sgi_uv_kobj, &hubless_base_attr_group);
 836        if (ret) {
 837                pr_warn("sysfs_create_group hubless_base_attr_group failed\n");
 838                kobject_put(sgi_uv_kobj);
 839        }
 840        return ret;
 841}
 842
 843static int __init uv_sysfs_init(void)
 844{
 845        int ret = 0;
 846
 847        if (!is_uv_system() && !uv_get_hubless_system())
 848                return -ENODEV;
 849
 850        num_cnodes = uv_num_possible_blades();
 851
 852        if (!sgi_uv_kobj)
 853                sgi_uv_kobj = kobject_create_and_add("sgi_uv", firmware_kobj);
 854        if (!sgi_uv_kobj) {
 855                pr_warn("kobject_create_and_add sgi_uv failed\n");
 856                return -EINVAL;
 857        }
 858
 859        if (uv_get_hubless_system())
 860                return uv_sysfs_hubless_init();
 861
 862        ret = sysfs_create_group(sgi_uv_kobj, &base_attr_group);
 863        if (ret) {
 864                pr_warn("sysfs_create_group base_attr_group failed\n");
 865                goto err_create_group;
 866        }
 867
 868        ret = initial_bios_setup();
 869        if (ret)
 870                goto err_bios_setup;
 871
 872        ret = uv_hubs_init();
 873        if (ret)
 874                goto err_hubs_init;
 875
 876        ret = uv_ports_init();
 877        if (ret)
 878                goto err_ports_init;
 879
 880        ret = pci_topology_init();
 881        if (ret)
 882                goto err_pci_init;
 883
 884        return 0;
 885
 886err_pci_init:
 887        uv_ports_exit();
 888err_ports_init:
 889        uv_hubs_exit();
 890err_hubs_init:
 891        vfree(uv_biosheap);
 892err_bios_setup:
 893        sysfs_remove_group(sgi_uv_kobj, &base_attr_group);
 894err_create_group:
 895        kobject_put(sgi_uv_kobj);
 896        return ret;
 897}
 898
 899static void __exit uv_sysfs_hubless_exit(void)
 900{
 901        sysfs_remove_group(sgi_uv_kobj, &hubless_base_attr_group);
 902        kobject_put(sgi_uv_kobj);
 903}
 904
 905static void __exit uv_sysfs_exit(void)
 906{
 907        if (!is_uv_system()) {
 908                if (uv_get_hubless_system())
 909                        uv_sysfs_hubless_exit();
 910                return;
 911        }
 912
 913        pci_topology_exit();
 914        uv_ports_exit();
 915        uv_hubs_exit();
 916        vfree(uv_biosheap);
 917        sysfs_remove_group(sgi_uv_kobj, &base_attr_group);
 918        kobject_put(sgi_uv_kobj);
 919}
 920
 921#ifndef MODULE
 922device_initcall(uv_sysfs_init);
 923#else
 924module_init(uv_sysfs_init);
 925#endif
 926module_exit(uv_sysfs_exit);
 927
 928MODULE_AUTHOR("Hewlett Packard Enterprise");
 929MODULE_LICENSE("GPL");
 930