Merge branch 'core/rodata' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux...
[linux-2.6] / arch / s390 / hypfs / hypfs_vm.c
1 /*
2  *    Hypervisor filesystem for Linux on s390. z/VM implementation.
3  *
4  *    Copyright (C) IBM Corp. 2006
5  *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
6  */
7
8 #include <linux/types.h>
9 #include <linux/errno.h>
10 #include <linux/string.h>
11 #include <linux/vmalloc.h>
12 #include <asm/ebcdic.h>
13 #include "hypfs.h"
14
15 #define NAME_LEN 8
16
17 static char local_guest[] = "        ";
18 static char all_guests[] = "*       ";
19 static char *guest_query;
20
21 struct diag2fc_data {
22         __u32 version;
23         __u32 flags;
24         __u64 used_cpu;
25         __u64 el_time;
26         __u64 mem_min_kb;
27         __u64 mem_max_kb;
28         __u64 mem_share_kb;
29         __u64 mem_used_kb;
30         __u32 pcpus;
31         __u32 lcpus;
32         __u32 vcpus;
33         __u32 cpu_min;
34         __u32 cpu_max;
35         __u32 cpu_shares;
36         __u32 cpu_use_samp;
37         __u32 cpu_delay_samp;
38         __u32 page_wait_samp;
39         __u32 idle_samp;
40         __u32 other_samp;
41         __u32 total_samp;
42         char  guest_name[NAME_LEN];
43 };
44
45 struct diag2fc_parm_list {
46         char userid[NAME_LEN];
47         char aci_grp[NAME_LEN];
48         __u64 addr;
49         __u32 size;
50         __u32 fmt;
51 };
52
53 static int diag2fc(int size, char* query, void *addr)
54 {
55         unsigned long residual_cnt;
56         unsigned long rc;
57         struct diag2fc_parm_list parm_list;
58
59         memcpy(parm_list.userid, query, NAME_LEN);
60         ASCEBC(parm_list.userid, NAME_LEN);
61         parm_list.addr = (unsigned long) addr ;
62         parm_list.size = size;
63         parm_list.fmt = 0x02;
64         memset(parm_list.aci_grp, 0x40, NAME_LEN);
65         rc = -1;
66
67         asm volatile(
68                 "       diag    %0,%1,0x2fc\n"
69                 "0:\n"
70                 EX_TABLE(0b,0b)
71                 : "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
72
73         if ((rc != 0 ) && (rc != -2))
74                 return rc;
75         else
76                 return -residual_cnt;
77 }
78
79 static struct diag2fc_data *diag2fc_store(char *query, int *count)
80 {
81         int size;
82         struct diag2fc_data *data;
83
84         do {
85                 size = diag2fc(0, query, NULL);
86                 if (size < 0)
87                         return ERR_PTR(-EACCES);
88                 data = vmalloc(size);
89                 if (!data)
90                         return ERR_PTR(-ENOMEM);
91                 if (diag2fc(size, query, data) == 0)
92                         break;
93                 vfree(data);
94         } while (1);
95         *count = (size / sizeof(*data));
96
97         return data;
98 }
99
100 static void diag2fc_free(void *data)
101 {
102         vfree(data);
103 }
104
105 #define ATTRIBUTE(sb, dir, name, member) \
106 do { \
107         void *rc; \
108         rc = hypfs_create_u64(sb, dir, name, member); \
109         if (IS_ERR(rc)) \
110                 return PTR_ERR(rc); \
111 } while(0)
112
113 static int hpyfs_vm_create_guest(struct super_block *sb,
114                                  struct dentry *systems_dir,
115                                  struct diag2fc_data *data)
116 {
117         char guest_name[NAME_LEN + 1] = {};
118         struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
119         int dedicated_flag, capped_value;
120
121         capped_value = (data->flags & 0x00000006) >> 1;
122         dedicated_flag = (data->flags & 0x00000008) >> 3;
123
124         /* guest dir */
125         memcpy(guest_name, data->guest_name, NAME_LEN);
126         EBCASC(guest_name, NAME_LEN);
127         strstrip(guest_name);
128         guest_dir = hypfs_mkdir(sb, systems_dir, guest_name);
129         if (IS_ERR(guest_dir))
130                 return PTR_ERR(guest_dir);
131         ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time);
132
133         /* logical cpu information */
134         cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus");
135         if (IS_ERR(cpus_dir))
136                 return PTR_ERR(cpus_dir);
137         ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu);
138         ATTRIBUTE(sb, cpus_dir, "capped", capped_value);
139         ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag);
140         ATTRIBUTE(sb, cpus_dir, "count", data->vcpus);
141         ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min);
142         ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max);
143         ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares);
144
145         /* memory information */
146         mem_dir = hypfs_mkdir(sb, guest_dir, "mem");
147         if (IS_ERR(mem_dir))
148                 return PTR_ERR(mem_dir);
149         ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb);
150         ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb);
151         ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb);
152         ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb);
153
154         /* samples */
155         samples_dir = hypfs_mkdir(sb, guest_dir, "samples");
156         if (IS_ERR(samples_dir))
157                 return PTR_ERR(samples_dir);
158         ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp);
159         ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp);
160         ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp);
161         ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp);
162         ATTRIBUTE(sb, samples_dir, "other", data->other_samp);
163         ATTRIBUTE(sb, samples_dir, "total", data->total_samp);
164         return 0;
165 }
166
167 int hypfs_vm_create_files(struct super_block *sb, struct dentry *root)
168 {
169         struct dentry *dir, *file;
170         struct diag2fc_data *data;
171         int rc, i, count = 0;
172
173         data = diag2fc_store(guest_query, &count);
174         if (IS_ERR(data))
175                 return PTR_ERR(data);
176
177         /* Hpervisor Info */
178         dir = hypfs_mkdir(sb, root, "hyp");
179         if (IS_ERR(dir)) {
180                 rc = PTR_ERR(dir);
181                 goto failed;
182         }
183         file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor");
184         if (IS_ERR(file)) {
185                 rc = PTR_ERR(file);
186                 goto failed;
187         }
188
189         /* physical cpus */
190         dir = hypfs_mkdir(sb, root, "cpus");
191         if (IS_ERR(dir)) {
192                 rc = PTR_ERR(dir);
193                 goto failed;
194         }
195         file = hypfs_create_u64(sb, dir, "count", data->lcpus);
196         if (IS_ERR(file)) {
197                 rc = PTR_ERR(file);
198                 goto failed;
199         }
200
201         /* guests */
202         dir = hypfs_mkdir(sb, root, "systems");
203         if (IS_ERR(dir)) {
204                 rc = PTR_ERR(dir);
205                 goto failed;
206         }
207
208         for (i = 0; i < count; i++) {
209                 rc = hpyfs_vm_create_guest(sb, dir, &(data[i]));
210                 if (rc)
211                         goto failed;
212         }
213         diag2fc_free(data);
214         return 0;
215
216 failed:
217         diag2fc_free(data);
218         return rc;
219 }
220
221 int hypfs_vm_init(void)
222 {
223         if (diag2fc(0, all_guests, NULL) > 0)
224                 guest_query = all_guests;
225         else if (diag2fc(0, local_guest, NULL) > 0)
226                 guest_query = local_guest;
227         else
228                 return -EACCES;
229
230         return 0;
231 }