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