]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/xen/sys-hypervisor.c
Merge remote-tracking branch 'asoc/fix/dapm' into asoc-linus
[karo-tx-linux.git] / drivers / xen / sys-hypervisor.c
1 /*
2  *  copyright (c) 2006 IBM Corporation
3  *  Authored by: Mike D. Day <ncmike@us.ibm.com>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License version 2 as
7  *  published by the Free Software Foundation.
8  */
9
10 #include <linux/slab.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/kobject.h>
14 #include <linux/err.h>
15
16 #include <asm/xen/hypervisor.h>
17 #include <asm/xen/hypercall.h>
18
19 #include <xen/xen.h>
20 #include <xen/xenbus.h>
21 #include <xen/interface/xen.h>
22 #include <xen/interface/version.h>
23 #ifdef CONFIG_XEN_HAVE_VPMU
24 #include <xen/interface/xenpmu.h>
25 #endif
26
27 #define HYPERVISOR_ATTR_RO(_name) \
28 static struct hyp_sysfs_attr  _name##_attr = __ATTR_RO(_name)
29
30 #define HYPERVISOR_ATTR_RW(_name) \
31 static struct hyp_sysfs_attr _name##_attr = \
32         __ATTR(_name, 0644, _name##_show, _name##_store)
33
34 struct hyp_sysfs_attr {
35         struct attribute attr;
36         ssize_t (*show)(struct hyp_sysfs_attr *, char *);
37         ssize_t (*store)(struct hyp_sysfs_attr *, const char *, size_t);
38         void *hyp_attr_data;
39 };
40
41 static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer)
42 {
43         return sprintf(buffer, "xen\n");
44 }
45
46 HYPERVISOR_ATTR_RO(type);
47
48 static int __init xen_sysfs_type_init(void)
49 {
50         return sysfs_create_file(hypervisor_kobj, &type_attr.attr);
51 }
52
53 static void xen_sysfs_type_destroy(void)
54 {
55         sysfs_remove_file(hypervisor_kobj, &type_attr.attr);
56 }
57
58 /* xen version attributes */
59 static ssize_t major_show(struct hyp_sysfs_attr *attr, char *buffer)
60 {
61         int version = HYPERVISOR_xen_version(XENVER_version, NULL);
62         if (version)
63                 return sprintf(buffer, "%d\n", version >> 16);
64         return -ENODEV;
65 }
66
67 HYPERVISOR_ATTR_RO(major);
68
69 static ssize_t minor_show(struct hyp_sysfs_attr *attr, char *buffer)
70 {
71         int version = HYPERVISOR_xen_version(XENVER_version, NULL);
72         if (version)
73                 return sprintf(buffer, "%d\n", version & 0xff);
74         return -ENODEV;
75 }
76
77 HYPERVISOR_ATTR_RO(minor);
78
79 static ssize_t extra_show(struct hyp_sysfs_attr *attr, char *buffer)
80 {
81         int ret = -ENOMEM;
82         char *extra;
83
84         extra = kmalloc(XEN_EXTRAVERSION_LEN, GFP_KERNEL);
85         if (extra) {
86                 ret = HYPERVISOR_xen_version(XENVER_extraversion, extra);
87                 if (!ret)
88                         ret = sprintf(buffer, "%s\n", extra);
89                 kfree(extra);
90         }
91
92         return ret;
93 }
94
95 HYPERVISOR_ATTR_RO(extra);
96
97 static struct attribute *version_attrs[] = {
98         &major_attr.attr,
99         &minor_attr.attr,
100         &extra_attr.attr,
101         NULL
102 };
103
104 static const struct attribute_group version_group = {
105         .name = "version",
106         .attrs = version_attrs,
107 };
108
109 static int __init xen_sysfs_version_init(void)
110 {
111         return sysfs_create_group(hypervisor_kobj, &version_group);
112 }
113
114 static void xen_sysfs_version_destroy(void)
115 {
116         sysfs_remove_group(hypervisor_kobj, &version_group);
117 }
118
119 /* UUID */
120
121 static ssize_t uuid_show_fallback(struct hyp_sysfs_attr *attr, char *buffer)
122 {
123         char *vm, *val;
124         int ret;
125         extern int xenstored_ready;
126
127         if (!xenstored_ready)
128                 return -EBUSY;
129
130         vm = xenbus_read(XBT_NIL, "vm", "", NULL);
131         if (IS_ERR(vm))
132                 return PTR_ERR(vm);
133         val = xenbus_read(XBT_NIL, vm, "uuid", NULL);
134         kfree(vm);
135         if (IS_ERR(val))
136                 return PTR_ERR(val);
137         ret = sprintf(buffer, "%s\n", val);
138         kfree(val);
139         return ret;
140 }
141
142 static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer)
143 {
144         xen_domain_handle_t uuid;
145         int ret;
146         ret = HYPERVISOR_xen_version(XENVER_guest_handle, uuid);
147         if (ret)
148                 return uuid_show_fallback(attr, buffer);
149         ret = sprintf(buffer, "%pU\n", uuid);
150         return ret;
151 }
152
153 HYPERVISOR_ATTR_RO(uuid);
154
155 static int __init xen_sysfs_uuid_init(void)
156 {
157         return sysfs_create_file(hypervisor_kobj, &uuid_attr.attr);
158 }
159
160 static void xen_sysfs_uuid_destroy(void)
161 {
162         sysfs_remove_file(hypervisor_kobj, &uuid_attr.attr);
163 }
164
165 /* xen compilation attributes */
166
167 static ssize_t compiler_show(struct hyp_sysfs_attr *attr, char *buffer)
168 {
169         int ret = -ENOMEM;
170         struct xen_compile_info *info;
171
172         info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
173         if (info) {
174                 ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
175                 if (!ret)
176                         ret = sprintf(buffer, "%s\n", info->compiler);
177                 kfree(info);
178         }
179
180         return ret;
181 }
182
183 HYPERVISOR_ATTR_RO(compiler);
184
185 static ssize_t compiled_by_show(struct hyp_sysfs_attr *attr, char *buffer)
186 {
187         int ret = -ENOMEM;
188         struct xen_compile_info *info;
189
190         info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
191         if (info) {
192                 ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
193                 if (!ret)
194                         ret = sprintf(buffer, "%s\n", info->compile_by);
195                 kfree(info);
196         }
197
198         return ret;
199 }
200
201 HYPERVISOR_ATTR_RO(compiled_by);
202
203 static ssize_t compile_date_show(struct hyp_sysfs_attr *attr, char *buffer)
204 {
205         int ret = -ENOMEM;
206         struct xen_compile_info *info;
207
208         info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
209         if (info) {
210                 ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
211                 if (!ret)
212                         ret = sprintf(buffer, "%s\n", info->compile_date);
213                 kfree(info);
214         }
215
216         return ret;
217 }
218
219 HYPERVISOR_ATTR_RO(compile_date);
220
221 static struct attribute *xen_compile_attrs[] = {
222         &compiler_attr.attr,
223         &compiled_by_attr.attr,
224         &compile_date_attr.attr,
225         NULL
226 };
227
228 static const struct attribute_group xen_compilation_group = {
229         .name = "compilation",
230         .attrs = xen_compile_attrs,
231 };
232
233 static int __init xen_compilation_init(void)
234 {
235         return sysfs_create_group(hypervisor_kobj, &xen_compilation_group);
236 }
237
238 static void xen_compilation_destroy(void)
239 {
240         sysfs_remove_group(hypervisor_kobj, &xen_compilation_group);
241 }
242
243 /* xen properties info */
244
245 static ssize_t capabilities_show(struct hyp_sysfs_attr *attr, char *buffer)
246 {
247         int ret = -ENOMEM;
248         char *caps;
249
250         caps = kmalloc(XEN_CAPABILITIES_INFO_LEN, GFP_KERNEL);
251         if (caps) {
252                 ret = HYPERVISOR_xen_version(XENVER_capabilities, caps);
253                 if (!ret)
254                         ret = sprintf(buffer, "%s\n", caps);
255                 kfree(caps);
256         }
257
258         return ret;
259 }
260
261 HYPERVISOR_ATTR_RO(capabilities);
262
263 static ssize_t changeset_show(struct hyp_sysfs_attr *attr, char *buffer)
264 {
265         int ret = -ENOMEM;
266         char *cset;
267
268         cset = kmalloc(XEN_CHANGESET_INFO_LEN, GFP_KERNEL);
269         if (cset) {
270                 ret = HYPERVISOR_xen_version(XENVER_changeset, cset);
271                 if (!ret)
272                         ret = sprintf(buffer, "%s\n", cset);
273                 kfree(cset);
274         }
275
276         return ret;
277 }
278
279 HYPERVISOR_ATTR_RO(changeset);
280
281 static ssize_t virtual_start_show(struct hyp_sysfs_attr *attr, char *buffer)
282 {
283         int ret = -ENOMEM;
284         struct xen_platform_parameters *parms;
285
286         parms = kmalloc(sizeof(struct xen_platform_parameters), GFP_KERNEL);
287         if (parms) {
288                 ret = HYPERVISOR_xen_version(XENVER_platform_parameters,
289                                              parms);
290                 if (!ret)
291                         ret = sprintf(buffer, "%"PRI_xen_ulong"\n",
292                                       parms->virt_start);
293                 kfree(parms);
294         }
295
296         return ret;
297 }
298
299 HYPERVISOR_ATTR_RO(virtual_start);
300
301 static ssize_t pagesize_show(struct hyp_sysfs_attr *attr, char *buffer)
302 {
303         int ret;
304
305         ret = HYPERVISOR_xen_version(XENVER_pagesize, NULL);
306         if (ret > 0)
307                 ret = sprintf(buffer, "%x\n", ret);
308
309         return ret;
310 }
311
312 HYPERVISOR_ATTR_RO(pagesize);
313
314 static ssize_t xen_feature_show(int index, char *buffer)
315 {
316         ssize_t ret;
317         struct xen_feature_info info;
318
319         info.submap_idx = index;
320         ret = HYPERVISOR_xen_version(XENVER_get_features, &info);
321         if (!ret)
322                 ret = sprintf(buffer, "%08x", info.submap);
323
324         return ret;
325 }
326
327 static ssize_t features_show(struct hyp_sysfs_attr *attr, char *buffer)
328 {
329         ssize_t len;
330         int i;
331
332         len = 0;
333         for (i = XENFEAT_NR_SUBMAPS-1; i >= 0; i--) {
334                 int ret = xen_feature_show(i, buffer + len);
335                 if (ret < 0) {
336                         if (len == 0)
337                                 len = ret;
338                         break;
339                 }
340                 len += ret;
341         }
342         if (len > 0)
343                 buffer[len++] = '\n';
344
345         return len;
346 }
347
348 HYPERVISOR_ATTR_RO(features);
349
350 static struct attribute *xen_properties_attrs[] = {
351         &capabilities_attr.attr,
352         &changeset_attr.attr,
353         &virtual_start_attr.attr,
354         &pagesize_attr.attr,
355         &features_attr.attr,
356         NULL
357 };
358
359 static const struct attribute_group xen_properties_group = {
360         .name = "properties",
361         .attrs = xen_properties_attrs,
362 };
363
364 static int __init xen_properties_init(void)
365 {
366         return sysfs_create_group(hypervisor_kobj, &xen_properties_group);
367 }
368
369 static void xen_properties_destroy(void)
370 {
371         sysfs_remove_group(hypervisor_kobj, &xen_properties_group);
372 }
373
374 #ifdef CONFIG_XEN_HAVE_VPMU
375 struct pmu_mode {
376         const char *name;
377         uint32_t mode;
378 };
379
380 static struct pmu_mode pmu_modes[] = {
381         {"off", XENPMU_MODE_OFF},
382         {"self", XENPMU_MODE_SELF},
383         {"hv", XENPMU_MODE_HV},
384         {"all", XENPMU_MODE_ALL}
385 };
386
387 static ssize_t pmu_mode_store(struct hyp_sysfs_attr *attr,
388                               const char *buffer, size_t len)
389 {
390         int ret;
391         struct xen_pmu_params xp;
392         int i;
393
394         for (i = 0; i < ARRAY_SIZE(pmu_modes); i++) {
395                 if (strncmp(buffer, pmu_modes[i].name, len - 1) == 0) {
396                         xp.val = pmu_modes[i].mode;
397                         break;
398                 }
399         }
400
401         if (i == ARRAY_SIZE(pmu_modes))
402                 return -EINVAL;
403
404         xp.version.maj = XENPMU_VER_MAJ;
405         xp.version.min = XENPMU_VER_MIN;
406         ret = HYPERVISOR_xenpmu_op(XENPMU_mode_set, &xp);
407         if (ret)
408                 return ret;
409
410         return len;
411 }
412
413 static ssize_t pmu_mode_show(struct hyp_sysfs_attr *attr, char *buffer)
414 {
415         int ret;
416         struct xen_pmu_params xp;
417         int i;
418         uint32_t mode;
419
420         xp.version.maj = XENPMU_VER_MAJ;
421         xp.version.min = XENPMU_VER_MIN;
422         ret = HYPERVISOR_xenpmu_op(XENPMU_mode_get, &xp);
423         if (ret)
424                 return ret;
425
426         mode = (uint32_t)xp.val;
427         for (i = 0; i < ARRAY_SIZE(pmu_modes); i++) {
428                 if (mode == pmu_modes[i].mode)
429                         return sprintf(buffer, "%s\n", pmu_modes[i].name);
430         }
431
432         return -EINVAL;
433 }
434 HYPERVISOR_ATTR_RW(pmu_mode);
435
436 static ssize_t pmu_features_store(struct hyp_sysfs_attr *attr,
437                                   const char *buffer, size_t len)
438 {
439         int ret;
440         uint32_t features;
441         struct xen_pmu_params xp;
442
443         ret = kstrtou32(buffer, 0, &features);
444         if (ret)
445                 return ret;
446
447         xp.val = features;
448         xp.version.maj = XENPMU_VER_MAJ;
449         xp.version.min = XENPMU_VER_MIN;
450         ret = HYPERVISOR_xenpmu_op(XENPMU_feature_set, &xp);
451         if (ret)
452                 return ret;
453
454         return len;
455 }
456
457 static ssize_t pmu_features_show(struct hyp_sysfs_attr *attr, char *buffer)
458 {
459         int ret;
460         struct xen_pmu_params xp;
461
462         xp.version.maj = XENPMU_VER_MAJ;
463         xp.version.min = XENPMU_VER_MIN;
464         ret = HYPERVISOR_xenpmu_op(XENPMU_feature_get, &xp);
465         if (ret)
466                 return ret;
467
468         return sprintf(buffer, "0x%x\n", (uint32_t)xp.val);
469 }
470 HYPERVISOR_ATTR_RW(pmu_features);
471
472 static struct attribute *xen_pmu_attrs[] = {
473         &pmu_mode_attr.attr,
474         &pmu_features_attr.attr,
475         NULL
476 };
477
478 static const struct attribute_group xen_pmu_group = {
479         .name = "pmu",
480         .attrs = xen_pmu_attrs,
481 };
482
483 static int __init xen_pmu_init(void)
484 {
485         return sysfs_create_group(hypervisor_kobj, &xen_pmu_group);
486 }
487
488 static void xen_pmu_destroy(void)
489 {
490         sysfs_remove_group(hypervisor_kobj, &xen_pmu_group);
491 }
492 #endif
493
494 static int __init hyper_sysfs_init(void)
495 {
496         int ret;
497
498         if (!xen_domain())
499                 return -ENODEV;
500
501         ret = xen_sysfs_type_init();
502         if (ret)
503                 goto out;
504         ret = xen_sysfs_version_init();
505         if (ret)
506                 goto version_out;
507         ret = xen_compilation_init();
508         if (ret)
509                 goto comp_out;
510         ret = xen_sysfs_uuid_init();
511         if (ret)
512                 goto uuid_out;
513         ret = xen_properties_init();
514         if (ret)
515                 goto prop_out;
516 #ifdef CONFIG_XEN_HAVE_VPMU
517         if (xen_initial_domain()) {
518                 ret = xen_pmu_init();
519                 if (ret) {
520                         xen_properties_destroy();
521                         goto prop_out;
522                 }
523         }
524 #endif
525         goto out;
526
527 prop_out:
528         xen_sysfs_uuid_destroy();
529 uuid_out:
530         xen_compilation_destroy();
531 comp_out:
532         xen_sysfs_version_destroy();
533 version_out:
534         xen_sysfs_type_destroy();
535 out:
536         return ret;
537 }
538
539 static void __exit hyper_sysfs_exit(void)
540 {
541 #ifdef CONFIG_XEN_HAVE_VPMU
542         xen_pmu_destroy();
543 #endif
544         xen_properties_destroy();
545         xen_compilation_destroy();
546         xen_sysfs_uuid_destroy();
547         xen_sysfs_version_destroy();
548         xen_sysfs_type_destroy();
549
550 }
551 module_init(hyper_sysfs_init);
552 module_exit(hyper_sysfs_exit);
553
554 static ssize_t hyp_sysfs_show(struct kobject *kobj,
555                               struct attribute *attr,
556                               char *buffer)
557 {
558         struct hyp_sysfs_attr *hyp_attr;
559         hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
560         if (hyp_attr->show)
561                 return hyp_attr->show(hyp_attr, buffer);
562         return 0;
563 }
564
565 static ssize_t hyp_sysfs_store(struct kobject *kobj,
566                                struct attribute *attr,
567                                const char *buffer,
568                                size_t len)
569 {
570         struct hyp_sysfs_attr *hyp_attr;
571         hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
572         if (hyp_attr->store)
573                 return hyp_attr->store(hyp_attr, buffer, len);
574         return 0;
575 }
576
577 static const struct sysfs_ops hyp_sysfs_ops = {
578         .show = hyp_sysfs_show,
579         .store = hyp_sysfs_store,
580 };
581
582 static struct kobj_type hyp_sysfs_kobj_type = {
583         .sysfs_ops = &hyp_sysfs_ops,
584 };
585
586 static int __init hypervisor_subsys_init(void)
587 {
588         if (!xen_domain())
589                 return -ENODEV;
590
591         hypervisor_kobj->ktype = &hyp_sysfs_kobj_type;
592         return 0;
593 }
594 device_initcall(hypervisor_subsys_init);