^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Hypervisor filesystem for Linux on s390. Diag 204 and 224
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * implementation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright IBM Corp. 2006, 2008
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author(s): Michael Holzheu <holzheu@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #define KMSG_COMPONENT "hypfs"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/diag.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/ebcdic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "hypfs.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define TMP_SIZE 64 /* size of temporary buffers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define DBFS_D204_HDR_VERSION 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static char *diag224_cpu_names; /* diag 224 name table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static enum diag204_sc diag204_store_sc; /* used subcode for store */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static enum diag204_format diag204_info_type; /* used diag 204 data format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static void *diag204_buf; /* 4K aligned buffer for diag204 data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static int diag204_buf_pages; /* number of pages for diag204 data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static struct dentry *dbfs_d204_file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * DIAG 204 member access functions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * Since we have two different diag 204 data formats for old and new s390
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * machines, we do not access the structs directly, but use getter functions for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * each struct member instead. This should make the code more readable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* Time information block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) static inline int info_blk_hdr__size(enum diag204_format type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return sizeof(struct diag204_info_blk_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return sizeof(struct diag204_x_info_blk_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static inline __u8 info_blk_hdr__npar(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return ((struct diag204_info_blk_hdr *)hdr)->npar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return ((struct diag204_x_info_blk_hdr *)hdr)->npar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return ((struct diag204_info_blk_hdr *)hdr)->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return ((struct diag204_x_info_blk_hdr *)hdr)->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return ((struct diag204_info_blk_hdr *)hdr)->phys_cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return ((struct diag204_x_info_blk_hdr *)hdr)->phys_cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* Partition header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static inline int part_hdr__size(enum diag204_format type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) return sizeof(struct diag204_part_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return sizeof(struct diag204_x_part_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static inline __u8 part_hdr__rcpus(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return ((struct diag204_part_hdr *)hdr)->cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return ((struct diag204_x_part_hdr *)hdr)->rcpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static inline void part_hdr__part_name(enum diag204_format type, void *hdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) memcpy(name, ((struct diag204_part_hdr *)hdr)->part_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) DIAG204_LPAR_NAME_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) memcpy(name, ((struct diag204_x_part_hdr *)hdr)->part_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) DIAG204_LPAR_NAME_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) EBCASC(name, DIAG204_LPAR_NAME_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) name[DIAG204_LPAR_NAME_LEN] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) strim(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* CPU info block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static inline int cpu_info__size(enum diag204_format type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return sizeof(struct diag204_cpu_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return sizeof(struct diag204_x_cpu_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static inline __u8 cpu_info__ctidx(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return ((struct diag204_cpu_info *)hdr)->ctidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return ((struct diag204_x_cpu_info *)hdr)->ctidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static inline __u16 cpu_info__cpu_addr(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return ((struct diag204_cpu_info *)hdr)->cpu_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return ((struct diag204_x_cpu_info *)hdr)->cpu_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static inline __u64 cpu_info__acc_time(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return ((struct diag204_cpu_info *)hdr)->acc_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return ((struct diag204_x_cpu_info *)hdr)->acc_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static inline __u64 cpu_info__lp_time(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return ((struct diag204_cpu_info *)hdr)->lp_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return ((struct diag204_x_cpu_info *)hdr)->lp_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static inline __u64 cpu_info__online_time(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return 0; /* online_time not available in simple info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return ((struct diag204_x_cpu_info *)hdr)->online_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) /* Physical header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) static inline int phys_hdr__size(enum diag204_format type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return sizeof(struct diag204_phys_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return sizeof(struct diag204_x_phys_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static inline __u8 phys_hdr__cpus(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return ((struct diag204_phys_hdr *)hdr)->cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return ((struct diag204_x_phys_hdr *)hdr)->cpus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /* Physical CPU info block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static inline int phys_cpu__size(enum diag204_format type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return sizeof(struct diag204_phys_cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) return sizeof(struct diag204_x_phys_cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) static inline __u16 phys_cpu__cpu_addr(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return ((struct diag204_phys_cpu *)hdr)->cpu_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return ((struct diag204_x_phys_cpu *)hdr)->cpu_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static inline __u64 phys_cpu__mgm_time(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return ((struct diag204_phys_cpu *)hdr)->mgm_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return ((struct diag204_x_phys_cpu *)hdr)->mgm_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static inline __u64 phys_cpu__ctidx(enum diag204_format type, void *hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (type == DIAG204_INFO_SIMPLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return ((struct diag204_phys_cpu *)hdr)->ctidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) else /* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) return ((struct diag204_x_phys_cpu *)hdr)->ctidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* Diagnose 204 functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * For the old diag subcode 4 with simple data format we have to use real
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * memory. If we use subcode 6 or 7 with extended data format, we can (and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * should) use vmalloc, since we need a lot of memory in that case. Currently
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * up to 93 pages!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static void diag204_free_buffer(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) if (!diag204_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (diag204_buf_vmalloc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) vfree(diag204_buf_vmalloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) diag204_buf_vmalloc = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) free_pages((unsigned long) diag204_buf, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) diag204_buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) static void *page_align_ptr(void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return (void *) PAGE_ALIGN((unsigned long) ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) static void *diag204_alloc_vbuf(int pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /* The buffer has to be page aligned! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) diag204_buf_vmalloc = vmalloc(array_size(PAGE_SIZE, (pages + 1)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (!diag204_buf_vmalloc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) diag204_buf = page_align_ptr(diag204_buf_vmalloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) diag204_buf_pages = pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return diag204_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static void *diag204_alloc_rbuf(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (!diag204_buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) diag204_buf_pages = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return diag204_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) static void *diag204_get_buffer(enum diag204_format fmt, int *pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (diag204_buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) *pages = diag204_buf_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return diag204_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (fmt == DIAG204_INFO_SIMPLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) *pages = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return diag204_alloc_rbuf();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) } else {/* DIAG204_INFO_EXT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) *pages = diag204((unsigned long)DIAG204_SUBC_RSI |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) (unsigned long)DIAG204_INFO_EXT, 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (*pages <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) return ERR_PTR(-ENOSYS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) return diag204_alloc_vbuf(*pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * diag204_probe() has to find out, which type of diagnose 204 implementation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * we have on our machine. Currently there are three possible scanarios:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) * - subcode 4 + simple data format (only one page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * - subcode 4-6 + extended data format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) * - subcode 4-7 + extended data format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * Subcode 5 is used to retrieve the size of the data, provided by subcodes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) * 6 and 7. Subcode 7 basically has the same function as subcode 6. In addition
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) * to subcode 6 it provides also information about secondary cpus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) * In order to get as much information as possible, we first try
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * subcode 7, then 6 and if both fail, we use subcode 4.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) static int diag204_probe(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) void *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) int pages, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) buf = diag204_get_buffer(DIAG204_INFO_EXT, &pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (!IS_ERR(buf)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (diag204((unsigned long)DIAG204_SUBC_STIB7 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) (unsigned long)DIAG204_INFO_EXT, pages, buf) >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) diag204_store_sc = DIAG204_SUBC_STIB7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) diag204_info_type = DIAG204_INFO_EXT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (diag204((unsigned long)DIAG204_SUBC_STIB6 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) (unsigned long)DIAG204_INFO_EXT, pages, buf) >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) diag204_store_sc = DIAG204_SUBC_STIB6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) diag204_info_type = DIAG204_INFO_EXT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) diag204_free_buffer();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) /* subcodes 6 and 7 failed, now try subcode 4 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) buf = diag204_get_buffer(DIAG204_INFO_SIMPLE, &pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (IS_ERR(buf)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) rc = PTR_ERR(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) goto fail_alloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (diag204((unsigned long)DIAG204_SUBC_STIB4 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) (unsigned long)DIAG204_INFO_SIMPLE, pages, buf) >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) diag204_store_sc = DIAG204_SUBC_STIB4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) diag204_info_type = DIAG204_INFO_SIMPLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) rc = -ENOSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) goto fail_store;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) fail_store:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) diag204_free_buffer();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) fail_alloc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) static int diag204_do_store(void *buf, int pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) rc = diag204((unsigned long) diag204_store_sc |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) (unsigned long) diag204_info_type, pages, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return rc < 0 ? -ENOSYS : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static void *diag204_store(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) void *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) int pages, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) buf = diag204_get_buffer(diag204_info_type, &pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (IS_ERR(buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) rc = diag204_do_store(buf, pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) return ERR_PTR(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) /* Diagnose 224 functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) static int diag224_get_name_table(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) /* memory must be below 2GB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) diag224_cpu_names = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (!diag224_cpu_names)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (diag224(diag224_cpu_names)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) free_page((unsigned long) diag224_cpu_names);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) static void diag224_delete_name_table(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) free_page((unsigned long) diag224_cpu_names);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) static int diag224_idx2name(int index, char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) memcpy(name, diag224_cpu_names + ((index + 1) * DIAG204_CPU_NAME_LEN),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) DIAG204_CPU_NAME_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) name[DIAG204_CPU_NAME_LEN] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) strim(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) struct dbfs_d204_hdr {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) u64 len; /* Length of d204 buffer without header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) u16 version; /* Version of header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) u8 sc; /* Used subcode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) char reserved[53];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) } __attribute__ ((packed));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) struct dbfs_d204 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) struct dbfs_d204_hdr hdr; /* 64 byte header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) char buf[]; /* d204 buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) } __attribute__ ((packed));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) struct dbfs_d204 *d204;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) int rc, buf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) void *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) base = vzalloc(buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (!base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) rc = diag204_do_store(d204->buf, diag204_buf_pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) vfree(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) d204->hdr.version = DBFS_D204_HDR_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) d204->hdr.len = PAGE_SIZE * diag204_buf_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) d204->hdr.sc = diag204_store_sc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) *data = d204;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) *data_free_ptr = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) *size = d204->hdr.len + sizeof(struct dbfs_d204_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) static struct hypfs_dbfs_file dbfs_file_d204 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) .name = "diag_204",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) .data_create = dbfs_d204_create,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) .data_free = vfree,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) __init int hypfs_diag_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) if (diag204_probe()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) pr_err("The hardware system does not support hypfs\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) if (diag204_info_type == DIAG204_INFO_EXT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) hypfs_dbfs_create_file(&dbfs_file_d204);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (MACHINE_IS_LPAR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) rc = diag224_get_name_table();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) pr_err("The hardware system does not provide all "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) "functions required by hypfs\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) debugfs_remove(dbfs_d204_file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) void hypfs_diag_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) debugfs_remove(dbfs_d204_file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) diag224_delete_name_table();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) diag204_free_buffer();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) hypfs_dbfs_remove_file(&dbfs_file_d204);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) * Functions to create the directory structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) * *******************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) struct dentry *cpu_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) char buffer[TMP_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) void *rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) cpu_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) cpu_dir = hypfs_mkdir(cpus_dir, buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) rc = hypfs_create_u64(cpu_dir, "mgmtime",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) cpu_info__acc_time(diag204_info_type, cpu_info) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) cpu_info__lp_time(diag204_info_type, cpu_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (IS_ERR(rc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) return PTR_ERR(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) rc = hypfs_create_u64(cpu_dir, "cputime",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) cpu_info__lp_time(diag204_info_type, cpu_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (IS_ERR(rc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return PTR_ERR(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) if (diag204_info_type == DIAG204_INFO_EXT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) rc = hypfs_create_u64(cpu_dir, "onlinetime",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) cpu_info__online_time(diag204_info_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) cpu_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (IS_ERR(rc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) return PTR_ERR(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) rc = hypfs_create_str(cpu_dir, "type", buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) return PTR_ERR_OR_ZERO(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) static void *hypfs_create_lpar_files(struct dentry *systems_dir, void *part_hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) struct dentry *cpus_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) struct dentry *lpar_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) char lpar_name[DIAG204_LPAR_NAME_LEN + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) void *cpu_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) part_hdr__part_name(diag204_info_type, part_hdr, lpar_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) lpar_name[DIAG204_LPAR_NAME_LEN] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) lpar_dir = hypfs_mkdir(systems_dir, lpar_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) if (IS_ERR(lpar_dir))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) return lpar_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) cpus_dir = hypfs_mkdir(lpar_dir, "cpus");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (IS_ERR(cpus_dir))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) return cpus_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) cpu_info = part_hdr + part_hdr__size(diag204_info_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) rc = hypfs_create_cpu_files(cpus_dir, cpu_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) return ERR_PTR(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) cpu_info += cpu_info__size(diag204_info_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) return cpu_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) static int hypfs_create_phys_cpu_files(struct dentry *cpus_dir, void *cpu_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) struct dentry *cpu_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) char buffer[TMP_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) void *rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) cpu_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) cpu_dir = hypfs_mkdir(cpus_dir, buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) if (IS_ERR(cpu_dir))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) return PTR_ERR(cpu_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) rc = hypfs_create_u64(cpu_dir, "mgmtime",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) phys_cpu__mgm_time(diag204_info_type, cpu_info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) if (IS_ERR(rc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) return PTR_ERR(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) rc = hypfs_create_str(cpu_dir, "type", buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) return PTR_ERR_OR_ZERO(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) static void *hypfs_create_phys_files(struct dentry *parent_dir, void *phys_hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) void *cpu_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) struct dentry *cpus_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) cpus_dir = hypfs_mkdir(parent_dir, "cpus");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) if (IS_ERR(cpus_dir))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return cpus_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) cpu_info = phys_hdr + phys_hdr__size(diag204_info_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) rc = hypfs_create_phys_cpu_files(cpus_dir, cpu_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) return ERR_PTR(rc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) cpu_info += phys_cpu__size(diag204_info_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) return cpu_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) int hypfs_diag_create_files(struct dentry *root)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) struct dentry *systems_dir, *hyp_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) void *time_hdr, *part_hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) int i, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) void *buffer, *ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) buffer = diag204_store();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) if (IS_ERR(buffer))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) return PTR_ERR(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) systems_dir = hypfs_mkdir(root, "systems");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) if (IS_ERR(systems_dir)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) rc = PTR_ERR(systems_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) time_hdr = (struct x_info_blk_hdr *)buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) part_hdr = hypfs_create_lpar_files(systems_dir, part_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) if (IS_ERR(part_hdr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) rc = PTR_ERR(part_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) if (info_blk_hdr__flags(diag204_info_type, time_hdr) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) DIAG204_LPAR_PHYS_FLG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) ptr = hypfs_create_phys_files(root, part_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) if (IS_ERR(ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) rc = PTR_ERR(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) hyp_dir = hypfs_mkdir(root, "hyp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) if (IS_ERR(hyp_dir)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) rc = PTR_ERR(hyp_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) ptr = hypfs_create_str(hyp_dir, "type", "LPAR Hypervisor");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (IS_ERR(ptr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) rc = PTR_ERR(ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) err_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) }