Merge tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / s390 / char / monwriter.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Character device driver for writing z/VM *MONITOR service records.
4  *
5  * Copyright IBM Corp. 2006, 2009
6  *
7  * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com>
8  */
9
10 #define KMSG_COMPONENT "monwriter"
11 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/init.h>
16 #include <linux/errno.h>
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/miscdevice.h>
20 #include <linux/ctype.h>
21 #include <linux/poll.h>
22 #include <linux/mutex.h>
23 #include <linux/slab.h>
24 #include <linux/uaccess.h>
25 #include <asm/ebcdic.h>
26 #include <asm/io.h>
27 #include <asm/appldata.h>
28 #include <asm/monwriter.h>
29
30 #define MONWRITE_MAX_DATALEN    4010
31
32 static int mon_max_bufs = 255;
33 static int mon_buf_count;
34
35 struct mon_buf {
36         struct list_head list;
37         struct monwrite_hdr hdr;
38         int diag_done;
39         char *data;
40 };
41
42 struct mon_private {
43         struct list_head list;
44         struct monwrite_hdr hdr;
45         size_t hdr_to_read;
46         size_t data_to_read;
47         struct mon_buf *current_buf;
48         struct mutex thread_mutex;
49 };
50
51 /*
52  * helper functions
53  */
54
55 static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
56 {
57         struct appldata_parameter_list *parm_list;
58         struct appldata_product_id *id;
59         int rc;
60
61         id = kmalloc(sizeof(*id), GFP_KERNEL);
62         parm_list = kmalloc(sizeof(*parm_list), GFP_KERNEL);
63         rc = -ENOMEM;
64         if (!id || !parm_list)
65                 goto out;
66         memcpy(id->prod_nr, "LNXAPPL", 7);
67         id->prod_fn = myhdr->applid;
68         id->record_nr = myhdr->record_num;
69         id->version_nr = myhdr->version;
70         id->release_nr = myhdr->release;
71         id->mod_lvl = myhdr->mod_level;
72         rc = appldata_asm(parm_list, id, fcn,
73                           (void *) buffer, myhdr->datalen);
74         if (rc <= 0)
75                 goto out;
76         pr_err("Writing monitor data failed with rc=%i\n", rc);
77         rc = (rc == 5) ? -EPERM : -EINVAL;
78 out:
79         kfree(id);
80         kfree(parm_list);
81         return rc;
82 }
83
84 static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
85                                          struct monwrite_hdr *monhdr)
86 {
87         struct mon_buf *entry, *next;
88
89         list_for_each_entry_safe(entry, next, &monpriv->list, list)
90                 if ((entry->hdr.mon_function == monhdr->mon_function ||
91                      monhdr->mon_function == MONWRITE_STOP_INTERVAL) &&
92                     entry->hdr.applid == monhdr->applid &&
93                     entry->hdr.record_num == monhdr->record_num &&
94                     entry->hdr.version == monhdr->version &&
95                     entry->hdr.release == monhdr->release &&
96                     entry->hdr.mod_level == monhdr->mod_level)
97                         return entry;
98
99         return NULL;
100 }
101
102 static int monwrite_new_hdr(struct mon_private *monpriv)
103 {
104         struct monwrite_hdr *monhdr = &monpriv->hdr;
105         struct mon_buf *monbuf;
106         int rc = 0;
107
108         if (monhdr->datalen > MONWRITE_MAX_DATALEN ||
109             monhdr->mon_function > MONWRITE_START_CONFIG ||
110             monhdr->hdrlen != sizeof(struct monwrite_hdr))
111                 return -EINVAL;
112         monbuf = NULL;
113         if (monhdr->mon_function != MONWRITE_GEN_EVENT)
114                 monbuf = monwrite_find_hdr(monpriv, monhdr);
115         if (monbuf) {
116                 if (monhdr->mon_function == MONWRITE_STOP_INTERVAL) {
117                         monhdr->datalen = monbuf->hdr.datalen;
118                         rc = monwrite_diag(monhdr, monbuf->data,
119                                            APPLDATA_STOP_REC);
120                         list_del(&monbuf->list);
121                         mon_buf_count--;
122                         kfree(monbuf->data);
123                         kfree(monbuf);
124                         monbuf = NULL;
125                 }
126         } else if (monhdr->mon_function != MONWRITE_STOP_INTERVAL) {
127                 if (mon_buf_count >= mon_max_bufs)
128                         return -ENOSPC;
129                 monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL);
130                 if (!monbuf)
131                         return -ENOMEM;
132                 monbuf->data = kzalloc(monhdr->datalen,
133                                        GFP_KERNEL | GFP_DMA);
134                 if (!monbuf->data) {
135                         kfree(monbuf);
136                         return -ENOMEM;
137                 }
138                 monbuf->hdr = *monhdr;
139                 list_add_tail(&monbuf->list, &monpriv->list);
140                 if (monhdr->mon_function != MONWRITE_GEN_EVENT)
141                         mon_buf_count++;
142         }
143         monpriv->current_buf = monbuf;
144         return rc;
145 }
146
147 static int monwrite_new_data(struct mon_private *monpriv)
148 {
149         struct monwrite_hdr *monhdr = &monpriv->hdr;
150         struct mon_buf *monbuf = monpriv->current_buf;
151         int rc = 0;
152
153         switch (monhdr->mon_function) {
154         case MONWRITE_START_INTERVAL:
155                 if (!monbuf->diag_done) {
156                         rc = monwrite_diag(monhdr, monbuf->data,
157                                            APPLDATA_START_INTERVAL_REC);
158                         monbuf->diag_done = 1;
159                 }
160                 break;
161         case MONWRITE_START_CONFIG:
162                 if (!monbuf->diag_done) {
163                         rc = monwrite_diag(monhdr, monbuf->data,
164                                            APPLDATA_START_CONFIG_REC);
165                         monbuf->diag_done = 1;
166                 }
167                 break;
168         case MONWRITE_GEN_EVENT:
169                 rc = monwrite_diag(monhdr, monbuf->data,
170                                    APPLDATA_GEN_EVENT_REC);
171                 list_del(&monpriv->current_buf->list);
172                 kfree(monpriv->current_buf->data);
173                 kfree(monpriv->current_buf);
174                 monpriv->current_buf = NULL;
175                 break;
176         default:
177                 /* monhdr->mon_function is checked in monwrite_new_hdr */
178                 BUG();
179         }
180         return rc;
181 }
182
183 /*
184  * file operations
185  */
186
187 static int monwrite_open(struct inode *inode, struct file *filp)
188 {
189         struct mon_private *monpriv;
190
191         monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
192         if (!monpriv)
193                 return -ENOMEM;
194         INIT_LIST_HEAD(&monpriv->list);
195         monpriv->hdr_to_read = sizeof(monpriv->hdr);
196         mutex_init(&monpriv->thread_mutex);
197         filp->private_data = monpriv;
198         return nonseekable_open(inode, filp);
199 }
200
201 static int monwrite_close(struct inode *inode, struct file *filp)
202 {
203         struct mon_private *monpriv = filp->private_data;
204         struct mon_buf *entry, *next;
205
206         list_for_each_entry_safe(entry, next, &monpriv->list, list) {
207                 if (entry->hdr.mon_function != MONWRITE_GEN_EVENT)
208                         monwrite_diag(&entry->hdr, entry->data,
209                                       APPLDATA_STOP_REC);
210                 mon_buf_count--;
211                 list_del(&entry->list);
212                 kfree(entry->data);
213                 kfree(entry);
214         }
215         kfree(monpriv);
216         return 0;
217 }
218
219 static ssize_t monwrite_write(struct file *filp, const char __user *data,
220                               size_t count, loff_t *ppos)
221 {
222         struct mon_private *monpriv = filp->private_data;
223         size_t len, written;
224         void *to;
225         int rc;
226
227         mutex_lock(&monpriv->thread_mutex);
228         for (written = 0; written < count; ) {
229                 if (monpriv->hdr_to_read) {
230                         len = min(count - written, monpriv->hdr_to_read);
231                         to = (char *) &monpriv->hdr +
232                                 sizeof(monpriv->hdr) - monpriv->hdr_to_read;
233                         if (copy_from_user(to, data + written, len)) {
234                                 rc = -EFAULT;
235                                 goto out_error;
236                         }
237                         monpriv->hdr_to_read -= len;
238                         written += len;
239                         if (monpriv->hdr_to_read > 0)
240                                 continue;
241                         rc = monwrite_new_hdr(monpriv);
242                         if (rc)
243                                 goto out_error;
244                         monpriv->data_to_read = monpriv->current_buf ?
245                                 monpriv->current_buf->hdr.datalen : 0;
246                 }
247
248                 if (monpriv->data_to_read) {
249                         len = min(count - written, monpriv->data_to_read);
250                         to = monpriv->current_buf->data +
251                                 monpriv->hdr.datalen - monpriv->data_to_read;
252                         if (copy_from_user(to, data + written, len)) {
253                                 rc = -EFAULT;
254                                 goto out_error;
255                         }
256                         monpriv->data_to_read -= len;
257                         written += len;
258                         if (monpriv->data_to_read > 0)
259                                 continue;
260                         rc = monwrite_new_data(monpriv);
261                         if (rc)
262                                 goto out_error;
263                 }
264                 monpriv->hdr_to_read = sizeof(monpriv->hdr);
265         }
266         mutex_unlock(&monpriv->thread_mutex);
267         return written;
268
269 out_error:
270         monpriv->data_to_read = 0;
271         monpriv->hdr_to_read = sizeof(struct monwrite_hdr);
272         mutex_unlock(&monpriv->thread_mutex);
273         return rc;
274 }
275
276 static const struct file_operations monwrite_fops = {
277         .owner   = THIS_MODULE,
278         .open    = &monwrite_open,
279         .release = &monwrite_close,
280         .write   = &monwrite_write,
281         .llseek  = noop_llseek,
282 };
283
284 static struct miscdevice mon_dev = {
285         .name   = "monwriter",
286         .fops   = &monwrite_fops,
287         .minor  = MISC_DYNAMIC_MINOR,
288 };
289
290 /*
291  * module init/exit
292  */
293
294 static int __init mon_init(void)
295 {
296         if (!MACHINE_IS_VM)
297                 return -ENODEV;
298         /*
299          * misc_register() has to be the last action in module_init(), because
300          * file operations will be available right after this.
301          */
302         return misc_register(&mon_dev);
303 }
304
305 static void __exit mon_exit(void)
306 {
307         misc_deregister(&mon_dev);
308 }
309
310 module_init(mon_init);
311 module_exit(mon_exit);
312
313 module_param_named(max_bufs, mon_max_bufs, int, 0644);
314 MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers "
315                  "that can be active at one time");
316
317 MODULE_AUTHOR("Melissa Howland <Melissa.Howland@us.ibm.com>");
318 MODULE_DESCRIPTION("Character device driver for writing z/VM "
319                    "APPLDATA monitor records.");
320 MODULE_LICENSE("GPL");