diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/char/vmcp.c | 89 | ||||
-rw-r--r-- | drivers/s390/char/vmcp.h | 4 |
2 files changed, 53 insertions, 40 deletions
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 82e6a6b253eb..2f419b0ea628 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2004,2005 IBM Corporation | 2 | * Copyright IBM Corp. 2004,2007 |
3 | * Interface implementation for communication with the z/VM control program | 3 | * Interface implementation for communication with the z/VM control program |
4 | * Author(s): Christian Borntraeger <cborntra@de.ibm.com> | 4 | * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> |
5 | * | 5 | * |
6 | * | 6 | * |
7 | * z/VMs CP offers the possibility to issue commands via the diagnose code 8 | 7 | * z/VMs CP offers the possibility to issue commands via the diagnose code 8 |
@@ -22,9 +22,11 @@ | |||
22 | #include "vmcp.h" | 22 | #include "vmcp.h" |
23 | 23 | ||
24 | MODULE_LICENSE("GPL"); | 24 | MODULE_LICENSE("GPL"); |
25 | MODULE_AUTHOR("Christian Borntraeger <cborntra@de.ibm.com>"); | 25 | MODULE_AUTHOR("Christian Borntraeger <borntraeger@de.ibm.com>"); |
26 | MODULE_DESCRIPTION("z/VM CP interface"); | 26 | MODULE_DESCRIPTION("z/VM CP interface"); |
27 | 27 | ||
28 | #define PRINTK_HEADER "vmcp: " | ||
29 | |||
28 | static debug_info_t *vmcp_debug; | 30 | static debug_info_t *vmcp_debug; |
29 | 31 | ||
30 | static int vmcp_open(struct inode *inode, struct file *file) | 32 | static int vmcp_open(struct inode *inode, struct file *file) |
@@ -40,7 +42,7 @@ static int vmcp_open(struct inode *inode, struct file *file) | |||
40 | session->bufsize = PAGE_SIZE; | 42 | session->bufsize = PAGE_SIZE; |
41 | session->response = NULL; | 43 | session->response = NULL; |
42 | session->resp_size = 0; | 44 | session->resp_size = 0; |
43 | init_MUTEX(&session->mutex); | 45 | mutex_init(&session->mutex); |
44 | file->private_data = session; | 46 | file->private_data = session; |
45 | return nonseekable_open(inode, file); | 47 | return nonseekable_open(inode, file); |
46 | } | 48 | } |
@@ -57,37 +59,37 @@ static int vmcp_release(struct inode *inode, struct file *file) | |||
57 | } | 59 | } |
58 | 60 | ||
59 | static ssize_t | 61 | static ssize_t |
60 | vmcp_read(struct file *file, char __user * buff, size_t count, loff_t * ppos) | 62 | vmcp_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) |
61 | { | 63 | { |
62 | size_t tocopy; | 64 | size_t tocopy; |
63 | struct vmcp_session *session; | 65 | struct vmcp_session *session; |
64 | 66 | ||
65 | session = (struct vmcp_session *)file->private_data; | 67 | session = (struct vmcp_session *)file->private_data; |
66 | if (down_interruptible(&session->mutex)) | 68 | if (mutex_lock_interruptible(&session->mutex)) |
67 | return -ERESTARTSYS; | 69 | return -ERESTARTSYS; |
68 | if (!session->response) { | 70 | if (!session->response) { |
69 | up(&session->mutex); | 71 | mutex_unlock(&session->mutex); |
70 | return 0; | 72 | return 0; |
71 | } | 73 | } |
72 | if (*ppos > session->resp_size) { | 74 | if (*ppos > session->resp_size) { |
73 | up(&session->mutex); | 75 | mutex_unlock(&session->mutex); |
74 | return 0; | 76 | return 0; |
75 | } | 77 | } |
76 | tocopy = min(session->resp_size - (size_t) (*ppos), count); | 78 | tocopy = min(session->resp_size - (size_t) (*ppos), count); |
77 | tocopy = min(tocopy,session->bufsize - (size_t) (*ppos)); | 79 | tocopy = min(tocopy, session->bufsize - (size_t) (*ppos)); |
78 | 80 | ||
79 | if (copy_to_user(buff, session->response + (*ppos), tocopy)) { | 81 | if (copy_to_user(buff, session->response + (*ppos), tocopy)) { |
80 | up(&session->mutex); | 82 | mutex_unlock(&session->mutex); |
81 | return -EFAULT; | 83 | return -EFAULT; |
82 | } | 84 | } |
83 | up(&session->mutex); | 85 | mutex_unlock(&session->mutex); |
84 | *ppos += tocopy; | 86 | *ppos += tocopy; |
85 | return tocopy; | 87 | return tocopy; |
86 | } | 88 | } |
87 | 89 | ||
88 | static ssize_t | 90 | static ssize_t |
89 | vmcp_write(struct file *file, const char __user * buff, size_t count, | 91 | vmcp_write(struct file *file, const char __user *buff, size_t count, |
90 | loff_t * ppos) | 92 | loff_t *ppos) |
91 | { | 93 | { |
92 | char *cmd; | 94 | char *cmd; |
93 | struct vmcp_session *session; | 95 | struct vmcp_session *session; |
@@ -103,24 +105,23 @@ vmcp_write(struct file *file, const char __user * buff, size_t count, | |||
103 | } | 105 | } |
104 | cmd[count] = '\0'; | 106 | cmd[count] = '\0'; |
105 | session = (struct vmcp_session *)file->private_data; | 107 | session = (struct vmcp_session *)file->private_data; |
106 | if (down_interruptible(&session->mutex)) { | 108 | if (mutex_lock_interruptible(&session->mutex)) { |
107 | kfree(cmd); | 109 | kfree(cmd); |
108 | return -ERESTARTSYS; | 110 | return -ERESTARTSYS; |
109 | } | 111 | } |
110 | if (!session->response) | 112 | if (!session->response) |
111 | session->response = (char *)__get_free_pages(GFP_KERNEL | 113 | session->response = (char *)__get_free_pages(GFP_KERNEL |
112 | | __GFP_REPEAT | GFP_DMA, | 114 | | __GFP_REPEAT | GFP_DMA, |
113 | get_order(session->bufsize)); | 115 | get_order(session->bufsize)); |
114 | if (!session->response) { | 116 | if (!session->response) { |
115 | up(&session->mutex); | 117 | mutex_unlock(&session->mutex); |
116 | kfree(cmd); | 118 | kfree(cmd); |
117 | return -ENOMEM; | 119 | return -ENOMEM; |
118 | } | 120 | } |
119 | debug_text_event(vmcp_debug, 1, cmd); | 121 | debug_text_event(vmcp_debug, 1, cmd); |
120 | session->resp_size = cpcmd(cmd, session->response, | 122 | session->resp_size = cpcmd(cmd, session->response, session->bufsize, |
121 | session->bufsize, | 123 | &session->resp_code); |
122 | &session->resp_code); | 124 | mutex_unlock(&session->mutex); |
123 | up(&session->mutex); | ||
124 | kfree(cmd); | 125 | kfree(cmd); |
125 | *ppos = 0; /* reset the file pointer after a command */ | 126 | *ppos = 0; /* reset the file pointer after a command */ |
126 | return count; | 127 | return count; |
@@ -145,12 +146,12 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
145 | int temp; | 146 | int temp; |
146 | 147 | ||
147 | session = (struct vmcp_session *)file->private_data; | 148 | session = (struct vmcp_session *)file->private_data; |
148 | if (down_interruptible(&session->mutex)) | 149 | if (mutex_lock_interruptible(&session->mutex)) |
149 | return -ERESTARTSYS; | 150 | return -ERESTARTSYS; |
150 | switch (cmd) { | 151 | switch (cmd) { |
151 | case VMCP_GETCODE: | 152 | case VMCP_GETCODE: |
152 | temp = session->resp_code; | 153 | temp = session->resp_code; |
153 | up(&session->mutex); | 154 | mutex_unlock(&session->mutex); |
154 | return put_user(temp, (int __user *)arg); | 155 | return put_user(temp, (int __user *)arg); |
155 | case VMCP_SETBUF: | 156 | case VMCP_SETBUF: |
156 | free_pages((unsigned long)session->response, | 157 | free_pages((unsigned long)session->response, |
@@ -161,14 +162,14 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
161 | session->bufsize = PAGE_SIZE; | 162 | session->bufsize = PAGE_SIZE; |
162 | temp = -EINVAL; | 163 | temp = -EINVAL; |
163 | } | 164 | } |
164 | up(&session->mutex); | 165 | mutex_unlock(&session->mutex); |
165 | return temp; | 166 | return temp; |
166 | case VMCP_GETSIZE: | 167 | case VMCP_GETSIZE: |
167 | temp = session->resp_size; | 168 | temp = session->resp_size; |
168 | up(&session->mutex); | 169 | mutex_unlock(&session->mutex); |
169 | return put_user(temp, (int __user *)arg); | 170 | return put_user(temp, (int __user *)arg); |
170 | default: | 171 | default: |
171 | up(&session->mutex); | 172 | mutex_unlock(&session->mutex); |
172 | return -ENOIOCTLCMD; | 173 | return -ENOIOCTLCMD; |
173 | } | 174 | } |
174 | } | 175 | } |
@@ -180,7 +181,7 @@ static const struct file_operations vmcp_fops = { | |||
180 | .read = vmcp_read, | 181 | .read = vmcp_read, |
181 | .write = vmcp_write, | 182 | .write = vmcp_write, |
182 | .unlocked_ioctl = vmcp_ioctl, | 183 | .unlocked_ioctl = vmcp_ioctl, |
183 | .compat_ioctl = vmcp_ioctl | 184 | .compat_ioctl = vmcp_ioctl, |
184 | }; | 185 | }; |
185 | 186 | ||
186 | static struct miscdevice vmcp_dev = { | 187 | static struct miscdevice vmcp_dev = { |
@@ -194,26 +195,38 @@ static int __init vmcp_init(void) | |||
194 | int ret; | 195 | int ret; |
195 | 196 | ||
196 | if (!MACHINE_IS_VM) { | 197 | if (!MACHINE_IS_VM) { |
197 | printk(KERN_WARNING | 198 | PRINT_WARN("z/VM CP interface is only available under z/VM\n"); |
198 | "z/VM CP interface is only available under z/VM\n"); | ||
199 | return -ENODEV; | 199 | return -ENODEV; |
200 | } | 200 | } |
201 | ret = misc_register(&vmcp_dev); | ||
202 | if (!ret) | ||
203 | printk(KERN_INFO "z/VM CP interface loaded\n"); | ||
204 | else | ||
205 | printk(KERN_WARNING | ||
206 | "z/VM CP interface not loaded. Could not register misc device.\n"); | ||
207 | vmcp_debug = debug_register("vmcp", 1, 1, 240); | 201 | vmcp_debug = debug_register("vmcp", 1, 1, 240); |
208 | debug_register_view(vmcp_debug, &debug_hex_ascii_view); | 202 | if (!vmcp_debug) { |
209 | return ret; | 203 | PRINT_ERR("z/VM CP interface not loaded. Could not register " |
204 | "debug feature\n"); | ||
205 | return -ENOMEM; | ||
206 | } | ||
207 | ret = debug_register_view(vmcp_debug, &debug_hex_ascii_view); | ||
208 | if (ret) { | ||
209 | PRINT_ERR("z/VM CP interface not loaded. Could not register " | ||
210 | "debug feature view. Error code: %d\n", ret); | ||
211 | debug_unregister(vmcp_debug); | ||
212 | return ret; | ||
213 | } | ||
214 | ret = misc_register(&vmcp_dev); | ||
215 | if (ret) { | ||
216 | PRINT_ERR("z/VM CP interface not loaded. Could not register " | ||
217 | "misc device. Error code: %d\n", ret); | ||
218 | debug_unregister(vmcp_debug); | ||
219 | return ret; | ||
220 | } | ||
221 | PRINT_INFO("z/VM CP interface loaded\n"); | ||
222 | return 0; | ||
210 | } | 223 | } |
211 | 224 | ||
212 | static void __exit vmcp_exit(void) | 225 | static void __exit vmcp_exit(void) |
213 | { | 226 | { |
214 | WARN_ON(misc_deregister(&vmcp_dev) != 0); | 227 | misc_deregister(&vmcp_dev); |
215 | debug_unregister(vmcp_debug); | 228 | debug_unregister(vmcp_debug); |
216 | printk(KERN_INFO "z/VM CP interface unloaded.\n"); | 229 | PRINT_INFO("z/VM CP interface unloaded.\n"); |
217 | } | 230 | } |
218 | 231 | ||
219 | module_init(vmcp_init); | 232 | module_init(vmcp_init); |
diff --git a/drivers/s390/char/vmcp.h b/drivers/s390/char/vmcp.h index 8a5975f3dad7..6a993948e188 100644 --- a/drivers/s390/char/vmcp.h +++ b/drivers/s390/char/vmcp.h | |||
@@ -12,8 +12,8 @@ | |||
12 | * The idea of this driver is based on cpint from Neale Ferguson | 12 | * The idea of this driver is based on cpint from Neale Ferguson |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <asm/semaphore.h> | ||
16 | #include <linux/ioctl.h> | 15 | #include <linux/ioctl.h> |
16 | #include <linux/mutex.h> | ||
17 | 17 | ||
18 | #define VMCP_GETCODE _IOR(0x10, 1, int) | 18 | #define VMCP_GETCODE _IOR(0x10, 1, int) |
19 | #define VMCP_SETBUF _IOW(0x10, 2, int) | 19 | #define VMCP_SETBUF _IOW(0x10, 2, int) |
@@ -26,5 +26,5 @@ struct vmcp_session { | |||
26 | int resp_code; | 26 | int resp_code; |
27 | /* As we use copy_from/to_user, which might * | 27 | /* As we use copy_from/to_user, which might * |
28 | * sleep and cannot use a spinlock */ | 28 | * sleep and cannot use a spinlock */ |
29 | struct semaphore mutex; | 29 | struct mutex mutex; |
30 | }; | 30 | }; |