1 /* 2 * Hypervisor filesystem for Linux on s390. z/VM implementation. 3 * 4 * Copyright (C) IBM Corp. 2006 5 * Author(s): Michael Holzheu <holzheu@de.ibm.com> 6 */ 7 8 #include <linux/types.h> 9 #include <linux/errno.h> 10 #include <linux/string.h> 11 #include <linux/vmalloc.h> 12 #include <asm/ebcdic.h> 13 #include "hypfs.h" 14 15 #define NAME_LEN 8 16 17 static char local_guest[] = " "; 18 static char all_guests[] = "* "; 19 static char *guest_query; 20 21 struct diag2fc_data { 22 __u32 version; 23 __u32 flags; 24 __u64 used_cpu; 25 __u64 el_time; 26 __u64 mem_min_kb; 27 __u64 mem_max_kb; 28 __u64 mem_share_kb; 29 __u64 mem_used_kb; 30 __u32 pcpus; 31 __u32 lcpus; 32 __u32 vcpus; 33 __u32 cpu_min; 34 __u32 cpu_max; 35 __u32 cpu_shares; 36 __u32 cpu_use_samp; 37 __u32 cpu_delay_samp; 38 __u32 page_wait_samp; 39 __u32 idle_samp; 40 __u32 other_samp; 41 __u32 total_samp; 42 char guest_name[NAME_LEN]; 43 }; 44 45 struct diag2fc_parm_list { 46 char userid[NAME_LEN]; 47 char aci_grp[NAME_LEN]; 48 __u64 addr; 49 __u32 size; 50 __u32 fmt; 51 }; 52 53 static int diag2fc(int size, char* query, void *addr) 54 { 55 unsigned long residual_cnt; 56 unsigned long rc; 57 struct diag2fc_parm_list parm_list; 58 59 memcpy(parm_list.userid, query, NAME_LEN); 60 ASCEBC(parm_list.userid, NAME_LEN); 61 parm_list.addr = (unsigned long) addr ; 62 parm_list.size = size; 63 parm_list.fmt = 0x02; 64 memset(parm_list.aci_grp, 0x40, NAME_LEN); 65 rc = -1; 66 67 asm volatile( 68 " diag %0,%1,0x2fc\n" 69 "0:\n" 70 EX_TABLE(0b,0b) 71 : "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory"); 72 73 if ((rc != 0 ) && (rc != -2)) 74 return rc; 75 else 76 return -residual_cnt; 77 } 78 79 static struct diag2fc_data *diag2fc_store(char *query, int *count) 80 { 81 int size; 82 struct diag2fc_data *data; 83 84 do { 85 size = diag2fc(0, query, NULL); 86 if (size < 0) 87 return ERR_PTR(-EACCES); 88 data = vmalloc(size); 89 if (!data) 90 return ERR_PTR(-ENOMEM); 91 if (diag2fc(size, query, data) == 0) 92 break; 93 vfree(data); 94 } while (1); 95 *count = (size / sizeof(*data)); 96 97 return data; 98 } 99 100 static void diag2fc_free(void *data) 101 { 102 vfree(data); 103 } 104 105 #define ATTRIBUTE(sb, dir, name, member) \ 106 do { \ 107 void *rc; \ 108 rc = hypfs_create_u64(sb, dir, name, member); \ 109 if (IS_ERR(rc)) \ 110 return PTR_ERR(rc); \ 111 } while(0) 112 113 static int hpyfs_vm_create_guest(struct super_block *sb, 114 struct dentry *systems_dir, 115 struct diag2fc_data *data) 116 { 117 char guest_name[NAME_LEN + 1] = {}; 118 struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir; 119 int dedicated_flag, capped_value; 120 121 capped_value = (data->flags & 0x00000006) >> 1; 122 dedicated_flag = (data->flags & 0x00000008) >> 3; 123 124 /* guest dir */ 125 memcpy(guest_name, data->guest_name, NAME_LEN); 126 EBCASC(guest_name, NAME_LEN); 127 strim(guest_name); 128 guest_dir = hypfs_mkdir(sb, systems_dir, guest_name); 129 if (IS_ERR(guest_dir)) 130 return PTR_ERR(guest_dir); 131 ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time); 132 133 /* logical cpu information */ 134 cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus"); 135 if (IS_ERR(cpus_dir)) 136 return PTR_ERR(cpus_dir); 137 ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu); 138 ATTRIBUTE(sb, cpus_dir, "capped", capped_value); 139 ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag); 140 ATTRIBUTE(sb, cpus_dir, "count", data->vcpus); 141 ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min); 142 ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max); 143 ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares); 144 145 /* memory information */ 146 mem_dir = hypfs_mkdir(sb, guest_dir, "mem"); 147 if (IS_ERR(mem_dir)) 148 return PTR_ERR(mem_dir); 149 ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb); 150 ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb); 151 ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb); 152 ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb); 153 154 /* samples */ 155 samples_dir = hypfs_mkdir(sb, guest_dir, "samples"); 156 if (IS_ERR(samples_dir)) 157 return PTR_ERR(samples_dir); 158 ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp); 159 ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp); 160 ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp); 161 ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp); 162 ATTRIBUTE(sb, samples_dir, "other", data->other_samp); 163 ATTRIBUTE(sb, samples_dir, "total", data->total_samp); 164 return 0; 165 } 166 167 int hypfs_vm_create_files(struct super_block *sb, struct dentry *root) 168 { 169 struct dentry *dir, *file; 170 struct diag2fc_data *data; 171 int rc, i, count = 0; 172 173 data = diag2fc_store(guest_query, &count); 174 if (IS_ERR(data)) 175 return PTR_ERR(data); 176 177 /* Hpervisor Info */ 178 dir = hypfs_mkdir(sb, root, "hyp"); 179 if (IS_ERR(dir)) { 180 rc = PTR_ERR(dir); 181 goto failed; 182 } 183 file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor"); 184 if (IS_ERR(file)) { 185 rc = PTR_ERR(file); 186 goto failed; 187 } 188 189 /* physical cpus */ 190 dir = hypfs_mkdir(sb, root, "cpus"); 191 if (IS_ERR(dir)) { 192 rc = PTR_ERR(dir); 193 goto failed; 194 } 195 file = hypfs_create_u64(sb, dir, "count", data->lcpus); 196 if (IS_ERR(file)) { 197 rc = PTR_ERR(file); 198 goto failed; 199 } 200 201 /* guests */ 202 dir = hypfs_mkdir(sb, root, "systems"); 203 if (IS_ERR(dir)) { 204 rc = PTR_ERR(dir); 205 goto failed; 206 } 207 208 for (i = 0; i < count; i++) { 209 rc = hpyfs_vm_create_guest(sb, dir, &(data[i])); 210 if (rc) 211 goto failed; 212 } 213 diag2fc_free(data); 214 return 0; 215 216 failed: 217 diag2fc_free(data); 218 return rc; 219 } 220 221 int hypfs_vm_init(void) 222 { 223 if (diag2fc(0, all_guests, NULL) > 0) 224 guest_query = all_guests; 225 else if (diag2fc(0, local_guest, NULL) > 0) 226 guest_query = local_guest; 227 else 228 return -EACCES; 229 230 return 0; 231 } 232