linux/arch/powerpc/platforms/ps3/repository.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  PS3 repository routines.
   4 *
   5 *  Copyright (C) 2006 Sony Computer Entertainment Inc.
   6 *  Copyright 2006 Sony Corp.
   7 */
   8
   9#include <asm/lv1call.h>
  10
  11#include "platform.h"
  12
  13enum ps3_vendor_id {
  14        PS3_VENDOR_ID_NONE = 0,
  15        PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
  16};
  17
  18enum ps3_lpar_id {
  19        PS3_LPAR_ID_CURRENT = 0,
  20        PS3_LPAR_ID_PME = 1,
  21};
  22
  23#define dump_field(_a, _b) _dump_field(_a, _b, __func__, __LINE__)
  24static void _dump_field(const char *hdr, u64 n, const char *func, int line)
  25{
  26#if defined(DEBUG)
  27        char s[16];
  28        const char *const in = (const char *)&n;
  29        unsigned int i;
  30
  31        for (i = 0; i < 8; i++)
  32                s[i] = (in[i] <= 126 && in[i] >= 32) ? in[i] : '.';
  33        s[i] = 0;
  34
  35        pr_devel("%s:%d: %s%016llx : %s\n", func, line, hdr, n, s);
  36#endif
  37}
  38
  39#define dump_node_name(_a, _b, _c, _d, _e) \
  40        _dump_node_name(_a, _b, _c, _d, _e, __func__, __LINE__)
  41static void _dump_node_name(unsigned int lpar_id, u64 n1, u64 n2, u64 n3,
  42        u64 n4, const char *func, int line)
  43{
  44        pr_devel("%s:%d: lpar: %u\n", func, line, lpar_id);
  45        _dump_field("n1: ", n1, func, line);
  46        _dump_field("n2: ", n2, func, line);
  47        _dump_field("n3: ", n3, func, line);
  48        _dump_field("n4: ", n4, func, line);
  49}
  50
  51#define dump_node(_a, _b, _c, _d, _e, _f, _g) \
  52        _dump_node(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__)
  53static void _dump_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,
  54        u64 v1, u64 v2, const char *func, int line)
  55{
  56        pr_devel("%s:%d: lpar: %u\n", func, line, lpar_id);
  57        _dump_field("n1: ", n1, func, line);
  58        _dump_field("n2: ", n2, func, line);
  59        _dump_field("n3: ", n3, func, line);
  60        _dump_field("n4: ", n4, func, line);
  61        pr_devel("%s:%d: v1: %016llx\n", func, line, v1);
  62        pr_devel("%s:%d: v2: %016llx\n", func, line, v2);
  63}
  64
  65/**
  66 * make_first_field - Make the first field of a repository node name.
  67 * @text: Text portion of the field.
  68 * @index: Numeric index portion of the field.  Use zero for 'don't care'.
  69 *
  70 * This routine sets the vendor id to zero (non-vendor specific).
  71 * Returns field value.
  72 */
  73
  74static u64 make_first_field(const char *text, u64 index)
  75{
  76        u64 n;
  77
  78        strncpy((char *)&n, text, 8);
  79        return PS3_VENDOR_ID_NONE + (n >> 32) + index;
  80}
  81
  82/**
  83 * make_field - Make subsequent fields of a repository node name.
  84 * @text: Text portion of the field.  Use "" for 'don't care'.
  85 * @index: Numeric index portion of the field.  Use zero for 'don't care'.
  86 *
  87 * Returns field value.
  88 */
  89
  90static u64 make_field(const char *text, u64 index)
  91{
  92        u64 n = 0;
  93
  94        memcpy((char *)&n, text, strnlen(text, sizeof(n)));
  95        return n + index;
  96}
  97
  98/**
  99 * read_node - Read a repository node from raw fields.
 100 * @n1: First field of node name.
 101 * @n2: Second field of node name.  Use zero for 'don't care'.
 102 * @n3: Third field of node name.  Use zero for 'don't care'.
 103 * @n4: Fourth field of node name.  Use zero for 'don't care'.
 104 * @v1: First repository value (high word).
 105 * @v2: Second repository value (low word).  Optional parameter, use zero
 106 *      for 'don't care'.
 107 */
 108
 109static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,
 110        u64 *_v1, u64 *_v2)
 111{
 112        int result;
 113        u64 v1;
 114        u64 v2;
 115
 116        if (lpar_id == PS3_LPAR_ID_CURRENT) {
 117                u64 id;
 118                lv1_get_logical_partition_id(&id);
 119                lpar_id = id;
 120        }
 121
 122        result = lv1_read_repository_node(lpar_id, n1, n2, n3, n4, &v1,
 123                &v2);
 124
 125        if (result) {
 126                pr_warn("%s:%d: lv1_read_repository_node failed: %s\n",
 127                        __func__, __LINE__, ps3_result(result));
 128                dump_node_name(lpar_id, n1, n2, n3, n4);
 129                return -ENOENT;
 130        }
 131
 132        dump_node(lpar_id, n1, n2, n3, n4, v1, v2);
 133
 134        if (_v1)
 135                *_v1 = v1;
 136        if (_v2)
 137                *_v2 = v2;
 138
 139        if (v1 && !_v1)
 140                pr_devel("%s:%d: warning: discarding non-zero v1: %016llx\n",
 141                        __func__, __LINE__, v1);
 142        if (v2 && !_v2)
 143                pr_devel("%s:%d: warning: discarding non-zero v2: %016llx\n",
 144                        __func__, __LINE__, v2);
 145
 146        return 0;
 147}
 148
 149int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
 150        u64 *value)
 151{
 152        return read_node(PS3_LPAR_ID_PME,
 153                make_first_field("bus", bus_index),
 154                make_field(bus_str, 0),
 155                0, 0,
 156                value, NULL);
 157}
 158
 159int ps3_repository_read_bus_id(unsigned int bus_index, u64 *bus_id)
 160{
 161        return read_node(PS3_LPAR_ID_PME, make_first_field("bus", bus_index),
 162                         make_field("id", 0), 0, 0, bus_id, NULL);
 163}
 164
 165int ps3_repository_read_bus_type(unsigned int bus_index,
 166        enum ps3_bus_type *bus_type)
 167{
 168        int result;
 169        u64 v1 = 0;
 170
 171        result = read_node(PS3_LPAR_ID_PME,
 172                make_first_field("bus", bus_index),
 173                make_field("type", 0),
 174                0, 0,
 175                &v1, NULL);
 176        *bus_type = v1;
 177        return result;
 178}
 179
 180int ps3_repository_read_bus_num_dev(unsigned int bus_index,
 181        unsigned int *num_dev)
 182{
 183        int result;
 184        u64 v1 = 0;
 185
 186        result = read_node(PS3_LPAR_ID_PME,
 187                make_first_field("bus", bus_index),
 188                make_field("num_dev", 0),
 189                0, 0,
 190                &v1, NULL);
 191        *num_dev = v1;
 192        return result;
 193}
 194
 195int ps3_repository_read_dev_str(unsigned int bus_index,
 196        unsigned int dev_index, const char *dev_str, u64 *value)
 197{
 198        return read_node(PS3_LPAR_ID_PME,
 199                make_first_field("bus", bus_index),
 200                make_field("dev", dev_index),
 201                make_field(dev_str, 0),
 202                0,
 203                value, NULL);
 204}
 205
 206int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index,
 207        u64 *dev_id)
 208{
 209        return read_node(PS3_LPAR_ID_PME, make_first_field("bus", bus_index),
 210                         make_field("dev", dev_index), make_field("id", 0), 0,
 211                         dev_id, NULL);
 212}
 213
 214int ps3_repository_read_dev_type(unsigned int bus_index,
 215        unsigned int dev_index, enum ps3_dev_type *dev_type)
 216{
 217        int result;
 218        u64 v1 = 0;
 219
 220        result = read_node(PS3_LPAR_ID_PME,
 221                make_first_field("bus", bus_index),
 222                make_field("dev", dev_index),
 223                make_field("type", 0),
 224                0,
 225                &v1, NULL);
 226        *dev_type = v1;
 227        return result;
 228}
 229
 230int ps3_repository_read_dev_intr(unsigned int bus_index,
 231        unsigned int dev_index, unsigned int intr_index,
 232        enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id)
 233{
 234        int result;
 235        u64 v1 = 0;
 236        u64 v2 = 0;
 237
 238        result = read_node(PS3_LPAR_ID_PME,
 239                make_first_field("bus", bus_index),
 240                make_field("dev", dev_index),
 241                make_field("intr", intr_index),
 242                0,
 243                &v1, &v2);
 244        *intr_type = v1;
 245        *interrupt_id = v2;
 246        return result;
 247}
 248
 249int ps3_repository_read_dev_reg_type(unsigned int bus_index,
 250        unsigned int dev_index, unsigned int reg_index,
 251        enum ps3_reg_type *reg_type)
 252{
 253        int result;
 254        u64 v1 = 0;
 255
 256        result = read_node(PS3_LPAR_ID_PME,
 257                make_first_field("bus", bus_index),
 258                make_field("dev", dev_index),
 259                make_field("reg", reg_index),
 260                make_field("type", 0),
 261                &v1, NULL);
 262        *reg_type = v1;
 263        return result;
 264}
 265
 266int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
 267        unsigned int dev_index, unsigned int reg_index, u64 *bus_addr, u64 *len)
 268{
 269        return read_node(PS3_LPAR_ID_PME,
 270                make_first_field("bus", bus_index),
 271                make_field("dev", dev_index),
 272                make_field("reg", reg_index),
 273                make_field("data", 0),
 274                bus_addr, len);
 275}
 276
 277int ps3_repository_read_dev_reg(unsigned int bus_index,
 278        unsigned int dev_index, unsigned int reg_index,
 279        enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len)
 280{
 281        int result = ps3_repository_read_dev_reg_type(bus_index, dev_index,
 282                reg_index, reg_type);
 283        return result ? result
 284                : ps3_repository_read_dev_reg_addr(bus_index, dev_index,
 285                reg_index, bus_addr, len);
 286}
 287
 288
 289
 290int ps3_repository_find_device(struct ps3_repository_device *repo)
 291{
 292        int result;
 293        struct ps3_repository_device tmp = *repo;
 294        unsigned int num_dev;
 295
 296        BUG_ON(repo->bus_index > 10);
 297        BUG_ON(repo->dev_index > 10);
 298
 299        result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev);
 300
 301        if (result) {
 302                pr_devel("%s:%d read_bus_num_dev failed\n", __func__, __LINE__);
 303                return result;
 304        }
 305
 306        pr_devel("%s:%d: bus_type %u, bus_index %u, bus_id %llu, num_dev %u\n",
 307                __func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id,
 308                num_dev);
 309
 310        if (tmp.dev_index >= num_dev) {
 311                pr_devel("%s:%d: no device found\n", __func__, __LINE__);
 312                return -ENODEV;
 313        }
 314
 315        result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index,
 316                &tmp.dev_type);
 317
 318        if (result) {
 319                pr_devel("%s:%d read_dev_type failed\n", __func__, __LINE__);
 320                return result;
 321        }
 322
 323        result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index,
 324                &tmp.dev_id);
 325
 326        if (result) {
 327                pr_devel("%s:%d ps3_repository_read_dev_id failed\n", __func__,
 328                __LINE__);
 329                return result;
 330        }
 331
 332        pr_devel("%s:%d: found: dev_type %u, dev_index %u, dev_id %llu\n",
 333                __func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id);
 334
 335        *repo = tmp;
 336        return 0;
 337}
 338
 339int ps3_repository_find_device_by_id(struct ps3_repository_device *repo,
 340                                     u64 bus_id, u64 dev_id)
 341{
 342        int result = -ENODEV;
 343        struct ps3_repository_device tmp;
 344        unsigned int num_dev;
 345
 346        pr_devel(" -> %s:%u: find device by id %llu:%llu\n", __func__, __LINE__,
 347                 bus_id, dev_id);
 348
 349        for (tmp.bus_index = 0; tmp.bus_index < 10; tmp.bus_index++) {
 350                result = ps3_repository_read_bus_id(tmp.bus_index,
 351                                                    &tmp.bus_id);
 352                if (result) {
 353                        pr_devel("%s:%u read_bus_id(%u) failed\n", __func__,
 354                                 __LINE__, tmp.bus_index);
 355                        return result;
 356                }
 357
 358                if (tmp.bus_id == bus_id)
 359                        goto found_bus;
 360
 361                pr_devel("%s:%u: skip, bus_id %llu\n", __func__, __LINE__,
 362                         tmp.bus_id);
 363        }
 364        pr_devel(" <- %s:%u: bus not found\n", __func__, __LINE__);
 365        return result;
 366
 367found_bus:
 368        result = ps3_repository_read_bus_type(tmp.bus_index, &tmp.bus_type);
 369        if (result) {
 370                pr_devel("%s:%u read_bus_type(%u) failed\n", __func__,
 371                         __LINE__, tmp.bus_index);
 372                return result;
 373        }
 374
 375        result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev);
 376        if (result) {
 377                pr_devel("%s:%u read_bus_num_dev failed\n", __func__,
 378                         __LINE__);
 379                return result;
 380        }
 381
 382        for (tmp.dev_index = 0; tmp.dev_index < num_dev; tmp.dev_index++) {
 383                result = ps3_repository_read_dev_id(tmp.bus_index,
 384                                                    tmp.dev_index,
 385                                                    &tmp.dev_id);
 386                if (result) {
 387                        pr_devel("%s:%u read_dev_id(%u:%u) failed\n", __func__,
 388                                 __LINE__, tmp.bus_index, tmp.dev_index);
 389                        return result;
 390                }
 391
 392                if (tmp.dev_id == dev_id)
 393                        goto found_dev;
 394
 395                pr_devel("%s:%u: skip, dev_id %llu\n", __func__, __LINE__,
 396                         tmp.dev_id);
 397        }
 398        pr_devel(" <- %s:%u: dev not found\n", __func__, __LINE__);
 399        return result;
 400
 401found_dev:
 402        result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index,
 403                                              &tmp.dev_type);
 404        if (result) {
 405                pr_devel("%s:%u read_dev_type failed\n", __func__, __LINE__);
 406                return result;
 407        }
 408
 409        pr_devel(" <- %s:%u: found: type (%u:%u) index (%u:%u) id (%llu:%llu)\n",
 410                 __func__, __LINE__, tmp.bus_type, tmp.dev_type, tmp.bus_index,
 411                 tmp.dev_index, tmp.bus_id, tmp.dev_id);
 412        *repo = tmp;
 413        return 0;
 414}
 415
 416int ps3_repository_find_devices(enum ps3_bus_type bus_type,
 417        int (*callback)(const struct ps3_repository_device *repo))
 418{
 419        int result = 0;
 420        struct ps3_repository_device repo;
 421
 422        pr_devel(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type);
 423
 424        repo.bus_type = bus_type;
 425        result = ps3_repository_find_bus(repo.bus_type, 0, &repo.bus_index);
 426        if (result) {
 427                pr_devel(" <- %s:%u: bus not found\n", __func__, __LINE__);
 428                return result;
 429        }
 430
 431        result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id);
 432        if (result) {
 433                pr_devel("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__,
 434                         repo.bus_index);
 435                return result;
 436        }
 437
 438        for (repo.dev_index = 0; ; repo.dev_index++) {
 439                result = ps3_repository_find_device(&repo);
 440                if (result == -ENODEV) {
 441                        result = 0;
 442                        break;
 443                } else if (result)
 444                        break;
 445
 446                result = callback(&repo);
 447                if (result) {
 448                        pr_devel("%s:%d: abort at callback\n", __func__,
 449                                __LINE__);
 450                        break;
 451                }
 452        }
 453
 454        pr_devel(" <- %s:%d\n", __func__, __LINE__);
 455        return result;
 456}
 457
 458int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from,
 459        unsigned int *bus_index)
 460{
 461        unsigned int i;
 462        enum ps3_bus_type type;
 463        int error;
 464
 465        for (i = from; i < 10; i++) {
 466                error = ps3_repository_read_bus_type(i, &type);
 467                if (error) {
 468                        pr_devel("%s:%d read_bus_type failed\n",
 469                                __func__, __LINE__);
 470                        *bus_index = UINT_MAX;
 471                        return error;
 472                }
 473                if (type == bus_type) {
 474                        *bus_index = i;
 475                        return 0;
 476                }
 477        }
 478        *bus_index = UINT_MAX;
 479        return -ENODEV;
 480}
 481
 482int ps3_repository_find_interrupt(const struct ps3_repository_device *repo,
 483        enum ps3_interrupt_type intr_type, unsigned int *interrupt_id)
 484{
 485        int result = 0;
 486        unsigned int res_index;
 487
 488        pr_devel("%s:%d: find intr_type %u\n", __func__, __LINE__, intr_type);
 489
 490        *interrupt_id = UINT_MAX;
 491
 492        for (res_index = 0; res_index < 10; res_index++) {
 493                enum ps3_interrupt_type t;
 494                unsigned int id;
 495
 496                result = ps3_repository_read_dev_intr(repo->bus_index,
 497                        repo->dev_index, res_index, &t, &id);
 498
 499                if (result) {
 500                        pr_devel("%s:%d read_dev_intr failed\n",
 501                                __func__, __LINE__);
 502                        return result;
 503                }
 504
 505                if (t == intr_type) {
 506                        *interrupt_id = id;
 507                        break;
 508                }
 509        }
 510
 511        if (res_index == 10)
 512                return -ENODEV;
 513
 514        pr_devel("%s:%d: found intr_type %u at res_index %u\n",
 515                __func__, __LINE__, intr_type, res_index);
 516
 517        return result;
 518}
 519
 520int ps3_repository_find_reg(const struct ps3_repository_device *repo,
 521        enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len)
 522{
 523        int result = 0;
 524        unsigned int res_index;
 525
 526        pr_devel("%s:%d: find reg_type %u\n", __func__, __LINE__, reg_type);
 527
 528        *bus_addr = *len = 0;
 529
 530        for (res_index = 0; res_index < 10; res_index++) {
 531                enum ps3_reg_type t;
 532                u64 a;
 533                u64 l;
 534
 535                result = ps3_repository_read_dev_reg(repo->bus_index,
 536                        repo->dev_index, res_index, &t, &a, &l);
 537
 538                if (result) {
 539                        pr_devel("%s:%d read_dev_reg failed\n",
 540                                __func__, __LINE__);
 541                        return result;
 542                }
 543
 544                if (t == reg_type) {
 545                        *bus_addr = a;
 546                        *len = l;
 547                        break;
 548                }
 549        }
 550
 551        if (res_index == 10)
 552                return -ENODEV;
 553
 554        pr_devel("%s:%d: found reg_type %u at res_index %u\n",
 555                __func__, __LINE__, reg_type, res_index);
 556
 557        return result;
 558}
 559
 560int ps3_repository_read_stor_dev_port(unsigned int bus_index,
 561        unsigned int dev_index, u64 *port)
 562{
 563        return read_node(PS3_LPAR_ID_PME,
 564                make_first_field("bus", bus_index),
 565                make_field("dev", dev_index),
 566                make_field("port", 0),
 567                0, port, NULL);
 568}
 569
 570int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index,
 571        unsigned int dev_index, u64 *blk_size)
 572{
 573        return read_node(PS3_LPAR_ID_PME,
 574                make_first_field("bus", bus_index),
 575                make_field("dev", dev_index),
 576                make_field("blk_size", 0),
 577                0, blk_size, NULL);
 578}
 579
 580int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index,
 581        unsigned int dev_index, u64 *num_blocks)
 582{
 583        return read_node(PS3_LPAR_ID_PME,
 584                make_first_field("bus", bus_index),
 585                make_field("dev", dev_index),
 586                make_field("n_blocks", 0),
 587                0, num_blocks, NULL);
 588}
 589
 590int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index,
 591        unsigned int dev_index, unsigned int *num_regions)
 592{
 593        int result;
 594        u64 v1 = 0;
 595
 596        result = read_node(PS3_LPAR_ID_PME,
 597                make_first_field("bus", bus_index),
 598                make_field("dev", dev_index),
 599                make_field("n_regs", 0),
 600                0, &v1, NULL);
 601        *num_regions = v1;
 602        return result;
 603}
 604
 605int ps3_repository_read_stor_dev_region_id(unsigned int bus_index,
 606        unsigned int dev_index, unsigned int region_index,
 607        unsigned int *region_id)
 608{
 609        int result;
 610        u64 v1 = 0;
 611
 612        result = read_node(PS3_LPAR_ID_PME,
 613            make_first_field("bus", bus_index),
 614            make_field("dev", dev_index),
 615            make_field("region", region_index),
 616            make_field("id", 0),
 617            &v1, NULL);
 618        *region_id = v1;
 619        return result;
 620}
 621
 622int ps3_repository_read_stor_dev_region_size(unsigned int bus_index,
 623        unsigned int dev_index, unsigned int region_index, u64 *region_size)
 624{
 625        return read_node(PS3_LPAR_ID_PME,
 626            make_first_field("bus", bus_index),
 627            make_field("dev", dev_index),
 628            make_field("region", region_index),
 629            make_field("size", 0),
 630            region_size, NULL);
 631}
 632
 633int ps3_repository_read_stor_dev_region_start(unsigned int bus_index,
 634        unsigned int dev_index, unsigned int region_index, u64 *region_start)
 635{
 636        return read_node(PS3_LPAR_ID_PME,
 637            make_first_field("bus", bus_index),
 638            make_field("dev", dev_index),
 639            make_field("region", region_index),
 640            make_field("start", 0),
 641            region_start, NULL);
 642}
 643
 644int ps3_repository_read_stor_dev_info(unsigned int bus_index,
 645        unsigned int dev_index, u64 *port, u64 *blk_size,
 646        u64 *num_blocks, unsigned int *num_regions)
 647{
 648        int result;
 649
 650        result = ps3_repository_read_stor_dev_port(bus_index, dev_index, port);
 651        if (result)
 652            return result;
 653
 654        result = ps3_repository_read_stor_dev_blk_size(bus_index, dev_index,
 655                blk_size);
 656        if (result)
 657            return result;
 658
 659        result = ps3_repository_read_stor_dev_num_blocks(bus_index, dev_index,
 660                num_blocks);
 661        if (result)
 662            return result;
 663
 664        result = ps3_repository_read_stor_dev_num_regions(bus_index, dev_index,
 665                num_regions);
 666        return result;
 667}
 668
 669int ps3_repository_read_stor_dev_region(unsigned int bus_index,
 670        unsigned int dev_index, unsigned int region_index,
 671        unsigned int *region_id, u64 *region_start, u64 *region_size)
 672{
 673        int result;
 674
 675        result = ps3_repository_read_stor_dev_region_id(bus_index, dev_index,
 676                region_index, region_id);
 677        if (result)
 678            return result;
 679
 680        result = ps3_repository_read_stor_dev_region_start(bus_index, dev_index,
 681                region_index, region_start);
 682        if (result)
 683            return result;
 684
 685        result = ps3_repository_read_stor_dev_region_size(bus_index, dev_index,
 686                region_index, region_size);
 687        return result;
 688}
 689
 690/**
 691 * ps3_repository_read_num_pu - Number of logical PU processors for this lpar.
 692 */
 693
 694int ps3_repository_read_num_pu(u64 *num_pu)
 695{
 696        *num_pu = 0;
 697        return read_node(PS3_LPAR_ID_CURRENT,
 698                           make_first_field("bi", 0),
 699                           make_field("pun", 0),
 700                           0, 0,
 701                           num_pu, NULL);
 702}
 703
 704/**
 705 * ps3_repository_read_pu_id - Read the logical PU id.
 706 * @pu_index: Zero based index.
 707 * @pu_id: The logical PU id.
 708 */
 709
 710int ps3_repository_read_pu_id(unsigned int pu_index, u64 *pu_id)
 711{
 712        return read_node(PS3_LPAR_ID_CURRENT,
 713                make_first_field("bi", 0),
 714                make_field("pu", pu_index),
 715                0, 0,
 716                pu_id, NULL);
 717}
 718
 719int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size)
 720{
 721        return read_node(PS3_LPAR_ID_CURRENT,
 722                make_first_field("bi", 0),
 723                make_field("pu", 0),
 724                ppe_id,
 725                make_field("rm_size", 0),
 726                rm_size, NULL);
 727}
 728
 729int ps3_repository_read_region_total(u64 *region_total)
 730{
 731        return read_node(PS3_LPAR_ID_CURRENT,
 732                make_first_field("bi", 0),
 733                make_field("rgntotal", 0),
 734                0, 0,
 735                region_total, NULL);
 736}
 737
 738/**
 739 * ps3_repository_read_mm_info - Read mm info for single pu system.
 740 * @rm_base: Real mode memory base address.
 741 * @rm_size: Real mode memory size.
 742 * @region_total: Maximum memory region size.
 743 */
 744
 745int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total)
 746{
 747        int result;
 748        u64 ppe_id;
 749
 750        lv1_get_logical_ppe_id(&ppe_id);
 751        *rm_base = 0;
 752        result = ps3_repository_read_rm_size(ppe_id, rm_size);
 753        return result ? result
 754                : ps3_repository_read_region_total(region_total);
 755}
 756
 757/**
 758 * ps3_repository_read_highmem_region_count - Read the number of highmem regions
 759 *
 760 * Bootloaders must arrange the repository nodes such that regions are indexed
 761 * with a region_index from 0 to region_count-1.
 762 */
 763
 764int ps3_repository_read_highmem_region_count(unsigned int *region_count)
 765{
 766        int result;
 767        u64 v1 = 0;
 768
 769        result = read_node(PS3_LPAR_ID_CURRENT,
 770                make_first_field("highmem", 0),
 771                make_field("region", 0),
 772                make_field("count", 0),
 773                0,
 774                &v1, NULL);
 775        *region_count = v1;
 776        return result;
 777}
 778
 779
 780int ps3_repository_read_highmem_base(unsigned int region_index,
 781        u64 *highmem_base)
 782{
 783        return read_node(PS3_LPAR_ID_CURRENT,
 784                make_first_field("highmem", 0),
 785                make_field("region", region_index),
 786                make_field("base", 0),
 787                0,
 788                highmem_base, NULL);
 789}
 790
 791int ps3_repository_read_highmem_size(unsigned int region_index,
 792        u64 *highmem_size)
 793{
 794        return read_node(PS3_LPAR_ID_CURRENT,
 795                make_first_field("highmem", 0),
 796                make_field("region", region_index),
 797                make_field("size", 0),
 798                0,
 799                highmem_size, NULL);
 800}
 801
 802/**
 803 * ps3_repository_read_highmem_info - Read high memory region info
 804 * @region_index: Region index, {0,..,region_count-1}.
 805 * @highmem_base: High memory base address.
 806 * @highmem_size: High memory size.
 807 *
 808 * Bootloaders that preallocate highmem regions must place the
 809 * region info into the repository at these well known nodes.
 810 */
 811
 812int ps3_repository_read_highmem_info(unsigned int region_index,
 813        u64 *highmem_base, u64 *highmem_size)
 814{
 815        int result;
 816
 817        *highmem_base = 0;
 818        result = ps3_repository_read_highmem_base(region_index, highmem_base);
 819        return result ? result
 820                : ps3_repository_read_highmem_size(region_index, highmem_size);
 821}
 822
 823/**
 824 * ps3_repository_read_num_spu_reserved - Number of physical spus reserved.
 825 * @num_spu: Number of physical spus.
 826 */
 827
 828int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved)
 829{
 830        int result;
 831        u64 v1 = 0;
 832
 833        result = read_node(PS3_LPAR_ID_CURRENT,
 834                make_first_field("bi", 0),
 835                make_field("spun", 0),
 836                0, 0,
 837                &v1, NULL);
 838        *num_spu_reserved = v1;
 839        return result;
 840}
 841
 842/**
 843 * ps3_repository_read_num_spu_resource_id - Number of spu resource reservations.
 844 * @num_resource_id: Number of spu resource ids.
 845 */
 846
 847int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id)
 848{
 849        int result;
 850        u64 v1 = 0;
 851
 852        result = read_node(PS3_LPAR_ID_CURRENT,
 853                make_first_field("bi", 0),
 854                make_field("spursvn", 0),
 855                0, 0,
 856                &v1, NULL);
 857        *num_resource_id = v1;
 858        return result;
 859}
 860
 861/**
 862 * ps3_repository_read_spu_resource_id - spu resource reservation id value.
 863 * @res_index: Resource reservation index.
 864 * @resource_type: Resource reservation type.
 865 * @resource_id: Resource reservation id.
 866 */
 867
 868int ps3_repository_read_spu_resource_id(unsigned int res_index,
 869        enum ps3_spu_resource_type *resource_type, unsigned int *resource_id)
 870{
 871        int result;
 872        u64 v1 = 0;
 873        u64 v2 = 0;
 874
 875        result = read_node(PS3_LPAR_ID_CURRENT,
 876                make_first_field("bi", 0),
 877                make_field("spursv", 0),
 878                res_index,
 879                0,
 880                &v1, &v2);
 881        *resource_type = v1;
 882        *resource_id = v2;
 883        return result;
 884}
 885
 886static int ps3_repository_read_boot_dat_address(u64 *address)
 887{
 888        return read_node(PS3_LPAR_ID_CURRENT,
 889                make_first_field("bi", 0),
 890                make_field("boot_dat", 0),
 891                make_field("address", 0),
 892                0,
 893                address, NULL);
 894}
 895
 896int ps3_repository_read_boot_dat_size(unsigned int *size)
 897{
 898        int result;
 899        u64 v1 = 0;
 900
 901        result = read_node(PS3_LPAR_ID_CURRENT,
 902                make_first_field("bi", 0),
 903                make_field("boot_dat", 0),
 904                make_field("size", 0),
 905                0,
 906                &v1, NULL);
 907        *size = v1;
 908        return result;
 909}
 910
 911int ps3_repository_read_vuart_av_port(unsigned int *port)
 912{
 913        int result;
 914        u64 v1 = 0;
 915
 916        result = read_node(PS3_LPAR_ID_CURRENT,
 917                make_first_field("bi", 0),
 918                make_field("vir_uart", 0),
 919                make_field("port", 0),
 920                make_field("avset", 0),
 921                &v1, NULL);
 922        *port = v1;
 923        return result;
 924}
 925
 926int ps3_repository_read_vuart_sysmgr_port(unsigned int *port)
 927{
 928        int result;
 929        u64 v1 = 0;
 930
 931        result = read_node(PS3_LPAR_ID_CURRENT,
 932                make_first_field("bi", 0),
 933                make_field("vir_uart", 0),
 934                make_field("port", 0),
 935                make_field("sysmgr", 0),
 936                &v1, NULL);
 937        *port = v1;
 938        return result;
 939}
 940
 941/**
 942  * ps3_repository_read_boot_dat_info - Get address and size of cell_ext_os_area.
 943  * address: lpar address of cell_ext_os_area
 944  * @size: size of cell_ext_os_area
 945  */
 946
 947int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size)
 948{
 949        int result;
 950
 951        *size = 0;
 952        result = ps3_repository_read_boot_dat_address(lpar_addr);
 953        return result ? result
 954                : ps3_repository_read_boot_dat_size(size);
 955}
 956
 957/**
 958 * ps3_repository_read_num_be - Number of physical BE processors in the system.
 959 */
 960
 961int ps3_repository_read_num_be(unsigned int *num_be)
 962{
 963        int result;
 964        u64 v1 = 0;
 965
 966        result = read_node(PS3_LPAR_ID_PME,
 967                make_first_field("ben", 0),
 968                0,
 969                0,
 970                0,
 971                &v1, NULL);
 972        *num_be = v1;
 973        return result;
 974}
 975
 976/**
 977 * ps3_repository_read_be_node_id - Read the physical BE processor node id.
 978 * @be_index: Zero based index.
 979 * @node_id: The BE processor node id.
 980 */
 981
 982int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id)
 983{
 984        return read_node(PS3_LPAR_ID_PME,
 985                make_first_field("be", be_index),
 986                0,
 987                0,
 988                0,
 989                node_id, NULL);
 990}
 991
 992/**
 993 * ps3_repository_read_be_id - Read the physical BE processor id.
 994 * @node_id: The BE processor node id.
 995 * @be_id: The BE processor id.
 996 */
 997
 998int ps3_repository_read_be_id(u64 node_id, u64 *be_id)
 999{
1000        return read_node(PS3_LPAR_ID_PME,
1001                make_first_field("be", 0),
1002                node_id,
1003                0,
1004                0,
1005                be_id, NULL);
1006}
1007
1008int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq)
1009{
1010        return read_node(PS3_LPAR_ID_PME,
1011                make_first_field("be", 0),
1012                node_id,
1013                make_field("clock", 0),
1014                0,
1015                tb_freq, NULL);
1016}
1017
1018int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq)
1019{
1020        int result;
1021        u64 node_id;
1022
1023        *tb_freq = 0;
1024        result = ps3_repository_read_be_node_id(be_index, &node_id);
1025        return result ? result
1026                : ps3_repository_read_tb_freq(node_id, tb_freq);
1027}
1028
1029int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar,
1030        u64 *rights)
1031{
1032        int result;
1033        u64 node_id;
1034
1035        *lpar = 0;
1036        *rights = 0;
1037        result = ps3_repository_read_be_node_id(be_index, &node_id);
1038        return result ? result
1039                : read_node(PS3_LPAR_ID_PME,
1040                            make_first_field("be", 0),
1041                            node_id,
1042                            make_field("lpm", 0),
1043                            make_field("priv", 0),
1044                            lpar, rights);
1045}
1046
1047#if defined(CONFIG_PS3_REPOSITORY_WRITE)
1048
1049static int create_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
1050{
1051        int result;
1052
1053        dump_node(0, n1, n2, n3, n4, v1, v2);
1054
1055        result = lv1_create_repository_node(n1, n2, n3, n4, v1, v2);
1056
1057        if (result) {
1058                pr_devel("%s:%d: lv1_create_repository_node failed: %s\n",
1059                        __func__, __LINE__, ps3_result(result));
1060                return -ENOENT;
1061        }
1062
1063        return 0;
1064}
1065
1066static int delete_node(u64 n1, u64 n2, u64 n3, u64 n4)
1067{
1068        int result;
1069
1070        dump_node(0, n1, n2, n3, n4, 0, 0);
1071
1072        result = lv1_delete_repository_node(n1, n2, n3, n4);
1073
1074        if (result) {
1075                pr_devel("%s:%d: lv1_delete_repository_node failed: %s\n",
1076                        __func__, __LINE__, ps3_result(result));
1077                return -ENOENT;
1078        }
1079
1080        return 0;
1081}
1082
1083static int write_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
1084{
1085        int result;
1086
1087        result = create_node(n1, n2, n3, n4, v1, v2);
1088
1089        if (!result)
1090                return 0;
1091
1092        result = lv1_write_repository_node(n1, n2, n3, n4, v1, v2);
1093
1094        if (result) {
1095                pr_devel("%s:%d: lv1_write_repository_node failed: %s\n",
1096                        __func__, __LINE__, ps3_result(result));
1097                return -ENOENT;
1098        }
1099
1100        return 0;
1101}
1102
1103int ps3_repository_write_highmem_region_count(unsigned int region_count)
1104{
1105        int result;
1106        u64 v1 = (u64)region_count;
1107
1108        result = write_node(
1109                make_first_field("highmem", 0),
1110                make_field("region", 0),
1111                make_field("count", 0),
1112                0,
1113                v1, 0);
1114        return result;
1115}
1116
1117int ps3_repository_write_highmem_base(unsigned int region_index,
1118        u64 highmem_base)
1119{
1120        return write_node(
1121                make_first_field("highmem", 0),
1122                make_field("region", region_index),
1123                make_field("base", 0),
1124                0,
1125                highmem_base, 0);
1126}
1127
1128int ps3_repository_write_highmem_size(unsigned int region_index,
1129        u64 highmem_size)
1130{
1131        return write_node(
1132                make_first_field("highmem", 0),
1133                make_field("region", region_index),
1134                make_field("size", 0),
1135                0,
1136                highmem_size, 0);
1137}
1138
1139int ps3_repository_write_highmem_info(unsigned int region_index,
1140        u64 highmem_base, u64 highmem_size)
1141{
1142        int result;
1143
1144        result = ps3_repository_write_highmem_base(region_index, highmem_base);
1145        return result ? result
1146                : ps3_repository_write_highmem_size(region_index, highmem_size);
1147}
1148
1149static int ps3_repository_delete_highmem_base(unsigned int region_index)
1150{
1151        return delete_node(
1152                make_first_field("highmem", 0),
1153                make_field("region", region_index),
1154                make_field("base", 0),
1155                0);
1156}
1157
1158static int ps3_repository_delete_highmem_size(unsigned int region_index)
1159{
1160        return delete_node(
1161                make_first_field("highmem", 0),
1162                make_field("region", region_index),
1163                make_field("size", 0),
1164                0);
1165}
1166
1167int ps3_repository_delete_highmem_info(unsigned int region_index)
1168{
1169        int result;
1170
1171        result = ps3_repository_delete_highmem_base(region_index);
1172        result += ps3_repository_delete_highmem_size(region_index);
1173
1174        return result ? -1 : 0;
1175}
1176
1177#endif /* defined(CONFIG_PS3_REPOSITORY_WRITE) */
1178
1179#if defined(DEBUG)
1180
1181int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)
1182{
1183        int result = 0;
1184        unsigned int res_index;
1185
1186        pr_devel(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
1187                repo->bus_index, repo->dev_index);
1188
1189        for (res_index = 0; res_index < 10; res_index++) {
1190                enum ps3_interrupt_type intr_type;
1191                unsigned int interrupt_id;
1192
1193                result = ps3_repository_read_dev_intr(repo->bus_index,
1194                        repo->dev_index, res_index, &intr_type, &interrupt_id);
1195
1196                if (result) {
1197                        if (result !=  LV1_NO_ENTRY)
1198                                pr_devel("%s:%d ps3_repository_read_dev_intr"
1199                                        " (%u:%u) failed\n", __func__, __LINE__,
1200                                        repo->bus_index, repo->dev_index);
1201                        break;
1202                }
1203
1204                pr_devel("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n",
1205                        __func__, __LINE__, repo->bus_index, repo->dev_index,
1206                        intr_type, interrupt_id);
1207        }
1208
1209        for (res_index = 0; res_index < 10; res_index++) {
1210                enum ps3_reg_type reg_type;
1211                u64 bus_addr;
1212                u64 len;
1213
1214                result = ps3_repository_read_dev_reg(repo->bus_index,
1215                        repo->dev_index, res_index, &reg_type, &bus_addr, &len);
1216
1217                if (result) {
1218                        if (result !=  LV1_NO_ENTRY)
1219                                pr_devel("%s:%d ps3_repository_read_dev_reg"
1220                                        " (%u:%u) failed\n", __func__, __LINE__,
1221                                        repo->bus_index, repo->dev_index);
1222                        break;
1223                }
1224
1225                pr_devel("%s:%d (%u:%u) reg_type %u, bus_addr %llxh, len %llxh\n",
1226                        __func__, __LINE__, repo->bus_index, repo->dev_index,
1227                        reg_type, bus_addr, len);
1228        }
1229
1230        pr_devel(" <- %s:%d\n", __func__, __LINE__);
1231        return result;
1232}
1233
1234static int dump_stor_dev_info(struct ps3_repository_device *repo)
1235{
1236        int result = 0;
1237        unsigned int num_regions, region_index;
1238        u64 port, blk_size, num_blocks;
1239
1240        pr_devel(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
1241                repo->bus_index, repo->dev_index);
1242
1243        result = ps3_repository_read_stor_dev_info(repo->bus_index,
1244                repo->dev_index, &port, &blk_size, &num_blocks, &num_regions);
1245        if (result) {
1246                pr_devel("%s:%d ps3_repository_read_stor_dev_info"
1247                        " (%u:%u) failed\n", __func__, __LINE__,
1248                        repo->bus_index, repo->dev_index);
1249                goto out;
1250        }
1251
1252        pr_devel("%s:%d  (%u:%u): port %llu, blk_size %llu, num_blocks "
1253                 "%llu, num_regions %u\n",
1254                 __func__, __LINE__, repo->bus_index, repo->dev_index,
1255                port, blk_size, num_blocks, num_regions);
1256
1257        for (region_index = 0; region_index < num_regions; region_index++) {
1258                unsigned int region_id;
1259                u64 region_start, region_size;
1260
1261                result = ps3_repository_read_stor_dev_region(repo->bus_index,
1262                        repo->dev_index, region_index, &region_id,
1263                        &region_start, &region_size);
1264                if (result) {
1265                         pr_devel("%s:%d ps3_repository_read_stor_dev_region"
1266                                  " (%u:%u) failed\n", __func__, __LINE__,
1267                                  repo->bus_index, repo->dev_index);
1268                        break;
1269                }
1270
1271                pr_devel("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n",
1272                        __func__, __LINE__, repo->bus_index, repo->dev_index,
1273                        region_id, (unsigned long)region_start,
1274                        (unsigned long)region_size);
1275        }
1276
1277out:
1278        pr_devel(" <- %s:%d\n", __func__, __LINE__);
1279        return result;
1280}
1281
1282static int dump_device_info(struct ps3_repository_device *repo,
1283        unsigned int num_dev)
1284{
1285        int result = 0;
1286
1287        pr_devel(" -> %s:%d: bus_%u\n", __func__, __LINE__, repo->bus_index);
1288
1289        for (repo->dev_index = 0; repo->dev_index < num_dev;
1290                repo->dev_index++) {
1291
1292                result = ps3_repository_read_dev_type(repo->bus_index,
1293                        repo->dev_index, &repo->dev_type);
1294
1295                if (result) {
1296                        pr_devel("%s:%d ps3_repository_read_dev_type"
1297                                " (%u:%u) failed\n", __func__, __LINE__,
1298                                repo->bus_index, repo->dev_index);
1299                        break;
1300                }
1301
1302                result = ps3_repository_read_dev_id(repo->bus_index,
1303                        repo->dev_index, &repo->dev_id);
1304
1305                if (result) {
1306                        pr_devel("%s:%d ps3_repository_read_dev_id"
1307                                " (%u:%u) failed\n", __func__, __LINE__,
1308                                repo->bus_index, repo->dev_index);
1309                        continue;
1310                }
1311
1312                pr_devel("%s:%d  (%u:%u): dev_type %u, dev_id %lu\n", __func__,
1313                        __LINE__, repo->bus_index, repo->dev_index,
1314                        repo->dev_type, (unsigned long)repo->dev_id);
1315
1316                ps3_repository_dump_resource_info(repo);
1317
1318                if (repo->bus_type == PS3_BUS_TYPE_STORAGE)
1319                        dump_stor_dev_info(repo);
1320        }
1321
1322        pr_devel(" <- %s:%d\n", __func__, __LINE__);
1323        return result;
1324}
1325
1326int ps3_repository_dump_bus_info(void)
1327{
1328        int result = 0;
1329        struct ps3_repository_device repo;
1330
1331        pr_devel(" -> %s:%d\n", __func__, __LINE__);
1332
1333        memset(&repo, 0, sizeof(repo));
1334
1335        for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) {
1336                unsigned int num_dev;
1337
1338                result = ps3_repository_read_bus_type(repo.bus_index,
1339                        &repo.bus_type);
1340
1341                if (result) {
1342                        pr_devel("%s:%d read_bus_type(%u) failed\n",
1343                                __func__, __LINE__, repo.bus_index);
1344                        break;
1345                }
1346
1347                result = ps3_repository_read_bus_id(repo.bus_index,
1348                        &repo.bus_id);
1349
1350                if (result) {
1351                        pr_devel("%s:%d read_bus_id(%u) failed\n",
1352                                __func__, __LINE__, repo.bus_index);
1353                        continue;
1354                }
1355
1356                if (repo.bus_index != repo.bus_id)
1357                        pr_devel("%s:%d bus_index != bus_id\n",
1358                                __func__, __LINE__);
1359
1360                result = ps3_repository_read_bus_num_dev(repo.bus_index,
1361                        &num_dev);
1362
1363                if (result) {
1364                        pr_devel("%s:%d read_bus_num_dev(%u) failed\n",
1365                                __func__, __LINE__, repo.bus_index);
1366                        continue;
1367                }
1368
1369                pr_devel("%s:%d bus_%u: bus_type %u, bus_id %lu, num_dev %u\n",
1370                        __func__, __LINE__, repo.bus_index, repo.bus_type,
1371                        (unsigned long)repo.bus_id, num_dev);
1372
1373                dump_device_info(&repo, num_dev);
1374        }
1375
1376        pr_devel(" <- %s:%d\n", __func__, __LINE__);
1377        return result;
1378}
1379
1380#endif /* defined(DEBUG) */
1381