linux/arch/s390/hypfs/hypfs_diag.c
<<
>>
Prefs
   1/*
   2 *    Hypervisor filesystem for Linux on s390. Diag 204 and 224
   3 *    implementation.
   4 *
   5 *    Copyright IBM Corp. 2006, 2008
   6 *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
   7 */
   8
   9#define KMSG_COMPONENT "hypfs"
  10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  11
  12#include <linux/types.h>
  13#include <linux/errno.h>
  14#include <linux/slab.h>
  15#include <linux/string.h>
  16#include <linux/vmalloc.h>
  17#include <linux/mm.h>
  18#include <asm/diag.h>
  19#include <asm/ebcdic.h>
  20#include "hypfs.h"
  21
  22#define LPAR_NAME_LEN 8         /* lpar name len in diag 204 data */
  23#define CPU_NAME_LEN 16         /* type name len of cpus in diag224 name table */
  24#define TMP_SIZE 64             /* size of temporary buffers */
  25
  26#define DBFS_D204_HDR_VERSION   0
  27
  28/* diag 204 subcodes */
  29enum diag204_sc {
  30        SUBC_STIB4 = 4,
  31        SUBC_RSI = 5,
  32        SUBC_STIB6 = 6,
  33        SUBC_STIB7 = 7
  34};
  35
  36/* The two available diag 204 data formats */
  37enum diag204_format {
  38        INFO_SIMPLE = 0,
  39        INFO_EXT = 0x00010000
  40};
  41
  42/* bit is set in flags, when physical cpu info is included in diag 204 data */
  43#define LPAR_PHYS_FLG  0x80
  44
  45static char *diag224_cpu_names;                 /* diag 224 name table */
  46static enum diag204_sc diag204_store_sc;        /* used subcode for store */
  47static enum diag204_format diag204_info_type;   /* used diag 204 data format */
  48
  49static void *diag204_buf;               /* 4K aligned buffer for diag204 data */
  50static void *diag204_buf_vmalloc;       /* vmalloc pointer for diag204 data */
  51static int diag204_buf_pages;           /* number of pages for diag204 data */
  52
  53static struct dentry *dbfs_d204_file;
  54
  55/*
  56 * DIAG 204 data structures and member access functions.
  57 *
  58 * Since we have two different diag 204 data formats for old and new s390
  59 * machines, we do not access the structs directly, but use getter functions for
  60 * each struct member instead. This should make the code more readable.
  61 */
  62
  63/* Time information block */
  64
  65struct info_blk_hdr {
  66        __u8  npar;
  67        __u8  flags;
  68        __u16 tslice;
  69        __u16 phys_cpus;
  70        __u16 this_part;
  71        __u64 curtod;
  72} __attribute__ ((packed));
  73
  74struct x_info_blk_hdr {
  75        __u8  npar;
  76        __u8  flags;
  77        __u16 tslice;
  78        __u16 phys_cpus;
  79        __u16 this_part;
  80        __u64 curtod1;
  81        __u64 curtod2;
  82        char reserved[40];
  83} __attribute__ ((packed));
  84
  85static inline int info_blk_hdr__size(enum diag204_format type)
  86{
  87        if (type == INFO_SIMPLE)
  88                return sizeof(struct info_blk_hdr);
  89        else /* INFO_EXT */
  90                return sizeof(struct x_info_blk_hdr);
  91}
  92
  93static inline __u8 info_blk_hdr__npar(enum diag204_format type, void *hdr)
  94{
  95        if (type == INFO_SIMPLE)
  96                return ((struct info_blk_hdr *)hdr)->npar;
  97        else /* INFO_EXT */
  98                return ((struct x_info_blk_hdr *)hdr)->npar;
  99}
 100
 101static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr)
 102{
 103        if (type == INFO_SIMPLE)
 104                return ((struct info_blk_hdr *)hdr)->flags;
 105        else /* INFO_EXT */
 106                return ((struct x_info_blk_hdr *)hdr)->flags;
 107}
 108
 109static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr)
 110{
 111        if (type == INFO_SIMPLE)
 112                return ((struct info_blk_hdr *)hdr)->phys_cpus;
 113        else /* INFO_EXT */
 114                return ((struct x_info_blk_hdr *)hdr)->phys_cpus;
 115}
 116
 117/* Partition header */
 118
 119struct part_hdr {
 120        __u8 pn;
 121        __u8 cpus;
 122        char reserved[6];
 123        char part_name[LPAR_NAME_LEN];
 124} __attribute__ ((packed));
 125
 126struct x_part_hdr {
 127        __u8  pn;
 128        __u8  cpus;
 129        __u8  rcpus;
 130        __u8  pflag;
 131        __u32 mlu;
 132        char  part_name[LPAR_NAME_LEN];
 133        char  lpc_name[8];
 134        char  os_name[8];
 135        __u64 online_cs;
 136        __u64 online_es;
 137        __u8  upid;
 138        char  reserved1[3];
 139        __u32 group_mlu;
 140        char  group_name[8];
 141        char  reserved2[32];
 142} __attribute__ ((packed));
 143
 144static inline int part_hdr__size(enum diag204_format type)
 145{
 146        if (type == INFO_SIMPLE)
 147                return sizeof(struct part_hdr);
 148        else /* INFO_EXT */
 149                return sizeof(struct x_part_hdr);
 150}
 151
 152static inline __u8 part_hdr__rcpus(enum diag204_format type, void *hdr)
 153{
 154        if (type == INFO_SIMPLE)
 155                return ((struct part_hdr *)hdr)->cpus;
 156        else /* INFO_EXT */
 157                return ((struct x_part_hdr *)hdr)->rcpus;
 158}
 159
 160static inline void part_hdr__part_name(enum diag204_format type, void *hdr,
 161                                       char *name)
 162{
 163        if (type == INFO_SIMPLE)
 164                memcpy(name, ((struct part_hdr *)hdr)->part_name,
 165                       LPAR_NAME_LEN);
 166        else /* INFO_EXT */
 167                memcpy(name, ((struct x_part_hdr *)hdr)->part_name,
 168                       LPAR_NAME_LEN);
 169        EBCASC(name, LPAR_NAME_LEN);
 170        name[LPAR_NAME_LEN] = 0;
 171        strim(name);
 172}
 173
 174struct cpu_info {
 175        __u16 cpu_addr;
 176        char  reserved1[2];
 177        __u8  ctidx;
 178        __u8  cflag;
 179        __u16 weight;
 180        __u64 acc_time;
 181        __u64 lp_time;
 182} __attribute__ ((packed));
 183
 184struct x_cpu_info {
 185        __u16 cpu_addr;
 186        char  reserved1[2];
 187        __u8  ctidx;
 188        __u8  cflag;
 189        __u16 weight;
 190        __u64 acc_time;
 191        __u64 lp_time;
 192        __u16 min_weight;
 193        __u16 cur_weight;
 194        __u16 max_weight;
 195        char  reseved2[2];
 196        __u64 online_time;
 197        __u64 wait_time;
 198        __u32 pma_weight;
 199        __u32 polar_weight;
 200        char  reserved3[40];
 201} __attribute__ ((packed));
 202
 203/* CPU info block */
 204
 205static inline int cpu_info__size(enum diag204_format type)
 206{
 207        if (type == INFO_SIMPLE)
 208                return sizeof(struct cpu_info);
 209        else /* INFO_EXT */
 210                return sizeof(struct x_cpu_info);
 211}
 212
 213static inline __u8 cpu_info__ctidx(enum diag204_format type, void *hdr)
 214{
 215        if (type == INFO_SIMPLE)
 216                return ((struct cpu_info *)hdr)->ctidx;
 217        else /* INFO_EXT */
 218                return ((struct x_cpu_info *)hdr)->ctidx;
 219}
 220
 221static inline __u16 cpu_info__cpu_addr(enum diag204_format type, void *hdr)
 222{
 223        if (type == INFO_SIMPLE)
 224                return ((struct cpu_info *)hdr)->cpu_addr;
 225        else /* INFO_EXT */
 226                return ((struct x_cpu_info *)hdr)->cpu_addr;
 227}
 228
 229static inline __u64 cpu_info__acc_time(enum diag204_format type, void *hdr)
 230{
 231        if (type == INFO_SIMPLE)
 232                return ((struct cpu_info *)hdr)->acc_time;
 233        else /* INFO_EXT */
 234                return ((struct x_cpu_info *)hdr)->acc_time;
 235}
 236
 237static inline __u64 cpu_info__lp_time(enum diag204_format type, void *hdr)
 238{
 239        if (type == INFO_SIMPLE)
 240                return ((struct cpu_info *)hdr)->lp_time;
 241        else /* INFO_EXT */
 242                return ((struct x_cpu_info *)hdr)->lp_time;
 243}
 244
 245static inline __u64 cpu_info__online_time(enum diag204_format type, void *hdr)
 246{
 247        if (type == INFO_SIMPLE)
 248                return 0;       /* online_time not available in simple info */
 249        else /* INFO_EXT */
 250                return ((struct x_cpu_info *)hdr)->online_time;
 251}
 252
 253/* Physical header */
 254
 255struct phys_hdr {
 256        char reserved1[1];
 257        __u8 cpus;
 258        char reserved2[6];
 259        char mgm_name[8];
 260} __attribute__ ((packed));
 261
 262struct x_phys_hdr {
 263        char reserved1[1];
 264        __u8 cpus;
 265        char reserved2[6];
 266        char mgm_name[8];
 267        char reserved3[80];
 268} __attribute__ ((packed));
 269
 270static inline int phys_hdr__size(enum diag204_format type)
 271{
 272        if (type == INFO_SIMPLE)
 273                return sizeof(struct phys_hdr);
 274        else /* INFO_EXT */
 275                return sizeof(struct x_phys_hdr);
 276}
 277
 278static inline __u8 phys_hdr__cpus(enum diag204_format type, void *hdr)
 279{
 280        if (type == INFO_SIMPLE)
 281                return ((struct phys_hdr *)hdr)->cpus;
 282        else /* INFO_EXT */
 283                return ((struct x_phys_hdr *)hdr)->cpus;
 284}
 285
 286/* Physical CPU info block */
 287
 288struct phys_cpu {
 289        __u16 cpu_addr;
 290        char  reserved1[2];
 291        __u8  ctidx;
 292        char  reserved2[3];
 293        __u64 mgm_time;
 294        char  reserved3[8];
 295} __attribute__ ((packed));
 296
 297struct x_phys_cpu {
 298        __u16 cpu_addr;
 299        char  reserved1[2];
 300        __u8  ctidx;
 301        char  reserved2[3];
 302        __u64 mgm_time;
 303        char  reserved3[80];
 304} __attribute__ ((packed));
 305
 306static inline int phys_cpu__size(enum diag204_format type)
 307{
 308        if (type == INFO_SIMPLE)
 309                return sizeof(struct phys_cpu);
 310        else /* INFO_EXT */
 311                return sizeof(struct x_phys_cpu);
 312}
 313
 314static inline __u16 phys_cpu__cpu_addr(enum diag204_format type, void *hdr)
 315{
 316        if (type == INFO_SIMPLE)
 317                return ((struct phys_cpu *)hdr)->cpu_addr;
 318        else /* INFO_EXT */
 319                return ((struct x_phys_cpu *)hdr)->cpu_addr;
 320}
 321
 322static inline __u64 phys_cpu__mgm_time(enum diag204_format type, void *hdr)
 323{
 324        if (type == INFO_SIMPLE)
 325                return ((struct phys_cpu *)hdr)->mgm_time;
 326        else /* INFO_EXT */
 327                return ((struct x_phys_cpu *)hdr)->mgm_time;
 328}
 329
 330static inline __u64 phys_cpu__ctidx(enum diag204_format type, void *hdr)
 331{
 332        if (type == INFO_SIMPLE)
 333                return ((struct phys_cpu *)hdr)->ctidx;
 334        else /* INFO_EXT */
 335                return ((struct x_phys_cpu *)hdr)->ctidx;
 336}
 337
 338/* Diagnose 204 functions */
 339
 340static inline int __diag204(unsigned long subcode, unsigned long size, void *addr)
 341{
 342        register unsigned long _subcode asm("0") = subcode;
 343        register unsigned long _size asm("1") = size;
 344
 345        asm volatile(
 346                "       diag    %2,%0,0x204\n"
 347                "0:\n"
 348                EX_TABLE(0b,0b)
 349                : "+d" (_subcode), "+d" (_size) : "d" (addr) : "memory");
 350        if (_subcode)
 351                return -1;
 352        return _size;
 353}
 354
 355static int diag204(unsigned long subcode, unsigned long size, void *addr)
 356{
 357        diag_stat_inc(DIAG_STAT_X204);
 358        return __diag204(subcode, size, addr);
 359}
 360
 361/*
 362 * For the old diag subcode 4 with simple data format we have to use real
 363 * memory. If we use subcode 6 or 7 with extended data format, we can (and
 364 * should) use vmalloc, since we need a lot of memory in that case. Currently
 365 * up to 93 pages!
 366 */
 367
 368static void diag204_free_buffer(void)
 369{
 370        if (!diag204_buf)
 371                return;
 372        if (diag204_buf_vmalloc) {
 373                vfree(diag204_buf_vmalloc);
 374                diag204_buf_vmalloc = NULL;
 375        } else {
 376                free_pages((unsigned long) diag204_buf, 0);
 377        }
 378        diag204_buf = NULL;
 379}
 380
 381static void *page_align_ptr(void *ptr)
 382{
 383        return (void *) PAGE_ALIGN((unsigned long) ptr);
 384}
 385
 386static void *diag204_alloc_vbuf(int pages)
 387{
 388        /* The buffer has to be page aligned! */
 389        diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1));
 390        if (!diag204_buf_vmalloc)
 391                return ERR_PTR(-ENOMEM);
 392        diag204_buf = page_align_ptr(diag204_buf_vmalloc);
 393        diag204_buf_pages = pages;
 394        return diag204_buf;
 395}
 396
 397static void *diag204_alloc_rbuf(void)
 398{
 399        diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0);
 400        if (!diag204_buf)
 401                return ERR_PTR(-ENOMEM);
 402        diag204_buf_pages = 1;
 403        return diag204_buf;
 404}
 405
 406static void *diag204_get_buffer(enum diag204_format fmt, int *pages)
 407{
 408        if (diag204_buf) {
 409                *pages = diag204_buf_pages;
 410                return diag204_buf;
 411        }
 412        if (fmt == INFO_SIMPLE) {
 413                *pages = 1;
 414                return diag204_alloc_rbuf();
 415        } else {/* INFO_EXT */
 416                *pages = diag204((unsigned long)SUBC_RSI |
 417                                 (unsigned long)INFO_EXT, 0, NULL);
 418                if (*pages <= 0)
 419                        return ERR_PTR(-ENOSYS);
 420                else
 421                        return diag204_alloc_vbuf(*pages);
 422        }
 423}
 424
 425/*
 426 * diag204_probe() has to find out, which type of diagnose 204 implementation
 427 * we have on our machine. Currently there are three possible scanarios:
 428 *   - subcode 4   + simple data format (only one page)
 429 *   - subcode 4-6 + extended data format
 430 *   - subcode 4-7 + extended data format
 431 *
 432 * Subcode 5 is used to retrieve the size of the data, provided by subcodes
 433 * 6 and 7. Subcode 7 basically has the same function as subcode 6. In addition
 434 * to subcode 6 it provides also information about secondary cpus.
 435 * In order to get as much information as possible, we first try
 436 * subcode 7, then 6 and if both fail, we use subcode 4.
 437 */
 438
 439static int diag204_probe(void)
 440{
 441        void *buf;
 442        int pages, rc;
 443
 444        buf = diag204_get_buffer(INFO_EXT, &pages);
 445        if (!IS_ERR(buf)) {
 446                if (diag204((unsigned long)SUBC_STIB7 |
 447                            (unsigned long)INFO_EXT, pages, buf) >= 0) {
 448                        diag204_store_sc = SUBC_STIB7;
 449                        diag204_info_type = INFO_EXT;
 450                        goto out;
 451                }
 452                if (diag204((unsigned long)SUBC_STIB6 |
 453                            (unsigned long)INFO_EXT, pages, buf) >= 0) {
 454                        diag204_store_sc = SUBC_STIB6;
 455                        diag204_info_type = INFO_EXT;
 456                        goto out;
 457                }
 458                diag204_free_buffer();
 459        }
 460
 461        /* subcodes 6 and 7 failed, now try subcode 4 */
 462
 463        buf = diag204_get_buffer(INFO_SIMPLE, &pages);
 464        if (IS_ERR(buf)) {
 465                rc = PTR_ERR(buf);
 466                goto fail_alloc;
 467        }
 468        if (diag204((unsigned long)SUBC_STIB4 |
 469                    (unsigned long)INFO_SIMPLE, pages, buf) >= 0) {
 470                diag204_store_sc = SUBC_STIB4;
 471                diag204_info_type = INFO_SIMPLE;
 472                goto out;
 473        } else {
 474                rc = -ENOSYS;
 475                goto fail_store;
 476        }
 477out:
 478        rc = 0;
 479fail_store:
 480        diag204_free_buffer();
 481fail_alloc:
 482        return rc;
 483}
 484
 485static int diag204_do_store(void *buf, int pages)
 486{
 487        int rc;
 488
 489        rc = diag204((unsigned long) diag204_store_sc |
 490                     (unsigned long) diag204_info_type, pages, buf);
 491        return rc < 0 ? -ENOSYS : 0;
 492}
 493
 494static void *diag204_store(void)
 495{
 496        void *buf;
 497        int pages, rc;
 498
 499        buf = diag204_get_buffer(diag204_info_type, &pages);
 500        if (IS_ERR(buf))
 501                goto out;
 502        rc = diag204_do_store(buf, pages);
 503        if (rc)
 504                return ERR_PTR(rc);
 505out:
 506        return buf;
 507}
 508
 509/* Diagnose 224 functions */
 510
 511static int diag224(void *ptr)
 512{
 513        int rc = -EOPNOTSUPP;
 514
 515        diag_stat_inc(DIAG_STAT_X224);
 516        asm volatile(
 517                "       diag    %1,%2,0x224\n"
 518                "0:     lhi     %0,0x0\n"
 519                "1:\n"
 520                EX_TABLE(0b,1b)
 521                : "+d" (rc) :"d" (0), "d" (ptr) : "memory");
 522        return rc;
 523}
 524
 525static int diag224_get_name_table(void)
 526{
 527        /* memory must be below 2GB */
 528        diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
 529        if (!diag224_cpu_names)
 530                return -ENOMEM;
 531        if (diag224(diag224_cpu_names)) {
 532                kfree(diag224_cpu_names);
 533                return -EOPNOTSUPP;
 534        }
 535        EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16);
 536        return 0;
 537}
 538
 539static void diag224_delete_name_table(void)
 540{
 541        kfree(diag224_cpu_names);
 542}
 543
 544static int diag224_idx2name(int index, char *name)
 545{
 546        memcpy(name, diag224_cpu_names + ((index + 1) * CPU_NAME_LEN),
 547                CPU_NAME_LEN);
 548        name[CPU_NAME_LEN] = 0;
 549        strim(name);
 550        return 0;
 551}
 552
 553struct dbfs_d204_hdr {
 554        u64     len;            /* Length of d204 buffer without header */
 555        u16     version;        /* Version of header */
 556        u8      sc;             /* Used subcode */
 557        char    reserved[53];
 558} __attribute__ ((packed));
 559
 560struct dbfs_d204 {
 561        struct dbfs_d204_hdr    hdr;    /* 64 byte header */
 562        char                    buf[];  /* d204 buffer */
 563} __attribute__ ((packed));
 564
 565static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size)
 566{
 567        struct dbfs_d204 *d204;
 568        int rc, buf_size;
 569        void *base;
 570
 571        buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr);
 572        base = vzalloc(buf_size);
 573        if (!base)
 574                return -ENOMEM;
 575        d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr);
 576        rc = diag204_do_store(d204->buf, diag204_buf_pages);
 577        if (rc) {
 578                vfree(base);
 579                return rc;
 580        }
 581        d204->hdr.version = DBFS_D204_HDR_VERSION;
 582        d204->hdr.len = PAGE_SIZE * diag204_buf_pages;
 583        d204->hdr.sc = diag204_store_sc;
 584        *data = d204;
 585        *data_free_ptr = base;
 586        *size = d204->hdr.len + sizeof(struct dbfs_d204_hdr);
 587        return 0;
 588}
 589
 590static struct hypfs_dbfs_file dbfs_file_d204 = {
 591        .name           = "diag_204",
 592        .data_create    = dbfs_d204_create,
 593        .data_free      = vfree,
 594};
 595
 596__init int hypfs_diag_init(void)
 597{
 598        int rc;
 599
 600        if (diag204_probe()) {
 601                pr_err("The hardware system does not support hypfs\n");
 602                return -ENODATA;
 603        }
 604        if (diag204_info_type == INFO_EXT) {
 605                rc = hypfs_dbfs_create_file(&dbfs_file_d204);
 606                if (rc)
 607                        return rc;
 608        }
 609        if (MACHINE_IS_LPAR) {
 610                rc = diag224_get_name_table();
 611                if (rc) {
 612                        pr_err("The hardware system does not provide all "
 613                               "functions required by hypfs\n");
 614                        debugfs_remove(dbfs_d204_file);
 615                        return rc;
 616                }
 617        }
 618        return 0;
 619}
 620
 621void hypfs_diag_exit(void)
 622{
 623        debugfs_remove(dbfs_d204_file);
 624        diag224_delete_name_table();
 625        diag204_free_buffer();
 626        hypfs_dbfs_remove_file(&dbfs_file_d204);
 627}
 628
 629/*
 630 * Functions to create the directory structure
 631 * *******************************************
 632 */
 633
 634static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info)
 635{
 636        struct dentry *cpu_dir;
 637        char buffer[TMP_SIZE];
 638        void *rc;
 639
 640        snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type,
 641                                                            cpu_info));
 642        cpu_dir = hypfs_mkdir(cpus_dir, buffer);
 643        rc = hypfs_create_u64(cpu_dir, "mgmtime",
 644                              cpu_info__acc_time(diag204_info_type, cpu_info) -
 645                              cpu_info__lp_time(diag204_info_type, cpu_info));
 646        if (IS_ERR(rc))
 647                return PTR_ERR(rc);
 648        rc = hypfs_create_u64(cpu_dir, "cputime",
 649                              cpu_info__lp_time(diag204_info_type, cpu_info));
 650        if (IS_ERR(rc))
 651                return PTR_ERR(rc);
 652        if (diag204_info_type == INFO_EXT) {
 653                rc = hypfs_create_u64(cpu_dir, "onlinetime",
 654                                      cpu_info__online_time(diag204_info_type,
 655                                                            cpu_info));
 656                if (IS_ERR(rc))
 657                        return PTR_ERR(rc);
 658        }
 659        diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer);
 660        rc = hypfs_create_str(cpu_dir, "type", buffer);
 661        return PTR_RET(rc);
 662}
 663
 664static void *hypfs_create_lpar_files(struct dentry *systems_dir, void *part_hdr)
 665{
 666        struct dentry *cpus_dir;
 667        struct dentry *lpar_dir;
 668        char lpar_name[LPAR_NAME_LEN + 1];
 669        void *cpu_info;
 670        int i;
 671
 672        part_hdr__part_name(diag204_info_type, part_hdr, lpar_name);
 673        lpar_name[LPAR_NAME_LEN] = 0;
 674        lpar_dir = hypfs_mkdir(systems_dir, lpar_name);
 675        if (IS_ERR(lpar_dir))
 676                return lpar_dir;
 677        cpus_dir = hypfs_mkdir(lpar_dir, "cpus");
 678        if (IS_ERR(cpus_dir))
 679                return cpus_dir;
 680        cpu_info = part_hdr + part_hdr__size(diag204_info_type);
 681        for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) {
 682                int rc;
 683                rc = hypfs_create_cpu_files(cpus_dir, cpu_info);
 684                if (rc)
 685                        return ERR_PTR(rc);
 686                cpu_info += cpu_info__size(diag204_info_type);
 687        }
 688        return cpu_info;
 689}
 690
 691static int hypfs_create_phys_cpu_files(struct dentry *cpus_dir, void *cpu_info)
 692{
 693        struct dentry *cpu_dir;
 694        char buffer[TMP_SIZE];
 695        void *rc;
 696
 697        snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type,
 698                                                            cpu_info));
 699        cpu_dir = hypfs_mkdir(cpus_dir, buffer);
 700        if (IS_ERR(cpu_dir))
 701                return PTR_ERR(cpu_dir);
 702        rc = hypfs_create_u64(cpu_dir, "mgmtime",
 703                              phys_cpu__mgm_time(diag204_info_type, cpu_info));
 704        if (IS_ERR(rc))
 705                return PTR_ERR(rc);
 706        diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer);
 707        rc = hypfs_create_str(cpu_dir, "type", buffer);
 708        return PTR_RET(rc);
 709}
 710
 711static void *hypfs_create_phys_files(struct dentry *parent_dir, void *phys_hdr)
 712{
 713        int i;
 714        void *cpu_info;
 715        struct dentry *cpus_dir;
 716
 717        cpus_dir = hypfs_mkdir(parent_dir, "cpus");
 718        if (IS_ERR(cpus_dir))
 719                return cpus_dir;
 720        cpu_info = phys_hdr + phys_hdr__size(diag204_info_type);
 721        for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) {
 722                int rc;
 723                rc = hypfs_create_phys_cpu_files(cpus_dir, cpu_info);
 724                if (rc)
 725                        return ERR_PTR(rc);
 726                cpu_info += phys_cpu__size(diag204_info_type);
 727        }
 728        return cpu_info;
 729}
 730
 731int hypfs_diag_create_files(struct dentry *root)
 732{
 733        struct dentry *systems_dir, *hyp_dir;
 734        void *time_hdr, *part_hdr;
 735        int i, rc;
 736        void *buffer, *ptr;
 737
 738        buffer = diag204_store();
 739        if (IS_ERR(buffer))
 740                return PTR_ERR(buffer);
 741
 742        systems_dir = hypfs_mkdir(root, "systems");
 743        if (IS_ERR(systems_dir)) {
 744                rc = PTR_ERR(systems_dir);
 745                goto err_out;
 746        }
 747        time_hdr = (struct x_info_blk_hdr *)buffer;
 748        part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type);
 749        for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) {
 750                part_hdr = hypfs_create_lpar_files(systems_dir, part_hdr);
 751                if (IS_ERR(part_hdr)) {
 752                        rc = PTR_ERR(part_hdr);
 753                        goto err_out;
 754                }
 755        }
 756        if (info_blk_hdr__flags(diag204_info_type, time_hdr) & LPAR_PHYS_FLG) {
 757                ptr = hypfs_create_phys_files(root, part_hdr);
 758                if (IS_ERR(ptr)) {
 759                        rc = PTR_ERR(ptr);
 760                        goto err_out;
 761                }
 762        }
 763        hyp_dir = hypfs_mkdir(root, "hyp");
 764        if (IS_ERR(hyp_dir)) {
 765                rc = PTR_ERR(hyp_dir);
 766                goto err_out;
 767        }
 768        ptr = hypfs_create_str(hyp_dir, "type", "LPAR Hypervisor");
 769        if (IS_ERR(ptr)) {
 770                rc = PTR_ERR(ptr);
 771                goto err_out;
 772        }
 773        rc = 0;
 774
 775err_out:
 776        return rc;
 777}
 778