~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/s390/hypfs/hypfs_diag.c

Version: ~ [ linux-5.11-rc3 ] ~ [ linux-5.10.7 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.89 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.167 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.215 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.251 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.251 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 */
 28 enum 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 */
 36 enum 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 
 44 static char *diag224_cpu_names;                 /* diag 224 name table */
 45 static enum diag204_sc diag204_store_sc;        /* used subcode for store */
 46 static enum diag204_format diag204_info_type;   /* used diag 204 data format */
 47 
 48 static void *diag204_buf;               /* 4K aligned buffer for diag204 data */
 49 static void *diag204_buf_vmalloc;       /* vmalloc pointer for diag204 data */
 50 static int diag204_buf_pages;           /* number of pages for diag204 data */
 51 
 52 static 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 
 64 struct 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 
 73 struct 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 
 84 static 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 
 92 static 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 
100 static 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 
108 static 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 
118 struct part_hdr {
119         __u8 pn;
120         __u8 cpus;
121         char reserved[6];
122         char part_name[LPAR_NAME_LEN];
123 } __attribute__ ((packed));
124 
125 struct 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 
143 static 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 
151 static 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 
159 static 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 
173 struct 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 
183 struct 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 
204 static 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 
212 static 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 
220 static 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 
228 static 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 
236 static 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 
244 static 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 
254 struct phys_hdr {
255         char reserved1[1];
256         __u8 cpus;
257         char reserved2[6];
258         char mgm_name[8];
259 } __attribute__ ((packed));
260 
261 struct 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 
269 static 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 
277 static 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 
287 struct 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 
296 struct 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 
305 static 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 
313 static 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 
321 static 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 
329 static 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 
339 static int diag204(unsigned long subcode, unsigned long size, void *addr)
340 {
341         register unsigned long _subcode asm("") = 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 
361 static 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 
374 static void *page_align_ptr(void *ptr)
375 {
376         return (void *) PAGE_ALIGN((unsigned long) ptr);
377 }
378 
379 static 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 
390 static 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 
399 static 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 
432 static 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         }
470 out:
471         rc = 0;
472 fail_store:
473         diag204_free_buffer();
474 fail_alloc:
475         return rc;
476 }
477 
478 static 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 
487 static 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);
498 out:
499         return buf;
500 }
501 
502 /* Diagnose 224 functions */
503 
504 static 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 
517 static 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 
531 static void diag224_delete_name_table(void)
532 {
533         kfree(diag224_cpu_names);
534 }
535 
536 static 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 
545 struct 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 
552 struct dbfs_d204 {
553         struct dbfs_d204_hdr    hdr;    /* 64 byte header */
554         char                    buf[];  /* d204 buffer */
555 } __attribute__ ((packed));
556 
557 static 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 
582 static 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 
613 void 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 
626 static 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 
656 static 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 
683 static 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 
703 static 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 
723 int 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 
767 err_out:
768         return rc;
769 }
770 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp