124bbb1faSMichael Holzheu /* 2f19bfb2cSMichael Holzheu * arch/s390/hypfs/hypfs_diag.c 324bbb1faSMichael Holzheu * Hypervisor filesystem for Linux on s390. Diag 204 and 224 424bbb1faSMichael Holzheu * implementation. 524bbb1faSMichael Holzheu * 6f55495baSMichael Holzheu * Copyright IBM Corp. 2006, 2008 724bbb1faSMichael Holzheu * Author(s): Michael Holzheu <holzheu@de.ibm.com> 824bbb1faSMichael Holzheu */ 924bbb1faSMichael Holzheu 10f55495baSMichael Holzheu #define KMSG_COMPONENT "hypfs" 11f55495baSMichael Holzheu #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 12f55495baSMichael Holzheu 1324bbb1faSMichael Holzheu #include <linux/types.h> 1424bbb1faSMichael Holzheu #include <linux/errno.h> 1533b26d79SHeiko Carstens #include <linux/slab.h> 1624bbb1faSMichael Holzheu #include <linux/string.h> 1724bbb1faSMichael Holzheu #include <linux/vmalloc.h> 1857b28f66SMichael Holzheu #include <linux/mm.h> 1924bbb1faSMichael Holzheu #include <asm/ebcdic.h> 2024bbb1faSMichael Holzheu #include "hypfs.h" 2124bbb1faSMichael Holzheu 2224bbb1faSMichael Holzheu #define LPAR_NAME_LEN 8 /* lpar name len in diag 204 data */ 2324bbb1faSMichael Holzheu #define CPU_NAME_LEN 16 /* type name len of cpus in diag224 name table */ 2424bbb1faSMichael Holzheu #define TMP_SIZE 64 /* size of temporary buffers */ 2524bbb1faSMichael Holzheu 2657b28f66SMichael Holzheu #define DBFS_D204_HDR_VERSION 0 2757b28f66SMichael Holzheu 2824bbb1faSMichael Holzheu /* diag 204 subcodes */ 2924bbb1faSMichael Holzheu enum diag204_sc { 3024bbb1faSMichael Holzheu SUBC_STIB4 = 4, 3124bbb1faSMichael Holzheu SUBC_RSI = 5, 3224bbb1faSMichael Holzheu SUBC_STIB6 = 6, 3324bbb1faSMichael Holzheu SUBC_STIB7 = 7 3424bbb1faSMichael Holzheu }; 3524bbb1faSMichael Holzheu 3624bbb1faSMichael Holzheu /* The two available diag 204 data formats */ 3724bbb1faSMichael Holzheu enum diag204_format { 3824bbb1faSMichael Holzheu INFO_SIMPLE = 0, 3924bbb1faSMichael Holzheu INFO_EXT = 0x00010000 4024bbb1faSMichael Holzheu }; 4124bbb1faSMichael Holzheu 4224bbb1faSMichael Holzheu /* bit is set in flags, when physical cpu info is included in diag 204 data */ 4324bbb1faSMichael Holzheu #define LPAR_PHYS_FLG 0x80 4424bbb1faSMichael Holzheu 4524bbb1faSMichael Holzheu static char *diag224_cpu_names; /* diag 224 name table */ 4624bbb1faSMichael Holzheu static enum diag204_sc diag204_store_sc; /* used subcode for store */ 4724bbb1faSMichael Holzheu static enum diag204_format diag204_info_type; /* used diag 204 data format */ 4824bbb1faSMichael Holzheu 4924bbb1faSMichael Holzheu static void *diag204_buf; /* 4K aligned buffer for diag204 data */ 5024bbb1faSMichael Holzheu static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */ 5124bbb1faSMichael Holzheu static int diag204_buf_pages; /* number of pages for diag204 data */ 5224bbb1faSMichael Holzheu 5357b28f66SMichael Holzheu static struct dentry *dbfs_d204_file; 5457b28f66SMichael Holzheu 5524bbb1faSMichael Holzheu /* 5624bbb1faSMichael Holzheu * DIAG 204 data structures and member access functions. 5724bbb1faSMichael Holzheu * 5824bbb1faSMichael Holzheu * Since we have two different diag 204 data formats for old and new s390 5924bbb1faSMichael Holzheu * machines, we do not access the structs directly, but use getter functions for 6024bbb1faSMichael Holzheu * each struct member instead. This should make the code more readable. 6124bbb1faSMichael Holzheu */ 6224bbb1faSMichael Holzheu 6324bbb1faSMichael Holzheu /* Time information block */ 6424bbb1faSMichael Holzheu 6524bbb1faSMichael Holzheu struct info_blk_hdr { 6624bbb1faSMichael Holzheu __u8 npar; 6724bbb1faSMichael Holzheu __u8 flags; 6824bbb1faSMichael Holzheu __u16 tslice; 6924bbb1faSMichael Holzheu __u16 phys_cpus; 7024bbb1faSMichael Holzheu __u16 this_part; 7124bbb1faSMichael Holzheu __u64 curtod; 7224bbb1faSMichael Holzheu } __attribute__ ((packed)); 7324bbb1faSMichael Holzheu 7424bbb1faSMichael Holzheu struct x_info_blk_hdr { 7524bbb1faSMichael Holzheu __u8 npar; 7624bbb1faSMichael Holzheu __u8 flags; 7724bbb1faSMichael Holzheu __u16 tslice; 7824bbb1faSMichael Holzheu __u16 phys_cpus; 7924bbb1faSMichael Holzheu __u16 this_part; 8024bbb1faSMichael Holzheu __u64 curtod1; 8124bbb1faSMichael Holzheu __u64 curtod2; 8224bbb1faSMichael Holzheu char reserved[40]; 8324bbb1faSMichael Holzheu } __attribute__ ((packed)); 8424bbb1faSMichael Holzheu 8524bbb1faSMichael Holzheu static inline int info_blk_hdr__size(enum diag204_format type) 8624bbb1faSMichael Holzheu { 8724bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 8824bbb1faSMichael Holzheu return sizeof(struct info_blk_hdr); 8924bbb1faSMichael Holzheu else /* INFO_EXT */ 9024bbb1faSMichael Holzheu return sizeof(struct x_info_blk_hdr); 9124bbb1faSMichael Holzheu } 9224bbb1faSMichael Holzheu 9324bbb1faSMichael Holzheu static inline __u8 info_blk_hdr__npar(enum diag204_format type, void *hdr) 9424bbb1faSMichael Holzheu { 9524bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 9624bbb1faSMichael Holzheu return ((struct info_blk_hdr *)hdr)->npar; 9724bbb1faSMichael Holzheu else /* INFO_EXT */ 9824bbb1faSMichael Holzheu return ((struct x_info_blk_hdr *)hdr)->npar; 9924bbb1faSMichael Holzheu } 10024bbb1faSMichael Holzheu 10124bbb1faSMichael Holzheu static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr) 10224bbb1faSMichael Holzheu { 10324bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 10424bbb1faSMichael Holzheu return ((struct info_blk_hdr *)hdr)->flags; 10524bbb1faSMichael Holzheu else /* INFO_EXT */ 10624bbb1faSMichael Holzheu return ((struct x_info_blk_hdr *)hdr)->flags; 10724bbb1faSMichael Holzheu } 10824bbb1faSMichael Holzheu 10924bbb1faSMichael Holzheu static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr) 11024bbb1faSMichael Holzheu { 11124bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 11224bbb1faSMichael Holzheu return ((struct info_blk_hdr *)hdr)->phys_cpus; 11324bbb1faSMichael Holzheu else /* INFO_EXT */ 11424bbb1faSMichael Holzheu return ((struct x_info_blk_hdr *)hdr)->phys_cpus; 11524bbb1faSMichael Holzheu } 11624bbb1faSMichael Holzheu 11724bbb1faSMichael Holzheu /* Partition header */ 11824bbb1faSMichael Holzheu 11924bbb1faSMichael Holzheu struct part_hdr { 12024bbb1faSMichael Holzheu __u8 pn; 12124bbb1faSMichael Holzheu __u8 cpus; 12224bbb1faSMichael Holzheu char reserved[6]; 12324bbb1faSMichael Holzheu char part_name[LPAR_NAME_LEN]; 12424bbb1faSMichael Holzheu } __attribute__ ((packed)); 12524bbb1faSMichael Holzheu 12624bbb1faSMichael Holzheu struct x_part_hdr { 12724bbb1faSMichael Holzheu __u8 pn; 12824bbb1faSMichael Holzheu __u8 cpus; 12924bbb1faSMichael Holzheu __u8 rcpus; 13024bbb1faSMichael Holzheu __u8 pflag; 13124bbb1faSMichael Holzheu __u32 mlu; 13224bbb1faSMichael Holzheu char part_name[LPAR_NAME_LEN]; 13324bbb1faSMichael Holzheu char lpc_name[8]; 13424bbb1faSMichael Holzheu char os_name[8]; 13524bbb1faSMichael Holzheu __u64 online_cs; 13624bbb1faSMichael Holzheu __u64 online_es; 13724bbb1faSMichael Holzheu __u8 upid; 13824bbb1faSMichael Holzheu char reserved1[3]; 13924bbb1faSMichael Holzheu __u32 group_mlu; 14024bbb1faSMichael Holzheu char group_name[8]; 14124bbb1faSMichael Holzheu char reserved2[32]; 14224bbb1faSMichael Holzheu } __attribute__ ((packed)); 14324bbb1faSMichael Holzheu 14424bbb1faSMichael Holzheu static inline int part_hdr__size(enum diag204_format type) 14524bbb1faSMichael Holzheu { 14624bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 14724bbb1faSMichael Holzheu return sizeof(struct part_hdr); 14824bbb1faSMichael Holzheu else /* INFO_EXT */ 14924bbb1faSMichael Holzheu return sizeof(struct x_part_hdr); 15024bbb1faSMichael Holzheu } 15124bbb1faSMichael Holzheu 15224bbb1faSMichael Holzheu static inline __u8 part_hdr__rcpus(enum diag204_format type, void *hdr) 15324bbb1faSMichael Holzheu { 15424bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 15524bbb1faSMichael Holzheu return ((struct part_hdr *)hdr)->cpus; 15624bbb1faSMichael Holzheu else /* INFO_EXT */ 15724bbb1faSMichael Holzheu return ((struct x_part_hdr *)hdr)->rcpus; 15824bbb1faSMichael Holzheu } 15924bbb1faSMichael Holzheu 16024bbb1faSMichael Holzheu static inline void part_hdr__part_name(enum diag204_format type, void *hdr, 16124bbb1faSMichael Holzheu char *name) 16224bbb1faSMichael Holzheu { 16324bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 16424bbb1faSMichael Holzheu memcpy(name, ((struct part_hdr *)hdr)->part_name, 16524bbb1faSMichael Holzheu LPAR_NAME_LEN); 16624bbb1faSMichael Holzheu else /* INFO_EXT */ 16724bbb1faSMichael Holzheu memcpy(name, ((struct x_part_hdr *)hdr)->part_name, 16824bbb1faSMichael Holzheu LPAR_NAME_LEN); 16924bbb1faSMichael Holzheu EBCASC(name, LPAR_NAME_LEN); 17024bbb1faSMichael Holzheu name[LPAR_NAME_LEN] = 0; 1711d802e24SHeiko Carstens strim(name); 17224bbb1faSMichael Holzheu } 17324bbb1faSMichael Holzheu 17424bbb1faSMichael Holzheu struct cpu_info { 17524bbb1faSMichael Holzheu __u16 cpu_addr; 17624bbb1faSMichael Holzheu char reserved1[2]; 17724bbb1faSMichael Holzheu __u8 ctidx; 17824bbb1faSMichael Holzheu __u8 cflag; 17924bbb1faSMichael Holzheu __u16 weight; 18024bbb1faSMichael Holzheu __u64 acc_time; 18124bbb1faSMichael Holzheu __u64 lp_time; 18224bbb1faSMichael Holzheu } __attribute__ ((packed)); 18324bbb1faSMichael Holzheu 18424bbb1faSMichael Holzheu struct x_cpu_info { 18524bbb1faSMichael Holzheu __u16 cpu_addr; 18624bbb1faSMichael Holzheu char reserved1[2]; 18724bbb1faSMichael Holzheu __u8 ctidx; 18824bbb1faSMichael Holzheu __u8 cflag; 18924bbb1faSMichael Holzheu __u16 weight; 19024bbb1faSMichael Holzheu __u64 acc_time; 19124bbb1faSMichael Holzheu __u64 lp_time; 19224bbb1faSMichael Holzheu __u16 min_weight; 19324bbb1faSMichael Holzheu __u16 cur_weight; 19424bbb1faSMichael Holzheu __u16 max_weight; 19524bbb1faSMichael Holzheu char reseved2[2]; 19624bbb1faSMichael Holzheu __u64 online_time; 19724bbb1faSMichael Holzheu __u64 wait_time; 19824bbb1faSMichael Holzheu __u32 pma_weight; 19924bbb1faSMichael Holzheu __u32 polar_weight; 20024bbb1faSMichael Holzheu char reserved3[40]; 20124bbb1faSMichael Holzheu } __attribute__ ((packed)); 20224bbb1faSMichael Holzheu 20324bbb1faSMichael Holzheu /* CPU info block */ 20424bbb1faSMichael Holzheu 20524bbb1faSMichael Holzheu static inline int cpu_info__size(enum diag204_format type) 20624bbb1faSMichael Holzheu { 20724bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 20824bbb1faSMichael Holzheu return sizeof(struct cpu_info); 20924bbb1faSMichael Holzheu else /* INFO_EXT */ 21024bbb1faSMichael Holzheu return sizeof(struct x_cpu_info); 21124bbb1faSMichael Holzheu } 21224bbb1faSMichael Holzheu 21324bbb1faSMichael Holzheu static inline __u8 cpu_info__ctidx(enum diag204_format type, void *hdr) 21424bbb1faSMichael Holzheu { 21524bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 21624bbb1faSMichael Holzheu return ((struct cpu_info *)hdr)->ctidx; 21724bbb1faSMichael Holzheu else /* INFO_EXT */ 21824bbb1faSMichael Holzheu return ((struct x_cpu_info *)hdr)->ctidx; 21924bbb1faSMichael Holzheu } 22024bbb1faSMichael Holzheu 22124bbb1faSMichael Holzheu static inline __u16 cpu_info__cpu_addr(enum diag204_format type, void *hdr) 22224bbb1faSMichael Holzheu { 22324bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 22424bbb1faSMichael Holzheu return ((struct cpu_info *)hdr)->cpu_addr; 22524bbb1faSMichael Holzheu else /* INFO_EXT */ 22624bbb1faSMichael Holzheu return ((struct x_cpu_info *)hdr)->cpu_addr; 22724bbb1faSMichael Holzheu } 22824bbb1faSMichael Holzheu 22924bbb1faSMichael Holzheu static inline __u64 cpu_info__acc_time(enum diag204_format type, void *hdr) 23024bbb1faSMichael Holzheu { 23124bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 23224bbb1faSMichael Holzheu return ((struct cpu_info *)hdr)->acc_time; 23324bbb1faSMichael Holzheu else /* INFO_EXT */ 23424bbb1faSMichael Holzheu return ((struct x_cpu_info *)hdr)->acc_time; 23524bbb1faSMichael Holzheu } 23624bbb1faSMichael Holzheu 23724bbb1faSMichael Holzheu static inline __u64 cpu_info__lp_time(enum diag204_format type, void *hdr) 23824bbb1faSMichael Holzheu { 23924bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 24024bbb1faSMichael Holzheu return ((struct cpu_info *)hdr)->lp_time; 24124bbb1faSMichael Holzheu else /* INFO_EXT */ 24224bbb1faSMichael Holzheu return ((struct x_cpu_info *)hdr)->lp_time; 24324bbb1faSMichael Holzheu } 24424bbb1faSMichael Holzheu 24524bbb1faSMichael Holzheu static inline __u64 cpu_info__online_time(enum diag204_format type, void *hdr) 24624bbb1faSMichael Holzheu { 24724bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 24824bbb1faSMichael Holzheu return 0; /* online_time not available in simple info */ 24924bbb1faSMichael Holzheu else /* INFO_EXT */ 25024bbb1faSMichael Holzheu return ((struct x_cpu_info *)hdr)->online_time; 25124bbb1faSMichael Holzheu } 25224bbb1faSMichael Holzheu 25324bbb1faSMichael Holzheu /* Physical header */ 25424bbb1faSMichael Holzheu 25524bbb1faSMichael Holzheu struct phys_hdr { 25624bbb1faSMichael Holzheu char reserved1[1]; 25724bbb1faSMichael Holzheu __u8 cpus; 25824bbb1faSMichael Holzheu char reserved2[6]; 25924bbb1faSMichael Holzheu char mgm_name[8]; 26024bbb1faSMichael Holzheu } __attribute__ ((packed)); 26124bbb1faSMichael Holzheu 26224bbb1faSMichael Holzheu struct x_phys_hdr { 26324bbb1faSMichael Holzheu char reserved1[1]; 26424bbb1faSMichael Holzheu __u8 cpus; 26524bbb1faSMichael Holzheu char reserved2[6]; 26624bbb1faSMichael Holzheu char mgm_name[8]; 26724bbb1faSMichael Holzheu char reserved3[80]; 26824bbb1faSMichael Holzheu } __attribute__ ((packed)); 26924bbb1faSMichael Holzheu 27024bbb1faSMichael Holzheu static inline int phys_hdr__size(enum diag204_format type) 27124bbb1faSMichael Holzheu { 27224bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 27324bbb1faSMichael Holzheu return sizeof(struct phys_hdr); 27424bbb1faSMichael Holzheu else /* INFO_EXT */ 27524bbb1faSMichael Holzheu return sizeof(struct x_phys_hdr); 27624bbb1faSMichael Holzheu } 27724bbb1faSMichael Holzheu 27824bbb1faSMichael Holzheu static inline __u8 phys_hdr__cpus(enum diag204_format type, void *hdr) 27924bbb1faSMichael Holzheu { 28024bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 28124bbb1faSMichael Holzheu return ((struct phys_hdr *)hdr)->cpus; 28224bbb1faSMichael Holzheu else /* INFO_EXT */ 28324bbb1faSMichael Holzheu return ((struct x_phys_hdr *)hdr)->cpus; 28424bbb1faSMichael Holzheu } 28524bbb1faSMichael Holzheu 28624bbb1faSMichael Holzheu /* Physical CPU info block */ 28724bbb1faSMichael Holzheu 28824bbb1faSMichael Holzheu struct phys_cpu { 28924bbb1faSMichael Holzheu __u16 cpu_addr; 29024bbb1faSMichael Holzheu char reserved1[2]; 29124bbb1faSMichael Holzheu __u8 ctidx; 29224bbb1faSMichael Holzheu char reserved2[3]; 29324bbb1faSMichael Holzheu __u64 mgm_time; 29424bbb1faSMichael Holzheu char reserved3[8]; 29524bbb1faSMichael Holzheu } __attribute__ ((packed)); 29624bbb1faSMichael Holzheu 29724bbb1faSMichael Holzheu struct x_phys_cpu { 29824bbb1faSMichael Holzheu __u16 cpu_addr; 29924bbb1faSMichael Holzheu char reserved1[2]; 30024bbb1faSMichael Holzheu __u8 ctidx; 30124bbb1faSMichael Holzheu char reserved2[3]; 30224bbb1faSMichael Holzheu __u64 mgm_time; 30324bbb1faSMichael Holzheu char reserved3[80]; 30424bbb1faSMichael Holzheu } __attribute__ ((packed)); 30524bbb1faSMichael Holzheu 30624bbb1faSMichael Holzheu static inline int phys_cpu__size(enum diag204_format type) 30724bbb1faSMichael Holzheu { 30824bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 30924bbb1faSMichael Holzheu return sizeof(struct phys_cpu); 31024bbb1faSMichael Holzheu else /* INFO_EXT */ 31124bbb1faSMichael Holzheu return sizeof(struct x_phys_cpu); 31224bbb1faSMichael Holzheu } 31324bbb1faSMichael Holzheu 31424bbb1faSMichael Holzheu static inline __u16 phys_cpu__cpu_addr(enum diag204_format type, void *hdr) 31524bbb1faSMichael Holzheu { 31624bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 31724bbb1faSMichael Holzheu return ((struct phys_cpu *)hdr)->cpu_addr; 31824bbb1faSMichael Holzheu else /* INFO_EXT */ 31924bbb1faSMichael Holzheu return ((struct x_phys_cpu *)hdr)->cpu_addr; 32024bbb1faSMichael Holzheu } 32124bbb1faSMichael Holzheu 32224bbb1faSMichael Holzheu static inline __u64 phys_cpu__mgm_time(enum diag204_format type, void *hdr) 32324bbb1faSMichael Holzheu { 32424bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 32524bbb1faSMichael Holzheu return ((struct phys_cpu *)hdr)->mgm_time; 32624bbb1faSMichael Holzheu else /* INFO_EXT */ 32724bbb1faSMichael Holzheu return ((struct x_phys_cpu *)hdr)->mgm_time; 32824bbb1faSMichael Holzheu } 32924bbb1faSMichael Holzheu 33024bbb1faSMichael Holzheu static inline __u64 phys_cpu__ctidx(enum diag204_format type, void *hdr) 33124bbb1faSMichael Holzheu { 33224bbb1faSMichael Holzheu if (type == INFO_SIMPLE) 33324bbb1faSMichael Holzheu return ((struct phys_cpu *)hdr)->ctidx; 33424bbb1faSMichael Holzheu else /* INFO_EXT */ 33524bbb1faSMichael Holzheu return ((struct x_phys_cpu *)hdr)->ctidx; 33624bbb1faSMichael Holzheu } 33724bbb1faSMichael Holzheu 33824bbb1faSMichael Holzheu /* Diagnose 204 functions */ 33924bbb1faSMichael Holzheu 34024bbb1faSMichael Holzheu static int diag204(unsigned long subcode, unsigned long size, void *addr) 34124bbb1faSMichael Holzheu { 34224bbb1faSMichael Holzheu register unsigned long _subcode asm("0") = subcode; 34324bbb1faSMichael Holzheu register unsigned long _size asm("1") = size; 34424bbb1faSMichael Holzheu 34594c12cc7SMartin Schwidefsky asm volatile( 34694c12cc7SMartin Schwidefsky " diag %2,%0,0x204\n" 34794c12cc7SMartin Schwidefsky "0:\n" 34894c12cc7SMartin Schwidefsky EX_TABLE(0b,0b) 34994c12cc7SMartin Schwidefsky : "+d" (_subcode), "+d" (_size) : "d" (addr) : "memory"); 35024bbb1faSMichael Holzheu if (_subcode) 35124bbb1faSMichael Holzheu return -1; 35224bbb1faSMichael Holzheu return _size; 35324bbb1faSMichael Holzheu } 35424bbb1faSMichael Holzheu 35524bbb1faSMichael Holzheu /* 35624bbb1faSMichael Holzheu * For the old diag subcode 4 with simple data format we have to use real 35724bbb1faSMichael Holzheu * memory. If we use subcode 6 or 7 with extended data format, we can (and 35824bbb1faSMichael Holzheu * should) use vmalloc, since we need a lot of memory in that case. Currently 35924bbb1faSMichael Holzheu * up to 93 pages! 36024bbb1faSMichael Holzheu */ 36124bbb1faSMichael Holzheu 36224bbb1faSMichael Holzheu static void diag204_free_buffer(void) 36324bbb1faSMichael Holzheu { 36424bbb1faSMichael Holzheu if (!diag204_buf) 36524bbb1faSMichael Holzheu return; 36624bbb1faSMichael Holzheu if (diag204_buf_vmalloc) { 36724bbb1faSMichael Holzheu vfree(diag204_buf_vmalloc); 36824bbb1faSMichael Holzheu diag204_buf_vmalloc = NULL; 36924bbb1faSMichael Holzheu } else { 37024bbb1faSMichael Holzheu free_pages((unsigned long) diag204_buf, 0); 37124bbb1faSMichael Holzheu } 37224bbb1faSMichael Holzheu diag204_buf = NULL; 37324bbb1faSMichael Holzheu } 37424bbb1faSMichael Holzheu 37557b28f66SMichael Holzheu static void *page_align_ptr(void *ptr) 37657b28f66SMichael Holzheu { 37757b28f66SMichael Holzheu return (void *) PAGE_ALIGN((unsigned long) ptr); 37857b28f66SMichael Holzheu } 37957b28f66SMichael Holzheu 38024bbb1faSMichael Holzheu static void *diag204_alloc_vbuf(int pages) 38124bbb1faSMichael Holzheu { 38224bbb1faSMichael Holzheu /* The buffer has to be page aligned! */ 38324bbb1faSMichael Holzheu diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1)); 38424bbb1faSMichael Holzheu if (!diag204_buf_vmalloc) 38524bbb1faSMichael Holzheu return ERR_PTR(-ENOMEM); 38657b28f66SMichael Holzheu diag204_buf = page_align_ptr(diag204_buf_vmalloc); 38724bbb1faSMichael Holzheu diag204_buf_pages = pages; 38824bbb1faSMichael Holzheu return diag204_buf; 38924bbb1faSMichael Holzheu } 39024bbb1faSMichael Holzheu 39124bbb1faSMichael Holzheu static void *diag204_alloc_rbuf(void) 39224bbb1faSMichael Holzheu { 39324bbb1faSMichael Holzheu diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0); 39486b22470SChristian Borntraeger if (!diag204_buf) 39524bbb1faSMichael Holzheu return ERR_PTR(-ENOMEM); 39624bbb1faSMichael Holzheu diag204_buf_pages = 1; 39724bbb1faSMichael Holzheu return diag204_buf; 39824bbb1faSMichael Holzheu } 39924bbb1faSMichael Holzheu 40024bbb1faSMichael Holzheu static void *diag204_get_buffer(enum diag204_format fmt, int *pages) 40124bbb1faSMichael Holzheu { 40224bbb1faSMichael Holzheu if (diag204_buf) { 40324bbb1faSMichael Holzheu *pages = diag204_buf_pages; 40424bbb1faSMichael Holzheu return diag204_buf; 40524bbb1faSMichael Holzheu } 40624bbb1faSMichael Holzheu if (fmt == INFO_SIMPLE) { 40724bbb1faSMichael Holzheu *pages = 1; 40824bbb1faSMichael Holzheu return diag204_alloc_rbuf(); 40924bbb1faSMichael Holzheu } else {/* INFO_EXT */ 41023c100d9SMichael Holzheu *pages = diag204((unsigned long)SUBC_RSI | 41123c100d9SMichael Holzheu (unsigned long)INFO_EXT, 0, NULL); 41224bbb1faSMichael Holzheu if (*pages <= 0) 41324bbb1faSMichael Holzheu return ERR_PTR(-ENOSYS); 41424bbb1faSMichael Holzheu else 41524bbb1faSMichael Holzheu return diag204_alloc_vbuf(*pages); 41624bbb1faSMichael Holzheu } 41724bbb1faSMichael Holzheu } 41824bbb1faSMichael Holzheu 41924bbb1faSMichael Holzheu /* 42024bbb1faSMichael Holzheu * diag204_probe() has to find out, which type of diagnose 204 implementation 42124bbb1faSMichael Holzheu * we have on our machine. Currently there are three possible scanarios: 42224bbb1faSMichael Holzheu * - subcode 4 + simple data format (only one page) 42324bbb1faSMichael Holzheu * - subcode 4-6 + extended data format 42424bbb1faSMichael Holzheu * - subcode 4-7 + extended data format 42524bbb1faSMichael Holzheu * 42624bbb1faSMichael Holzheu * Subcode 5 is used to retrieve the size of the data, provided by subcodes 42724bbb1faSMichael Holzheu * 6 and 7. Subcode 7 basically has the same function as subcode 6. In addition 42824bbb1faSMichael Holzheu * to subcode 6 it provides also information about secondary cpus. 42924bbb1faSMichael Holzheu * In order to get as much information as possible, we first try 43024bbb1faSMichael Holzheu * subcode 7, then 6 and if both fail, we use subcode 4. 43124bbb1faSMichael Holzheu */ 43224bbb1faSMichael Holzheu 43324bbb1faSMichael Holzheu static int diag204_probe(void) 43424bbb1faSMichael Holzheu { 43524bbb1faSMichael Holzheu void *buf; 43624bbb1faSMichael Holzheu int pages, rc; 43724bbb1faSMichael Holzheu 43824bbb1faSMichael Holzheu buf = diag204_get_buffer(INFO_EXT, &pages); 43924bbb1faSMichael Holzheu if (!IS_ERR(buf)) { 440331c982dSMichael Holzheu if (diag204((unsigned long)SUBC_STIB7 | 441331c982dSMichael Holzheu (unsigned long)INFO_EXT, pages, buf) >= 0) { 44224bbb1faSMichael Holzheu diag204_store_sc = SUBC_STIB7; 44324bbb1faSMichael Holzheu diag204_info_type = INFO_EXT; 44424bbb1faSMichael Holzheu goto out; 44524bbb1faSMichael Holzheu } 446331c982dSMichael Holzheu if (diag204((unsigned long)SUBC_STIB6 | 447331c982dSMichael Holzheu (unsigned long)INFO_EXT, pages, buf) >= 0) { 4487874b1b6SMichael Holzheu diag204_store_sc = SUBC_STIB6; 44924bbb1faSMichael Holzheu diag204_info_type = INFO_EXT; 45024bbb1faSMichael Holzheu goto out; 45124bbb1faSMichael Holzheu } 45224bbb1faSMichael Holzheu diag204_free_buffer(); 45324bbb1faSMichael Holzheu } 45424bbb1faSMichael Holzheu 45524bbb1faSMichael Holzheu /* subcodes 6 and 7 failed, now try subcode 4 */ 45624bbb1faSMichael Holzheu 45724bbb1faSMichael Holzheu buf = diag204_get_buffer(INFO_SIMPLE, &pages); 45824bbb1faSMichael Holzheu if (IS_ERR(buf)) { 45924bbb1faSMichael Holzheu rc = PTR_ERR(buf); 46024bbb1faSMichael Holzheu goto fail_alloc; 46124bbb1faSMichael Holzheu } 462331c982dSMichael Holzheu if (diag204((unsigned long)SUBC_STIB4 | 463331c982dSMichael Holzheu (unsigned long)INFO_SIMPLE, pages, buf) >= 0) { 46424bbb1faSMichael Holzheu diag204_store_sc = SUBC_STIB4; 46524bbb1faSMichael Holzheu diag204_info_type = INFO_SIMPLE; 46624bbb1faSMichael Holzheu goto out; 46724bbb1faSMichael Holzheu } else { 46824bbb1faSMichael Holzheu rc = -ENOSYS; 46924bbb1faSMichael Holzheu goto fail_store; 47024bbb1faSMichael Holzheu } 47124bbb1faSMichael Holzheu out: 47224bbb1faSMichael Holzheu rc = 0; 47324bbb1faSMichael Holzheu fail_store: 47424bbb1faSMichael Holzheu diag204_free_buffer(); 47524bbb1faSMichael Holzheu fail_alloc: 47624bbb1faSMichael Holzheu return rc; 47724bbb1faSMichael Holzheu } 47824bbb1faSMichael Holzheu 47957b28f66SMichael Holzheu static int diag204_do_store(void *buf, int pages) 48057b28f66SMichael Holzheu { 48157b28f66SMichael Holzheu int rc; 48257b28f66SMichael Holzheu 48357b28f66SMichael Holzheu rc = diag204((unsigned long) diag204_store_sc | 48457b28f66SMichael Holzheu (unsigned long) diag204_info_type, pages, buf); 48557b28f66SMichael Holzheu return rc < 0 ? -ENOSYS : 0; 48657b28f66SMichael Holzheu } 48757b28f66SMichael Holzheu 48824bbb1faSMichael Holzheu static void *diag204_store(void) 48924bbb1faSMichael Holzheu { 49024bbb1faSMichael Holzheu void *buf; 49157b28f66SMichael Holzheu int pages, rc; 49224bbb1faSMichael Holzheu 49324bbb1faSMichael Holzheu buf = diag204_get_buffer(diag204_info_type, &pages); 49424bbb1faSMichael Holzheu if (IS_ERR(buf)) 49524bbb1faSMichael Holzheu goto out; 49657b28f66SMichael Holzheu rc = diag204_do_store(buf, pages); 49757b28f66SMichael Holzheu if (rc) 49857b28f66SMichael Holzheu return ERR_PTR(rc); 49924bbb1faSMichael Holzheu out: 50024bbb1faSMichael Holzheu return buf; 50124bbb1faSMichael Holzheu } 50224bbb1faSMichael Holzheu 50324bbb1faSMichael Holzheu /* Diagnose 224 functions */ 50424bbb1faSMichael Holzheu 505c41d4e3eSMichael Holzheu static int diag224(void *ptr) 50624bbb1faSMichael Holzheu { 507b8e660b8SHeiko Carstens int rc = -EOPNOTSUPP; 508c41d4e3eSMichael Holzheu 509c41d4e3eSMichael Holzheu asm volatile( 510c41d4e3eSMichael Holzheu " diag %1,%2,0x224\n" 511c41d4e3eSMichael Holzheu "0: lhi %0,0x0\n" 512c41d4e3eSMichael Holzheu "1:\n" 513c41d4e3eSMichael Holzheu EX_TABLE(0b,1b) 514c41d4e3eSMichael Holzheu : "+d" (rc) :"d" (0), "d" (ptr) : "memory"); 515c41d4e3eSMichael Holzheu return rc; 51624bbb1faSMichael Holzheu } 51724bbb1faSMichael Holzheu 51824bbb1faSMichael Holzheu static int diag224_get_name_table(void) 51924bbb1faSMichael Holzheu { 52024bbb1faSMichael Holzheu /* memory must be below 2GB */ 52124bbb1faSMichael Holzheu diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); 52224bbb1faSMichael Holzheu if (!diag224_cpu_names) 52324bbb1faSMichael Holzheu return -ENOMEM; 524c41d4e3eSMichael Holzheu if (diag224(diag224_cpu_names)) { 525c41d4e3eSMichael Holzheu kfree(diag224_cpu_names); 526b8e660b8SHeiko Carstens return -EOPNOTSUPP; 527c41d4e3eSMichael Holzheu } 52824bbb1faSMichael Holzheu EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16); 52924bbb1faSMichael Holzheu return 0; 53024bbb1faSMichael Holzheu } 53124bbb1faSMichael Holzheu 53224bbb1faSMichael Holzheu static void diag224_delete_name_table(void) 53324bbb1faSMichael Holzheu { 53424bbb1faSMichael Holzheu kfree(diag224_cpu_names); 53524bbb1faSMichael Holzheu } 53624bbb1faSMichael Holzheu 53724bbb1faSMichael Holzheu static int diag224_idx2name(int index, char *name) 53824bbb1faSMichael Holzheu { 53924bbb1faSMichael Holzheu memcpy(name, diag224_cpu_names + ((index + 1) * CPU_NAME_LEN), 54024bbb1faSMichael Holzheu CPU_NAME_LEN); 54124bbb1faSMichael Holzheu name[CPU_NAME_LEN] = 0; 5421d802e24SHeiko Carstens strim(name); 54324bbb1faSMichael Holzheu return 0; 54424bbb1faSMichael Holzheu } 54524bbb1faSMichael Holzheu 54657b28f66SMichael Holzheu struct dbfs_d204_hdr { 54757b28f66SMichael Holzheu u64 len; /* Length of d204 buffer without header */ 54857b28f66SMichael Holzheu u16 version; /* Version of header */ 54957b28f66SMichael Holzheu u8 sc; /* Used subcode */ 55057b28f66SMichael Holzheu char reserved[53]; 55157b28f66SMichael Holzheu } __attribute__ ((packed)); 55257b28f66SMichael Holzheu 55357b28f66SMichael Holzheu struct dbfs_d204 { 55457b28f66SMichael Holzheu struct dbfs_d204_hdr hdr; /* 64 byte header */ 55557b28f66SMichael Holzheu char buf[]; /* d204 buffer */ 55657b28f66SMichael Holzheu } __attribute__ ((packed)); 55757b28f66SMichael Holzheu 558*2fcb3686SMichael Holzheu static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size) 55957b28f66SMichael Holzheu { 56057b28f66SMichael Holzheu struct dbfs_d204 *d204; 56157b28f66SMichael Holzheu int rc, buf_size; 562*2fcb3686SMichael Holzheu void *base; 56357b28f66SMichael Holzheu 56457b28f66SMichael Holzheu buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr); 565*2fcb3686SMichael Holzheu base = vmalloc(buf_size); 566*2fcb3686SMichael Holzheu if (!base) 567*2fcb3686SMichael Holzheu return -ENOMEM; 568*2fcb3686SMichael Holzheu memset(base, 0, buf_size); 569*2fcb3686SMichael Holzheu d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr); 570*2fcb3686SMichael Holzheu rc = diag204_do_store(d204->buf, diag204_buf_pages); 571*2fcb3686SMichael Holzheu if (rc) { 572*2fcb3686SMichael Holzheu vfree(base); 573*2fcb3686SMichael Holzheu return rc; 57457b28f66SMichael Holzheu } 57557b28f66SMichael Holzheu d204->hdr.version = DBFS_D204_HDR_VERSION; 57657b28f66SMichael Holzheu d204->hdr.len = PAGE_SIZE * diag204_buf_pages; 57757b28f66SMichael Holzheu d204->hdr.sc = diag204_store_sc; 578*2fcb3686SMichael Holzheu *data = d204; 579*2fcb3686SMichael Holzheu *data_free_ptr = base; 580*2fcb3686SMichael Holzheu *size = d204->hdr.len + sizeof(struct dbfs_d204_hdr); 58157b28f66SMichael Holzheu return 0; 58257b28f66SMichael Holzheu } 58357b28f66SMichael Holzheu 584*2fcb3686SMichael Holzheu static struct hypfs_dbfs_file dbfs_file_d204 = { 585*2fcb3686SMichael Holzheu .name = "diag_204", 586*2fcb3686SMichael Holzheu .data_create = dbfs_d204_create, 587*2fcb3686SMichael Holzheu .data_free = vfree, 58857b28f66SMichael Holzheu }; 58957b28f66SMichael Holzheu 59024bbb1faSMichael Holzheu __init int hypfs_diag_init(void) 59124bbb1faSMichael Holzheu { 59224bbb1faSMichael Holzheu int rc; 59324bbb1faSMichael Holzheu 59424bbb1faSMichael Holzheu if (diag204_probe()) { 595f55495baSMichael Holzheu pr_err("The hardware system does not support hypfs\n"); 59624bbb1faSMichael Holzheu return -ENODATA; 59724bbb1faSMichael Holzheu } 59857b28f66SMichael Holzheu if (diag204_info_type == INFO_EXT) { 599*2fcb3686SMichael Holzheu rc = hypfs_dbfs_create_file(&dbfs_file_d204); 60057b28f66SMichael Holzheu if (rc) 60124bbb1faSMichael Holzheu return rc; 60224bbb1faSMichael Holzheu } 6033c8ebca0SMichael Holzheu if (MACHINE_IS_LPAR) { 6043c8ebca0SMichael Holzheu rc = diag224_get_name_table(); 6053c8ebca0SMichael Holzheu if (rc) { 6063c8ebca0SMichael Holzheu pr_err("The hardware system does not provide all " 6073c8ebca0SMichael Holzheu "functions required by hypfs\n"); 6083c8ebca0SMichael Holzheu debugfs_remove(dbfs_d204_file); 6093c8ebca0SMichael Holzheu return rc; 6103c8ebca0SMichael Holzheu } 6113c8ebca0SMichael Holzheu } 6123c8ebca0SMichael Holzheu return 0; 6133c8ebca0SMichael Holzheu } 61424bbb1faSMichael Holzheu 6151375fc1fSHeiko Carstens void hypfs_diag_exit(void) 61624bbb1faSMichael Holzheu { 61757b28f66SMichael Holzheu debugfs_remove(dbfs_d204_file); 61824bbb1faSMichael Holzheu diag224_delete_name_table(); 61924bbb1faSMichael Holzheu diag204_free_buffer(); 620*2fcb3686SMichael Holzheu hypfs_dbfs_remove_file(&dbfs_file_d204); 62124bbb1faSMichael Holzheu } 62224bbb1faSMichael Holzheu 62324bbb1faSMichael Holzheu /* 62424bbb1faSMichael Holzheu * Functions to create the directory structure 62524bbb1faSMichael Holzheu * ******************************************* 62624bbb1faSMichael Holzheu */ 62724bbb1faSMichael Holzheu 62824bbb1faSMichael Holzheu static int hypfs_create_cpu_files(struct super_block *sb, 62924bbb1faSMichael Holzheu struct dentry *cpus_dir, void *cpu_info) 63024bbb1faSMichael Holzheu { 63124bbb1faSMichael Holzheu struct dentry *cpu_dir; 63224bbb1faSMichael Holzheu char buffer[TMP_SIZE]; 63324bbb1faSMichael Holzheu void *rc; 63424bbb1faSMichael Holzheu 63524bbb1faSMichael Holzheu snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type, 63624bbb1faSMichael Holzheu cpu_info)); 63724bbb1faSMichael Holzheu cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer); 63824bbb1faSMichael Holzheu rc = hypfs_create_u64(sb, cpu_dir, "mgmtime", 63924bbb1faSMichael Holzheu cpu_info__acc_time(diag204_info_type, cpu_info) - 64024bbb1faSMichael Holzheu cpu_info__lp_time(diag204_info_type, cpu_info)); 64124bbb1faSMichael Holzheu if (IS_ERR(rc)) 64224bbb1faSMichael Holzheu return PTR_ERR(rc); 64324bbb1faSMichael Holzheu rc = hypfs_create_u64(sb, cpu_dir, "cputime", 64424bbb1faSMichael Holzheu cpu_info__lp_time(diag204_info_type, cpu_info)); 64524bbb1faSMichael Holzheu if (IS_ERR(rc)) 64624bbb1faSMichael Holzheu return PTR_ERR(rc); 64724bbb1faSMichael Holzheu if (diag204_info_type == INFO_EXT) { 64824bbb1faSMichael Holzheu rc = hypfs_create_u64(sb, cpu_dir, "onlinetime", 64924bbb1faSMichael Holzheu cpu_info__online_time(diag204_info_type, 65024bbb1faSMichael Holzheu cpu_info)); 65124bbb1faSMichael Holzheu if (IS_ERR(rc)) 65224bbb1faSMichael Holzheu return PTR_ERR(rc); 65324bbb1faSMichael Holzheu } 65424bbb1faSMichael Holzheu diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer); 65524bbb1faSMichael Holzheu rc = hypfs_create_str(sb, cpu_dir, "type", buffer); 65624bbb1faSMichael Holzheu if (IS_ERR(rc)) 65724bbb1faSMichael Holzheu return PTR_ERR(rc); 65824bbb1faSMichael Holzheu return 0; 65924bbb1faSMichael Holzheu } 66024bbb1faSMichael Holzheu 66124bbb1faSMichael Holzheu static void *hypfs_create_lpar_files(struct super_block *sb, 66224bbb1faSMichael Holzheu struct dentry *systems_dir, void *part_hdr) 66324bbb1faSMichael Holzheu { 66424bbb1faSMichael Holzheu struct dentry *cpus_dir; 66524bbb1faSMichael Holzheu struct dentry *lpar_dir; 66624bbb1faSMichael Holzheu char lpar_name[LPAR_NAME_LEN + 1]; 66724bbb1faSMichael Holzheu void *cpu_info; 66824bbb1faSMichael Holzheu int i; 66924bbb1faSMichael Holzheu 67024bbb1faSMichael Holzheu part_hdr__part_name(diag204_info_type, part_hdr, lpar_name); 67124bbb1faSMichael Holzheu lpar_name[LPAR_NAME_LEN] = 0; 67224bbb1faSMichael Holzheu lpar_dir = hypfs_mkdir(sb, systems_dir, lpar_name); 67324bbb1faSMichael Holzheu if (IS_ERR(lpar_dir)) 67424bbb1faSMichael Holzheu return lpar_dir; 67524bbb1faSMichael Holzheu cpus_dir = hypfs_mkdir(sb, lpar_dir, "cpus"); 67624bbb1faSMichael Holzheu if (IS_ERR(cpus_dir)) 67724bbb1faSMichael Holzheu return cpus_dir; 67824bbb1faSMichael Holzheu cpu_info = part_hdr + part_hdr__size(diag204_info_type); 67924bbb1faSMichael Holzheu for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) { 68024bbb1faSMichael Holzheu int rc; 68124bbb1faSMichael Holzheu rc = hypfs_create_cpu_files(sb, cpus_dir, cpu_info); 68224bbb1faSMichael Holzheu if (rc) 68324bbb1faSMichael Holzheu return ERR_PTR(rc); 68424bbb1faSMichael Holzheu cpu_info += cpu_info__size(diag204_info_type); 68524bbb1faSMichael Holzheu } 68624bbb1faSMichael Holzheu return cpu_info; 68724bbb1faSMichael Holzheu } 68824bbb1faSMichael Holzheu 68924bbb1faSMichael Holzheu static int hypfs_create_phys_cpu_files(struct super_block *sb, 69024bbb1faSMichael Holzheu struct dentry *cpus_dir, void *cpu_info) 69124bbb1faSMichael Holzheu { 69224bbb1faSMichael Holzheu struct dentry *cpu_dir; 69324bbb1faSMichael Holzheu char buffer[TMP_SIZE]; 69424bbb1faSMichael Holzheu void *rc; 69524bbb1faSMichael Holzheu 69624bbb1faSMichael Holzheu snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type, 69724bbb1faSMichael Holzheu cpu_info)); 69824bbb1faSMichael Holzheu cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer); 69924bbb1faSMichael Holzheu if (IS_ERR(cpu_dir)) 70024bbb1faSMichael Holzheu return PTR_ERR(cpu_dir); 70124bbb1faSMichael Holzheu rc = hypfs_create_u64(sb, cpu_dir, "mgmtime", 70224bbb1faSMichael Holzheu phys_cpu__mgm_time(diag204_info_type, cpu_info)); 70324bbb1faSMichael Holzheu if (IS_ERR(rc)) 70424bbb1faSMichael Holzheu return PTR_ERR(rc); 70524bbb1faSMichael Holzheu diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer); 70624bbb1faSMichael Holzheu rc = hypfs_create_str(sb, cpu_dir, "type", buffer); 70724bbb1faSMichael Holzheu if (IS_ERR(rc)) 70824bbb1faSMichael Holzheu return PTR_ERR(rc); 70924bbb1faSMichael Holzheu return 0; 71024bbb1faSMichael Holzheu } 71124bbb1faSMichael Holzheu 71224bbb1faSMichael Holzheu static void *hypfs_create_phys_files(struct super_block *sb, 71324bbb1faSMichael Holzheu struct dentry *parent_dir, void *phys_hdr) 71424bbb1faSMichael Holzheu { 71524bbb1faSMichael Holzheu int i; 71624bbb1faSMichael Holzheu void *cpu_info; 71724bbb1faSMichael Holzheu struct dentry *cpus_dir; 71824bbb1faSMichael Holzheu 71924bbb1faSMichael Holzheu cpus_dir = hypfs_mkdir(sb, parent_dir, "cpus"); 72024bbb1faSMichael Holzheu if (IS_ERR(cpus_dir)) 72124bbb1faSMichael Holzheu return cpus_dir; 72224bbb1faSMichael Holzheu cpu_info = phys_hdr + phys_hdr__size(diag204_info_type); 72324bbb1faSMichael Holzheu for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) { 72424bbb1faSMichael Holzheu int rc; 72524bbb1faSMichael Holzheu rc = hypfs_create_phys_cpu_files(sb, cpus_dir, cpu_info); 72624bbb1faSMichael Holzheu if (rc) 72724bbb1faSMichael Holzheu return ERR_PTR(rc); 72824bbb1faSMichael Holzheu cpu_info += phys_cpu__size(diag204_info_type); 72924bbb1faSMichael Holzheu } 73024bbb1faSMichael Holzheu return cpu_info; 73124bbb1faSMichael Holzheu } 73224bbb1faSMichael Holzheu 73324bbb1faSMichael Holzheu int hypfs_diag_create_files(struct super_block *sb, struct dentry *root) 73424bbb1faSMichael Holzheu { 73524bbb1faSMichael Holzheu struct dentry *systems_dir, *hyp_dir; 73624bbb1faSMichael Holzheu void *time_hdr, *part_hdr; 73724bbb1faSMichael Holzheu int i, rc; 73824bbb1faSMichael Holzheu void *buffer, *ptr; 73924bbb1faSMichael Holzheu 74024bbb1faSMichael Holzheu buffer = diag204_store(); 74124bbb1faSMichael Holzheu if (IS_ERR(buffer)) 74224bbb1faSMichael Holzheu return PTR_ERR(buffer); 74324bbb1faSMichael Holzheu 74424bbb1faSMichael Holzheu systems_dir = hypfs_mkdir(sb, root, "systems"); 74524bbb1faSMichael Holzheu if (IS_ERR(systems_dir)) { 74624bbb1faSMichael Holzheu rc = PTR_ERR(systems_dir); 74724bbb1faSMichael Holzheu goto err_out; 74824bbb1faSMichael Holzheu } 74924bbb1faSMichael Holzheu time_hdr = (struct x_info_blk_hdr *)buffer; 75024bbb1faSMichael Holzheu part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type); 75124bbb1faSMichael Holzheu for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) { 75224bbb1faSMichael Holzheu part_hdr = hypfs_create_lpar_files(sb, systems_dir, part_hdr); 75324bbb1faSMichael Holzheu if (IS_ERR(part_hdr)) { 75424bbb1faSMichael Holzheu rc = PTR_ERR(part_hdr); 75524bbb1faSMichael Holzheu goto err_out; 75624bbb1faSMichael Holzheu } 75724bbb1faSMichael Holzheu } 75824bbb1faSMichael Holzheu if (info_blk_hdr__flags(diag204_info_type, time_hdr) & LPAR_PHYS_FLG) { 75924bbb1faSMichael Holzheu ptr = hypfs_create_phys_files(sb, root, part_hdr); 76024bbb1faSMichael Holzheu if (IS_ERR(ptr)) { 76124bbb1faSMichael Holzheu rc = PTR_ERR(ptr); 76224bbb1faSMichael Holzheu goto err_out; 76324bbb1faSMichael Holzheu } 76424bbb1faSMichael Holzheu } 76524bbb1faSMichael Holzheu hyp_dir = hypfs_mkdir(sb, root, "hyp"); 76624bbb1faSMichael Holzheu if (IS_ERR(hyp_dir)) { 76724bbb1faSMichael Holzheu rc = PTR_ERR(hyp_dir); 76824bbb1faSMichael Holzheu goto err_out; 76924bbb1faSMichael Holzheu } 77024bbb1faSMichael Holzheu ptr = hypfs_create_str(sb, hyp_dir, "type", "LPAR Hypervisor"); 77124bbb1faSMichael Holzheu if (IS_ERR(ptr)) { 77224bbb1faSMichael Holzheu rc = PTR_ERR(ptr); 77324bbb1faSMichael Holzheu goto err_out; 77424bbb1faSMichael Holzheu } 77524bbb1faSMichael Holzheu rc = 0; 77624bbb1faSMichael Holzheu 77724bbb1faSMichael Holzheu err_out: 77824bbb1faSMichael Holzheu return rc; 77924bbb1faSMichael Holzheu } 780