aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2014-01-24 03:18:52 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2014-01-24 03:40:59 -0500
commit07be0382097027cde68d9268cc628741069b5762 (patch)
treefee25ed4434d1d3d1d670b53065864ccc12c0d18
parentfded4329da9e8486b434d6c4aceab1ab3f433d8a (diff)
s390/hypfs: add interface for diagnose 0x304
To provide access to the set-partition-resource-parameter interface to user space add a new attribute to hypfs/debugfs: * s390_hypsfs/diag_304 The data for the query-partition-resource-parameters command can be access by a read on the attribute. All other diagnose 0x304 requests need to be submitted via ioctl with CAP_SYS_ADMIN rights. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--Documentation/ioctl/ioctl-number.txt1
-rw-r--r--arch/s390/hypfs/Makefile2
-rw-r--r--arch/s390/hypfs/hypfs.h7
-rw-r--r--arch/s390/hypfs/hypfs_dbfs.c16
-rw-r--r--arch/s390/hypfs/hypfs_sprp.c141
-rw-r--r--arch/s390/hypfs/inode.c15
-rw-r--r--arch/s390/include/asm/sclp.h1
-rw-r--r--arch/s390/include/uapi/asm/hypfs.h25
-rw-r--r--drivers/s390/char/sclp_cmd.c5
9 files changed, 208 insertions, 5 deletions
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 7cbfa3c4fc3d..d7e43fa88575 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -73,6 +73,7 @@ Code Seq#(hex) Include File Comments
730x09 all linux/raid/md_u.h 730x09 all linux/raid/md_u.h
740x10 00-0F drivers/char/s390/vmcp.h 740x10 00-0F drivers/char/s390/vmcp.h
750x10 10-1F arch/s390/include/uapi/sclp_ctl.h 750x10 10-1F arch/s390/include/uapi/sclp_ctl.h
760x10 20-2F arch/s390/include/uapi/asm/hypfs.h
760x12 all linux/fs.h 770x12 all linux/fs.h
77 linux/blkpg.h 78 linux/blkpg.h
780x1b all InfiniBand Subsystem <http://infiniband.sourceforge.net/> 790x1b all InfiniBand Subsystem <http://infiniband.sourceforge.net/>
diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile
index 2e671d5004ca..06f8d95a16cd 100644
--- a/arch/s390/hypfs/Makefile
+++ b/arch/s390/hypfs/Makefile
@@ -4,4 +4,4 @@
4 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 7s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o
diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h
index 79f2ac55253f..b34b5ab90a31 100644
--- a/arch/s390/hypfs/hypfs.h
+++ b/arch/s390/hypfs/hypfs.h
@@ -13,6 +13,7 @@
13#include <linux/debugfs.h> 13#include <linux/debugfs.h>
14#include <linux/workqueue.h> 14#include <linux/workqueue.h>
15#include <linux/kref.h> 15#include <linux/kref.h>
16#include <asm/hypfs.h>
16 17
17#define REG_FILE_MODE 0440 18#define REG_FILE_MODE 0440
18#define UPDATE_FILE_MODE 0220 19#define UPDATE_FILE_MODE 0220
@@ -36,6 +37,10 @@ extern int hypfs_vm_init(void);
36extern void hypfs_vm_exit(void); 37extern void hypfs_vm_exit(void);
37extern int hypfs_vm_create_files(struct dentry *root); 38extern int hypfs_vm_create_files(struct dentry *root);
38 39
40/* Set Partition-Resource Parameter */
41int hypfs_sprp_init(void);
42void hypfs_sprp_exit(void);
43
39/* debugfs interface */ 44/* debugfs interface */
40struct hypfs_dbfs_file; 45struct hypfs_dbfs_file;
41 46
@@ -52,6 +57,8 @@ struct hypfs_dbfs_file {
52 int (*data_create)(void **data, void **data_free_ptr, 57 int (*data_create)(void **data, void **data_free_ptr,
53 size_t *size); 58 size_t *size);
54 void (*data_free)(const void *buf_free_ptr); 59 void (*data_free)(const void *buf_free_ptr);
60 long (*unlocked_ioctl) (struct file *, unsigned int,
61 unsigned long);
55 62
56 /* Private data for hypfs_dbfs.c */ 63 /* Private data for hypfs_dbfs.c */
57 struct hypfs_dbfs_data *data; 64 struct hypfs_dbfs_data *data;
diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c
index 17ab8b7b53cc..2badf2bf9cd7 100644
--- a/arch/s390/hypfs/hypfs_dbfs.c
+++ b/arch/s390/hypfs/hypfs_dbfs.c
@@ -81,9 +81,25 @@ static ssize_t dbfs_read(struct file *file, char __user *buf,
81 return rc; 81 return rc;
82} 82}
83 83
84static long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
85{
86 struct hypfs_dbfs_file *df;
87 long rc;
88
89 df = file->f_path.dentry->d_inode->i_private;
90 mutex_lock(&df->lock);
91 if (df->unlocked_ioctl)
92 rc = df->unlocked_ioctl(file, cmd, arg);
93 else
94 rc = -ENOTTY;
95 mutex_unlock(&df->lock);
96 return rc;
97}
98
84static const struct file_operations dbfs_ops = { 99static const struct file_operations dbfs_ops = {
85 .read = dbfs_read, 100 .read = dbfs_read,
86 .llseek = no_llseek, 101 .llseek = no_llseek,
102 .unlocked_ioctl = dbfs_ioctl,
87}; 103};
88 104
89int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df) 105int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df)
diff --git a/arch/s390/hypfs/hypfs_sprp.c b/arch/s390/hypfs/hypfs_sprp.c
new file mode 100644
index 000000000000..f043c3c7e73c
--- /dev/null
+++ b/arch/s390/hypfs/hypfs_sprp.c
@@ -0,0 +1,141 @@
1/*
2 * Hypervisor filesystem for Linux on s390.
3 * Set Partition-Resource Parameter interface.
4 *
5 * Copyright IBM Corp. 2013
6 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
7 */
8
9#include <linux/compat.h>
10#include <linux/errno.h>
11#include <linux/gfp.h>
12#include <linux/string.h>
13#include <linux/types.h>
14#include <linux/uaccess.h>
15#include <asm/compat.h>
16#include <asm/sclp.h>
17#include "hypfs.h"
18
19#define DIAG304_SET_WEIGHTS 0
20#define DIAG304_QUERY_PRP 1
21#define DIAG304_SET_CAPPING 2
22
23#define DIAG304_CMD_MAX 2
24
25static unsigned long hypfs_sprp_diag304(void *data, unsigned long cmd)
26{
27 register unsigned long _data asm("2") = (unsigned long) data;
28 register unsigned long _rc asm("3");
29 register unsigned long _cmd asm("4") = cmd;
30
31 asm volatile("diag %1,%2,0x304\n"
32 : "=d" (_rc) : "d" (_data), "d" (_cmd) : "memory");
33
34 return _rc;
35}
36
37static void hypfs_sprp_free(const void *data)
38{
39 free_page((unsigned long) data);
40}
41
42static int hypfs_sprp_create(void **data_ptr, void **free_ptr, size_t *size)
43{
44 unsigned long rc;
45 void *data;
46
47 data = (void *) get_zeroed_page(GFP_KERNEL);
48 if (!data)
49 return -ENOMEM;
50 rc = hypfs_sprp_diag304(data, DIAG304_QUERY_PRP);
51 if (rc != 1) {
52 *data_ptr = *free_ptr = NULL;
53 *size = 0;
54 free_page((unsigned long) data);
55 return -EIO;
56 }
57 *data_ptr = *free_ptr = data;
58 *size = PAGE_SIZE;
59 return 0;
60}
61
62static int __hypfs_sprp_ioctl(void __user *user_area)
63{
64 struct hypfs_diag304 diag304;
65 unsigned long cmd;
66 void __user *udata;
67 void *data;
68 int rc;
69
70 if (copy_from_user(&diag304, user_area, sizeof(diag304)))
71 return -EFAULT;
72 if ((diag304.args[0] >> 8) != 0 || diag304.args[1] > DIAG304_CMD_MAX)
73 return -EINVAL;
74
75 data = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
76 if (!data)
77 return -ENOMEM;
78
79 udata = (void __user *)(unsigned long) diag304.data;
80 if (diag304.args[1] == DIAG304_SET_WEIGHTS ||
81 diag304.args[1] == DIAG304_SET_CAPPING)
82 if (copy_from_user(data, udata, PAGE_SIZE)) {
83 rc = -EFAULT;
84 goto out;
85 }
86
87 cmd = *(unsigned long *) &diag304.args[0];
88 diag304.rc = hypfs_sprp_diag304(data, cmd);
89
90 if (diag304.args[1] == DIAG304_QUERY_PRP)
91 if (copy_to_user(udata, data, PAGE_SIZE)) {
92 rc = -EFAULT;
93 goto out;
94 }
95
96 rc = copy_to_user(user_area, &diag304, sizeof(diag304)) ? -EFAULT : 0;
97out:
98 free_page((unsigned long) data);
99 return rc;
100}
101
102static long hypfs_sprp_ioctl(struct file *file, unsigned int cmd,
103 unsigned long arg)
104{
105 void __user *argp;
106
107 if (!capable(CAP_SYS_ADMIN))
108 return -EACCES;
109 if (is_compat_task())
110 argp = compat_ptr(arg);
111 else
112 argp = (void __user *) arg;
113 switch (cmd) {
114 case HYPFS_DIAG304:
115 return __hypfs_sprp_ioctl(argp);
116 default: /* unknown ioctl number */
117 return -ENOTTY;
118 }
119 return 0;
120}
121
122static struct hypfs_dbfs_file hypfs_sprp_file = {
123 .name = "diag_304",
124 .data_create = hypfs_sprp_create,
125 .data_free = hypfs_sprp_free,
126 .unlocked_ioctl = hypfs_sprp_ioctl,
127};
128
129int hypfs_sprp_init(void)
130{
131 if (!sclp_has_sprp())
132 return 0;
133 return hypfs_dbfs_create_file(&hypfs_sprp_file);
134}
135
136void hypfs_sprp_exit(void)
137{
138 if (!sclp_has_sprp())
139 return;
140 hypfs_dbfs_remove_file(&hypfs_sprp_file);
141}
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index ddfe09b45134..c952b981e4f2 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -478,10 +478,14 @@ static int __init hypfs_init(void)
478 rc = -ENODATA; 478 rc = -ENODATA;
479 goto fail_hypfs_diag_exit; 479 goto fail_hypfs_diag_exit;
480 } 480 }
481 if (hypfs_sprp_init()) {
482 rc = -ENODATA;
483 goto fail_hypfs_vm_exit;
484 }
481 s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); 485 s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
482 if (!s390_kobj) { 486 if (!s390_kobj) {
483 rc = -ENOMEM; 487 rc = -ENOMEM;
484 goto fail_hypfs_vm_exit; 488 goto fail_hypfs_sprp_exit;
485 } 489 }
486 rc = register_filesystem(&hypfs_type); 490 rc = register_filesystem(&hypfs_type);
487 if (rc) 491 if (rc)
@@ -490,6 +494,8 @@ static int __init hypfs_init(void)
490 494
491fail_filesystem: 495fail_filesystem:
492 kobject_put(s390_kobj); 496 kobject_put(s390_kobj);
497fail_hypfs_sprp_exit:
498 hypfs_sprp_exit();
493fail_hypfs_vm_exit: 499fail_hypfs_vm_exit:
494 hypfs_vm_exit(); 500 hypfs_vm_exit();
495fail_hypfs_diag_exit: 501fail_hypfs_diag_exit:
@@ -502,11 +508,12 @@ fail_dbfs_exit:
502 508
503static void __exit hypfs_exit(void) 509static void __exit hypfs_exit(void)
504{ 510{
505 hypfs_diag_exit();
506 hypfs_vm_exit();
507 hypfs_dbfs_exit();
508 unregister_filesystem(&hypfs_type); 511 unregister_filesystem(&hypfs_type);
509 kobject_put(s390_kobj); 512 kobject_put(s390_kobj);
513 hypfs_sprp_exit();
514 hypfs_vm_exit();
515 hypfs_diag_exit();
516 hypfs_dbfs_exit();
510} 517}
511 518
512module_init(hypfs_init) 519module_init(hypfs_init)
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index 220e171413f8..abaca2275c7a 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -54,6 +54,7 @@ int sclp_chp_read_info(struct sclp_chp_info *info);
54void sclp_get_ipl_info(struct sclp_ipl_info *info); 54void sclp_get_ipl_info(struct sclp_ipl_info *info);
55bool __init sclp_has_linemode(void); 55bool __init sclp_has_linemode(void);
56bool __init sclp_has_vt220(void); 56bool __init sclp_has_vt220(void);
57bool sclp_has_sprp(void);
57int sclp_pci_configure(u32 fid); 58int sclp_pci_configure(u32 fid);
58int sclp_pci_deconfigure(u32 fid); 59int sclp_pci_deconfigure(u32 fid);
59int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode); 60int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode);
diff --git a/arch/s390/include/uapi/asm/hypfs.h b/arch/s390/include/uapi/asm/hypfs.h
new file mode 100644
index 000000000000..37998b449531
--- /dev/null
+++ b/arch/s390/include/uapi/asm/hypfs.h
@@ -0,0 +1,25 @@
1/*
2 * IOCTL interface for hypfs
3 *
4 * Copyright IBM Corp. 2013
5 *
6 * Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
7 */
8
9#ifndef _ASM_HYPFS_CTL_H
10#define _ASM_HYPFS_CTL_H
11
12#include <linux/types.h>
13
14struct hypfs_diag304 {
15 __u32 args[2];
16 __u64 data;
17 __u64 rc;
18} __attribute__((packed));
19
20#define HYPFS_IOCTL_MAGIC 0x10
21
22#define HYPFS_DIAG304 \
23 _IOWR(HYPFS_IOCTL_MAGIC, 0x20, struct hypfs_diag304)
24
25#endif
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index cb3c4e05a385..49af8eeb90ea 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -700,3 +700,8 @@ out:
700 free_page((unsigned long) sccb); 700 free_page((unsigned long) sccb);
701 return rc; 701 return rc;
702} 702}
703
704bool sclp_has_sprp(void)
705{
706 return !!(sclp_fac84 & 0x2);
707}