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