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