diff options
| -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); |
