Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *    Hypervisor filesystem for Linux on s390. z/VM implementation.
  4 *
  5 *    Copyright IBM Corp. 2006
  6 *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
  7 */
  8
  9#include <linux/types.h>
 10#include <linux/errno.h>
 11#include <linux/string.h>
 12#include <linux/vmalloc.h>
 13#include <asm/extable.h>
 14#include <asm/diag.h>
 15#include <asm/ebcdic.h>
 16#include <asm/timex.h>
 17#include "hypfs.h"
 18
 19#define NAME_LEN 8
 20#define DBFS_D2FC_HDR_VERSION 0
 21
 22static char local_guest[] = "        ";
 23static char all_guests[] = "*       ";
 24static char *all_groups = all_guests;
 25static char *guest_query;
 26
 27struct diag2fc_data {
 28	__u32 version;
 29	__u32 flags;
 30	__u64 used_cpu;
 31	__u64 el_time;
 32	__u64 mem_min_kb;
 33	__u64 mem_max_kb;
 34	__u64 mem_share_kb;
 35	__u64 mem_used_kb;
 36	__u32 pcpus;
 37	__u32 lcpus;
 38	__u32 vcpus;
 39	__u32 ocpus;
 40	__u32 cpu_max;
 41	__u32 cpu_shares;
 42	__u32 cpu_use_samp;
 43	__u32 cpu_delay_samp;
 44	__u32 page_wait_samp;
 45	__u32 idle_samp;
 46	__u32 other_samp;
 47	__u32 total_samp;
 48	char  guest_name[NAME_LEN];
 49};
 50
 51struct diag2fc_parm_list {
 52	char userid[NAME_LEN];
 53	char aci_grp[NAME_LEN];
 54	__u64 addr;
 55	__u32 size;
 56	__u32 fmt;
 57};
 58
 59static int diag2fc(int size, char* query, void *addr)
 60{
 61	unsigned long residual_cnt;
 62	unsigned long rc;
 63	struct diag2fc_parm_list parm_list;
 64
 65	memcpy(parm_list.userid, query, NAME_LEN);
 66	ASCEBC(parm_list.userid, NAME_LEN);
 67	memcpy(parm_list.aci_grp, all_groups, NAME_LEN);
 68	ASCEBC(parm_list.aci_grp, NAME_LEN);
 69	parm_list.addr = (unsigned long)addr;
 70	parm_list.size = size;
 71	parm_list.fmt = 0x02;
 
 72	rc = -1;
 73
 74	diag_stat_inc(DIAG_STAT_X2FC);
 75	asm volatile(
 76		"	diag    %0,%1,0x2fc\n"
 77		"0:	nopr	%%r7\n"
 78		EX_TABLE(0b,0b)
 79		: "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
 80
 81	if ((rc != 0 ) && (rc != -2))
 82		return rc;
 83	else
 84		return -residual_cnt;
 85}
 86
 87/*
 88 * Allocate buffer for "query" and store diag 2fc at "offset"
 89 */
 90static void *diag2fc_store(char *query, unsigned int *count, int offset)
 91{
 92	void *data;
 93	int size;
 94
 95	do {
 96		size = diag2fc(0, query, NULL);
 97		if (size < 0)
 98			return ERR_PTR(-EACCES);
 99		data = vmalloc(size + offset);
100		if (!data)
101			return ERR_PTR(-ENOMEM);
102		if (diag2fc(size, query, data + offset) == 0)
103			break;
104		vfree(data);
105	} while (1);
106	*count = (size / sizeof(struct diag2fc_data));
107
108	return data;
109}
110
111static void diag2fc_free(const void *data)
112{
113	vfree(data);
114}
115
116#define ATTRIBUTE(dir, name, member) \
117do { \
118	void *rc; \
119	rc = hypfs_create_u64(dir, name, member); \
120	if (IS_ERR(rc)) \
121		return PTR_ERR(rc); \
122} while(0)
123
124static int hypfs_vm_create_guest(struct dentry *systems_dir,
125				 struct diag2fc_data *data)
126{
127	char guest_name[NAME_LEN + 1] = {};
128	struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
129	int dedicated_flag, capped_value;
130
131	capped_value = (data->flags & 0x00000006) >> 1;
132	dedicated_flag = (data->flags & 0x00000008) >> 3;
133
134	/* guest dir */
135	memcpy(guest_name, data->guest_name, NAME_LEN);
136	EBCASC(guest_name, NAME_LEN);
137	strim(guest_name);
138	guest_dir = hypfs_mkdir(systems_dir, guest_name);
139	if (IS_ERR(guest_dir))
140		return PTR_ERR(guest_dir);
141	ATTRIBUTE(guest_dir, "onlinetime_us", data->el_time);
142
143	/* logical cpu information */
144	cpus_dir = hypfs_mkdir(guest_dir, "cpus");
145	if (IS_ERR(cpus_dir))
146		return PTR_ERR(cpus_dir);
147	ATTRIBUTE(cpus_dir, "cputime_us", data->used_cpu);
148	ATTRIBUTE(cpus_dir, "capped", capped_value);
149	ATTRIBUTE(cpus_dir, "dedicated", dedicated_flag);
150	ATTRIBUTE(cpus_dir, "count", data->vcpus);
151	/*
152	 * Note: The "weight_min" attribute got the wrong name.
153	 * The value represents the number of non-stopped (operating)
154	 * CPUS.
155	 */
156	ATTRIBUTE(cpus_dir, "weight_min", data->ocpus);
157	ATTRIBUTE(cpus_dir, "weight_max", data->cpu_max);
158	ATTRIBUTE(cpus_dir, "weight_cur", data->cpu_shares);
159
160	/* memory information */
161	mem_dir = hypfs_mkdir(guest_dir, "mem");
162	if (IS_ERR(mem_dir))
163		return PTR_ERR(mem_dir);
164	ATTRIBUTE(mem_dir, "min_KiB", data->mem_min_kb);
165	ATTRIBUTE(mem_dir, "max_KiB", data->mem_max_kb);
166	ATTRIBUTE(mem_dir, "used_KiB", data->mem_used_kb);
167	ATTRIBUTE(mem_dir, "share_KiB", data->mem_share_kb);
168
169	/* samples */
170	samples_dir = hypfs_mkdir(guest_dir, "samples");
171	if (IS_ERR(samples_dir))
172		return PTR_ERR(samples_dir);
173	ATTRIBUTE(samples_dir, "cpu_using", data->cpu_use_samp);
174	ATTRIBUTE(samples_dir, "cpu_delay", data->cpu_delay_samp);
175	ATTRIBUTE(samples_dir, "mem_delay", data->page_wait_samp);
176	ATTRIBUTE(samples_dir, "idle", data->idle_samp);
177	ATTRIBUTE(samples_dir, "other", data->other_samp);
178	ATTRIBUTE(samples_dir, "total", data->total_samp);
179	return 0;
180}
181
182int hypfs_vm_create_files(struct dentry *root)
183{
184	struct dentry *dir, *file;
185	struct diag2fc_data *data;
186	unsigned int count = 0;
187	int rc, i;
188
189	data = diag2fc_store(guest_query, &count, 0);
190	if (IS_ERR(data))
191		return PTR_ERR(data);
192
193	/* Hypervisor Info */
194	dir = hypfs_mkdir(root, "hyp");
195	if (IS_ERR(dir)) {
196		rc = PTR_ERR(dir);
197		goto failed;
198	}
199	file = hypfs_create_str(dir, "type", "z/VM Hypervisor");
200	if (IS_ERR(file)) {
201		rc = PTR_ERR(file);
202		goto failed;
203	}
204
205	/* physical cpus */
206	dir = hypfs_mkdir(root, "cpus");
207	if (IS_ERR(dir)) {
208		rc = PTR_ERR(dir);
209		goto failed;
210	}
211	file = hypfs_create_u64(dir, "count", data->lcpus);
212	if (IS_ERR(file)) {
213		rc = PTR_ERR(file);
214		goto failed;
215	}
216
217	/* guests */
218	dir = hypfs_mkdir(root, "systems");
219	if (IS_ERR(dir)) {
220		rc = PTR_ERR(dir);
221		goto failed;
222	}
223
224	for (i = 0; i < count; i++) {
225		rc = hypfs_vm_create_guest(dir, &(data[i]));
226		if (rc)
227			goto failed;
228	}
229	diag2fc_free(data);
230	return 0;
231
232failed:
233	diag2fc_free(data);
234	return rc;
235}
236
237struct dbfs_d2fc_hdr {
238	u64	len;		/* Length of d2fc buffer without header */
239	u16	version;	/* Version of header */
240	union tod_clock tod_ext; /* TOD clock for d2fc */
241	u64	count;		/* Number of VM guests in d2fc buffer */
242	char	reserved[30];
243} __attribute__ ((packed));
244
245struct dbfs_d2fc {
246	struct dbfs_d2fc_hdr	hdr;	/* 64 byte header */
247	char			buf[];	/* d2fc buffer */
248} __attribute__ ((packed));
249
250static int dbfs_diag2fc_create(void **data, void **data_free_ptr, size_t *size)
251{
252	struct dbfs_d2fc *d2fc;
253	unsigned int count;
254
255	d2fc = diag2fc_store(guest_query, &count, sizeof(d2fc->hdr));
256	if (IS_ERR(d2fc))
257		return PTR_ERR(d2fc);
258	store_tod_clock_ext(&d2fc->hdr.tod_ext);
259	d2fc->hdr.len = count * sizeof(struct diag2fc_data);
260	d2fc->hdr.version = DBFS_D2FC_HDR_VERSION;
261	d2fc->hdr.count = count;
262	memset(&d2fc->hdr.reserved, 0, sizeof(d2fc->hdr.reserved));
263	*data = d2fc;
264	*data_free_ptr = d2fc;
265	*size = d2fc->hdr.len + sizeof(struct dbfs_d2fc_hdr);
266	return 0;
267}
268
269static struct hypfs_dbfs_file dbfs_file_2fc = {
270	.name		= "diag_2fc",
271	.data_create	= dbfs_diag2fc_create,
272	.data_free	= diag2fc_free,
273};
274
275int hypfs_vm_init(void)
276{
277	if (!MACHINE_IS_VM)
278		return 0;
279	if (diag2fc(0, all_guests, NULL) > 0)
280		guest_query = all_guests;
281	else if (diag2fc(0, local_guest, NULL) > 0)
282		guest_query = local_guest;
283	else
284		return -EACCES;
285	hypfs_dbfs_create_file(&dbfs_file_2fc);
286	return 0;
287}
288
289void hypfs_vm_exit(void)
290{
291	if (!MACHINE_IS_VM)
292		return;
293	hypfs_dbfs_remove_file(&dbfs_file_2fc);
294}
v5.4
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *    Hypervisor filesystem for Linux on s390. z/VM implementation.
  4 *
  5 *    Copyright IBM Corp. 2006
  6 *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
  7 */
  8
  9#include <linux/types.h>
 10#include <linux/errno.h>
 11#include <linux/string.h>
 12#include <linux/vmalloc.h>
 
 13#include <asm/diag.h>
 14#include <asm/ebcdic.h>
 15#include <asm/timex.h>
 16#include "hypfs.h"
 17
 18#define NAME_LEN 8
 19#define DBFS_D2FC_HDR_VERSION 0
 20
 21static char local_guest[] = "        ";
 22static char all_guests[] = "*       ";
 
 23static char *guest_query;
 24
 25struct diag2fc_data {
 26	__u32 version;
 27	__u32 flags;
 28	__u64 used_cpu;
 29	__u64 el_time;
 30	__u64 mem_min_kb;
 31	__u64 mem_max_kb;
 32	__u64 mem_share_kb;
 33	__u64 mem_used_kb;
 34	__u32 pcpus;
 35	__u32 lcpus;
 36	__u32 vcpus;
 37	__u32 ocpus;
 38	__u32 cpu_max;
 39	__u32 cpu_shares;
 40	__u32 cpu_use_samp;
 41	__u32 cpu_delay_samp;
 42	__u32 page_wait_samp;
 43	__u32 idle_samp;
 44	__u32 other_samp;
 45	__u32 total_samp;
 46	char  guest_name[NAME_LEN];
 47};
 48
 49struct diag2fc_parm_list {
 50	char userid[NAME_LEN];
 51	char aci_grp[NAME_LEN];
 52	__u64 addr;
 53	__u32 size;
 54	__u32 fmt;
 55};
 56
 57static int diag2fc(int size, char* query, void *addr)
 58{
 59	unsigned long residual_cnt;
 60	unsigned long rc;
 61	struct diag2fc_parm_list parm_list;
 62
 63	memcpy(parm_list.userid, query, NAME_LEN);
 64	ASCEBC(parm_list.userid, NAME_LEN);
 65	parm_list.addr = (unsigned long) addr ;
 
 
 66	parm_list.size = size;
 67	parm_list.fmt = 0x02;
 68	memset(parm_list.aci_grp, 0x40, NAME_LEN);
 69	rc = -1;
 70
 71	diag_stat_inc(DIAG_STAT_X2FC);
 72	asm volatile(
 73		"	diag    %0,%1,0x2fc\n"
 74		"0:	nopr	%%r7\n"
 75		EX_TABLE(0b,0b)
 76		: "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
 77
 78	if ((rc != 0 ) && (rc != -2))
 79		return rc;
 80	else
 81		return -residual_cnt;
 82}
 83
 84/*
 85 * Allocate buffer for "query" and store diag 2fc at "offset"
 86 */
 87static void *diag2fc_store(char *query, unsigned int *count, int offset)
 88{
 89	void *data;
 90	int size;
 91
 92	do {
 93		size = diag2fc(0, query, NULL);
 94		if (size < 0)
 95			return ERR_PTR(-EACCES);
 96		data = vmalloc(size + offset);
 97		if (!data)
 98			return ERR_PTR(-ENOMEM);
 99		if (diag2fc(size, query, data + offset) == 0)
100			break;
101		vfree(data);
102	} while (1);
103	*count = (size / sizeof(struct diag2fc_data));
104
105	return data;
106}
107
108static void diag2fc_free(const void *data)
109{
110	vfree(data);
111}
112
113#define ATTRIBUTE(dir, name, member) \
114do { \
115	void *rc; \
116	rc = hypfs_create_u64(dir, name, member); \
117	if (IS_ERR(rc)) \
118		return PTR_ERR(rc); \
119} while(0)
120
121static int hypfs_vm_create_guest(struct dentry *systems_dir,
122				 struct diag2fc_data *data)
123{
124	char guest_name[NAME_LEN + 1] = {};
125	struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
126	int dedicated_flag, capped_value;
127
128	capped_value = (data->flags & 0x00000006) >> 1;
129	dedicated_flag = (data->flags & 0x00000008) >> 3;
130
131	/* guest dir */
132	memcpy(guest_name, data->guest_name, NAME_LEN);
133	EBCASC(guest_name, NAME_LEN);
134	strim(guest_name);
135	guest_dir = hypfs_mkdir(systems_dir, guest_name);
136	if (IS_ERR(guest_dir))
137		return PTR_ERR(guest_dir);
138	ATTRIBUTE(guest_dir, "onlinetime_us", data->el_time);
139
140	/* logical cpu information */
141	cpus_dir = hypfs_mkdir(guest_dir, "cpus");
142	if (IS_ERR(cpus_dir))
143		return PTR_ERR(cpus_dir);
144	ATTRIBUTE(cpus_dir, "cputime_us", data->used_cpu);
145	ATTRIBUTE(cpus_dir, "capped", capped_value);
146	ATTRIBUTE(cpus_dir, "dedicated", dedicated_flag);
147	ATTRIBUTE(cpus_dir, "count", data->vcpus);
148	/*
149	 * Note: The "weight_min" attribute got the wrong name.
150	 * The value represents the number of non-stopped (operating)
151	 * CPUS.
152	 */
153	ATTRIBUTE(cpus_dir, "weight_min", data->ocpus);
154	ATTRIBUTE(cpus_dir, "weight_max", data->cpu_max);
155	ATTRIBUTE(cpus_dir, "weight_cur", data->cpu_shares);
156
157	/* memory information */
158	mem_dir = hypfs_mkdir(guest_dir, "mem");
159	if (IS_ERR(mem_dir))
160		return PTR_ERR(mem_dir);
161	ATTRIBUTE(mem_dir, "min_KiB", data->mem_min_kb);
162	ATTRIBUTE(mem_dir, "max_KiB", data->mem_max_kb);
163	ATTRIBUTE(mem_dir, "used_KiB", data->mem_used_kb);
164	ATTRIBUTE(mem_dir, "share_KiB", data->mem_share_kb);
165
166	/* samples */
167	samples_dir = hypfs_mkdir(guest_dir, "samples");
168	if (IS_ERR(samples_dir))
169		return PTR_ERR(samples_dir);
170	ATTRIBUTE(samples_dir, "cpu_using", data->cpu_use_samp);
171	ATTRIBUTE(samples_dir, "cpu_delay", data->cpu_delay_samp);
172	ATTRIBUTE(samples_dir, "mem_delay", data->page_wait_samp);
173	ATTRIBUTE(samples_dir, "idle", data->idle_samp);
174	ATTRIBUTE(samples_dir, "other", data->other_samp);
175	ATTRIBUTE(samples_dir, "total", data->total_samp);
176	return 0;
177}
178
179int hypfs_vm_create_files(struct dentry *root)
180{
181	struct dentry *dir, *file;
182	struct diag2fc_data *data;
183	unsigned int count = 0;
184	int rc, i;
185
186	data = diag2fc_store(guest_query, &count, 0);
187	if (IS_ERR(data))
188		return PTR_ERR(data);
189
190	/* Hpervisor Info */
191	dir = hypfs_mkdir(root, "hyp");
192	if (IS_ERR(dir)) {
193		rc = PTR_ERR(dir);
194		goto failed;
195	}
196	file = hypfs_create_str(dir, "type", "z/VM Hypervisor");
197	if (IS_ERR(file)) {
198		rc = PTR_ERR(file);
199		goto failed;
200	}
201
202	/* physical cpus */
203	dir = hypfs_mkdir(root, "cpus");
204	if (IS_ERR(dir)) {
205		rc = PTR_ERR(dir);
206		goto failed;
207	}
208	file = hypfs_create_u64(dir, "count", data->lcpus);
209	if (IS_ERR(file)) {
210		rc = PTR_ERR(file);
211		goto failed;
212	}
213
214	/* guests */
215	dir = hypfs_mkdir(root, "systems");
216	if (IS_ERR(dir)) {
217		rc = PTR_ERR(dir);
218		goto failed;
219	}
220
221	for (i = 0; i < count; i++) {
222		rc = hypfs_vm_create_guest(dir, &(data[i]));
223		if (rc)
224			goto failed;
225	}
226	diag2fc_free(data);
227	return 0;
228
229failed:
230	diag2fc_free(data);
231	return rc;
232}
233
234struct dbfs_d2fc_hdr {
235	u64	len;		/* Length of d2fc buffer without header */
236	u16	version;	/* Version of header */
237	char	tod_ext[STORE_CLOCK_EXT_SIZE]; /* TOD clock for d2fc */
238	u64	count;		/* Number of VM guests in d2fc buffer */
239	char	reserved[30];
240} __attribute__ ((packed));
241
242struct dbfs_d2fc {
243	struct dbfs_d2fc_hdr	hdr;	/* 64 byte header */
244	char			buf[];	/* d2fc buffer */
245} __attribute__ ((packed));
246
247static int dbfs_diag2fc_create(void **data, void **data_free_ptr, size_t *size)
248{
249	struct dbfs_d2fc *d2fc;
250	unsigned int count;
251
252	d2fc = diag2fc_store(guest_query, &count, sizeof(d2fc->hdr));
253	if (IS_ERR(d2fc))
254		return PTR_ERR(d2fc);
255	get_tod_clock_ext(d2fc->hdr.tod_ext);
256	d2fc->hdr.len = count * sizeof(struct diag2fc_data);
257	d2fc->hdr.version = DBFS_D2FC_HDR_VERSION;
258	d2fc->hdr.count = count;
259	memset(&d2fc->hdr.reserved, 0, sizeof(d2fc->hdr.reserved));
260	*data = d2fc;
261	*data_free_ptr = d2fc;
262	*size = d2fc->hdr.len + sizeof(struct dbfs_d2fc_hdr);
263	return 0;
264}
265
266static struct hypfs_dbfs_file dbfs_file_2fc = {
267	.name		= "diag_2fc",
268	.data_create	= dbfs_diag2fc_create,
269	.data_free	= diag2fc_free,
270};
271
272int hypfs_vm_init(void)
273{
274	if (!MACHINE_IS_VM)
275		return 0;
276	if (diag2fc(0, all_guests, NULL) > 0)
277		guest_query = all_guests;
278	else if (diag2fc(0, local_guest, NULL) > 0)
279		guest_query = local_guest;
280	else
281		return -EACCES;
282	hypfs_dbfs_create_file(&dbfs_file_2fc);
283	return 0;
284}
285
286void hypfs_vm_exit(void)
287{
288	if (!MACHINE_IS_VM)
289		return;
290	hypfs_dbfs_remove_file(&dbfs_file_2fc);
291}