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 */ 28 enum 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 */ 36 enum 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 44 static char *diag224_cpu_names; /* diag 224 name table */ 45 static enum diag204_sc diag204_store_sc; /* used subcode for store */ 46 static enum diag204_format diag204_info_type; /* used diag 204 data format */ 47 48 static void *diag204_buf; /* 4K aligned buffer for diag204 data */ 49 static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */ 50 static int diag204_buf_pages; /* number of pages for diag204 data */ 51 52 static 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 64 struct 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 73 struct 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 84 static 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 92 static 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 100 static 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 108 static 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 118 struct part_hdr { 119 __u8 pn; 120 __u8 cpus; 121 char reserved[6]; 122 char part_name[LPAR_NAME_LEN]; 123 } __attribute__ ((packed)); 124 125 struct 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 143 static 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 151 static 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 159 static 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 173 struct 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 183 struct 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 204 static 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 212 static 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 220 static 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 228 static 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 236 static 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 244 static 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 254 struct phys_hdr { 255 char reserved1[1]; 256 __u8 cpus; 257 char reserved2[6]; 258 char mgm_name[8]; 259 } __attribute__ ((packed)); 260 261 struct 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 269 static 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 277 static 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 287 struct 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 296 struct 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 305 static 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 313 static 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 321 static 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 329 static 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 339 static 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 361 static 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 374 static void *page_align_ptr(void *ptr) 375 { 376 return (void *) PAGE_ALIGN((unsigned long) ptr); 377 } 378 379 static 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 390 static 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 399 static 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 432 static 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 } 470 out: 471 rc = 0; 472 fail_store: 473 diag204_free_buffer(); 474 fail_alloc: 475 return rc; 476 } 477 478 static 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 487 static 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); 498 out: 499 return buf; 500 } 501 502 /* Diagnose 224 functions */ 503 504 static 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 517 static 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 531 static void diag224_delete_name_table(void) 532 { 533 kfree(diag224_cpu_names); 534 } 535 536 static 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 545 struct 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 552 struct dbfs_d204 { 553 struct dbfs_d204_hdr hdr; /* 64 byte header */ 554 char buf[]; /* d204 buffer */ 555 } __attribute__ ((packed)); 556 557 static 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 582 static 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 613 void 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 626 static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info) 627 { 628 struct dentry *cpu_dir; 629 char buffer[TMP_SIZE]; 630 void *rc; 631 632 snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type, 633 cpu_info)); 634 cpu_dir = hypfs_mkdir(cpus_dir, buffer); 635 rc = hypfs_create_u64(cpu_dir, "mgmtime", 636 cpu_info__acc_time(diag204_info_type, cpu_info) - 637 cpu_info__lp_time(diag204_info_type, cpu_info)); 638 if (IS_ERR(rc)) 639 return PTR_ERR(rc); 640 rc = hypfs_create_u64(cpu_dir, "cputime", 641 cpu_info__lp_time(diag204_info_type, cpu_info)); 642 if (IS_ERR(rc)) 643 return PTR_ERR(rc); 644 if (diag204_info_type == INFO_EXT) { 645 rc = hypfs_create_u64(cpu_dir, "onlinetime", 646 cpu_info__online_time(diag204_info_type, 647 cpu_info)); 648 if (IS_ERR(rc)) 649 return PTR_ERR(rc); 650 } 651 diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer); 652 rc = hypfs_create_str(cpu_dir, "type", buffer); 653 return PTR_RET(rc); 654 } 655 656 static void *hypfs_create_lpar_files(struct dentry *systems_dir, void *part_hdr) 657 { 658 struct dentry *cpus_dir; 659 struct dentry *lpar_dir; 660 char lpar_name[LPAR_NAME_LEN + 1]; 661 void *cpu_info; 662 int i; 663 664 part_hdr__part_name(diag204_info_type, part_hdr, lpar_name); 665 lpar_name[LPAR_NAME_LEN] = 0; 666 lpar_dir = hypfs_mkdir(systems_dir, lpar_name); 667 if (IS_ERR(lpar_dir)) 668 return lpar_dir; 669 cpus_dir = hypfs_mkdir(lpar_dir, "cpus"); 670 if (IS_ERR(cpus_dir)) 671 return cpus_dir; 672 cpu_info = part_hdr + part_hdr__size(diag204_info_type); 673 for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) { 674 int rc; 675 rc = hypfs_create_cpu_files(cpus_dir, cpu_info); 676 if (rc) 677 return ERR_PTR(rc); 678 cpu_info += cpu_info__size(diag204_info_type); 679 } 680 return cpu_info; 681 } 682 683 static int hypfs_create_phys_cpu_files(struct dentry *cpus_dir, void *cpu_info) 684 { 685 struct dentry *cpu_dir; 686 char buffer[TMP_SIZE]; 687 void *rc; 688 689 snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type, 690 cpu_info)); 691 cpu_dir = hypfs_mkdir(cpus_dir, buffer); 692 if (IS_ERR(cpu_dir)) 693 return PTR_ERR(cpu_dir); 694 rc = hypfs_create_u64(cpu_dir, "mgmtime", 695 phys_cpu__mgm_time(diag204_info_type, cpu_info)); 696 if (IS_ERR(rc)) 697 return PTR_ERR(rc); 698 diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer); 699 rc = hypfs_create_str(cpu_dir, "type", buffer); 700 return PTR_RET(rc); 701 } 702 703 static void *hypfs_create_phys_files(struct dentry *parent_dir, void *phys_hdr) 704 { 705 int i; 706 void *cpu_info; 707 struct dentry *cpus_dir; 708 709 cpus_dir = hypfs_mkdir(parent_dir, "cpus"); 710 if (IS_ERR(cpus_dir)) 711 return cpus_dir; 712 cpu_info = phys_hdr + phys_hdr__size(diag204_info_type); 713 for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) { 714 int rc; 715 rc = hypfs_create_phys_cpu_files(cpus_dir, cpu_info); 716 if (rc) 717 return ERR_PTR(rc); 718 cpu_info += phys_cpu__size(diag204_info_type); 719 } 720 return cpu_info; 721 } 722 723 int hypfs_diag_create_files(struct dentry *root) 724 { 725 struct dentry *systems_dir, *hyp_dir; 726 void *time_hdr, *part_hdr; 727 int i, rc; 728 void *buffer, *ptr; 729 730 buffer = diag204_store(); 731 if (IS_ERR(buffer)) 732 return PTR_ERR(buffer); 733 734 systems_dir = hypfs_mkdir(root, "systems"); 735 if (IS_ERR(systems_dir)) { 736 rc = PTR_ERR(systems_dir); 737 goto err_out; 738 } 739 time_hdr = (struct x_info_blk_hdr *)buffer; 740 part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type); 741 for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) { 742 part_hdr = hypfs_create_lpar_files(systems_dir, part_hdr); 743 if (IS_ERR(part_hdr)) { 744 rc = PTR_ERR(part_hdr); 745 goto err_out; 746 } 747 } 748 if (info_blk_hdr__flags(diag204_info_type, time_hdr) & LPAR_PHYS_FLG) { 749 ptr = hypfs_create_phys_files(root, part_hdr); 750 if (IS_ERR(ptr)) { 751 rc = PTR_ERR(ptr); 752 goto err_out; 753 } 754 } 755 hyp_dir = hypfs_mkdir(root, "hyp"); 756 if (IS_ERR(hyp_dir)) { 757 rc = PTR_ERR(hyp_dir); 758 goto err_out; 759 } 760 ptr = hypfs_create_str(hyp_dir, "type", "LPAR Hypervisor"); 761 if (IS_ERR(ptr)) { 762 rc = PTR_ERR(ptr); 763 goto err_out; 764 } 765 rc = 0; 766 767 err_out: 768 return rc; 769 } 770