1 /* 2 * arch/s390/hypfs/hypfs_diag.c 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/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 */ 29 enum 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 */ 37 enum 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 45 static char *diag224_cpu_names; /* diag 224 name table */ 46 static enum diag204_sc diag204_store_sc; /* used subcode for store */ 47 static enum diag204_format diag204_info_type; /* used diag 204 data format */ 48 49 static void *diag204_buf; /* 4K aligned buffer for diag204 data */ 50 static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */ 51 static int diag204_buf_pages; /* number of pages for diag204 data */ 52 53 static 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 65 struct 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 74 struct 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 85 static 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 93 static 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 101 static 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 109 static 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 119 struct part_hdr { 120 __u8 pn; 121 __u8 cpus; 122 char reserved[6]; 123 char part_name[LPAR_NAME_LEN]; 124 } __attribute__ ((packed)); 125 126 struct 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 144 static 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 152 static 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 160 static 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 174 struct 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 184 struct 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 205 static 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 213 static 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 221 static 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 229 static 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 237 static 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 245 static 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 255 struct phys_hdr { 256 char reserved1[1]; 257 __u8 cpus; 258 char reserved2[6]; 259 char mgm_name[8]; 260 } __attribute__ ((packed)); 261 262 struct 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 270 static 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 278 static 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 288 struct 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 297 struct 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 306 static 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 314 static 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 322 static 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 330 static 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 340 static 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 355 /* 356 * For the old diag subcode 4 with simple data format we have to use real 357 * memory. If we use subcode 6 or 7 with extended data format, we can (and 358 * should) use vmalloc, since we need a lot of memory in that case. Currently 359 * up to 93 pages! 360 */ 361 362 static void diag204_free_buffer(void) 363 { 364 if (!diag204_buf) 365 return; 366 if (diag204_buf_vmalloc) { 367 vfree(diag204_buf_vmalloc); 368 diag204_buf_vmalloc = NULL; 369 } else { 370 free_pages((unsigned long) diag204_buf, 0); 371 } 372 diag204_buf = NULL; 373 } 374 375 static void *page_align_ptr(void *ptr) 376 { 377 return (void *) PAGE_ALIGN((unsigned long) ptr); 378 } 379 380 static void *diag204_alloc_vbuf(int pages) 381 { 382 /* The buffer has to be page aligned! */ 383 diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1)); 384 if (!diag204_buf_vmalloc) 385 return ERR_PTR(-ENOMEM); 386 diag204_buf = page_align_ptr(diag204_buf_vmalloc); 387 diag204_buf_pages = pages; 388 return diag204_buf; 389 } 390 391 static void *diag204_alloc_rbuf(void) 392 { 393 diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0); 394 if (!diag204_buf) 395 return ERR_PTR(-ENOMEM); 396 diag204_buf_pages = 1; 397 return diag204_buf; 398 } 399 400 static void *diag204_get_buffer(enum diag204_format fmt, int *pages) 401 { 402 if (diag204_buf) { 403 *pages = diag204_buf_pages; 404 return diag204_buf; 405 } 406 if (fmt == INFO_SIMPLE) { 407 *pages = 1; 408 return diag204_alloc_rbuf(); 409 } else {/* INFO_EXT */ 410 *pages = diag204((unsigned long)SUBC_RSI | 411 (unsigned long)INFO_EXT, 0, NULL); 412 if (*pages <= 0) 413 return ERR_PTR(-ENOSYS); 414 else 415 return diag204_alloc_vbuf(*pages); 416 } 417 } 418 419 /* 420 * diag204_probe() has to find out, which type of diagnose 204 implementation 421 * we have on our machine. Currently there are three possible scanarios: 422 * - subcode 4 + simple data format (only one page) 423 * - subcode 4-6 + extended data format 424 * - subcode 4-7 + extended data format 425 * 426 * Subcode 5 is used to retrieve the size of the data, provided by subcodes 427 * 6 and 7. Subcode 7 basically has the same function as subcode 6. In addition 428 * to subcode 6 it provides also information about secondary cpus. 429 * In order to get as much information as possible, we first try 430 * subcode 7, then 6 and if both fail, we use subcode 4. 431 */ 432 433 static int diag204_probe(void) 434 { 435 void *buf; 436 int pages, rc; 437 438 buf = diag204_get_buffer(INFO_EXT, &pages); 439 if (!IS_ERR(buf)) { 440 if (diag204((unsigned long)SUBC_STIB7 | 441 (unsigned long)INFO_EXT, pages, buf) >= 0) { 442 diag204_store_sc = SUBC_STIB7; 443 diag204_info_type = INFO_EXT; 444 goto out; 445 } 446 if (diag204((unsigned long)SUBC_STIB6 | 447 (unsigned long)INFO_EXT, pages, buf) >= 0) { 448 diag204_store_sc = SUBC_STIB6; 449 diag204_info_type = INFO_EXT; 450 goto out; 451 } 452 diag204_free_buffer(); 453 } 454 455 /* subcodes 6 and 7 failed, now try subcode 4 */ 456 457 buf = diag204_get_buffer(INFO_SIMPLE, &pages); 458 if (IS_ERR(buf)) { 459 rc = PTR_ERR(buf); 460 goto fail_alloc; 461 } 462 if (diag204((unsigned long)SUBC_STIB4 | 463 (unsigned long)INFO_SIMPLE, pages, buf) >= 0) { 464 diag204_store_sc = SUBC_STIB4; 465 diag204_info_type = INFO_SIMPLE; 466 goto out; 467 } else { 468 rc = -ENOSYS; 469 goto fail_store; 470 } 471 out: 472 rc = 0; 473 fail_store: 474 diag204_free_buffer(); 475 fail_alloc: 476 return rc; 477 } 478 479 static int diag204_do_store(void *buf, int pages) 480 { 481 int rc; 482 483 rc = diag204((unsigned long) diag204_store_sc | 484 (unsigned long) diag204_info_type, pages, buf); 485 return rc < 0 ? -ENOSYS : 0; 486 } 487 488 static void *diag204_store(void) 489 { 490 void *buf; 491 int pages, rc; 492 493 buf = diag204_get_buffer(diag204_info_type, &pages); 494 if (IS_ERR(buf)) 495 goto out; 496 rc = diag204_do_store(buf, pages); 497 if (rc) 498 return ERR_PTR(rc); 499 out: 500 return buf; 501 } 502 503 /* Diagnose 224 functions */ 504 505 static int diag224(void *ptr) 506 { 507 int rc = -EOPNOTSUPP; 508 509 asm volatile( 510 " diag %1,%2,0x224\n" 511 "0: lhi %0,0x0\n" 512 "1:\n" 513 EX_TABLE(0b,1b) 514 : "+d" (rc) :"d" (0), "d" (ptr) : "memory"); 515 return rc; 516 } 517 518 static int diag224_get_name_table(void) 519 { 520 /* memory must be below 2GB */ 521 diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); 522 if (!diag224_cpu_names) 523 return -ENOMEM; 524 if (diag224(diag224_cpu_names)) { 525 kfree(diag224_cpu_names); 526 return -EOPNOTSUPP; 527 } 528 EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16); 529 return 0; 530 } 531 532 static void diag224_delete_name_table(void) 533 { 534 kfree(diag224_cpu_names); 535 } 536 537 static int diag224_idx2name(int index, char *name) 538 { 539 memcpy(name, diag224_cpu_names + ((index + 1) * CPU_NAME_LEN), 540 CPU_NAME_LEN); 541 name[CPU_NAME_LEN] = 0; 542 strim(name); 543 return 0; 544 } 545 546 struct dbfs_d204_hdr { 547 u64 len; /* Length of d204 buffer without header */ 548 u16 version; /* Version of header */ 549 u8 sc; /* Used subcode */ 550 char reserved[53]; 551 } __attribute__ ((packed)); 552 553 struct dbfs_d204 { 554 struct dbfs_d204_hdr hdr; /* 64 byte header */ 555 char buf[]; /* d204 buffer */ 556 } __attribute__ ((packed)); 557 558 static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size) 559 { 560 struct dbfs_d204 *d204; 561 int rc, buf_size; 562 void *base; 563 564 buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr); 565 base = vmalloc(buf_size); 566 if (!base) 567 return -ENOMEM; 568 memset(base, 0, buf_size); 569 d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr); 570 rc = diag204_do_store(d204->buf, diag204_buf_pages); 571 if (rc) { 572 vfree(base); 573 return rc; 574 } 575 d204->hdr.version = DBFS_D204_HDR_VERSION; 576 d204->hdr.len = PAGE_SIZE * diag204_buf_pages; 577 d204->hdr.sc = diag204_store_sc; 578 *data = d204; 579 *data_free_ptr = base; 580 *size = d204->hdr.len + sizeof(struct dbfs_d204_hdr); 581 return 0; 582 } 583 584 static struct hypfs_dbfs_file dbfs_file_d204 = { 585 .name = "diag_204", 586 .data_create = dbfs_d204_create, 587 .data_free = vfree, 588 }; 589 590 __init int hypfs_diag_init(void) 591 { 592 int rc; 593 594 if (diag204_probe()) { 595 pr_err("The hardware system does not support hypfs\n"); 596 return -ENODATA; 597 } 598 if (diag204_info_type == INFO_EXT) { 599 rc = hypfs_dbfs_create_file(&dbfs_file_d204); 600 if (rc) 601 return rc; 602 } 603 if (MACHINE_IS_LPAR) { 604 rc = diag224_get_name_table(); 605 if (rc) { 606 pr_err("The hardware system does not provide all " 607 "functions required by hypfs\n"); 608 debugfs_remove(dbfs_d204_file); 609 return rc; 610 } 611 } 612 return 0; 613 } 614 615 void hypfs_diag_exit(void) 616 { 617 debugfs_remove(dbfs_d204_file); 618 diag224_delete_name_table(); 619 diag204_free_buffer(); 620 hypfs_dbfs_remove_file(&dbfs_file_d204); 621 } 622 623 /* 624 * Functions to create the directory structure 625 * ******************************************* 626 */ 627 628 static int hypfs_create_cpu_files(struct super_block *sb, 629 struct dentry *cpus_dir, void *cpu_info) 630 { 631 struct dentry *cpu_dir; 632 char buffer[TMP_SIZE]; 633 void *rc; 634 635 snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type, 636 cpu_info)); 637 cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer); 638 rc = hypfs_create_u64(sb, cpu_dir, "mgmtime", 639 cpu_info__acc_time(diag204_info_type, cpu_info) - 640 cpu_info__lp_time(diag204_info_type, cpu_info)); 641 if (IS_ERR(rc)) 642 return PTR_ERR(rc); 643 rc = hypfs_create_u64(sb, cpu_dir, "cputime", 644 cpu_info__lp_time(diag204_info_type, cpu_info)); 645 if (IS_ERR(rc)) 646 return PTR_ERR(rc); 647 if (diag204_info_type == INFO_EXT) { 648 rc = hypfs_create_u64(sb, cpu_dir, "onlinetime", 649 cpu_info__online_time(diag204_info_type, 650 cpu_info)); 651 if (IS_ERR(rc)) 652 return PTR_ERR(rc); 653 } 654 diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer); 655 rc = hypfs_create_str(sb, cpu_dir, "type", buffer); 656 if (IS_ERR(rc)) 657 return PTR_ERR(rc); 658 return 0; 659 } 660 661 static void *hypfs_create_lpar_files(struct super_block *sb, 662 struct dentry *systems_dir, void *part_hdr) 663 { 664 struct dentry *cpus_dir; 665 struct dentry *lpar_dir; 666 char lpar_name[LPAR_NAME_LEN + 1]; 667 void *cpu_info; 668 int i; 669 670 part_hdr__part_name(diag204_info_type, part_hdr, lpar_name); 671 lpar_name[LPAR_NAME_LEN] = 0; 672 lpar_dir = hypfs_mkdir(sb, systems_dir, lpar_name); 673 if (IS_ERR(lpar_dir)) 674 return lpar_dir; 675 cpus_dir = hypfs_mkdir(sb, lpar_dir, "cpus"); 676 if (IS_ERR(cpus_dir)) 677 return cpus_dir; 678 cpu_info = part_hdr + part_hdr__size(diag204_info_type); 679 for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) { 680 int rc; 681 rc = hypfs_create_cpu_files(sb, cpus_dir, cpu_info); 682 if (rc) 683 return ERR_PTR(rc); 684 cpu_info += cpu_info__size(diag204_info_type); 685 } 686 return cpu_info; 687 } 688 689 static int hypfs_create_phys_cpu_files(struct super_block *sb, 690 struct dentry *cpus_dir, void *cpu_info) 691 { 692 struct dentry *cpu_dir; 693 char buffer[TMP_SIZE]; 694 void *rc; 695 696 snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type, 697 cpu_info)); 698 cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer); 699 if (IS_ERR(cpu_dir)) 700 return PTR_ERR(cpu_dir); 701 rc = hypfs_create_u64(sb, cpu_dir, "mgmtime", 702 phys_cpu__mgm_time(diag204_info_type, cpu_info)); 703 if (IS_ERR(rc)) 704 return PTR_ERR(rc); 705 diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer); 706 rc = hypfs_create_str(sb, cpu_dir, "type", buffer); 707 if (IS_ERR(rc)) 708 return PTR_ERR(rc); 709 return 0; 710 } 711 712 static void *hypfs_create_phys_files(struct super_block *sb, 713 struct dentry *parent_dir, void *phys_hdr) 714 { 715 int i; 716 void *cpu_info; 717 struct dentry *cpus_dir; 718 719 cpus_dir = hypfs_mkdir(sb, parent_dir, "cpus"); 720 if (IS_ERR(cpus_dir)) 721 return cpus_dir; 722 cpu_info = phys_hdr + phys_hdr__size(diag204_info_type); 723 for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) { 724 int rc; 725 rc = hypfs_create_phys_cpu_files(sb, cpus_dir, cpu_info); 726 if (rc) 727 return ERR_PTR(rc); 728 cpu_info += phys_cpu__size(diag204_info_type); 729 } 730 return cpu_info; 731 } 732 733 int hypfs_diag_create_files(struct super_block *sb, struct dentry *root) 734 { 735 struct dentry *systems_dir, *hyp_dir; 736 void *time_hdr, *part_hdr; 737 int i, rc; 738 void *buffer, *ptr; 739 740 buffer = diag204_store(); 741 if (IS_ERR(buffer)) 742 return PTR_ERR(buffer); 743 744 systems_dir = hypfs_mkdir(sb, root, "systems"); 745 if (IS_ERR(systems_dir)) { 746 rc = PTR_ERR(systems_dir); 747 goto err_out; 748 } 749 time_hdr = (struct x_info_blk_hdr *)buffer; 750 part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type); 751 for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) { 752 part_hdr = hypfs_create_lpar_files(sb, systems_dir, part_hdr); 753 if (IS_ERR(part_hdr)) { 754 rc = PTR_ERR(part_hdr); 755 goto err_out; 756 } 757 } 758 if (info_blk_hdr__flags(diag204_info_type, time_hdr) & LPAR_PHYS_FLG) { 759 ptr = hypfs_create_phys_files(sb, root, part_hdr); 760 if (IS_ERR(ptr)) { 761 rc = PTR_ERR(ptr); 762 goto err_out; 763 } 764 } 765 hyp_dir = hypfs_mkdir(sb, root, "hyp"); 766 if (IS_ERR(hyp_dir)) { 767 rc = PTR_ERR(hyp_dir); 768 goto err_out; 769 } 770 ptr = hypfs_create_str(sb, hyp_dir, "type", "LPAR Hypervisor"); 771 if (IS_ERR(ptr)) { 772 rc = PTR_ERR(ptr); 773 goto err_out; 774 } 775 rc = 0; 776 777 err_out: 778 return rc; 779 } 780