aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@linux.vnet.ibm.com>2015-02-09 08:49:10 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2015-02-10 10:38:58 -0500
commit34c0dad752294f373a0720840f59e186788ba227 (patch)
tree4d9da02c1edf8c5b4cf57016164747bfabd6faee
parent45cce4ccafe3cddc924ef5221d22b9853fc9a13c (diff)
s390/hypfs: Add diagnose 0c support
With this feature, you can read the CPU performance metrics provided by the z/VM diagnose 0C. This then allows to get the management time for each online CPU of the guest where the diagnose is executed. The new debugfs file /sys/kernel/debug/s390_hypfs/diag_0c exports the diag0C binary data to user space via an open/read/close interface. The binary data consists out of a header structure followed by an array that contains the diagnose 0c data for each online CPU. Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/hypfs/Makefile1
-rw-r--r--arch/s390/hypfs/hypfs.h4
-rw-r--r--arch/s390/hypfs/hypfs_diag0c.c139
-rw-r--r--arch/s390/hypfs/inode.c9
-rw-r--r--arch/s390/include/uapi/asm/hypfs.h35
5 files changed, 184 insertions, 4 deletions
diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile
index 06f8d95a16cd..2ee25ba252d6 100644
--- a/arch/s390/hypfs/Makefile
+++ b/arch/s390/hypfs/Makefile
@@ -5,3 +5,4 @@
5obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o 5obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
6 6
7s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o 7s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o
8s390_hypfs-objs += hypfs_diag0c.o
diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h
index b34b5ab90a31..36d093fa9fb3 100644
--- a/arch/s390/hypfs/hypfs.h
+++ b/arch/s390/hypfs/hypfs.h
@@ -37,6 +37,10 @@ extern int hypfs_vm_init(void);
37extern void hypfs_vm_exit(void); 37extern void hypfs_vm_exit(void);
38extern int hypfs_vm_create_files(struct dentry *root); 38extern int hypfs_vm_create_files(struct dentry *root);
39 39
40/* VM diagnose 0c */
41int hypfs_diag0c_init(void);
42void hypfs_diag0c_exit(void);
43
40/* Set Partition-Resource Parameter */ 44/* Set Partition-Resource Parameter */
41int hypfs_sprp_init(void); 45int hypfs_sprp_init(void);
42void hypfs_sprp_exit(void); 46void hypfs_sprp_exit(void);
diff --git a/arch/s390/hypfs/hypfs_diag0c.c b/arch/s390/hypfs/hypfs_diag0c.c
new file mode 100644
index 000000000000..d4c0d3717543
--- /dev/null
+++ b/arch/s390/hypfs/hypfs_diag0c.c
@@ -0,0 +1,139 @@
1/*
2 * Hypervisor filesystem for Linux on s390
3 *
4 * Diag 0C implementation
5 *
6 * Copyright IBM Corp. 2014
7 */
8
9#include <linux/slab.h>
10#include <linux/cpu.h>
11#include <asm/hypfs.h>
12#include "hypfs.h"
13
14#define DBFS_D0C_HDR_VERSION 0
15
16/*
17 * Execute diagnose 0c in 31 bit mode
18 */
19static void diag0c(struct hypfs_diag0c_entry *entry)
20{
21 asm volatile (
22#ifdef CONFIG_64BIT
23 " sam31\n"
24 " diag %0,%0,0x0c\n"
25 " sam64\n"
26#else
27 " diag %0,%0,0x0c\n"
28#endif
29 : /* no output register */
30 : "a" (entry)
31 : "memory");
32}
33
34/*
35 * Get hypfs_diag0c_entry from CPU vector and store diag0c data
36 */
37static void diag0c_fn(void *data)
38{
39 diag0c(((void **) data)[smp_processor_id()]);
40}
41
42/*
43 * Allocate buffer and store diag 0c data
44 */
45static void *diag0c_store(unsigned int *count)
46{
47 struct hypfs_diag0c_data *diag0c_data;
48 unsigned int cpu_count, cpu, i;
49 void **cpu_vec;
50
51 get_online_cpus();
52 cpu_count = num_online_cpus();
53 cpu_vec = kmalloc(sizeof(*cpu_vec) * num_possible_cpus(), GFP_KERNEL);
54 if (!cpu_vec)
55 goto fail_put_online_cpus;
56 /* Note: Diag 0c needs 8 byte alignment and real storage */
57 diag0c_data = kzalloc(sizeof(struct hypfs_diag0c_hdr) +
58 cpu_count * sizeof(struct hypfs_diag0c_entry),
59 GFP_KERNEL | GFP_DMA);
60 if (!diag0c_data)
61 goto fail_kfree_cpu_vec;
62 i = 0;
63 /* Fill CPU vector for each online CPU */
64 for_each_online_cpu(cpu) {
65 diag0c_data->entry[i].cpu = cpu;
66 cpu_vec[cpu] = &diag0c_data->entry[i++];
67 }
68 /* Collect data all CPUs */
69 on_each_cpu(diag0c_fn, cpu_vec, 1);
70 *count = cpu_count;
71 kfree(cpu_vec);
72 put_online_cpus();
73 return diag0c_data;
74
75fail_kfree_cpu_vec:
76 kfree(cpu_vec);
77fail_put_online_cpus:
78 put_online_cpus();
79 return ERR_PTR(-ENOMEM);
80}
81
82/*
83 * Hypfs DBFS callback: Free diag 0c data
84 */
85static void dbfs_diag0c_free(const void *data)
86{
87 kfree(data);
88}
89
90/*
91 * Hypfs DBFS callback: Create diag 0c data
92 */
93static int dbfs_diag0c_create(void **data, void **data_free_ptr, size_t *size)
94{
95 struct hypfs_diag0c_data *diag0c_data;
96 unsigned int count;
97
98 diag0c_data = diag0c_store(&count);
99 if (IS_ERR(diag0c_data))
100 return PTR_ERR(diag0c_data);
101 memset(&diag0c_data->hdr, 0, sizeof(diag0c_data->hdr));
102 get_tod_clock_ext(diag0c_data->hdr.tod_ext);
103 diag0c_data->hdr.len = count * sizeof(struct hypfs_diag0c_entry);
104 diag0c_data->hdr.version = DBFS_D0C_HDR_VERSION;
105 diag0c_data->hdr.count = count;
106 *data = diag0c_data;
107 *data_free_ptr = diag0c_data;
108 *size = diag0c_data->hdr.len + sizeof(struct hypfs_diag0c_hdr);
109 return 0;
110}
111
112/*
113 * Hypfs DBFS file structure
114 */
115static struct hypfs_dbfs_file dbfs_file_0c = {
116 .name = "diag_0c",
117 .data_create = dbfs_diag0c_create,
118 .data_free = dbfs_diag0c_free,
119};
120
121/*
122 * Initialize diag 0c interface for z/VM
123 */
124int __init hypfs_diag0c_init(void)
125{
126 if (!MACHINE_IS_VM)
127 return 0;
128 return hypfs_dbfs_create_file(&dbfs_file_0c);
129}
130
131/*
132 * Shutdown diag 0c interface for z/VM
133 */
134void hypfs_diag0c_exit(void)
135{
136 if (!MACHINE_IS_VM)
137 return;
138 hypfs_dbfs_remove_file(&dbfs_file_0c);
139}
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index c952b981e4f2..4c8008dd938e 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -482,10 +482,14 @@ static int __init hypfs_init(void)
482 rc = -ENODATA; 482 rc = -ENODATA;
483 goto fail_hypfs_vm_exit; 483 goto fail_hypfs_vm_exit;
484 } 484 }
485 if (hypfs_diag0c_init()) {
486 rc = -ENODATA;
487 goto fail_hypfs_sprp_exit;
488 }
485 s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); 489 s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
486 if (!s390_kobj) { 490 if (!s390_kobj) {
487 rc = -ENOMEM; 491 rc = -ENOMEM;
488 goto fail_hypfs_sprp_exit; 492 goto fail_hypfs_diag0c_exit;
489 } 493 }
490 rc = register_filesystem(&hypfs_type); 494 rc = register_filesystem(&hypfs_type);
491 if (rc) 495 if (rc)
@@ -494,6 +498,8 @@ static int __init hypfs_init(void)
494 498
495fail_filesystem: 499fail_filesystem:
496 kobject_put(s390_kobj); 500 kobject_put(s390_kobj);
501fail_hypfs_diag0c_exit:
502 hypfs_diag0c_exit();
497fail_hypfs_sprp_exit: 503fail_hypfs_sprp_exit:
498 hypfs_sprp_exit(); 504 hypfs_sprp_exit();
499fail_hypfs_vm_exit: 505fail_hypfs_vm_exit:
@@ -510,6 +516,7 @@ static void __exit hypfs_exit(void)
510{ 516{
511 unregister_filesystem(&hypfs_type); 517 unregister_filesystem(&hypfs_type);
512 kobject_put(s390_kobj); 518 kobject_put(s390_kobj);
519 hypfs_diag0c_exit();
513 hypfs_sprp_exit(); 520 hypfs_sprp_exit();
514 hypfs_vm_exit(); 521 hypfs_vm_exit();
515 hypfs_diag_exit(); 522 hypfs_diag_exit();
diff --git a/arch/s390/include/uapi/asm/hypfs.h b/arch/s390/include/uapi/asm/hypfs.h
index 37998b449531..b3fe12d8dd87 100644
--- a/arch/s390/include/uapi/asm/hypfs.h
+++ b/arch/s390/include/uapi/asm/hypfs.h
@@ -1,16 +1,19 @@
1/* 1/*
2 * IOCTL interface for hypfs 2 * Structures for hypfs interface
3 * 3 *
4 * Copyright IBM Corp. 2013 4 * Copyright IBM Corp. 2013
5 * 5 *
6 * Author: Martin Schwidefsky <schwidefsky@de.ibm.com> 6 * Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
7 */ 7 */
8 8
9#ifndef _ASM_HYPFS_CTL_H 9#ifndef _ASM_HYPFS_H
10#define _ASM_HYPFS_CTL_H 10#define _ASM_HYPFS_H
11 11
12#include <linux/types.h> 12#include <linux/types.h>
13 13
14/*
15 * IOCTL for binary interface /sys/kernel/debug/diag_304
16 */
14struct hypfs_diag304 { 17struct hypfs_diag304 {
15 __u32 args[2]; 18 __u32 args[2];
16 __u64 data; 19 __u64 data;
@@ -22,4 +25,30 @@ struct hypfs_diag304 {
22#define HYPFS_DIAG304 \ 25#define HYPFS_DIAG304 \
23 _IOWR(HYPFS_IOCTL_MAGIC, 0x20, struct hypfs_diag304) 26 _IOWR(HYPFS_IOCTL_MAGIC, 0x20, struct hypfs_diag304)
24 27
28/*
29 * Structures for binary interface /sys/kernel/debug/diag_0c
30 */
31struct hypfs_diag0c_hdr {
32 __u64 len; /* Length of diag0c buffer without header */
33 __u16 version; /* Version of header */
34 char reserved1[6]; /* Reserved */
35 char tod_ext[16]; /* TOD clock for diag0c */
36 __u64 count; /* Number of entries (CPUs) in diag0c array */
37 char reserved2[24]; /* Reserved */
38};
39
40struct hypfs_diag0c_entry {
41 char date[8]; /* MM/DD/YY in EBCDIC */
42 char time[8]; /* HH:MM:SS in EBCDIC */
43 __u64 virtcpu; /* Virtual time consumed by the virt CPU (us) */
44 __u64 totalproc; /* Total of virtual and simulation time (us) */
45 __u32 cpu; /* Linux logical CPU number */
46 __u32 reserved; /* Align to 8 byte */
47};
48
49struct hypfs_diag0c_data {
50 struct hypfs_diag0c_hdr hdr; /* 64 byte header */
51 struct hypfs_diag0c_entry entry[]; /* diag0c entry array */
52};
53
25#endif 54#endif