xref: /openbmc/linux/arch/s390/hypfs/hypfs_vm.c (revision a09d2831)
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