• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  arch/s390/hypfs/hypfs_diag.c
3  *    Hypervisor filesystem for Linux on s390. Diag 204 and 224
4  *    implementation.
5  *
6  *    Copyright IBM Corp. 2006, 2008
7  *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
8  */
9 
10 #define KMSG_COMPONENT "hypfs"
11 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12 
13 #include <linux/types.h>
14 #include <linux/errno.h>
15 #include <linux/string.h>
16 #include <linux/vmalloc.h>
17 #include <asm/ebcdic.h>
18 #include "hypfs.h"
19 
20 #define LPAR_NAME_LEN 8		/* lpar name len in diag 204 data */
21 #define CPU_NAME_LEN 16		/* type name len of cpus in diag224 name table */
22 #define TMP_SIZE 64		/* size of temporary buffers */
23 
24 /* diag 204 subcodes */
25 enum diag204_sc {
26 	SUBC_STIB4 = 4,
27 	SUBC_RSI = 5,
28 	SUBC_STIB6 = 6,
29 	SUBC_STIB7 = 7
30 };
31 
32 /* The two available diag 204 data formats */
33 enum diag204_format {
34 	INFO_SIMPLE = 0,
35 	INFO_EXT = 0x00010000
36 };
37 
38 /* bit is set in flags, when physical cpu info is included in diag 204 data */
39 #define LPAR_PHYS_FLG  0x80
40 
41 static char *diag224_cpu_names;			/* diag 224 name table */
42 static enum diag204_sc diag204_store_sc;	/* used subcode for store */
43 static enum diag204_format diag204_info_type;	/* used diag 204 data format */
44 
45 static void *diag204_buf;		/* 4K aligned buffer for diag204 data */
46 static void *diag204_buf_vmalloc;	/* vmalloc pointer for diag204 data */
47 static int diag204_buf_pages;		/* number of pages for diag204 data */
48 
49 /*
50  * DIAG 204 data structures and member access functions.
51  *
52  * Since we have two different diag 204 data formats for old and new s390
53  * machines, we do not access the structs directly, but use getter functions for
54  * each struct member instead. This should make the code more readable.
55  */
56 
57 /* Time information block */
58 
59 struct info_blk_hdr {
60 	__u8  npar;
61 	__u8  flags;
62 	__u16 tslice;
63 	__u16 phys_cpus;
64 	__u16 this_part;
65 	__u64 curtod;
66 } __attribute__ ((packed));
67 
68 struct x_info_blk_hdr {
69 	__u8  npar;
70 	__u8  flags;
71 	__u16 tslice;
72 	__u16 phys_cpus;
73 	__u16 this_part;
74 	__u64 curtod1;
75 	__u64 curtod2;
76 	char reserved[40];
77 } __attribute__ ((packed));
78 
info_blk_hdr__size(enum diag204_format type)79 static inline int info_blk_hdr__size(enum diag204_format type)
80 {
81 	if (type == INFO_SIMPLE)
82 		return sizeof(struct info_blk_hdr);
83 	else /* INFO_EXT */
84 		return sizeof(struct x_info_blk_hdr);
85 }
86 
info_blk_hdr__npar(enum diag204_format type,void * hdr)87 static inline __u8 info_blk_hdr__npar(enum diag204_format type, void *hdr)
88 {
89 	if (type == INFO_SIMPLE)
90 		return ((struct info_blk_hdr *)hdr)->npar;
91 	else /* INFO_EXT */
92 		return ((struct x_info_blk_hdr *)hdr)->npar;
93 }
94 
info_blk_hdr__flags(enum diag204_format type,void * hdr)95 static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr)
96 {
97 	if (type == INFO_SIMPLE)
98 		return ((struct info_blk_hdr *)hdr)->flags;
99 	else /* INFO_EXT */
100 		return ((struct x_info_blk_hdr *)hdr)->flags;
101 }
102 
info_blk_hdr__pcpus(enum diag204_format type,void * hdr)103 static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr)
104 {
105 	if (type == INFO_SIMPLE)
106 		return ((struct info_blk_hdr *)hdr)->phys_cpus;
107 	else /* INFO_EXT */
108 		return ((struct x_info_blk_hdr *)hdr)->phys_cpus;
109 }
110 
111 /* Partition header */
112 
113 struct part_hdr {
114 	__u8 pn;
115 	__u8 cpus;
116 	char reserved[6];
117 	char part_name[LPAR_NAME_LEN];
118 } __attribute__ ((packed));
119 
120 struct x_part_hdr {
121 	__u8  pn;
122 	__u8  cpus;
123 	__u8  rcpus;
124 	__u8  pflag;
125 	__u32 mlu;
126 	char  part_name[LPAR_NAME_LEN];
127 	char  lpc_name[8];
128 	char  os_name[8];
129 	__u64 online_cs;
130 	__u64 online_es;
131 	__u8  upid;
132 	char  reserved1[3];
133 	__u32 group_mlu;
134 	char  group_name[8];
135 	char  reserved2[32];
136 } __attribute__ ((packed));
137 
part_hdr__size(enum diag204_format type)138 static inline int part_hdr__size(enum diag204_format type)
139 {
140 	if (type == INFO_SIMPLE)
141 		return sizeof(struct part_hdr);
142 	else /* INFO_EXT */
143 		return sizeof(struct x_part_hdr);
144 }
145 
part_hdr__rcpus(enum diag204_format type,void * hdr)146 static inline __u8 part_hdr__rcpus(enum diag204_format type, void *hdr)
147 {
148 	if (type == INFO_SIMPLE)
149 		return ((struct part_hdr *)hdr)->cpus;
150 	else /* INFO_EXT */
151 		return ((struct x_part_hdr *)hdr)->rcpus;
152 }
153 
part_hdr__part_name(enum diag204_format type,void * hdr,char * name)154 static inline void part_hdr__part_name(enum diag204_format type, void *hdr,
155 				       char *name)
156 {
157 	if (type == INFO_SIMPLE)
158 		memcpy(name, ((struct part_hdr *)hdr)->part_name,
159 		       LPAR_NAME_LEN);
160 	else /* INFO_EXT */
161 		memcpy(name, ((struct x_part_hdr *)hdr)->part_name,
162 		       LPAR_NAME_LEN);
163 	EBCASC(name, LPAR_NAME_LEN);
164 	name[LPAR_NAME_LEN] = 0;
165 	strstrip(name);
166 }
167 
168 struct cpu_info {
169 	__u16 cpu_addr;
170 	char  reserved1[2];
171 	__u8  ctidx;
172 	__u8  cflag;
173 	__u16 weight;
174 	__u64 acc_time;
175 	__u64 lp_time;
176 } __attribute__ ((packed));
177 
178 struct x_cpu_info {
179 	__u16 cpu_addr;
180 	char  reserved1[2];
181 	__u8  ctidx;
182 	__u8  cflag;
183 	__u16 weight;
184 	__u64 acc_time;
185 	__u64 lp_time;
186 	__u16 min_weight;
187 	__u16 cur_weight;
188 	__u16 max_weight;
189 	char  reseved2[2];
190 	__u64 online_time;
191 	__u64 wait_time;
192 	__u32 pma_weight;
193 	__u32 polar_weight;
194 	char  reserved3[40];
195 } __attribute__ ((packed));
196 
197 /* CPU info block */
198 
cpu_info__size(enum diag204_format type)199 static inline int cpu_info__size(enum diag204_format type)
200 {
201 	if (type == INFO_SIMPLE)
202 		return sizeof(struct cpu_info);
203 	else /* INFO_EXT */
204 		return sizeof(struct x_cpu_info);
205 }
206 
cpu_info__ctidx(enum diag204_format type,void * hdr)207 static inline __u8 cpu_info__ctidx(enum diag204_format type, void *hdr)
208 {
209 	if (type == INFO_SIMPLE)
210 		return ((struct cpu_info *)hdr)->ctidx;
211 	else /* INFO_EXT */
212 		return ((struct x_cpu_info *)hdr)->ctidx;
213 }
214 
cpu_info__cpu_addr(enum diag204_format type,void * hdr)215 static inline __u16 cpu_info__cpu_addr(enum diag204_format type, void *hdr)
216 {
217 	if (type == INFO_SIMPLE)
218 		return ((struct cpu_info *)hdr)->cpu_addr;
219 	else /* INFO_EXT */
220 		return ((struct x_cpu_info *)hdr)->cpu_addr;
221 }
222 
cpu_info__acc_time(enum diag204_format type,void * hdr)223 static inline __u64 cpu_info__acc_time(enum diag204_format type, void *hdr)
224 {
225 	if (type == INFO_SIMPLE)
226 		return ((struct cpu_info *)hdr)->acc_time;
227 	else /* INFO_EXT */
228 		return ((struct x_cpu_info *)hdr)->acc_time;
229 }
230 
cpu_info__lp_time(enum diag204_format type,void * hdr)231 static inline __u64 cpu_info__lp_time(enum diag204_format type, void *hdr)
232 {
233 	if (type == INFO_SIMPLE)
234 		return ((struct cpu_info *)hdr)->lp_time;
235 	else /* INFO_EXT */
236 		return ((struct x_cpu_info *)hdr)->lp_time;
237 }
238 
cpu_info__online_time(enum diag204_format type,void * hdr)239 static inline __u64 cpu_info__online_time(enum diag204_format type, void *hdr)
240 {
241 	if (type == INFO_SIMPLE)
242 		return 0;	/* online_time not available in simple info */
243 	else /* INFO_EXT */
244 		return ((struct x_cpu_info *)hdr)->online_time;
245 }
246 
247 /* Physical header */
248 
249 struct phys_hdr {
250 	char reserved1[1];
251 	__u8 cpus;
252 	char reserved2[6];
253 	char mgm_name[8];
254 } __attribute__ ((packed));
255 
256 struct x_phys_hdr {
257 	char reserved1[1];
258 	__u8 cpus;
259 	char reserved2[6];
260 	char mgm_name[8];
261 	char reserved3[80];
262 } __attribute__ ((packed));
263 
phys_hdr__size(enum diag204_format type)264 static inline int phys_hdr__size(enum diag204_format type)
265 {
266 	if (type == INFO_SIMPLE)
267 		return sizeof(struct phys_hdr);
268 	else /* INFO_EXT */
269 		return sizeof(struct x_phys_hdr);
270 }
271 
phys_hdr__cpus(enum diag204_format type,void * hdr)272 static inline __u8 phys_hdr__cpus(enum diag204_format type, void *hdr)
273 {
274 	if (type == INFO_SIMPLE)
275 		return ((struct phys_hdr *)hdr)->cpus;
276 	else /* INFO_EXT */
277 		return ((struct x_phys_hdr *)hdr)->cpus;
278 }
279 
280 /* Physical CPU info block */
281 
282 struct phys_cpu {
283 	__u16 cpu_addr;
284 	char  reserved1[2];
285 	__u8  ctidx;
286 	char  reserved2[3];
287 	__u64 mgm_time;
288 	char  reserved3[8];
289 } __attribute__ ((packed));
290 
291 struct x_phys_cpu {
292 	__u16 cpu_addr;
293 	char  reserved1[2];
294 	__u8  ctidx;
295 	char  reserved2[3];
296 	__u64 mgm_time;
297 	char  reserved3[80];
298 } __attribute__ ((packed));
299 
phys_cpu__size(enum diag204_format type)300 static inline int phys_cpu__size(enum diag204_format type)
301 {
302 	if (type == INFO_SIMPLE)
303 		return sizeof(struct phys_cpu);
304 	else /* INFO_EXT */
305 		return sizeof(struct x_phys_cpu);
306 }
307 
phys_cpu__cpu_addr(enum diag204_format type,void * hdr)308 static inline __u16 phys_cpu__cpu_addr(enum diag204_format type, void *hdr)
309 {
310 	if (type == INFO_SIMPLE)
311 		return ((struct phys_cpu *)hdr)->cpu_addr;
312 	else /* INFO_EXT */
313 		return ((struct x_phys_cpu *)hdr)->cpu_addr;
314 }
315 
phys_cpu__mgm_time(enum diag204_format type,void * hdr)316 static inline __u64 phys_cpu__mgm_time(enum diag204_format type, void *hdr)
317 {
318 	if (type == INFO_SIMPLE)
319 		return ((struct phys_cpu *)hdr)->mgm_time;
320 	else /* INFO_EXT */
321 		return ((struct x_phys_cpu *)hdr)->mgm_time;
322 }
323 
phys_cpu__ctidx(enum diag204_format type,void * hdr)324 static inline __u64 phys_cpu__ctidx(enum diag204_format type, void *hdr)
325 {
326 	if (type == INFO_SIMPLE)
327 		return ((struct phys_cpu *)hdr)->ctidx;
328 	else /* INFO_EXT */
329 		return ((struct x_phys_cpu *)hdr)->ctidx;
330 }
331 
332 /* Diagnose 204 functions */
333 
diag204(unsigned long subcode,unsigned long size,void * addr)334 static int diag204(unsigned long subcode, unsigned long size, void *addr)
335 {
336 	register unsigned long _subcode asm("0") = subcode;
337 	register unsigned long _size asm("1") = size;
338 
339 	asm volatile(
340 		"	diag	%2,%0,0x204\n"
341 		"0:\n"
342 		EX_TABLE(0b,0b)
343 		: "+d" (_subcode), "+d" (_size) : "d" (addr) : "memory");
344 	if (_subcode)
345 		return -1;
346 	return _size;
347 }
348 
349 /*
350  * For the old diag subcode 4 with simple data format we have to use real
351  * memory. If we use subcode 6 or 7 with extended data format, we can (and
352  * should) use vmalloc, since we need a lot of memory in that case. Currently
353  * up to 93 pages!
354  */
355 
diag204_free_buffer(void)356 static void diag204_free_buffer(void)
357 {
358 	if (!diag204_buf)
359 		return;
360 	if (diag204_buf_vmalloc) {
361 		vfree(diag204_buf_vmalloc);
362 		diag204_buf_vmalloc = NULL;
363 	} else {
364 		free_pages((unsigned long) diag204_buf, 0);
365 	}
366 	diag204_buf_pages = 0;
367 	diag204_buf = NULL;
368 }
369 
diag204_alloc_vbuf(int pages)370 static void *diag204_alloc_vbuf(int pages)
371 {
372 	/* The buffer has to be page aligned! */
373 	diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1));
374 	if (!diag204_buf_vmalloc)
375 		return ERR_PTR(-ENOMEM);
376 	diag204_buf = (void*)((unsigned long)diag204_buf_vmalloc
377 				& ~0xfffUL) + 0x1000;
378 	diag204_buf_pages = pages;
379 	return diag204_buf;
380 }
381 
diag204_alloc_rbuf(void)382 static void *diag204_alloc_rbuf(void)
383 {
384 	diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0);
385 	if (!diag204_buf)
386 		return ERR_PTR(-ENOMEM);
387 	diag204_buf_pages = 1;
388 	return diag204_buf;
389 }
390 
diag204_get_buffer(enum diag204_format fmt,int * pages)391 static void *diag204_get_buffer(enum diag204_format fmt, int *pages)
392 {
393 	if (diag204_buf) {
394 		*pages = diag204_buf_pages;
395 		return diag204_buf;
396 	}
397 	if (fmt == INFO_SIMPLE) {
398 		*pages = 1;
399 		return diag204_alloc_rbuf();
400 	} else {/* INFO_EXT */
401 		*pages = diag204((unsigned long)SUBC_RSI |
402 				 (unsigned long)INFO_EXT, 0, NULL);
403 		if (*pages <= 0)
404 			return ERR_PTR(-ENOSYS);
405 		else
406 			return diag204_alloc_vbuf(*pages);
407 	}
408 }
409 
410 /*
411  * diag204_probe() has to find out, which type of diagnose 204 implementation
412  * we have on our machine. Currently there are three possible scanarios:
413  *   - subcode 4   + simple data format (only one page)
414  *   - subcode 4-6 + extended data format
415  *   - subcode 4-7 + extended data format
416  *
417  * Subcode 5 is used to retrieve the size of the data, provided by subcodes
418  * 6 and 7. Subcode 7 basically has the same function as subcode 6. In addition
419  * to subcode 6 it provides also information about secondary cpus.
420  * In order to get as much information as possible, we first try
421  * subcode 7, then 6 and if both fail, we use subcode 4.
422  */
423 
diag204_probe(void)424 static int diag204_probe(void)
425 {
426 	void *buf;
427 	int pages, rc;
428 
429 	buf = diag204_get_buffer(INFO_EXT, &pages);
430 	if (!IS_ERR(buf)) {
431 		if (diag204((unsigned long)SUBC_STIB7 |
432 			    (unsigned long)INFO_EXT, pages, buf) >= 0) {
433 			diag204_store_sc = SUBC_STIB7;
434 			diag204_info_type = INFO_EXT;
435 			goto out;
436 		}
437 		if (diag204((unsigned long)SUBC_STIB6 |
438 			    (unsigned long)INFO_EXT, pages, buf) >= 0) {
439 			diag204_store_sc = SUBC_STIB7;
440 			diag204_info_type = INFO_EXT;
441 			goto out;
442 		}
443 		diag204_free_buffer();
444 	}
445 
446 	/* subcodes 6 and 7 failed, now try subcode 4 */
447 
448 	buf = diag204_get_buffer(INFO_SIMPLE, &pages);
449 	if (IS_ERR(buf)) {
450 		rc = PTR_ERR(buf);
451 		goto fail_alloc;
452 	}
453 	if (diag204((unsigned long)SUBC_STIB4 |
454 		    (unsigned long)INFO_SIMPLE, pages, buf) >= 0) {
455 		diag204_store_sc = SUBC_STIB4;
456 		diag204_info_type = INFO_SIMPLE;
457 		goto out;
458 	} else {
459 		rc = -ENOSYS;
460 		goto fail_store;
461 	}
462 out:
463 	rc = 0;
464 fail_store:
465 	diag204_free_buffer();
466 fail_alloc:
467 	return rc;
468 }
469 
diag204_store(void)470 static void *diag204_store(void)
471 {
472 	void *buf;
473 	int pages;
474 
475 	buf = diag204_get_buffer(diag204_info_type, &pages);
476 	if (IS_ERR(buf))
477 		goto out;
478 	if (diag204((unsigned long)diag204_store_sc |
479 		    (unsigned long)diag204_info_type, pages, buf) < 0)
480 		return ERR_PTR(-ENOSYS);
481 out:
482 	return buf;
483 }
484 
485 /* Diagnose 224 functions */
486 
diag224(void * ptr)487 static int diag224(void *ptr)
488 {
489 	int rc = -ENOTSUPP;
490 
491 	asm volatile(
492 		"	diag	%1,%2,0x224\n"
493 		"0:	lhi	%0,0x0\n"
494 		"1:\n"
495 		EX_TABLE(0b,1b)
496 		: "+d" (rc) :"d" (0), "d" (ptr) : "memory");
497 	return rc;
498 }
499 
diag224_get_name_table(void)500 static int diag224_get_name_table(void)
501 {
502 	/* memory must be below 2GB */
503 	diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
504 	if (!diag224_cpu_names)
505 		return -ENOMEM;
506 	if (diag224(diag224_cpu_names)) {
507 		kfree(diag224_cpu_names);
508 		return -ENOTSUPP;
509 	}
510 	EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16);
511 	return 0;
512 }
513 
diag224_delete_name_table(void)514 static void diag224_delete_name_table(void)
515 {
516 	kfree(diag224_cpu_names);
517 }
518 
diag224_idx2name(int index,char * name)519 static int diag224_idx2name(int index, char *name)
520 {
521 	memcpy(name, diag224_cpu_names + ((index + 1) * CPU_NAME_LEN),
522 		CPU_NAME_LEN);
523 	name[CPU_NAME_LEN] = 0;
524 	strstrip(name);
525 	return 0;
526 }
527 
hypfs_diag_init(void)528 __init int hypfs_diag_init(void)
529 {
530 	int rc;
531 
532 	if (diag204_probe()) {
533 		pr_err("The hardware system does not support hypfs\n");
534 		return -ENODATA;
535 	}
536 	rc = diag224_get_name_table();
537 	if (rc) {
538 		diag204_free_buffer();
539 		pr_err("The hardware system does not provide all "
540 		       "functions required by hypfs\n");
541 	}
542 	return rc;
543 }
544 
hypfs_diag_exit(void)545 void hypfs_diag_exit(void)
546 {
547 	diag224_delete_name_table();
548 	diag204_free_buffer();
549 }
550 
551 /*
552  * Functions to create the directory structure
553  * *******************************************
554  */
555 
hypfs_create_cpu_files(struct super_block * sb,struct dentry * cpus_dir,void * cpu_info)556 static int hypfs_create_cpu_files(struct super_block *sb,
557 				  struct dentry *cpus_dir, void *cpu_info)
558 {
559 	struct dentry *cpu_dir;
560 	char buffer[TMP_SIZE];
561 	void *rc;
562 
563 	snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type,
564 							    cpu_info));
565 	cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer);
566 	rc = hypfs_create_u64(sb, cpu_dir, "mgmtime",
567 			      cpu_info__acc_time(diag204_info_type, cpu_info) -
568 			      cpu_info__lp_time(diag204_info_type, cpu_info));
569 	if (IS_ERR(rc))
570 		return PTR_ERR(rc);
571 	rc = hypfs_create_u64(sb, cpu_dir, "cputime",
572 			      cpu_info__lp_time(diag204_info_type, cpu_info));
573 	if (IS_ERR(rc))
574 		return PTR_ERR(rc);
575 	if (diag204_info_type == INFO_EXT) {
576 		rc = hypfs_create_u64(sb, cpu_dir, "onlinetime",
577 				      cpu_info__online_time(diag204_info_type,
578 							    cpu_info));
579 		if (IS_ERR(rc))
580 			return PTR_ERR(rc);
581 	}
582 	diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer);
583 	rc = hypfs_create_str(sb, cpu_dir, "type", buffer);
584 	if (IS_ERR(rc))
585 		return PTR_ERR(rc);
586 	return 0;
587 }
588 
hypfs_create_lpar_files(struct super_block * sb,struct dentry * systems_dir,void * part_hdr)589 static void *hypfs_create_lpar_files(struct super_block *sb,
590 				     struct dentry *systems_dir, void *part_hdr)
591 {
592 	struct dentry *cpus_dir;
593 	struct dentry *lpar_dir;
594 	char lpar_name[LPAR_NAME_LEN + 1];
595 	void *cpu_info;
596 	int i;
597 
598 	part_hdr__part_name(diag204_info_type, part_hdr, lpar_name);
599 	lpar_name[LPAR_NAME_LEN] = 0;
600 	lpar_dir = hypfs_mkdir(sb, systems_dir, lpar_name);
601 	if (IS_ERR(lpar_dir))
602 		return lpar_dir;
603 	cpus_dir = hypfs_mkdir(sb, lpar_dir, "cpus");
604 	if (IS_ERR(cpus_dir))
605 		return cpus_dir;
606 	cpu_info = part_hdr + part_hdr__size(diag204_info_type);
607 	for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) {
608 		int rc;
609 		rc = hypfs_create_cpu_files(sb, cpus_dir, cpu_info);
610 		if (rc)
611 			return ERR_PTR(rc);
612 		cpu_info += cpu_info__size(diag204_info_type);
613 	}
614 	return cpu_info;
615 }
616 
hypfs_create_phys_cpu_files(struct super_block * sb,struct dentry * cpus_dir,void * cpu_info)617 static int hypfs_create_phys_cpu_files(struct super_block *sb,
618 				       struct dentry *cpus_dir, void *cpu_info)
619 {
620 	struct dentry *cpu_dir;
621 	char buffer[TMP_SIZE];
622 	void *rc;
623 
624 	snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type,
625 							    cpu_info));
626 	cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer);
627 	if (IS_ERR(cpu_dir))
628 		return PTR_ERR(cpu_dir);
629 	rc = hypfs_create_u64(sb, cpu_dir, "mgmtime",
630 			      phys_cpu__mgm_time(diag204_info_type, cpu_info));
631 	if (IS_ERR(rc))
632 		return PTR_ERR(rc);
633 	diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer);
634 	rc = hypfs_create_str(sb, cpu_dir, "type", buffer);
635 	if (IS_ERR(rc))
636 		return PTR_ERR(rc);
637 	return 0;
638 }
639 
hypfs_create_phys_files(struct super_block * sb,struct dentry * parent_dir,void * phys_hdr)640 static void *hypfs_create_phys_files(struct super_block *sb,
641 				     struct dentry *parent_dir, void *phys_hdr)
642 {
643 	int i;
644 	void *cpu_info;
645 	struct dentry *cpus_dir;
646 
647 	cpus_dir = hypfs_mkdir(sb, parent_dir, "cpus");
648 	if (IS_ERR(cpus_dir))
649 		return cpus_dir;
650 	cpu_info = phys_hdr + phys_hdr__size(diag204_info_type);
651 	for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) {
652 		int rc;
653 		rc = hypfs_create_phys_cpu_files(sb, cpus_dir, cpu_info);
654 		if (rc)
655 			return ERR_PTR(rc);
656 		cpu_info += phys_cpu__size(diag204_info_type);
657 	}
658 	return cpu_info;
659 }
660 
hypfs_diag_create_files(struct super_block * sb,struct dentry * root)661 int hypfs_diag_create_files(struct super_block *sb, struct dentry *root)
662 {
663 	struct dentry *systems_dir, *hyp_dir;
664 	void *time_hdr, *part_hdr;
665 	int i, rc;
666 	void *buffer, *ptr;
667 
668 	buffer = diag204_store();
669 	if (IS_ERR(buffer))
670 		return PTR_ERR(buffer);
671 
672 	systems_dir = hypfs_mkdir(sb, root, "systems");
673 	if (IS_ERR(systems_dir)) {
674 		rc = PTR_ERR(systems_dir);
675 		goto err_out;
676 	}
677 	time_hdr = (struct x_info_blk_hdr *)buffer;
678 	part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type);
679 	for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) {
680 		part_hdr = hypfs_create_lpar_files(sb, systems_dir, part_hdr);
681 		if (IS_ERR(part_hdr)) {
682 			rc = PTR_ERR(part_hdr);
683 			goto err_out;
684 		}
685 	}
686 	if (info_blk_hdr__flags(diag204_info_type, time_hdr) & LPAR_PHYS_FLG) {
687 		ptr = hypfs_create_phys_files(sb, root, part_hdr);
688 		if (IS_ERR(ptr)) {
689 			rc = PTR_ERR(ptr);
690 			goto err_out;
691 		}
692 	}
693 	hyp_dir = hypfs_mkdir(sb, root, "hyp");
694 	if (IS_ERR(hyp_dir)) {
695 		rc = PTR_ERR(hyp_dir);
696 		goto err_out;
697 	}
698 	ptr = hypfs_create_str(sb, hyp_dir, "type", "LPAR Hypervisor");
699 	if (IS_ERR(ptr)) {
700 		rc = PTR_ERR(ptr);
701 		goto err_out;
702 	}
703 	rc = 0;
704 
705 err_out:
706 	return rc;
707 }
708