xref: /OK3568_Linux_fs/kernel/arch/s390/hypfs/hypfs_diag.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *    Hypervisor filesystem for Linux on s390. Diag 204 and 224
4*4882a593Smuzhiyun  *    implementation.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *    Copyright IBM Corp. 2006, 2008
7*4882a593Smuzhiyun  *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #define KMSG_COMPONENT "hypfs"
11*4882a593Smuzhiyun #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/types.h>
14*4882a593Smuzhiyun #include <linux/errno.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/string.h>
17*4882a593Smuzhiyun #include <linux/vmalloc.h>
18*4882a593Smuzhiyun #include <linux/mm.h>
19*4882a593Smuzhiyun #include <asm/diag.h>
20*4882a593Smuzhiyun #include <asm/ebcdic.h>
21*4882a593Smuzhiyun #include "hypfs.h"
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define TMP_SIZE 64		/* size of temporary buffers */
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define DBFS_D204_HDR_VERSION	0
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun static char *diag224_cpu_names;			/* diag 224 name table */
28*4882a593Smuzhiyun static enum diag204_sc diag204_store_sc;	/* used subcode for store */
29*4882a593Smuzhiyun static enum diag204_format diag204_info_type;	/* used diag 204 data format */
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun static void *diag204_buf;		/* 4K aligned buffer for diag204 data */
32*4882a593Smuzhiyun static void *diag204_buf_vmalloc;	/* vmalloc pointer for diag204 data */
33*4882a593Smuzhiyun static int diag204_buf_pages;		/* number of pages for diag204 data */
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun static struct dentry *dbfs_d204_file;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /*
38*4882a593Smuzhiyun  * DIAG 204 member access functions.
39*4882a593Smuzhiyun  *
40*4882a593Smuzhiyun  * Since we have two different diag 204 data formats for old and new s390
41*4882a593Smuzhiyun  * machines, we do not access the structs directly, but use getter functions for
42*4882a593Smuzhiyun  * each struct member instead. This should make the code more readable.
43*4882a593Smuzhiyun  */
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun /* Time information block */
46*4882a593Smuzhiyun 
info_blk_hdr__size(enum diag204_format type)47*4882a593Smuzhiyun static inline int info_blk_hdr__size(enum diag204_format type)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
50*4882a593Smuzhiyun 		return sizeof(struct diag204_info_blk_hdr);
51*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
52*4882a593Smuzhiyun 		return sizeof(struct diag204_x_info_blk_hdr);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun 
info_blk_hdr__npar(enum diag204_format type,void * hdr)55*4882a593Smuzhiyun static inline __u8 info_blk_hdr__npar(enum diag204_format type, void *hdr)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
58*4882a593Smuzhiyun 		return ((struct diag204_info_blk_hdr *)hdr)->npar;
59*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
60*4882a593Smuzhiyun 		return ((struct diag204_x_info_blk_hdr *)hdr)->npar;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
info_blk_hdr__flags(enum diag204_format type,void * hdr)63*4882a593Smuzhiyun static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
66*4882a593Smuzhiyun 		return ((struct diag204_info_blk_hdr *)hdr)->flags;
67*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
68*4882a593Smuzhiyun 		return ((struct diag204_x_info_blk_hdr *)hdr)->flags;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
info_blk_hdr__pcpus(enum diag204_format type,void * hdr)71*4882a593Smuzhiyun static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
74*4882a593Smuzhiyun 		return ((struct diag204_info_blk_hdr *)hdr)->phys_cpus;
75*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
76*4882a593Smuzhiyun 		return ((struct diag204_x_info_blk_hdr *)hdr)->phys_cpus;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun /* Partition header */
80*4882a593Smuzhiyun 
part_hdr__size(enum diag204_format type)81*4882a593Smuzhiyun static inline int part_hdr__size(enum diag204_format type)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
84*4882a593Smuzhiyun 		return sizeof(struct diag204_part_hdr);
85*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
86*4882a593Smuzhiyun 		return sizeof(struct diag204_x_part_hdr);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
part_hdr__rcpus(enum diag204_format type,void * hdr)89*4882a593Smuzhiyun static inline __u8 part_hdr__rcpus(enum diag204_format type, void *hdr)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
92*4882a593Smuzhiyun 		return ((struct diag204_part_hdr *)hdr)->cpus;
93*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
94*4882a593Smuzhiyun 		return ((struct diag204_x_part_hdr *)hdr)->rcpus;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
part_hdr__part_name(enum diag204_format type,void * hdr,char * name)97*4882a593Smuzhiyun static inline void part_hdr__part_name(enum diag204_format type, void *hdr,
98*4882a593Smuzhiyun 				       char *name)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
101*4882a593Smuzhiyun 		memcpy(name, ((struct diag204_part_hdr *)hdr)->part_name,
102*4882a593Smuzhiyun 		       DIAG204_LPAR_NAME_LEN);
103*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
104*4882a593Smuzhiyun 		memcpy(name, ((struct diag204_x_part_hdr *)hdr)->part_name,
105*4882a593Smuzhiyun 		       DIAG204_LPAR_NAME_LEN);
106*4882a593Smuzhiyun 	EBCASC(name, DIAG204_LPAR_NAME_LEN);
107*4882a593Smuzhiyun 	name[DIAG204_LPAR_NAME_LEN] = 0;
108*4882a593Smuzhiyun 	strim(name);
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun /* CPU info block */
112*4882a593Smuzhiyun 
cpu_info__size(enum diag204_format type)113*4882a593Smuzhiyun static inline int cpu_info__size(enum diag204_format type)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
116*4882a593Smuzhiyun 		return sizeof(struct diag204_cpu_info);
117*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
118*4882a593Smuzhiyun 		return sizeof(struct diag204_x_cpu_info);
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
cpu_info__ctidx(enum diag204_format type,void * hdr)121*4882a593Smuzhiyun static inline __u8 cpu_info__ctidx(enum diag204_format type, void *hdr)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
124*4882a593Smuzhiyun 		return ((struct diag204_cpu_info *)hdr)->ctidx;
125*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
126*4882a593Smuzhiyun 		return ((struct diag204_x_cpu_info *)hdr)->ctidx;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
cpu_info__cpu_addr(enum diag204_format type,void * hdr)129*4882a593Smuzhiyun static inline __u16 cpu_info__cpu_addr(enum diag204_format type, void *hdr)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
132*4882a593Smuzhiyun 		return ((struct diag204_cpu_info *)hdr)->cpu_addr;
133*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
134*4882a593Smuzhiyun 		return ((struct diag204_x_cpu_info *)hdr)->cpu_addr;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
cpu_info__acc_time(enum diag204_format type,void * hdr)137*4882a593Smuzhiyun static inline __u64 cpu_info__acc_time(enum diag204_format type, void *hdr)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
140*4882a593Smuzhiyun 		return ((struct diag204_cpu_info *)hdr)->acc_time;
141*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
142*4882a593Smuzhiyun 		return ((struct diag204_x_cpu_info *)hdr)->acc_time;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
cpu_info__lp_time(enum diag204_format type,void * hdr)145*4882a593Smuzhiyun static inline __u64 cpu_info__lp_time(enum diag204_format type, void *hdr)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
148*4882a593Smuzhiyun 		return ((struct diag204_cpu_info *)hdr)->lp_time;
149*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
150*4882a593Smuzhiyun 		return ((struct diag204_x_cpu_info *)hdr)->lp_time;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
cpu_info__online_time(enum diag204_format type,void * hdr)153*4882a593Smuzhiyun static inline __u64 cpu_info__online_time(enum diag204_format type, void *hdr)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
156*4882a593Smuzhiyun 		return 0;	/* online_time not available in simple info */
157*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
158*4882a593Smuzhiyun 		return ((struct diag204_x_cpu_info *)hdr)->online_time;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun /* Physical header */
162*4882a593Smuzhiyun 
phys_hdr__size(enum diag204_format type)163*4882a593Smuzhiyun static inline int phys_hdr__size(enum diag204_format type)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
166*4882a593Smuzhiyun 		return sizeof(struct diag204_phys_hdr);
167*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
168*4882a593Smuzhiyun 		return sizeof(struct diag204_x_phys_hdr);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
phys_hdr__cpus(enum diag204_format type,void * hdr)171*4882a593Smuzhiyun static inline __u8 phys_hdr__cpus(enum diag204_format type, void *hdr)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
174*4882a593Smuzhiyun 		return ((struct diag204_phys_hdr *)hdr)->cpus;
175*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
176*4882a593Smuzhiyun 		return ((struct diag204_x_phys_hdr *)hdr)->cpus;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun /* Physical CPU info block */
180*4882a593Smuzhiyun 
phys_cpu__size(enum diag204_format type)181*4882a593Smuzhiyun static inline int phys_cpu__size(enum diag204_format type)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
184*4882a593Smuzhiyun 		return sizeof(struct diag204_phys_cpu);
185*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
186*4882a593Smuzhiyun 		return sizeof(struct diag204_x_phys_cpu);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
phys_cpu__cpu_addr(enum diag204_format type,void * hdr)189*4882a593Smuzhiyun static inline __u16 phys_cpu__cpu_addr(enum diag204_format type, void *hdr)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
192*4882a593Smuzhiyun 		return ((struct diag204_phys_cpu *)hdr)->cpu_addr;
193*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
194*4882a593Smuzhiyun 		return ((struct diag204_x_phys_cpu *)hdr)->cpu_addr;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
phys_cpu__mgm_time(enum diag204_format type,void * hdr)197*4882a593Smuzhiyun static inline __u64 phys_cpu__mgm_time(enum diag204_format type, void *hdr)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
200*4882a593Smuzhiyun 		return ((struct diag204_phys_cpu *)hdr)->mgm_time;
201*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
202*4882a593Smuzhiyun 		return ((struct diag204_x_phys_cpu *)hdr)->mgm_time;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
phys_cpu__ctidx(enum diag204_format type,void * hdr)205*4882a593Smuzhiyun static inline __u64 phys_cpu__ctidx(enum diag204_format type, void *hdr)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	if (type == DIAG204_INFO_SIMPLE)
208*4882a593Smuzhiyun 		return ((struct diag204_phys_cpu *)hdr)->ctidx;
209*4882a593Smuzhiyun 	else /* DIAG204_INFO_EXT */
210*4882a593Smuzhiyun 		return ((struct diag204_x_phys_cpu *)hdr)->ctidx;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun /* Diagnose 204 functions */
214*4882a593Smuzhiyun /*
215*4882a593Smuzhiyun  * For the old diag subcode 4 with simple data format we have to use real
216*4882a593Smuzhiyun  * memory. If we use subcode 6 or 7 with extended data format, we can (and
217*4882a593Smuzhiyun  * should) use vmalloc, since we need a lot of memory in that case. Currently
218*4882a593Smuzhiyun  * up to 93 pages!
219*4882a593Smuzhiyun  */
220*4882a593Smuzhiyun 
diag204_free_buffer(void)221*4882a593Smuzhiyun static void diag204_free_buffer(void)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	if (!diag204_buf)
224*4882a593Smuzhiyun 		return;
225*4882a593Smuzhiyun 	if (diag204_buf_vmalloc) {
226*4882a593Smuzhiyun 		vfree(diag204_buf_vmalloc);
227*4882a593Smuzhiyun 		diag204_buf_vmalloc = NULL;
228*4882a593Smuzhiyun 	} else {
229*4882a593Smuzhiyun 		free_pages((unsigned long) diag204_buf, 0);
230*4882a593Smuzhiyun 	}
231*4882a593Smuzhiyun 	diag204_buf = NULL;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
page_align_ptr(void * ptr)234*4882a593Smuzhiyun static void *page_align_ptr(void *ptr)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	return (void *) PAGE_ALIGN((unsigned long) ptr);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun 
diag204_alloc_vbuf(int pages)239*4882a593Smuzhiyun static void *diag204_alloc_vbuf(int pages)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	/* The buffer has to be page aligned! */
242*4882a593Smuzhiyun 	diag204_buf_vmalloc = vmalloc(array_size(PAGE_SIZE, (pages + 1)));
243*4882a593Smuzhiyun 	if (!diag204_buf_vmalloc)
244*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
245*4882a593Smuzhiyun 	diag204_buf = page_align_ptr(diag204_buf_vmalloc);
246*4882a593Smuzhiyun 	diag204_buf_pages = pages;
247*4882a593Smuzhiyun 	return diag204_buf;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun 
diag204_alloc_rbuf(void)250*4882a593Smuzhiyun static void *diag204_alloc_rbuf(void)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0);
253*4882a593Smuzhiyun 	if (!diag204_buf)
254*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
255*4882a593Smuzhiyun 	diag204_buf_pages = 1;
256*4882a593Smuzhiyun 	return diag204_buf;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
diag204_get_buffer(enum diag204_format fmt,int * pages)259*4882a593Smuzhiyun static void *diag204_get_buffer(enum diag204_format fmt, int *pages)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	if (diag204_buf) {
262*4882a593Smuzhiyun 		*pages = diag204_buf_pages;
263*4882a593Smuzhiyun 		return diag204_buf;
264*4882a593Smuzhiyun 	}
265*4882a593Smuzhiyun 	if (fmt == DIAG204_INFO_SIMPLE) {
266*4882a593Smuzhiyun 		*pages = 1;
267*4882a593Smuzhiyun 		return diag204_alloc_rbuf();
268*4882a593Smuzhiyun 	} else {/* DIAG204_INFO_EXT */
269*4882a593Smuzhiyun 		*pages = diag204((unsigned long)DIAG204_SUBC_RSI |
270*4882a593Smuzhiyun 				 (unsigned long)DIAG204_INFO_EXT, 0, NULL);
271*4882a593Smuzhiyun 		if (*pages <= 0)
272*4882a593Smuzhiyun 			return ERR_PTR(-ENOSYS);
273*4882a593Smuzhiyun 		else
274*4882a593Smuzhiyun 			return diag204_alloc_vbuf(*pages);
275*4882a593Smuzhiyun 	}
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun /*
279*4882a593Smuzhiyun  * diag204_probe() has to find out, which type of diagnose 204 implementation
280*4882a593Smuzhiyun  * we have on our machine. Currently there are three possible scanarios:
281*4882a593Smuzhiyun  *   - subcode 4   + simple data format (only one page)
282*4882a593Smuzhiyun  *   - subcode 4-6 + extended data format
283*4882a593Smuzhiyun  *   - subcode 4-7 + extended data format
284*4882a593Smuzhiyun  *
285*4882a593Smuzhiyun  * Subcode 5 is used to retrieve the size of the data, provided by subcodes
286*4882a593Smuzhiyun  * 6 and 7. Subcode 7 basically has the same function as subcode 6. In addition
287*4882a593Smuzhiyun  * to subcode 6 it provides also information about secondary cpus.
288*4882a593Smuzhiyun  * In order to get as much information as possible, we first try
289*4882a593Smuzhiyun  * subcode 7, then 6 and if both fail, we use subcode 4.
290*4882a593Smuzhiyun  */
291*4882a593Smuzhiyun 
diag204_probe(void)292*4882a593Smuzhiyun static int diag204_probe(void)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	void *buf;
295*4882a593Smuzhiyun 	int pages, rc;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	buf = diag204_get_buffer(DIAG204_INFO_EXT, &pages);
298*4882a593Smuzhiyun 	if (!IS_ERR(buf)) {
299*4882a593Smuzhiyun 		if (diag204((unsigned long)DIAG204_SUBC_STIB7 |
300*4882a593Smuzhiyun 			    (unsigned long)DIAG204_INFO_EXT, pages, buf) >= 0) {
301*4882a593Smuzhiyun 			diag204_store_sc = DIAG204_SUBC_STIB7;
302*4882a593Smuzhiyun 			diag204_info_type = DIAG204_INFO_EXT;
303*4882a593Smuzhiyun 			goto out;
304*4882a593Smuzhiyun 		}
305*4882a593Smuzhiyun 		if (diag204((unsigned long)DIAG204_SUBC_STIB6 |
306*4882a593Smuzhiyun 			    (unsigned long)DIAG204_INFO_EXT, pages, buf) >= 0) {
307*4882a593Smuzhiyun 			diag204_store_sc = DIAG204_SUBC_STIB6;
308*4882a593Smuzhiyun 			diag204_info_type = DIAG204_INFO_EXT;
309*4882a593Smuzhiyun 			goto out;
310*4882a593Smuzhiyun 		}
311*4882a593Smuzhiyun 		diag204_free_buffer();
312*4882a593Smuzhiyun 	}
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	/* subcodes 6 and 7 failed, now try subcode 4 */
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	buf = diag204_get_buffer(DIAG204_INFO_SIMPLE, &pages);
317*4882a593Smuzhiyun 	if (IS_ERR(buf)) {
318*4882a593Smuzhiyun 		rc = PTR_ERR(buf);
319*4882a593Smuzhiyun 		goto fail_alloc;
320*4882a593Smuzhiyun 	}
321*4882a593Smuzhiyun 	if (diag204((unsigned long)DIAG204_SUBC_STIB4 |
322*4882a593Smuzhiyun 		    (unsigned long)DIAG204_INFO_SIMPLE, pages, buf) >= 0) {
323*4882a593Smuzhiyun 		diag204_store_sc = DIAG204_SUBC_STIB4;
324*4882a593Smuzhiyun 		diag204_info_type = DIAG204_INFO_SIMPLE;
325*4882a593Smuzhiyun 		goto out;
326*4882a593Smuzhiyun 	} else {
327*4882a593Smuzhiyun 		rc = -ENOSYS;
328*4882a593Smuzhiyun 		goto fail_store;
329*4882a593Smuzhiyun 	}
330*4882a593Smuzhiyun out:
331*4882a593Smuzhiyun 	rc = 0;
332*4882a593Smuzhiyun fail_store:
333*4882a593Smuzhiyun 	diag204_free_buffer();
334*4882a593Smuzhiyun fail_alloc:
335*4882a593Smuzhiyun 	return rc;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun 
diag204_do_store(void * buf,int pages)338*4882a593Smuzhiyun static int diag204_do_store(void *buf, int pages)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun 	int rc;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	rc = diag204((unsigned long) diag204_store_sc |
343*4882a593Smuzhiyun 		     (unsigned long) diag204_info_type, pages, buf);
344*4882a593Smuzhiyun 	return rc < 0 ? -ENOSYS : 0;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
diag204_store(void)347*4882a593Smuzhiyun static void *diag204_store(void)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun 	void *buf;
350*4882a593Smuzhiyun 	int pages, rc;
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	buf = diag204_get_buffer(diag204_info_type, &pages);
353*4882a593Smuzhiyun 	if (IS_ERR(buf))
354*4882a593Smuzhiyun 		goto out;
355*4882a593Smuzhiyun 	rc = diag204_do_store(buf, pages);
356*4882a593Smuzhiyun 	if (rc)
357*4882a593Smuzhiyun 		return ERR_PTR(rc);
358*4882a593Smuzhiyun out:
359*4882a593Smuzhiyun 	return buf;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun /* Diagnose 224 functions */
363*4882a593Smuzhiyun 
diag224_get_name_table(void)364*4882a593Smuzhiyun static int diag224_get_name_table(void)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun 	/* memory must be below 2GB */
367*4882a593Smuzhiyun 	diag224_cpu_names = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);
368*4882a593Smuzhiyun 	if (!diag224_cpu_names)
369*4882a593Smuzhiyun 		return -ENOMEM;
370*4882a593Smuzhiyun 	if (diag224(diag224_cpu_names)) {
371*4882a593Smuzhiyun 		free_page((unsigned long) diag224_cpu_names);
372*4882a593Smuzhiyun 		return -EOPNOTSUPP;
373*4882a593Smuzhiyun 	}
374*4882a593Smuzhiyun 	EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16);
375*4882a593Smuzhiyun 	return 0;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun 
diag224_delete_name_table(void)378*4882a593Smuzhiyun static void diag224_delete_name_table(void)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun 	free_page((unsigned long) diag224_cpu_names);
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun 
diag224_idx2name(int index,char * name)383*4882a593Smuzhiyun static int diag224_idx2name(int index, char *name)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun 	memcpy(name, diag224_cpu_names + ((index + 1) * DIAG204_CPU_NAME_LEN),
386*4882a593Smuzhiyun 	       DIAG204_CPU_NAME_LEN);
387*4882a593Smuzhiyun 	name[DIAG204_CPU_NAME_LEN] = 0;
388*4882a593Smuzhiyun 	strim(name);
389*4882a593Smuzhiyun 	return 0;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun struct dbfs_d204_hdr {
393*4882a593Smuzhiyun 	u64	len;		/* Length of d204 buffer without header */
394*4882a593Smuzhiyun 	u16	version;	/* Version of header */
395*4882a593Smuzhiyun 	u8	sc;		/* Used subcode */
396*4882a593Smuzhiyun 	char	reserved[53];
397*4882a593Smuzhiyun } __attribute__ ((packed));
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun struct dbfs_d204 {
400*4882a593Smuzhiyun 	struct dbfs_d204_hdr	hdr;	/* 64 byte header */
401*4882a593Smuzhiyun 	char			buf[];	/* d204 buffer */
402*4882a593Smuzhiyun } __attribute__ ((packed));
403*4882a593Smuzhiyun 
dbfs_d204_create(void ** data,void ** data_free_ptr,size_t * size)404*4882a593Smuzhiyun static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun 	struct dbfs_d204 *d204;
407*4882a593Smuzhiyun 	int rc, buf_size;
408*4882a593Smuzhiyun 	void *base;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr);
411*4882a593Smuzhiyun 	base = vzalloc(buf_size);
412*4882a593Smuzhiyun 	if (!base)
413*4882a593Smuzhiyun 		return -ENOMEM;
414*4882a593Smuzhiyun 	d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr);
415*4882a593Smuzhiyun 	rc = diag204_do_store(d204->buf, diag204_buf_pages);
416*4882a593Smuzhiyun 	if (rc) {
417*4882a593Smuzhiyun 		vfree(base);
418*4882a593Smuzhiyun 		return rc;
419*4882a593Smuzhiyun 	}
420*4882a593Smuzhiyun 	d204->hdr.version = DBFS_D204_HDR_VERSION;
421*4882a593Smuzhiyun 	d204->hdr.len = PAGE_SIZE * diag204_buf_pages;
422*4882a593Smuzhiyun 	d204->hdr.sc = diag204_store_sc;
423*4882a593Smuzhiyun 	*data = d204;
424*4882a593Smuzhiyun 	*data_free_ptr = base;
425*4882a593Smuzhiyun 	*size = d204->hdr.len + sizeof(struct dbfs_d204_hdr);
426*4882a593Smuzhiyun 	return 0;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun static struct hypfs_dbfs_file dbfs_file_d204 = {
430*4882a593Smuzhiyun 	.name		= "diag_204",
431*4882a593Smuzhiyun 	.data_create	= dbfs_d204_create,
432*4882a593Smuzhiyun 	.data_free	= vfree,
433*4882a593Smuzhiyun };
434*4882a593Smuzhiyun 
hypfs_diag_init(void)435*4882a593Smuzhiyun __init int hypfs_diag_init(void)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun 	int rc;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	if (diag204_probe()) {
440*4882a593Smuzhiyun 		pr_info("The hardware system does not support hypfs\n");
441*4882a593Smuzhiyun 		return -ENODATA;
442*4882a593Smuzhiyun 	}
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	if (diag204_info_type == DIAG204_INFO_EXT)
445*4882a593Smuzhiyun 		hypfs_dbfs_create_file(&dbfs_file_d204);
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	if (MACHINE_IS_LPAR) {
448*4882a593Smuzhiyun 		rc = diag224_get_name_table();
449*4882a593Smuzhiyun 		if (rc) {
450*4882a593Smuzhiyun 			pr_err("The hardware system does not provide all "
451*4882a593Smuzhiyun 			       "functions required by hypfs\n");
452*4882a593Smuzhiyun 			debugfs_remove(dbfs_d204_file);
453*4882a593Smuzhiyun 			return rc;
454*4882a593Smuzhiyun 		}
455*4882a593Smuzhiyun 	}
456*4882a593Smuzhiyun 	return 0;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun 
hypfs_diag_exit(void)459*4882a593Smuzhiyun void hypfs_diag_exit(void)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	debugfs_remove(dbfs_d204_file);
462*4882a593Smuzhiyun 	diag224_delete_name_table();
463*4882a593Smuzhiyun 	diag204_free_buffer();
464*4882a593Smuzhiyun 	hypfs_dbfs_remove_file(&dbfs_file_d204);
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun /*
468*4882a593Smuzhiyun  * Functions to create the directory structure
469*4882a593Smuzhiyun  * *******************************************
470*4882a593Smuzhiyun  */
471*4882a593Smuzhiyun 
hypfs_create_cpu_files(struct dentry * cpus_dir,void * cpu_info)472*4882a593Smuzhiyun static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun 	struct dentry *cpu_dir;
475*4882a593Smuzhiyun 	char buffer[TMP_SIZE];
476*4882a593Smuzhiyun 	void *rc;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type,
479*4882a593Smuzhiyun 							    cpu_info));
480*4882a593Smuzhiyun 	cpu_dir = hypfs_mkdir(cpus_dir, buffer);
481*4882a593Smuzhiyun 	rc = hypfs_create_u64(cpu_dir, "mgmtime",
482*4882a593Smuzhiyun 			      cpu_info__acc_time(diag204_info_type, cpu_info) -
483*4882a593Smuzhiyun 			      cpu_info__lp_time(diag204_info_type, cpu_info));
484*4882a593Smuzhiyun 	if (IS_ERR(rc))
485*4882a593Smuzhiyun 		return PTR_ERR(rc);
486*4882a593Smuzhiyun 	rc = hypfs_create_u64(cpu_dir, "cputime",
487*4882a593Smuzhiyun 			      cpu_info__lp_time(diag204_info_type, cpu_info));
488*4882a593Smuzhiyun 	if (IS_ERR(rc))
489*4882a593Smuzhiyun 		return PTR_ERR(rc);
490*4882a593Smuzhiyun 	if (diag204_info_type == DIAG204_INFO_EXT) {
491*4882a593Smuzhiyun 		rc = hypfs_create_u64(cpu_dir, "onlinetime",
492*4882a593Smuzhiyun 				      cpu_info__online_time(diag204_info_type,
493*4882a593Smuzhiyun 							    cpu_info));
494*4882a593Smuzhiyun 		if (IS_ERR(rc))
495*4882a593Smuzhiyun 			return PTR_ERR(rc);
496*4882a593Smuzhiyun 	}
497*4882a593Smuzhiyun 	diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer);
498*4882a593Smuzhiyun 	rc = hypfs_create_str(cpu_dir, "type", buffer);
499*4882a593Smuzhiyun 	return PTR_ERR_OR_ZERO(rc);
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun 
hypfs_create_lpar_files(struct dentry * systems_dir,void * part_hdr)502*4882a593Smuzhiyun static void *hypfs_create_lpar_files(struct dentry *systems_dir, void *part_hdr)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun 	struct dentry *cpus_dir;
505*4882a593Smuzhiyun 	struct dentry *lpar_dir;
506*4882a593Smuzhiyun 	char lpar_name[DIAG204_LPAR_NAME_LEN + 1];
507*4882a593Smuzhiyun 	void *cpu_info;
508*4882a593Smuzhiyun 	int i;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	part_hdr__part_name(diag204_info_type, part_hdr, lpar_name);
511*4882a593Smuzhiyun 	lpar_name[DIAG204_LPAR_NAME_LEN] = 0;
512*4882a593Smuzhiyun 	lpar_dir = hypfs_mkdir(systems_dir, lpar_name);
513*4882a593Smuzhiyun 	if (IS_ERR(lpar_dir))
514*4882a593Smuzhiyun 		return lpar_dir;
515*4882a593Smuzhiyun 	cpus_dir = hypfs_mkdir(lpar_dir, "cpus");
516*4882a593Smuzhiyun 	if (IS_ERR(cpus_dir))
517*4882a593Smuzhiyun 		return cpus_dir;
518*4882a593Smuzhiyun 	cpu_info = part_hdr + part_hdr__size(diag204_info_type);
519*4882a593Smuzhiyun 	for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) {
520*4882a593Smuzhiyun 		int rc;
521*4882a593Smuzhiyun 		rc = hypfs_create_cpu_files(cpus_dir, cpu_info);
522*4882a593Smuzhiyun 		if (rc)
523*4882a593Smuzhiyun 			return ERR_PTR(rc);
524*4882a593Smuzhiyun 		cpu_info += cpu_info__size(diag204_info_type);
525*4882a593Smuzhiyun 	}
526*4882a593Smuzhiyun 	return cpu_info;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun 
hypfs_create_phys_cpu_files(struct dentry * cpus_dir,void * cpu_info)529*4882a593Smuzhiyun static int hypfs_create_phys_cpu_files(struct dentry *cpus_dir, void *cpu_info)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun 	struct dentry *cpu_dir;
532*4882a593Smuzhiyun 	char buffer[TMP_SIZE];
533*4882a593Smuzhiyun 	void *rc;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type,
536*4882a593Smuzhiyun 							    cpu_info));
537*4882a593Smuzhiyun 	cpu_dir = hypfs_mkdir(cpus_dir, buffer);
538*4882a593Smuzhiyun 	if (IS_ERR(cpu_dir))
539*4882a593Smuzhiyun 		return PTR_ERR(cpu_dir);
540*4882a593Smuzhiyun 	rc = hypfs_create_u64(cpu_dir, "mgmtime",
541*4882a593Smuzhiyun 			      phys_cpu__mgm_time(diag204_info_type, cpu_info));
542*4882a593Smuzhiyun 	if (IS_ERR(rc))
543*4882a593Smuzhiyun 		return PTR_ERR(rc);
544*4882a593Smuzhiyun 	diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer);
545*4882a593Smuzhiyun 	rc = hypfs_create_str(cpu_dir, "type", buffer);
546*4882a593Smuzhiyun 	return PTR_ERR_OR_ZERO(rc);
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun 
hypfs_create_phys_files(struct dentry * parent_dir,void * phys_hdr)549*4882a593Smuzhiyun static void *hypfs_create_phys_files(struct dentry *parent_dir, void *phys_hdr)
550*4882a593Smuzhiyun {
551*4882a593Smuzhiyun 	int i;
552*4882a593Smuzhiyun 	void *cpu_info;
553*4882a593Smuzhiyun 	struct dentry *cpus_dir;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	cpus_dir = hypfs_mkdir(parent_dir, "cpus");
556*4882a593Smuzhiyun 	if (IS_ERR(cpus_dir))
557*4882a593Smuzhiyun 		return cpus_dir;
558*4882a593Smuzhiyun 	cpu_info = phys_hdr + phys_hdr__size(diag204_info_type);
559*4882a593Smuzhiyun 	for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) {
560*4882a593Smuzhiyun 		int rc;
561*4882a593Smuzhiyun 		rc = hypfs_create_phys_cpu_files(cpus_dir, cpu_info);
562*4882a593Smuzhiyun 		if (rc)
563*4882a593Smuzhiyun 			return ERR_PTR(rc);
564*4882a593Smuzhiyun 		cpu_info += phys_cpu__size(diag204_info_type);
565*4882a593Smuzhiyun 	}
566*4882a593Smuzhiyun 	return cpu_info;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun 
hypfs_diag_create_files(struct dentry * root)569*4882a593Smuzhiyun int hypfs_diag_create_files(struct dentry *root)
570*4882a593Smuzhiyun {
571*4882a593Smuzhiyun 	struct dentry *systems_dir, *hyp_dir;
572*4882a593Smuzhiyun 	void *time_hdr, *part_hdr;
573*4882a593Smuzhiyun 	int i, rc;
574*4882a593Smuzhiyun 	void *buffer, *ptr;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	buffer = diag204_store();
577*4882a593Smuzhiyun 	if (IS_ERR(buffer))
578*4882a593Smuzhiyun 		return PTR_ERR(buffer);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	systems_dir = hypfs_mkdir(root, "systems");
581*4882a593Smuzhiyun 	if (IS_ERR(systems_dir)) {
582*4882a593Smuzhiyun 		rc = PTR_ERR(systems_dir);
583*4882a593Smuzhiyun 		goto err_out;
584*4882a593Smuzhiyun 	}
585*4882a593Smuzhiyun 	time_hdr = (struct x_info_blk_hdr *)buffer;
586*4882a593Smuzhiyun 	part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type);
587*4882a593Smuzhiyun 	for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) {
588*4882a593Smuzhiyun 		part_hdr = hypfs_create_lpar_files(systems_dir, part_hdr);
589*4882a593Smuzhiyun 		if (IS_ERR(part_hdr)) {
590*4882a593Smuzhiyun 			rc = PTR_ERR(part_hdr);
591*4882a593Smuzhiyun 			goto err_out;
592*4882a593Smuzhiyun 		}
593*4882a593Smuzhiyun 	}
594*4882a593Smuzhiyun 	if (info_blk_hdr__flags(diag204_info_type, time_hdr) &
595*4882a593Smuzhiyun 	    DIAG204_LPAR_PHYS_FLG) {
596*4882a593Smuzhiyun 		ptr = hypfs_create_phys_files(root, part_hdr);
597*4882a593Smuzhiyun 		if (IS_ERR(ptr)) {
598*4882a593Smuzhiyun 			rc = PTR_ERR(ptr);
599*4882a593Smuzhiyun 			goto err_out;
600*4882a593Smuzhiyun 		}
601*4882a593Smuzhiyun 	}
602*4882a593Smuzhiyun 	hyp_dir = hypfs_mkdir(root, "hyp");
603*4882a593Smuzhiyun 	if (IS_ERR(hyp_dir)) {
604*4882a593Smuzhiyun 		rc = PTR_ERR(hyp_dir);
605*4882a593Smuzhiyun 		goto err_out;
606*4882a593Smuzhiyun 	}
607*4882a593Smuzhiyun 	ptr = hypfs_create_str(hyp_dir, "type", "LPAR Hypervisor");
608*4882a593Smuzhiyun 	if (IS_ERR(ptr)) {
609*4882a593Smuzhiyun 		rc = PTR_ERR(ptr);
610*4882a593Smuzhiyun 		goto err_out;
611*4882a593Smuzhiyun 	}
612*4882a593Smuzhiyun 	rc = 0;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun err_out:
615*4882a593Smuzhiyun 	return rc;
616*4882a593Smuzhiyun }
617