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