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