diff options
Diffstat (limited to 'drivers/s390/char/monwriter.c')
-rw-r--r-- | drivers/s390/char/monwriter.c | 98 |
1 files changed, 92 insertions, 6 deletions
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index c7d7483bab9a..66fb8eba93f4 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/monwriter.c | ||
3 | * | ||
4 | * Character device driver for writing z/VM *MONITOR service records. | 2 | * Character device driver for writing z/VM *MONITOR service records. |
5 | * | 3 | * |
6 | * Copyright (C) IBM Corp. 2006 | 4 | * Copyright IBM Corp. 2006, 2009 |
7 | * | 5 | * |
8 | * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com> | 6 | * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com> |
9 | */ | 7 | */ |
@@ -22,6 +20,7 @@ | |||
22 | #include <linux/ctype.h> | 20 | #include <linux/ctype.h> |
23 | #include <linux/poll.h> | 21 | #include <linux/poll.h> |
24 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/platform_device.h> | ||
25 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
26 | #include <asm/ebcdic.h> | 25 | #include <asm/ebcdic.h> |
27 | #include <asm/io.h> | 26 | #include <asm/io.h> |
@@ -40,7 +39,10 @@ struct mon_buf { | |||
40 | char *data; | 39 | char *data; |
41 | }; | 40 | }; |
42 | 41 | ||
42 | static LIST_HEAD(mon_priv_list); | ||
43 | |||
43 | struct mon_private { | 44 | struct mon_private { |
45 | struct list_head priv_list; | ||
44 | struct list_head list; | 46 | struct list_head list; |
45 | struct monwrite_hdr hdr; | 47 | struct monwrite_hdr hdr; |
46 | size_t hdr_to_read; | 48 | size_t hdr_to_read; |
@@ -188,6 +190,7 @@ static int monwrite_open(struct inode *inode, struct file *filp) | |||
188 | monpriv->hdr_to_read = sizeof(monpriv->hdr); | 190 | monpriv->hdr_to_read = sizeof(monpriv->hdr); |
189 | mutex_init(&monpriv->thread_mutex); | 191 | mutex_init(&monpriv->thread_mutex); |
190 | filp->private_data = monpriv; | 192 | filp->private_data = monpriv; |
193 | list_add_tail(&monpriv->priv_list, &mon_priv_list); | ||
191 | unlock_kernel(); | 194 | unlock_kernel(); |
192 | return nonseekable_open(inode, filp); | 195 | return nonseekable_open(inode, filp); |
193 | } | 196 | } |
@@ -206,6 +209,7 @@ static int monwrite_close(struct inode *inode, struct file *filp) | |||
206 | kfree(entry->data); | 209 | kfree(entry->data); |
207 | kfree(entry); | 210 | kfree(entry); |
208 | } | 211 | } |
212 | list_del(&monpriv->priv_list); | ||
209 | kfree(monpriv); | 213 | kfree(monpriv); |
210 | return 0; | 214 | return 0; |
211 | } | 215 | } |
@@ -281,20 +285,102 @@ static struct miscdevice mon_dev = { | |||
281 | }; | 285 | }; |
282 | 286 | ||
283 | /* | 287 | /* |
288 | * suspend/resume | ||
289 | */ | ||
290 | |||
291 | static int monwriter_freeze(struct device *dev) | ||
292 | { | ||
293 | struct mon_private *monpriv; | ||
294 | struct mon_buf *monbuf; | ||
295 | |||
296 | list_for_each_entry(monpriv, &mon_priv_list, priv_list) { | ||
297 | list_for_each_entry(monbuf, &monpriv->list, list) { | ||
298 | if (monbuf->hdr.mon_function != MONWRITE_GEN_EVENT) | ||
299 | monwrite_diag(&monbuf->hdr, monbuf->data, | ||
300 | APPLDATA_STOP_REC); | ||
301 | } | ||
302 | } | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int monwriter_restore(struct device *dev) | ||
307 | { | ||
308 | struct mon_private *monpriv; | ||
309 | struct mon_buf *monbuf; | ||
310 | |||
311 | list_for_each_entry(monpriv, &mon_priv_list, priv_list) { | ||
312 | list_for_each_entry(monbuf, &monpriv->list, list) { | ||
313 | if (monbuf->hdr.mon_function == MONWRITE_START_INTERVAL) | ||
314 | monwrite_diag(&monbuf->hdr, monbuf->data, | ||
315 | APPLDATA_START_INTERVAL_REC); | ||
316 | if (monbuf->hdr.mon_function == MONWRITE_START_CONFIG) | ||
317 | monwrite_diag(&monbuf->hdr, monbuf->data, | ||
318 | APPLDATA_START_CONFIG_REC); | ||
319 | } | ||
320 | } | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static int monwriter_thaw(struct device *dev) | ||
325 | { | ||
326 | return monwriter_restore(dev); | ||
327 | } | ||
328 | |||
329 | static struct dev_pm_ops monwriter_pm_ops = { | ||
330 | .freeze = monwriter_freeze, | ||
331 | .thaw = monwriter_thaw, | ||
332 | .restore = monwriter_restore, | ||
333 | }; | ||
334 | |||
335 | static struct platform_driver monwriter_pdrv = { | ||
336 | .driver = { | ||
337 | .name = "monwriter", | ||
338 | .owner = THIS_MODULE, | ||
339 | .pm = &monwriter_pm_ops, | ||
340 | }, | ||
341 | }; | ||
342 | |||
343 | static struct platform_device *monwriter_pdev; | ||
344 | |||
345 | /* | ||
284 | * module init/exit | 346 | * module init/exit |
285 | */ | 347 | */ |
286 | 348 | ||
287 | static int __init mon_init(void) | 349 | static int __init mon_init(void) |
288 | { | 350 | { |
289 | if (MACHINE_IS_VM) | 351 | int rc; |
290 | return misc_register(&mon_dev); | 352 | |
291 | else | 353 | if (!MACHINE_IS_VM) |
292 | return -ENODEV; | 354 | return -ENODEV; |
355 | |||
356 | rc = platform_driver_register(&monwriter_pdrv); | ||
357 | if (rc) | ||
358 | return rc; | ||
359 | |||
360 | monwriter_pdev = platform_device_register_simple("monwriter", -1, NULL, | ||
361 | 0); | ||
362 | if (IS_ERR(monwriter_pdev)) { | ||
363 | rc = PTR_ERR(monwriter_pdev); | ||
364 | goto out_driver; | ||
365 | } | ||
366 | |||
367 | rc = misc_register(&mon_dev); | ||
368 | if (rc) | ||
369 | goto out_device; | ||
370 | return 0; | ||
371 | |||
372 | out_device: | ||
373 | platform_device_unregister(monwriter_pdev); | ||
374 | out_driver: | ||
375 | platform_driver_unregister(&monwriter_pdrv); | ||
376 | return rc; | ||
293 | } | 377 | } |
294 | 378 | ||
295 | static void __exit mon_exit(void) | 379 | static void __exit mon_exit(void) |
296 | { | 380 | { |
297 | WARN_ON(misc_deregister(&mon_dev) != 0); | 381 | WARN_ON(misc_deregister(&mon_dev) != 0); |
382 | platform_device_unregister(monwriter_pdev); | ||
383 | platform_driver_unregister(&monwriter_pdrv); | ||
298 | } | 384 | } |
299 | 385 | ||
300 | module_init(mon_init); | 386 | module_init(mon_init); |