162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Hypervisor filesystem for Linux on s390. Diag 204 and 224 462306a36Sopenharmony_ci * implementation. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright IBM Corp. 2006, 2008 762306a36Sopenharmony_ci * Author(s): Michael Holzheu <holzheu@de.ibm.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define KMSG_COMPONENT "hypfs" 1162306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/types.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci#include <linux/vmalloc.h> 1862306a36Sopenharmony_ci#include <linux/mm.h> 1962306a36Sopenharmony_ci#include <asm/diag.h> 2062306a36Sopenharmony_ci#include <asm/ebcdic.h> 2162306a36Sopenharmony_ci#include "hypfs_diag.h" 2262306a36Sopenharmony_ci#include "hypfs.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define TMP_SIZE 64 /* size of temporary buffers */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic char *diag224_cpu_names; /* diag 224 name table */ 2762306a36Sopenharmony_cistatic int diag224_idx2name(int index, char *name); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * DIAG 204 member access functions. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * Since we have two different diag 204 data formats for old and new s390 3362306a36Sopenharmony_ci * machines, we do not access the structs directly, but use getter functions for 3462306a36Sopenharmony_ci * each struct member instead. This should make the code more readable. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* Time information block */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic inline int info_blk_hdr__size(enum diag204_format type) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 4262306a36Sopenharmony_ci return sizeof(struct diag204_info_blk_hdr); 4362306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 4462306a36Sopenharmony_ci return sizeof(struct diag204_x_info_blk_hdr); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic inline __u8 info_blk_hdr__npar(enum diag204_format type, void *hdr) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 5062306a36Sopenharmony_ci return ((struct diag204_info_blk_hdr *)hdr)->npar; 5162306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 5262306a36Sopenharmony_ci return ((struct diag204_x_info_blk_hdr *)hdr)->npar; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 5862306a36Sopenharmony_ci return ((struct diag204_info_blk_hdr *)hdr)->flags; 5962306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 6062306a36Sopenharmony_ci return ((struct diag204_x_info_blk_hdr *)hdr)->flags; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* Partition header */ 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic inline int part_hdr__size(enum diag204_format type) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 6862306a36Sopenharmony_ci return sizeof(struct diag204_part_hdr); 6962306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 7062306a36Sopenharmony_ci return sizeof(struct diag204_x_part_hdr); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic inline __u8 part_hdr__rcpus(enum diag204_format type, void *hdr) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 7662306a36Sopenharmony_ci return ((struct diag204_part_hdr *)hdr)->cpus; 7762306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 7862306a36Sopenharmony_ci return ((struct diag204_x_part_hdr *)hdr)->rcpus; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic inline void part_hdr__part_name(enum diag204_format type, void *hdr, 8262306a36Sopenharmony_ci char *name) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 8562306a36Sopenharmony_ci memcpy(name, ((struct diag204_part_hdr *)hdr)->part_name, 8662306a36Sopenharmony_ci DIAG204_LPAR_NAME_LEN); 8762306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 8862306a36Sopenharmony_ci memcpy(name, ((struct diag204_x_part_hdr *)hdr)->part_name, 8962306a36Sopenharmony_ci DIAG204_LPAR_NAME_LEN); 9062306a36Sopenharmony_ci EBCASC(name, DIAG204_LPAR_NAME_LEN); 9162306a36Sopenharmony_ci name[DIAG204_LPAR_NAME_LEN] = 0; 9262306a36Sopenharmony_ci strim(name); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* CPU info block */ 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic inline int cpu_info__size(enum diag204_format type) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 10062306a36Sopenharmony_ci return sizeof(struct diag204_cpu_info); 10162306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 10262306a36Sopenharmony_ci return sizeof(struct diag204_x_cpu_info); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic inline __u8 cpu_info__ctidx(enum diag204_format type, void *hdr) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 10862306a36Sopenharmony_ci return ((struct diag204_cpu_info *)hdr)->ctidx; 10962306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 11062306a36Sopenharmony_ci return ((struct diag204_x_cpu_info *)hdr)->ctidx; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic inline __u16 cpu_info__cpu_addr(enum diag204_format type, void *hdr) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 11662306a36Sopenharmony_ci return ((struct diag204_cpu_info *)hdr)->cpu_addr; 11762306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 11862306a36Sopenharmony_ci return ((struct diag204_x_cpu_info *)hdr)->cpu_addr; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic inline __u64 cpu_info__acc_time(enum diag204_format type, void *hdr) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 12462306a36Sopenharmony_ci return ((struct diag204_cpu_info *)hdr)->acc_time; 12562306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 12662306a36Sopenharmony_ci return ((struct diag204_x_cpu_info *)hdr)->acc_time; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic inline __u64 cpu_info__lp_time(enum diag204_format type, void *hdr) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 13262306a36Sopenharmony_ci return ((struct diag204_cpu_info *)hdr)->lp_time; 13362306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 13462306a36Sopenharmony_ci return ((struct diag204_x_cpu_info *)hdr)->lp_time; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic inline __u64 cpu_info__online_time(enum diag204_format type, void *hdr) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 14062306a36Sopenharmony_ci return 0; /* online_time not available in simple info */ 14162306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 14262306a36Sopenharmony_ci return ((struct diag204_x_cpu_info *)hdr)->online_time; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* Physical header */ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic inline int phys_hdr__size(enum diag204_format type) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 15062306a36Sopenharmony_ci return sizeof(struct diag204_phys_hdr); 15162306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 15262306a36Sopenharmony_ci return sizeof(struct diag204_x_phys_hdr); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic inline __u8 phys_hdr__cpus(enum diag204_format type, void *hdr) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 15862306a36Sopenharmony_ci return ((struct diag204_phys_hdr *)hdr)->cpus; 15962306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 16062306a36Sopenharmony_ci return ((struct diag204_x_phys_hdr *)hdr)->cpus; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/* Physical CPU info block */ 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic inline int phys_cpu__size(enum diag204_format type) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 16862306a36Sopenharmony_ci return sizeof(struct diag204_phys_cpu); 16962306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 17062306a36Sopenharmony_ci return sizeof(struct diag204_x_phys_cpu); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic inline __u16 phys_cpu__cpu_addr(enum diag204_format type, void *hdr) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 17662306a36Sopenharmony_ci return ((struct diag204_phys_cpu *)hdr)->cpu_addr; 17762306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 17862306a36Sopenharmony_ci return ((struct diag204_x_phys_cpu *)hdr)->cpu_addr; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic inline __u64 phys_cpu__mgm_time(enum diag204_format type, void *hdr) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 18462306a36Sopenharmony_ci return ((struct diag204_phys_cpu *)hdr)->mgm_time; 18562306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 18662306a36Sopenharmony_ci return ((struct diag204_x_phys_cpu *)hdr)->mgm_time; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic inline __u64 phys_cpu__ctidx(enum diag204_format type, void *hdr) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci if (type == DIAG204_INFO_SIMPLE) 19262306a36Sopenharmony_ci return ((struct diag204_phys_cpu *)hdr)->ctidx; 19362306a36Sopenharmony_ci else /* DIAG204_INFO_EXT */ 19462306a36Sopenharmony_ci return ((struct diag204_x_phys_cpu *)hdr)->ctidx; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* 19862306a36Sopenharmony_ci * Functions to create the directory structure 19962306a36Sopenharmony_ci * ******************************************* 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct dentry *cpu_dir; 20562306a36Sopenharmony_ci char buffer[TMP_SIZE]; 20662306a36Sopenharmony_ci void *rc; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_get_info_type(), 20962306a36Sopenharmony_ci cpu_info)); 21062306a36Sopenharmony_ci cpu_dir = hypfs_mkdir(cpus_dir, buffer); 21162306a36Sopenharmony_ci rc = hypfs_create_u64(cpu_dir, "mgmtime", 21262306a36Sopenharmony_ci cpu_info__acc_time(diag204_get_info_type(), cpu_info) - 21362306a36Sopenharmony_ci cpu_info__lp_time(diag204_get_info_type(), cpu_info)); 21462306a36Sopenharmony_ci if (IS_ERR(rc)) 21562306a36Sopenharmony_ci return PTR_ERR(rc); 21662306a36Sopenharmony_ci rc = hypfs_create_u64(cpu_dir, "cputime", 21762306a36Sopenharmony_ci cpu_info__lp_time(diag204_get_info_type(), cpu_info)); 21862306a36Sopenharmony_ci if (IS_ERR(rc)) 21962306a36Sopenharmony_ci return PTR_ERR(rc); 22062306a36Sopenharmony_ci if (diag204_get_info_type() == DIAG204_INFO_EXT) { 22162306a36Sopenharmony_ci rc = hypfs_create_u64(cpu_dir, "onlinetime", 22262306a36Sopenharmony_ci cpu_info__online_time(diag204_get_info_type(), 22362306a36Sopenharmony_ci cpu_info)); 22462306a36Sopenharmony_ci if (IS_ERR(rc)) 22562306a36Sopenharmony_ci return PTR_ERR(rc); 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci diag224_idx2name(cpu_info__ctidx(diag204_get_info_type(), cpu_info), buffer); 22862306a36Sopenharmony_ci rc = hypfs_create_str(cpu_dir, "type", buffer); 22962306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(rc); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic void *hypfs_create_lpar_files(struct dentry *systems_dir, void *part_hdr) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct dentry *cpus_dir; 23562306a36Sopenharmony_ci struct dentry *lpar_dir; 23662306a36Sopenharmony_ci char lpar_name[DIAG204_LPAR_NAME_LEN + 1]; 23762306a36Sopenharmony_ci void *cpu_info; 23862306a36Sopenharmony_ci int i; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci part_hdr__part_name(diag204_get_info_type(), part_hdr, lpar_name); 24162306a36Sopenharmony_ci lpar_name[DIAG204_LPAR_NAME_LEN] = 0; 24262306a36Sopenharmony_ci lpar_dir = hypfs_mkdir(systems_dir, lpar_name); 24362306a36Sopenharmony_ci if (IS_ERR(lpar_dir)) 24462306a36Sopenharmony_ci return lpar_dir; 24562306a36Sopenharmony_ci cpus_dir = hypfs_mkdir(lpar_dir, "cpus"); 24662306a36Sopenharmony_ci if (IS_ERR(cpus_dir)) 24762306a36Sopenharmony_ci return cpus_dir; 24862306a36Sopenharmony_ci cpu_info = part_hdr + part_hdr__size(diag204_get_info_type()); 24962306a36Sopenharmony_ci for (i = 0; i < part_hdr__rcpus(diag204_get_info_type(), part_hdr); i++) { 25062306a36Sopenharmony_ci int rc; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci rc = hypfs_create_cpu_files(cpus_dir, cpu_info); 25362306a36Sopenharmony_ci if (rc) 25462306a36Sopenharmony_ci return ERR_PTR(rc); 25562306a36Sopenharmony_ci cpu_info += cpu_info__size(diag204_get_info_type()); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci return cpu_info; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int hypfs_create_phys_cpu_files(struct dentry *cpus_dir, void *cpu_info) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct dentry *cpu_dir; 26362306a36Sopenharmony_ci char buffer[TMP_SIZE]; 26462306a36Sopenharmony_ci void *rc; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_get_info_type(), 26762306a36Sopenharmony_ci cpu_info)); 26862306a36Sopenharmony_ci cpu_dir = hypfs_mkdir(cpus_dir, buffer); 26962306a36Sopenharmony_ci if (IS_ERR(cpu_dir)) 27062306a36Sopenharmony_ci return PTR_ERR(cpu_dir); 27162306a36Sopenharmony_ci rc = hypfs_create_u64(cpu_dir, "mgmtime", 27262306a36Sopenharmony_ci phys_cpu__mgm_time(diag204_get_info_type(), cpu_info)); 27362306a36Sopenharmony_ci if (IS_ERR(rc)) 27462306a36Sopenharmony_ci return PTR_ERR(rc); 27562306a36Sopenharmony_ci diag224_idx2name(phys_cpu__ctidx(diag204_get_info_type(), cpu_info), buffer); 27662306a36Sopenharmony_ci rc = hypfs_create_str(cpu_dir, "type", buffer); 27762306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(rc); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic void *hypfs_create_phys_files(struct dentry *parent_dir, void *phys_hdr) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci int i; 28362306a36Sopenharmony_ci void *cpu_info; 28462306a36Sopenharmony_ci struct dentry *cpus_dir; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci cpus_dir = hypfs_mkdir(parent_dir, "cpus"); 28762306a36Sopenharmony_ci if (IS_ERR(cpus_dir)) 28862306a36Sopenharmony_ci return cpus_dir; 28962306a36Sopenharmony_ci cpu_info = phys_hdr + phys_hdr__size(diag204_get_info_type()); 29062306a36Sopenharmony_ci for (i = 0; i < phys_hdr__cpus(diag204_get_info_type(), phys_hdr); i++) { 29162306a36Sopenharmony_ci int rc; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci rc = hypfs_create_phys_cpu_files(cpus_dir, cpu_info); 29462306a36Sopenharmony_ci if (rc) 29562306a36Sopenharmony_ci return ERR_PTR(rc); 29662306a36Sopenharmony_ci cpu_info += phys_cpu__size(diag204_get_info_type()); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci return cpu_info; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ciint hypfs_diag_create_files(struct dentry *root) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct dentry *systems_dir, *hyp_dir; 30462306a36Sopenharmony_ci void *time_hdr, *part_hdr; 30562306a36Sopenharmony_ci void *buffer, *ptr; 30662306a36Sopenharmony_ci int i, rc, pages; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci buffer = diag204_get_buffer(diag204_get_info_type(), &pages); 30962306a36Sopenharmony_ci if (IS_ERR(buffer)) 31062306a36Sopenharmony_ci return PTR_ERR(buffer); 31162306a36Sopenharmony_ci rc = diag204_store(buffer, pages); 31262306a36Sopenharmony_ci if (rc) 31362306a36Sopenharmony_ci return rc; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci systems_dir = hypfs_mkdir(root, "systems"); 31662306a36Sopenharmony_ci if (IS_ERR(systems_dir)) { 31762306a36Sopenharmony_ci rc = PTR_ERR(systems_dir); 31862306a36Sopenharmony_ci goto err_out; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci time_hdr = (struct x_info_blk_hdr *)buffer; 32162306a36Sopenharmony_ci part_hdr = time_hdr + info_blk_hdr__size(diag204_get_info_type()); 32262306a36Sopenharmony_ci for (i = 0; i < info_blk_hdr__npar(diag204_get_info_type(), time_hdr); i++) { 32362306a36Sopenharmony_ci part_hdr = hypfs_create_lpar_files(systems_dir, part_hdr); 32462306a36Sopenharmony_ci if (IS_ERR(part_hdr)) { 32562306a36Sopenharmony_ci rc = PTR_ERR(part_hdr); 32662306a36Sopenharmony_ci goto err_out; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci if (info_blk_hdr__flags(diag204_get_info_type(), time_hdr) & 33062306a36Sopenharmony_ci DIAG204_LPAR_PHYS_FLG) { 33162306a36Sopenharmony_ci ptr = hypfs_create_phys_files(root, part_hdr); 33262306a36Sopenharmony_ci if (IS_ERR(ptr)) { 33362306a36Sopenharmony_ci rc = PTR_ERR(ptr); 33462306a36Sopenharmony_ci goto err_out; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci hyp_dir = hypfs_mkdir(root, "hyp"); 33862306a36Sopenharmony_ci if (IS_ERR(hyp_dir)) { 33962306a36Sopenharmony_ci rc = PTR_ERR(hyp_dir); 34062306a36Sopenharmony_ci goto err_out; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci ptr = hypfs_create_str(hyp_dir, "type", "LPAR Hypervisor"); 34362306a36Sopenharmony_ci if (IS_ERR(ptr)) { 34462306a36Sopenharmony_ci rc = PTR_ERR(ptr); 34562306a36Sopenharmony_ci goto err_out; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci rc = 0; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cierr_out: 35062306a36Sopenharmony_ci return rc; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci/* Diagnose 224 functions */ 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int diag224_idx2name(int index, char *name) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci memcpy(name, diag224_cpu_names + ((index + 1) * DIAG204_CPU_NAME_LEN), 35862306a36Sopenharmony_ci DIAG204_CPU_NAME_LEN); 35962306a36Sopenharmony_ci name[DIAG204_CPU_NAME_LEN] = 0; 36062306a36Sopenharmony_ci strim(name); 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic int diag224_get_name_table(void) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci /* memory must be below 2GB */ 36762306a36Sopenharmony_ci diag224_cpu_names = (char *)__get_free_page(GFP_KERNEL | GFP_DMA); 36862306a36Sopenharmony_ci if (!diag224_cpu_names) 36962306a36Sopenharmony_ci return -ENOMEM; 37062306a36Sopenharmony_ci if (diag224(diag224_cpu_names)) { 37162306a36Sopenharmony_ci free_page((unsigned long)diag224_cpu_names); 37262306a36Sopenharmony_ci return -EOPNOTSUPP; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16); 37562306a36Sopenharmony_ci return 0; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic void diag224_delete_name_table(void) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci free_page((unsigned long)diag224_cpu_names); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ciint __init __hypfs_diag_fs_init(void) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci if (MACHINE_IS_LPAR) 38662306a36Sopenharmony_ci return diag224_get_name_table(); 38762306a36Sopenharmony_ci return 0; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_civoid __hypfs_diag_fs_exit(void) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci diag224_delete_name_table(); 39362306a36Sopenharmony_ci} 394