root/arch/s390/hypfs/hypfs_diag.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. info_blk_hdr__size
  2. info_blk_hdr__npar
  3. info_blk_hdr__flags
  4. info_blk_hdr__pcpus
  5. part_hdr__size
  6. part_hdr__rcpus
  7. part_hdr__part_name
  8. cpu_info__size
  9. cpu_info__ctidx
  10. cpu_info__cpu_addr
  11. cpu_info__acc_time
  12. cpu_info__lp_time
  13. cpu_info__online_time
  14. phys_hdr__size
  15. phys_hdr__cpus
  16. phys_cpu__size
  17. phys_cpu__cpu_addr
  18. phys_cpu__mgm_time
  19. phys_cpu__ctidx
  20. diag204_free_buffer
  21. page_align_ptr
  22. diag204_alloc_vbuf
  23. diag204_alloc_rbuf
  24. diag204_get_buffer
  25. diag204_probe
  26. diag204_do_store
  27. diag204_store
  28. diag224_get_name_table
  29. diag224_delete_name_table
  30. diag224_idx2name
  31. dbfs_d204_create
  32. hypfs_diag_init
  33. hypfs_diag_exit
  34. hypfs_create_cpu_files
  35. hypfs_create_lpar_files
  36. hypfs_create_phys_cpu_files
  37. hypfs_create_phys_files
  38. hypfs_diag_create_files

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *    Hypervisor filesystem for Linux on s390. Diag 204 and 224
   4  *    implementation.
   5  *
   6  *    Copyright IBM Corp. 2006, 2008
   7  *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
   8  */
   9 
  10 #define KMSG_COMPONENT "hypfs"
  11 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  12 
  13 #include <linux/types.h>
  14 #include <linux/errno.h>
  15 #include <linux/slab.h>
  16 #include <linux/string.h>
  17 #include <linux/vmalloc.h>
  18 #include <linux/mm.h>
  19 #include <asm/diag.h>
  20 #include <asm/ebcdic.h>
  21 #include "hypfs.h"
  22 
  23 #define TMP_SIZE 64             /* size of temporary buffers */
  24 
  25 #define DBFS_D204_HDR_VERSION   0
  26 
  27 static char *diag224_cpu_names;                 /* diag 224 name table */
  28 static enum diag204_sc diag204_store_sc;        /* used subcode for store */
  29 static enum diag204_format diag204_info_type;   /* used diag 204 data format */
  30 
  31 static void *diag204_buf;               /* 4K aligned buffer for diag204 data */
  32 static void *diag204_buf_vmalloc;       /* vmalloc pointer for diag204 data */
  33 static int diag204_buf_pages;           /* number of pages for diag204 data */
  34 
  35 static struct dentry *dbfs_d204_file;
  36 
  37 /*
  38  * DIAG 204 member access functions.
  39  *
  40  * Since we have two different diag 204 data formats for old and new s390
  41  * machines, we do not access the structs directly, but use getter functions for
  42  * each struct member instead. This should make the code more readable.
  43  */
  44 
  45 /* Time information block */
  46 
  47 static inline int info_blk_hdr__size(enum diag204_format type)
  48 {
  49         if (type == DIAG204_INFO_SIMPLE)
  50                 return sizeof(struct diag204_info_blk_hdr);
  51         else /* DIAG204_INFO_EXT */
  52                 return sizeof(struct diag204_x_info_blk_hdr);
  53 }
  54 
  55 static inline __u8 info_blk_hdr__npar(enum diag204_format type, void *hdr)
  56 {
  57         if (type == DIAG204_INFO_SIMPLE)
  58                 return ((struct diag204_info_blk_hdr *)hdr)->npar;
  59         else /* DIAG204_INFO_EXT */
  60                 return ((struct diag204_x_info_blk_hdr *)hdr)->npar;
  61 }
  62 
  63 static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr)
  64 {
  65         if (type == DIAG204_INFO_SIMPLE)
  66                 return ((struct diag204_info_blk_hdr *)hdr)->flags;
  67         else /* DIAG204_INFO_EXT */
  68                 return ((struct diag204_x_info_blk_hdr *)hdr)->flags;
  69 }
  70 
  71 static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr)
  72 {
  73         if (type == DIAG204_INFO_SIMPLE)
  74                 return ((struct diag204_info_blk_hdr *)hdr)->phys_cpus;
  75         else /* DIAG204_INFO_EXT */
  76                 return ((struct diag204_x_info_blk_hdr *)hdr)->phys_cpus;
  77 }
  78 
  79 /* Partition header */
  80 
  81 static inline int part_hdr__size(enum diag204_format type)
  82 {
  83         if (type == DIAG204_INFO_SIMPLE)
  84                 return sizeof(struct diag204_part_hdr);
  85         else /* DIAG204_INFO_EXT */
  86                 return sizeof(struct diag204_x_part_hdr);
  87 }
  88 
  89 static inline __u8 part_hdr__rcpus(enum diag204_format type, void *hdr)
  90 {
  91         if (type == DIAG204_INFO_SIMPLE)
  92                 return ((struct diag204_part_hdr *)hdr)->cpus;
  93         else /* DIAG204_INFO_EXT */
  94                 return ((struct diag204_x_part_hdr *)hdr)->rcpus;
  95 }
  96 
  97 static inline void part_hdr__part_name(enum diag204_format type, void *hdr,
  98                                        char *name)
  99 {
 100         if (type == DIAG204_INFO_SIMPLE)
 101                 memcpy(name, ((struct diag204_part_hdr *)hdr)->part_name,
 102                        DIAG204_LPAR_NAME_LEN);
 103         else /* DIAG204_INFO_EXT */
 104                 memcpy(name, ((struct diag204_x_part_hdr *)hdr)->part_name,
 105                        DIAG204_LPAR_NAME_LEN);
 106         EBCASC(name, DIAG204_LPAR_NAME_LEN);
 107         name[DIAG204_LPAR_NAME_LEN] = 0;
 108         strim(name);
 109 }
 110 
 111 /* CPU info block */
 112 
 113 static inline int cpu_info__size(enum diag204_format type)
 114 {
 115         if (type == DIAG204_INFO_SIMPLE)
 116                 return sizeof(struct diag204_cpu_info);
 117         else /* DIAG204_INFO_EXT */
 118                 return sizeof(struct diag204_x_cpu_info);
 119 }
 120 
 121 static inline __u8 cpu_info__ctidx(enum diag204_format type, void *hdr)
 122 {
 123         if (type == DIAG204_INFO_SIMPLE)
 124                 return ((struct diag204_cpu_info *)hdr)->ctidx;
 125         else /* DIAG204_INFO_EXT */
 126                 return ((struct diag204_x_cpu_info *)hdr)->ctidx;
 127 }
 128 
 129 static inline __u16 cpu_info__cpu_addr(enum diag204_format type, void *hdr)
 130 {
 131         if (type == DIAG204_INFO_SIMPLE)
 132                 return ((struct diag204_cpu_info *)hdr)->cpu_addr;
 133         else /* DIAG204_INFO_EXT */
 134                 return ((struct diag204_x_cpu_info *)hdr)->cpu_addr;
 135 }
 136 
 137 static inline __u64 cpu_info__acc_time(enum diag204_format type, void *hdr)
 138 {
 139         if (type == DIAG204_INFO_SIMPLE)
 140                 return ((struct diag204_cpu_info *)hdr)->acc_time;
 141         else /* DIAG204_INFO_EXT */
 142                 return ((struct diag204_x_cpu_info *)hdr)->acc_time;
 143 }
 144 
 145 static inline __u64 cpu_info__lp_time(enum diag204_format type, void *hdr)
 146 {
 147         if (type == DIAG204_INFO_SIMPLE)
 148                 return ((struct diag204_cpu_info *)hdr)->lp_time;
 149         else /* DIAG204_INFO_EXT */
 150                 return ((struct diag204_x_cpu_info *)hdr)->lp_time;
 151 }
 152 
 153 static inline __u64 cpu_info__online_time(enum diag204_format type, void *hdr)
 154 {
 155         if (type == DIAG204_INFO_SIMPLE)
 156                 return 0;       /* online_time not available in simple info */
 157         else /* DIAG204_INFO_EXT */
 158                 return ((struct diag204_x_cpu_info *)hdr)->online_time;
 159 }
 160 
 161 /* Physical header */
 162 
 163 static inline int phys_hdr__size(enum diag204_format type)
 164 {
 165         if (type == DIAG204_INFO_SIMPLE)
 166                 return sizeof(struct diag204_phys_hdr);
 167         else /* DIAG204_INFO_EXT */
 168                 return sizeof(struct diag204_x_phys_hdr);
 169 }
 170 
 171 static inline __u8 phys_hdr__cpus(enum diag204_format type, void *hdr)
 172 {
 173         if (type == DIAG204_INFO_SIMPLE)
 174                 return ((struct diag204_phys_hdr *)hdr)->cpus;
 175         else /* DIAG204_INFO_EXT */
 176                 return ((struct diag204_x_phys_hdr *)hdr)->cpus;
 177 }
 178 
 179 /* Physical CPU info block */
 180 
 181 static inline int phys_cpu__size(enum diag204_format type)
 182 {
 183         if (type == DIAG204_INFO_SIMPLE)
 184                 return sizeof(struct diag204_phys_cpu);
 185         else /* DIAG204_INFO_EXT */
 186                 return sizeof(struct diag204_x_phys_cpu);
 187 }
 188 
 189 static inline __u16 phys_cpu__cpu_addr(enum diag204_format type, void *hdr)
 190 {
 191         if (type == DIAG204_INFO_SIMPLE)
 192                 return ((struct diag204_phys_cpu *)hdr)->cpu_addr;
 193         else /* DIAG204_INFO_EXT */
 194                 return ((struct diag204_x_phys_cpu *)hdr)->cpu_addr;
 195 }
 196 
 197 static inline __u64 phys_cpu__mgm_time(enum diag204_format type, void *hdr)
 198 {
 199         if (type == DIAG204_INFO_SIMPLE)
 200                 return ((struct diag204_phys_cpu *)hdr)->mgm_time;
 201         else /* DIAG204_INFO_EXT */
 202                 return ((struct diag204_x_phys_cpu *)hdr)->mgm_time;
 203 }
 204 
 205 static inline __u64 phys_cpu__ctidx(enum diag204_format type, void *hdr)
 206 {
 207         if (type == DIAG204_INFO_SIMPLE)
 208                 return ((struct diag204_phys_cpu *)hdr)->ctidx;
 209         else /* DIAG204_INFO_EXT */
 210                 return ((struct diag204_x_phys_cpu *)hdr)->ctidx;
 211 }
 212 
 213 /* Diagnose 204 functions */
 214 /*
 215  * For the old diag subcode 4 with simple data format we have to use real
 216  * memory. If we use subcode 6 or 7 with extended data format, we can (and
 217  * should) use vmalloc, since we need a lot of memory in that case. Currently
 218  * up to 93 pages!
 219  */
 220 
 221 static void diag204_free_buffer(void)
 222 {
 223         if (!diag204_buf)
 224                 return;
 225         if (diag204_buf_vmalloc) {
 226                 vfree(diag204_buf_vmalloc);
 227                 diag204_buf_vmalloc = NULL;
 228         } else {
 229                 free_pages((unsigned long) diag204_buf, 0);
 230         }
 231         diag204_buf = NULL;
 232 }
 233 
 234 static void *page_align_ptr(void *ptr)
 235 {
 236         return (void *) PAGE_ALIGN((unsigned long) ptr);
 237 }
 238 
 239 static void *diag204_alloc_vbuf(int pages)
 240 {
 241         /* The buffer has to be page aligned! */
 242         diag204_buf_vmalloc = vmalloc(array_size(PAGE_SIZE, (pages + 1)));
 243         if (!diag204_buf_vmalloc)
 244                 return ERR_PTR(-ENOMEM);
 245         diag204_buf = page_align_ptr(diag204_buf_vmalloc);
 246         diag204_buf_pages = pages;
 247         return diag204_buf;
 248 }
 249 
 250 static void *diag204_alloc_rbuf(void)
 251 {
 252         diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0);
 253         if (!diag204_buf)
 254                 return ERR_PTR(-ENOMEM);
 255         diag204_buf_pages = 1;
 256         return diag204_buf;
 257 }
 258 
 259 static void *diag204_get_buffer(enum diag204_format fmt, int *pages)
 260 {
 261         if (diag204_buf) {
 262                 *pages = diag204_buf_pages;
 263                 return diag204_buf;
 264         }
 265         if (fmt == DIAG204_INFO_SIMPLE) {
 266                 *pages = 1;
 267                 return diag204_alloc_rbuf();
 268         } else {/* DIAG204_INFO_EXT */
 269                 *pages = diag204((unsigned long)DIAG204_SUBC_RSI |
 270                                  (unsigned long)DIAG204_INFO_EXT, 0, NULL);
 271                 if (*pages <= 0)
 272                         return ERR_PTR(-ENOSYS);
 273                 else
 274                         return diag204_alloc_vbuf(*pages);
 275         }
 276 }
 277 
 278 /*
 279  * diag204_probe() has to find out, which type of diagnose 204 implementation
 280  * we have on our machine. Currently there are three possible scanarios:
 281  *   - subcode 4   + simple data format (only one page)
 282  *   - subcode 4-6 + extended data format
 283  *   - subcode 4-7 + extended data format
 284  *
 285  * Subcode 5 is used to retrieve the size of the data, provided by subcodes
 286  * 6 and 7. Subcode 7 basically has the same function as subcode 6. In addition
 287  * to subcode 6 it provides also information about secondary cpus.
 288  * In order to get as much information as possible, we first try
 289  * subcode 7, then 6 and if both fail, we use subcode 4.
 290  */
 291 
 292 static int diag204_probe(void)
 293 {
 294         void *buf;
 295         int pages, rc;
 296 
 297         buf = diag204_get_buffer(DIAG204_INFO_EXT, &pages);
 298         if (!IS_ERR(buf)) {
 299                 if (diag204((unsigned long)DIAG204_SUBC_STIB7 |
 300                             (unsigned long)DIAG204_INFO_EXT, pages, buf) >= 0) {
 301                         diag204_store_sc = DIAG204_SUBC_STIB7;
 302                         diag204_info_type = DIAG204_INFO_EXT;
 303                         goto out;
 304                 }
 305                 if (diag204((unsigned long)DIAG204_SUBC_STIB6 |
 306                             (unsigned long)DIAG204_INFO_EXT, pages, buf) >= 0) {
 307                         diag204_store_sc = DIAG204_SUBC_STIB6;
 308                         diag204_info_type = DIAG204_INFO_EXT;
 309                         goto out;
 310                 }
 311                 diag204_free_buffer();
 312         }
 313 
 314         /* subcodes 6 and 7 failed, now try subcode 4 */
 315 
 316         buf = diag204_get_buffer(DIAG204_INFO_SIMPLE, &pages);
 317         if (IS_ERR(buf)) {
 318                 rc = PTR_ERR(buf);
 319                 goto fail_alloc;
 320         }
 321         if (diag204((unsigned long)DIAG204_SUBC_STIB4 |
 322                     (unsigned long)DIAG204_INFO_SIMPLE, pages, buf) >= 0) {
 323                 diag204_store_sc = DIAG204_SUBC_STIB4;
 324                 diag204_info_type = DIAG204_INFO_SIMPLE;
 325                 goto out;
 326         } else {
 327                 rc = -ENOSYS;
 328                 goto fail_store;
 329         }
 330 out:
 331         rc = 0;
 332 fail_store:
 333         diag204_free_buffer();
 334 fail_alloc:
 335         return rc;
 336 }
 337 
 338 static int diag204_do_store(void *buf, int pages)
 339 {
 340         int rc;
 341 
 342         rc = diag204((unsigned long) diag204_store_sc |
 343                      (unsigned long) diag204_info_type, pages, buf);
 344         return rc < 0 ? -ENOSYS : 0;
 345 }
 346 
 347 static void *diag204_store(void)
 348 {
 349         void *buf;
 350         int pages, rc;
 351 
 352         buf = diag204_get_buffer(diag204_info_type, &pages);
 353         if (IS_ERR(buf))
 354                 goto out;
 355         rc = diag204_do_store(buf, pages);
 356         if (rc)
 357                 return ERR_PTR(rc);
 358 out:
 359         return buf;
 360 }
 361 
 362 /* Diagnose 224 functions */
 363 
 364 static int diag224_get_name_table(void)
 365 {
 366         /* memory must be below 2GB */
 367         diag224_cpu_names = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);
 368         if (!diag224_cpu_names)
 369                 return -ENOMEM;
 370         if (diag224(diag224_cpu_names)) {
 371                 free_page((unsigned long) diag224_cpu_names);
 372                 return -EOPNOTSUPP;
 373         }
 374         EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16);
 375         return 0;
 376 }
 377 
 378 static void diag224_delete_name_table(void)
 379 {
 380         free_page((unsigned long) diag224_cpu_names);
 381 }
 382 
 383 static int diag224_idx2name(int index, char *name)
 384 {
 385         memcpy(name, diag224_cpu_names + ((index + 1) * DIAG204_CPU_NAME_LEN),
 386                DIAG204_CPU_NAME_LEN);
 387         name[DIAG204_CPU_NAME_LEN] = 0;
 388         strim(name);
 389         return 0;
 390 }
 391 
 392 struct dbfs_d204_hdr {
 393         u64     len;            /* Length of d204 buffer without header */
 394         u16     version;        /* Version of header */
 395         u8      sc;             /* Used subcode */
 396         char    reserved[53];
 397 } __attribute__ ((packed));
 398 
 399 struct dbfs_d204 {
 400         struct dbfs_d204_hdr    hdr;    /* 64 byte header */
 401         char                    buf[];  /* d204 buffer */
 402 } __attribute__ ((packed));
 403 
 404 static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size)
 405 {
 406         struct dbfs_d204 *d204;
 407         int rc, buf_size;
 408         void *base;
 409 
 410         buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr);
 411         base = vzalloc(buf_size);
 412         if (!base)
 413                 return -ENOMEM;
 414         d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr);
 415         rc = diag204_do_store(d204->buf, diag204_buf_pages);
 416         if (rc) {
 417                 vfree(base);
 418                 return rc;
 419         }
 420         d204->hdr.version = DBFS_D204_HDR_VERSION;
 421         d204->hdr.len = PAGE_SIZE * diag204_buf_pages;
 422         d204->hdr.sc = diag204_store_sc;
 423         *data = d204;
 424         *data_free_ptr = base;
 425         *size = d204->hdr.len + sizeof(struct dbfs_d204_hdr);
 426         return 0;
 427 }
 428 
 429 static struct hypfs_dbfs_file dbfs_file_d204 = {
 430         .name           = "diag_204",
 431         .data_create    = dbfs_d204_create,
 432         .data_free      = vfree,
 433 };
 434 
 435 __init int hypfs_diag_init(void)
 436 {
 437         int rc;
 438 
 439         if (diag204_probe()) {
 440                 pr_err("The hardware system does not support hypfs\n");
 441                 return -ENODATA;
 442         }
 443 
 444         if (diag204_info_type == DIAG204_INFO_EXT)
 445                 hypfs_dbfs_create_file(&dbfs_file_d204);
 446 
 447         if (MACHINE_IS_LPAR) {
 448                 rc = diag224_get_name_table();
 449                 if (rc) {
 450                         pr_err("The hardware system does not provide all "
 451                                "functions required by hypfs\n");
 452                         debugfs_remove(dbfs_d204_file);
 453                         return rc;
 454                 }
 455         }
 456         return 0;
 457 }
 458 
 459 void hypfs_diag_exit(void)
 460 {
 461         debugfs_remove(dbfs_d204_file);
 462         diag224_delete_name_table();
 463         diag204_free_buffer();
 464         hypfs_dbfs_remove_file(&dbfs_file_d204);
 465 }
 466 
 467 /*
 468  * Functions to create the directory structure
 469  * *******************************************
 470  */
 471 
 472 static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info)
 473 {
 474         struct dentry *cpu_dir;
 475         char buffer[TMP_SIZE];
 476         void *rc;
 477 
 478         snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type,
 479                                                             cpu_info));
 480         cpu_dir = hypfs_mkdir(cpus_dir, buffer);
 481         rc = hypfs_create_u64(cpu_dir, "mgmtime",
 482                               cpu_info__acc_time(diag204_info_type, cpu_info) -
 483                               cpu_info__lp_time(diag204_info_type, cpu_info));
 484         if (IS_ERR(rc))
 485                 return PTR_ERR(rc);
 486         rc = hypfs_create_u64(cpu_dir, "cputime",
 487                               cpu_info__lp_time(diag204_info_type, cpu_info));
 488         if (IS_ERR(rc))
 489                 return PTR_ERR(rc);
 490         if (diag204_info_type == DIAG204_INFO_EXT) {
 491                 rc = hypfs_create_u64(cpu_dir, "onlinetime",
 492                                       cpu_info__online_time(diag204_info_type,
 493                                                             cpu_info));
 494                 if (IS_ERR(rc))
 495                         return PTR_ERR(rc);
 496         }
 497         diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer);
 498         rc = hypfs_create_str(cpu_dir, "type", buffer);
 499         return PTR_ERR_OR_ZERO(rc);
 500 }
 501 
 502 static void *hypfs_create_lpar_files(struct dentry *systems_dir, void *part_hdr)
 503 {
 504         struct dentry *cpus_dir;
 505         struct dentry *lpar_dir;
 506         char lpar_name[DIAG204_LPAR_NAME_LEN + 1];
 507         void *cpu_info;
 508         int i;
 509 
 510         part_hdr__part_name(diag204_info_type, part_hdr, lpar_name);
 511         lpar_name[DIAG204_LPAR_NAME_LEN] = 0;
 512         lpar_dir = hypfs_mkdir(systems_dir, lpar_name);
 513         if (IS_ERR(lpar_dir))
 514                 return lpar_dir;
 515         cpus_dir = hypfs_mkdir(lpar_dir, "cpus");
 516         if (IS_ERR(cpus_dir))
 517                 return cpus_dir;
 518         cpu_info = part_hdr + part_hdr__size(diag204_info_type);
 519         for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) {
 520                 int rc;
 521                 rc = hypfs_create_cpu_files(cpus_dir, cpu_info);
 522                 if (rc)
 523                         return ERR_PTR(rc);
 524                 cpu_info += cpu_info__size(diag204_info_type);
 525         }
 526         return cpu_info;
 527 }
 528 
 529 static int hypfs_create_phys_cpu_files(struct dentry *cpus_dir, void *cpu_info)
 530 {
 531         struct dentry *cpu_dir;
 532         char buffer[TMP_SIZE];
 533         void *rc;
 534 
 535         snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type,
 536                                                             cpu_info));
 537         cpu_dir = hypfs_mkdir(cpus_dir, buffer);
 538         if (IS_ERR(cpu_dir))
 539                 return PTR_ERR(cpu_dir);
 540         rc = hypfs_create_u64(cpu_dir, "mgmtime",
 541                               phys_cpu__mgm_time(diag204_info_type, cpu_info));
 542         if (IS_ERR(rc))
 543                 return PTR_ERR(rc);
 544         diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer);
 545         rc = hypfs_create_str(cpu_dir, "type", buffer);
 546         return PTR_ERR_OR_ZERO(rc);
 547 }
 548 
 549 static void *hypfs_create_phys_files(struct dentry *parent_dir, void *phys_hdr)
 550 {
 551         int i;
 552         void *cpu_info;
 553         struct dentry *cpus_dir;
 554 
 555         cpus_dir = hypfs_mkdir(parent_dir, "cpus");
 556         if (IS_ERR(cpus_dir))
 557                 return cpus_dir;
 558         cpu_info = phys_hdr + phys_hdr__size(diag204_info_type);
 559         for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) {
 560                 int rc;
 561                 rc = hypfs_create_phys_cpu_files(cpus_dir, cpu_info);
 562                 if (rc)
 563                         return ERR_PTR(rc);
 564                 cpu_info += phys_cpu__size(diag204_info_type);
 565         }
 566         return cpu_info;
 567 }
 568 
 569 int hypfs_diag_create_files(struct dentry *root)
 570 {
 571         struct dentry *systems_dir, *hyp_dir;
 572         void *time_hdr, *part_hdr;
 573         int i, rc;
 574         void *buffer, *ptr;
 575 
 576         buffer = diag204_store();
 577         if (IS_ERR(buffer))
 578                 return PTR_ERR(buffer);
 579 
 580         systems_dir = hypfs_mkdir(root, "systems");
 581         if (IS_ERR(systems_dir)) {
 582                 rc = PTR_ERR(systems_dir);
 583                 goto err_out;
 584         }
 585         time_hdr = (struct x_info_blk_hdr *)buffer;
 586         part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type);
 587         for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) {
 588                 part_hdr = hypfs_create_lpar_files(systems_dir, part_hdr);
 589                 if (IS_ERR(part_hdr)) {
 590                         rc = PTR_ERR(part_hdr);
 591                         goto err_out;
 592                 }
 593         }
 594         if (info_blk_hdr__flags(diag204_info_type, time_hdr) &
 595             DIAG204_LPAR_PHYS_FLG) {
 596                 ptr = hypfs_create_phys_files(root, part_hdr);
 597                 if (IS_ERR(ptr)) {
 598                         rc = PTR_ERR(ptr);
 599                         goto err_out;
 600                 }
 601         }
 602         hyp_dir = hypfs_mkdir(root, "hyp");
 603         if (IS_ERR(hyp_dir)) {
 604                 rc = PTR_ERR(hyp_dir);
 605                 goto err_out;
 606         }
 607         ptr = hypfs_create_str(hyp_dir, "type", "LPAR Hypervisor");
 608         if (IS_ERR(ptr)) {
 609                 rc = PTR_ERR(ptr);
 610                 goto err_out;
 611         }
 612         rc = 0;
 613 
 614 err_out:
 615         return rc;
 616 }

/* [<][>][^][v][top][bottom][index][help] */