Linux Audio

Check our new training course

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