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 = vzalloc(buf_size); 566 if (!base) 567 return -ENOMEM; 568 d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr); 569 rc = diag204_do_store(d204->buf, diag204_buf_pages); 570 if (rc) { 571 vfree(base); 572 return rc; 573 } 574 d204->hdr.version = DBFS_D204_HDR_VERSION; 575 d204->hdr.len = PAGE_SIZE * diag204_buf_pages; 576 d204->hdr.sc = diag204_store_sc; 577 *data = d204; 578 *data_free_ptr = base; 579 *size = d204->hdr.len + sizeof(struct dbfs_d204_hdr); 580 return 0; 581 } 582 583 static struct hypfs_dbfs_file dbfs_file_d204 = { 584 .name = "diag_204", 585 .data_create = dbfs_d204_create, 586 .data_free = vfree, 587 }; 588 589 __init int hypfs_diag_init(void) 590 { 591 int rc; 592 593 if (diag204_probe()) { 594 pr_err("The hardware system does not support hypfs\n"); 595 return -ENODATA; 596 } 597 if (diag204_info_type == INFO_EXT) { 598 rc = hypfs_dbfs_create_file(&dbfs_file_d204); 599 if (rc) 600 return rc; 601 } 602 if (MACHINE_IS_LPAR) { 603 rc = diag224_get_name_table(); 604 if (rc) { 605 pr_err("The hardware system does not provide all " 606 "functions required by hypfs\n"); 607 debugfs_remove(dbfs_d204_file); 608 return rc; 609 } 610 } 611 return 0; 612 } 613 614 void hypfs_diag_exit(void) 615 { 616 debugfs_remove(dbfs_d204_file); 617 diag224_delete_name_table(); 618 diag204_free_buffer(); 619 hypfs_dbfs_remove_file(&dbfs_file_d204); 620 } 621 622 /* 623 * Functions to create the directory structure 624 * ******************************************* 625 */ 626 627 static int hypfs_create_cpu_files(struct super_block *sb, 628 struct dentry *cpus_dir, void *cpu_info) 629 { 630 struct dentry *cpu_dir; 631 char buffer[TMP_SIZE]; 632 void *rc; 633 634 snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type, 635 cpu_info)); 636 cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer); 637 rc = hypfs_create_u64(sb, cpu_dir, "mgmtime", 638 cpu_info__acc_time(diag204_info_type, cpu_info) - 639 cpu_info__lp_time(diag204_info_type, cpu_info)); 640 if (IS_ERR(rc)) 641 return PTR_ERR(rc); 642 rc = hypfs_create_u64(sb, cpu_dir, "cputime", 643 cpu_info__lp_time(diag204_info_type, cpu_info)); 644 if (IS_ERR(rc)) 645 return PTR_ERR(rc); 646 if (diag204_info_type == INFO_EXT) { 647 rc = hypfs_create_u64(sb, cpu_dir, "onlinetime", 648 cpu_info__online_time(diag204_info_type, 649 cpu_info)); 650 if (IS_ERR(rc)) 651 return PTR_ERR(rc); 652 } 653 diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer); 654 rc = hypfs_create_str(sb, cpu_dir, "type", buffer); 655 if (IS_ERR(rc)) 656 return PTR_ERR(rc); 657 return 0; 658 } 659 660 static void *hypfs_create_lpar_files(struct super_block *sb, 661 struct dentry *systems_dir, void *part_hdr) 662 { 663 struct dentry *cpus_dir; 664 struct dentry *lpar_dir; 665 char lpar_name[LPAR_NAME_LEN + 1]; 666 void *cpu_info; 667 int i; 668 669 part_hdr__part_name(diag204_info_type, part_hdr, lpar_name); 670 lpar_name[LPAR_NAME_LEN] = 0; 671 lpar_dir = hypfs_mkdir(sb, systems_dir, lpar_name); 672 if (IS_ERR(lpar_dir)) 673 return lpar_dir; 674 cpus_dir = hypfs_mkdir(sb, lpar_dir, "cpus"); 675 if (IS_ERR(cpus_dir)) 676 return cpus_dir; 677 cpu_info = part_hdr + part_hdr__size(diag204_info_type); 678 for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) { 679 int rc; 680 rc = hypfs_create_cpu_files(sb, cpus_dir, cpu_info); 681 if (rc) 682 return ERR_PTR(rc); 683 cpu_info += cpu_info__size(diag204_info_type); 684 } 685 return cpu_info; 686 } 687 688 static int hypfs_create_phys_cpu_files(struct super_block *sb, 689 struct dentry *cpus_dir, void *cpu_info) 690 { 691 struct dentry *cpu_dir; 692 char buffer[TMP_SIZE]; 693 void *rc; 694 695 snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type, 696 cpu_info)); 697 cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer); 698 if (IS_ERR(cpu_dir)) 699 return PTR_ERR(cpu_dir); 700 rc = hypfs_create_u64(sb, cpu_dir, "mgmtime", 701 phys_cpu__mgm_time(diag204_info_type, cpu_info)); 702 if (IS_ERR(rc)) 703 return PTR_ERR(rc); 704 diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer); 705 rc = hypfs_create_str(sb, cpu_dir, "type", buffer); 706 if (IS_ERR(rc)) 707 return PTR_ERR(rc); 708 return 0; 709 } 710 711 static void *hypfs_create_phys_files(struct super_block *sb, 712 struct dentry *parent_dir, void *phys_hdr) 713 { 714 int i; 715 void *cpu_info; 716 struct dentry *cpus_dir; 717 718 cpus_dir = hypfs_mkdir(sb, parent_dir, "cpus"); 719 if (IS_ERR(cpus_dir)) 720 return cpus_dir; 721 cpu_info = phys_hdr + phys_hdr__size(diag204_info_type); 722 for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) { 723 int rc; 724 rc = hypfs_create_phys_cpu_files(sb, cpus_dir, cpu_info); 725 if (rc) 726 return ERR_PTR(rc); 727 cpu_info += phys_cpu__size(diag204_info_type); 728 } 729 return cpu_info; 730 } 731 732 int hypfs_diag_create_files(struct super_block *sb, struct dentry *root) 733 { 734 struct dentry *systems_dir, *hyp_dir; 735 void *time_hdr, *part_hdr; 736 int i, rc; 737 void *buffer, *ptr; 738 739 buffer = diag204_store(); 740 if (IS_ERR(buffer)) 741 return PTR_ERR(buffer); 742 743 systems_dir = hypfs_mkdir(sb, root, "systems"); 744 if (IS_ERR(systems_dir)) { 745 rc = PTR_ERR(systems_dir); 746 goto err_out; 747 } 748 time_hdr = (struct x_info_blk_hdr *)buffer; 749 part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type); 750 for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) { 751 part_hdr = hypfs_create_lpar_files(sb, systems_dir, part_hdr); 752 if (IS_ERR(part_hdr)) { 753 rc = PTR_ERR(part_hdr); 754 goto err_out; 755 } 756 } 757 if (info_blk_hdr__flags(diag204_info_type, time_hdr) & LPAR_PHYS_FLG) { 758 ptr = hypfs_create_phys_files(sb, root, part_hdr); 759 if (IS_ERR(ptr)) { 760 rc = PTR_ERR(ptr); 761 goto err_out; 762 } 763 } 764 hyp_dir = hypfs_mkdir(sb, root, "hyp"); 765 if (IS_ERR(hyp_dir)) { 766 rc = PTR_ERR(hyp_dir); 767 goto err_out; 768 } 769 ptr = hypfs_create_str(sb, hyp_dir, "type", "LPAR Hypervisor"); 770 if (IS_ERR(ptr)) { 771 rc = PTR_ERR(ptr); 772 goto err_out; 773 } 774 rc = 0; 775 776 err_out: 777 return rc; 778 } 779