1 /* 2 * arch/s390/appldata/appldata_base.c 3 * 4 * Base infrastructure for Linux-z/VM Monitor Stream, Stage 1. 5 * Exports appldata_register_ops() and appldata_unregister_ops() for the 6 * data gathering modules. 7 * 8 * Copyright IBM Corp. 2003, 2009 9 * 10 * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> 11 */ 12 13 #define KMSG_COMPONENT "appldata" 14 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 15 16 #include <linux/module.h> 17 #include <linux/init.h> 18 #include <linux/slab.h> 19 #include <linux/errno.h> 20 #include <linux/interrupt.h> 21 #include <linux/proc_fs.h> 22 #include <linux/mm.h> 23 #include <linux/swap.h> 24 #include <linux/pagemap.h> 25 #include <linux/sysctl.h> 26 #include <linux/notifier.h> 27 #include <linux/cpu.h> 28 #include <linux/workqueue.h> 29 #include <linux/suspend.h> 30 #include <linux/platform_device.h> 31 #include <asm/appldata.h> 32 #include <asm/timer.h> 33 #include <asm/uaccess.h> 34 #include <asm/io.h> 35 #include <asm/smp.h> 36 37 #include "appldata.h" 38 39 40 #define APPLDATA_CPU_INTERVAL 10000 /* default (CPU) time for 41 sampling interval in 42 milliseconds */ 43 44 #define TOD_MICRO 0x01000 /* nr. of TOD clock units 45 for 1 microsecond */ 46 47 static struct platform_device *appldata_pdev; 48 49 /* 50 * /proc entries (sysctl) 51 */ 52 static const char appldata_proc_name[APPLDATA_PROC_NAME_LENGTH] = "appldata"; 53 static int appldata_timer_handler(ctl_table *ctl, int write, struct file *filp, 54 void __user *buffer, size_t *lenp, loff_t *ppos); 55 static int appldata_interval_handler(ctl_table *ctl, int write, 56 struct file *filp, 57 void __user *buffer, 58 size_t *lenp, loff_t *ppos); 59 60 static struct ctl_table_header *appldata_sysctl_header; 61 static struct ctl_table appldata_table[] = { 62 { 63 .procname = "timer", 64 .mode = S_IRUGO | S_IWUSR, 65 .proc_handler = &appldata_timer_handler, 66 }, 67 { 68 .procname = "interval", 69 .mode = S_IRUGO | S_IWUSR, 70 .proc_handler = &appldata_interval_handler, 71 }, 72 { }, 73 }; 74 75 static struct ctl_table appldata_dir_table[] = { 76 { 77 .procname = appldata_proc_name, 78 .maxlen = 0, 79 .mode = S_IRUGO | S_IXUGO, 80 .child = appldata_table, 81 }, 82 { }, 83 }; 84 85 /* 86 * Timer 87 */ 88 static DEFINE_PER_CPU(struct vtimer_list, appldata_timer); 89 static atomic_t appldata_expire_count = ATOMIC_INIT(0); 90 91 static DEFINE_SPINLOCK(appldata_timer_lock); 92 static int appldata_interval = APPLDATA_CPU_INTERVAL; 93 static int appldata_timer_active; 94 static int appldata_timer_suspended = 0; 95 96 /* 97 * Work queue 98 */ 99 static struct workqueue_struct *appldata_wq; 100 static void appldata_work_fn(struct work_struct *work); 101 static DECLARE_WORK(appldata_work, appldata_work_fn); 102 103 104 /* 105 * Ops list 106 */ 107 static DEFINE_MUTEX(appldata_ops_mutex); 108 static LIST_HEAD(appldata_ops_list); 109 110 111 /*************************** timer, work, DIAG *******************************/ 112 /* 113 * appldata_timer_function() 114 * 115 * schedule work and reschedule timer 116 */ 117 static void appldata_timer_function(unsigned long data) 118 { 119 if (atomic_dec_and_test(&appldata_expire_count)) { 120 atomic_set(&appldata_expire_count, num_online_cpus()); 121 queue_work(appldata_wq, (struct work_struct *) data); 122 } 123 } 124 125 /* 126 * appldata_work_fn() 127 * 128 * call data gathering function for each (active) module 129 */ 130 static void appldata_work_fn(struct work_struct *work) 131 { 132 struct list_head *lh; 133 struct appldata_ops *ops; 134 int i; 135 136 i = 0; 137 get_online_cpus(); 138 mutex_lock(&appldata_ops_mutex); 139 list_for_each(lh, &appldata_ops_list) { 140 ops = list_entry(lh, struct appldata_ops, list); 141 if (ops->active == 1) { 142 ops->callback(ops->data); 143 } 144 } 145 mutex_unlock(&appldata_ops_mutex); 146 put_online_cpus(); 147 } 148 149 /* 150 * appldata_diag() 151 * 152 * prepare parameter list, issue DIAG 0xDC 153 */ 154 int appldata_diag(char record_nr, u16 function, unsigned long buffer, 155 u16 length, char *mod_lvl) 156 { 157 struct appldata_product_id id = { 158 .prod_nr = {0xD3, 0xC9, 0xD5, 0xE4, 159 0xE7, 0xD2, 0xD9}, /* "LINUXKR" */ 160 .prod_fn = 0xD5D3, /* "NL" */ 161 .version_nr = 0xF2F6, /* "26" */ 162 .release_nr = 0xF0F1, /* "01" */ 163 }; 164 165 id.record_nr = record_nr; 166 id.mod_lvl = (mod_lvl[0]) << 8 | mod_lvl[1]; 167 return appldata_asm(&id, function, (void *) buffer, length); 168 } 169 /************************ timer, work, DIAG <END> ****************************/ 170 171 172 /****************************** /proc stuff **********************************/ 173 174 /* 175 * appldata_mod_vtimer_wrap() 176 * 177 * wrapper function for mod_virt_timer(), because smp_call_function_single() 178 * accepts only one parameter. 179 */ 180 static void __appldata_mod_vtimer_wrap(void *p) { 181 struct { 182 struct vtimer_list *timer; 183 u64 expires; 184 } *args = p; 185 mod_virt_timer_periodic(args->timer, args->expires); 186 } 187 188 #define APPLDATA_ADD_TIMER 0 189 #define APPLDATA_DEL_TIMER 1 190 #define APPLDATA_MOD_TIMER 2 191 192 /* 193 * __appldata_vtimer_setup() 194 * 195 * Add, delete or modify virtual timers on all online cpus. 196 * The caller needs to get the appldata_timer_lock spinlock. 197 */ 198 static void 199 __appldata_vtimer_setup(int cmd) 200 { 201 u64 per_cpu_interval; 202 int i; 203 204 switch (cmd) { 205 case APPLDATA_ADD_TIMER: 206 if (appldata_timer_active) 207 break; 208 per_cpu_interval = (u64) (appldata_interval*1000 / 209 num_online_cpus()) * TOD_MICRO; 210 for_each_online_cpu(i) { 211 per_cpu(appldata_timer, i).expires = per_cpu_interval; 212 smp_call_function_single(i, add_virt_timer_periodic, 213 &per_cpu(appldata_timer, i), 214 1); 215 } 216 appldata_timer_active = 1; 217 break; 218 case APPLDATA_DEL_TIMER: 219 for_each_online_cpu(i) 220 del_virt_timer(&per_cpu(appldata_timer, i)); 221 if (!appldata_timer_active) 222 break; 223 appldata_timer_active = 0; 224 atomic_set(&appldata_expire_count, num_online_cpus()); 225 break; 226 case APPLDATA_MOD_TIMER: 227 per_cpu_interval = (u64) (appldata_interval*1000 / 228 num_online_cpus()) * TOD_MICRO; 229 if (!appldata_timer_active) 230 break; 231 for_each_online_cpu(i) { 232 struct { 233 struct vtimer_list *timer; 234 u64 expires; 235 } args; 236 args.timer = &per_cpu(appldata_timer, i); 237 args.expires = per_cpu_interval; 238 smp_call_function_single(i, __appldata_mod_vtimer_wrap, 239 &args, 1); 240 } 241 } 242 } 243 244 /* 245 * appldata_timer_handler() 246 * 247 * Start/Stop timer, show status of timer (0 = not active, 1 = active) 248 */ 249 static int 250 appldata_timer_handler(ctl_table *ctl, int write, struct file *filp, 251 void __user *buffer, size_t *lenp, loff_t *ppos) 252 { 253 int len; 254 char buf[2]; 255 256 if (!*lenp || *ppos) { 257 *lenp = 0; 258 return 0; 259 } 260 if (!write) { 261 len = sprintf(buf, appldata_timer_active ? "1\n" : "0\n"); 262 if (len > *lenp) 263 len = *lenp; 264 if (copy_to_user(buffer, buf, len)) 265 return -EFAULT; 266 goto out; 267 } 268 len = *lenp; 269 if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) 270 return -EFAULT; 271 get_online_cpus(); 272 spin_lock(&appldata_timer_lock); 273 if (buf[0] == '1') 274 __appldata_vtimer_setup(APPLDATA_ADD_TIMER); 275 else if (buf[0] == '0') 276 __appldata_vtimer_setup(APPLDATA_DEL_TIMER); 277 spin_unlock(&appldata_timer_lock); 278 put_online_cpus(); 279 out: 280 *lenp = len; 281 *ppos += len; 282 return 0; 283 } 284 285 /* 286 * appldata_interval_handler() 287 * 288 * Set (CPU) timer interval for collection of data (in milliseconds), show 289 * current timer interval. 290 */ 291 static int 292 appldata_interval_handler(ctl_table *ctl, int write, struct file *filp, 293 void __user *buffer, size_t *lenp, loff_t *ppos) 294 { 295 int len, interval; 296 char buf[16]; 297 298 if (!*lenp || *ppos) { 299 *lenp = 0; 300 return 0; 301 } 302 if (!write) { 303 len = sprintf(buf, "%i\n", appldata_interval); 304 if (len > *lenp) 305 len = *lenp; 306 if (copy_to_user(buffer, buf, len)) 307 return -EFAULT; 308 goto out; 309 } 310 len = *lenp; 311 if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) { 312 return -EFAULT; 313 } 314 interval = 0; 315 sscanf(buf, "%i", &interval); 316 if (interval <= 0) 317 return -EINVAL; 318 319 get_online_cpus(); 320 spin_lock(&appldata_timer_lock); 321 appldata_interval = interval; 322 __appldata_vtimer_setup(APPLDATA_MOD_TIMER); 323 spin_unlock(&appldata_timer_lock); 324 put_online_cpus(); 325 out: 326 *lenp = len; 327 *ppos += len; 328 return 0; 329 } 330 331 /* 332 * appldata_generic_handler() 333 * 334 * Generic start/stop monitoring and DIAG, show status of 335 * monitoring (0 = not in process, 1 = in process) 336 */ 337 static int 338 appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, 339 void __user *buffer, size_t *lenp, loff_t *ppos) 340 { 341 struct appldata_ops *ops = NULL, *tmp_ops; 342 int rc, len, found; 343 char buf[2]; 344 struct list_head *lh; 345 346 found = 0; 347 mutex_lock(&appldata_ops_mutex); 348 list_for_each(lh, &appldata_ops_list) { 349 tmp_ops = list_entry(lh, struct appldata_ops, list); 350 if (&tmp_ops->ctl_table[2] == ctl) { 351 found = 1; 352 } 353 } 354 if (!found) { 355 mutex_unlock(&appldata_ops_mutex); 356 return -ENODEV; 357 } 358 ops = ctl->data; 359 if (!try_module_get(ops->owner)) { // protect this function 360 mutex_unlock(&appldata_ops_mutex); 361 return -ENODEV; 362 } 363 mutex_unlock(&appldata_ops_mutex); 364 365 if (!*lenp || *ppos) { 366 *lenp = 0; 367 module_put(ops->owner); 368 return 0; 369 } 370 if (!write) { 371 len = sprintf(buf, ops->active ? "1\n" : "0\n"); 372 if (len > *lenp) 373 len = *lenp; 374 if (copy_to_user(buffer, buf, len)) { 375 module_put(ops->owner); 376 return -EFAULT; 377 } 378 goto out; 379 } 380 len = *lenp; 381 if (copy_from_user(buf, buffer, 382 len > sizeof(buf) ? sizeof(buf) : len)) { 383 module_put(ops->owner); 384 return -EFAULT; 385 } 386 387 mutex_lock(&appldata_ops_mutex); 388 if ((buf[0] == '1') && (ops->active == 0)) { 389 // protect work queue callback 390 if (!try_module_get(ops->owner)) { 391 mutex_unlock(&appldata_ops_mutex); 392 module_put(ops->owner); 393 return -ENODEV; 394 } 395 ops->callback(ops->data); // init record 396 rc = appldata_diag(ops->record_nr, 397 APPLDATA_START_INTERVAL_REC, 398 (unsigned long) ops->data, ops->size, 399 ops->mod_lvl); 400 if (rc != 0) { 401 pr_err("Starting the data collection for %s " 402 "failed with rc=%d\n", ops->name, rc); 403 module_put(ops->owner); 404 } else 405 ops->active = 1; 406 } else if ((buf[0] == '0') && (ops->active == 1)) { 407 ops->active = 0; 408 rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC, 409 (unsigned long) ops->data, ops->size, 410 ops->mod_lvl); 411 if (rc != 0) 412 pr_err("Stopping the data collection for %s " 413 "failed with rc=%d\n", ops->name, rc); 414 module_put(ops->owner); 415 } 416 mutex_unlock(&appldata_ops_mutex); 417 out: 418 *lenp = len; 419 *ppos += len; 420 module_put(ops->owner); 421 return 0; 422 } 423 424 /*************************** /proc stuff <END> *******************************/ 425 426 427 /************************* module-ops management *****************************/ 428 /* 429 * appldata_register_ops() 430 * 431 * update ops list, register /proc/sys entries 432 */ 433 int appldata_register_ops(struct appldata_ops *ops) 434 { 435 if (ops->size > APPLDATA_MAX_REC_SIZE) 436 return -EINVAL; 437 438 ops->ctl_table = kzalloc(4 * sizeof(struct ctl_table), GFP_KERNEL); 439 if (!ops->ctl_table) 440 return -ENOMEM; 441 442 mutex_lock(&appldata_ops_mutex); 443 list_add(&ops->list, &appldata_ops_list); 444 mutex_unlock(&appldata_ops_mutex); 445 446 ops->ctl_table[0].procname = appldata_proc_name; 447 ops->ctl_table[0].maxlen = 0; 448 ops->ctl_table[0].mode = S_IRUGO | S_IXUGO; 449 ops->ctl_table[0].child = &ops->ctl_table[2]; 450 451 ops->ctl_table[2].procname = ops->name; 452 ops->ctl_table[2].mode = S_IRUGO | S_IWUSR; 453 ops->ctl_table[2].proc_handler = appldata_generic_handler; 454 ops->ctl_table[2].data = ops; 455 456 ops->sysctl_header = register_sysctl_table(ops->ctl_table); 457 if (!ops->sysctl_header) 458 goto out; 459 return 0; 460 out: 461 mutex_lock(&appldata_ops_mutex); 462 list_del(&ops->list); 463 mutex_unlock(&appldata_ops_mutex); 464 kfree(ops->ctl_table); 465 return -ENOMEM; 466 } 467 468 /* 469 * appldata_unregister_ops() 470 * 471 * update ops list, unregister /proc entries, stop DIAG if necessary 472 */ 473 void appldata_unregister_ops(struct appldata_ops *ops) 474 { 475 mutex_lock(&appldata_ops_mutex); 476 list_del(&ops->list); 477 mutex_unlock(&appldata_ops_mutex); 478 unregister_sysctl_table(ops->sysctl_header); 479 kfree(ops->ctl_table); 480 } 481 /********************** module-ops management <END> **************************/ 482 483 484 /**************************** suspend / resume *******************************/ 485 static int appldata_freeze(struct device *dev) 486 { 487 struct appldata_ops *ops; 488 int rc; 489 struct list_head *lh; 490 491 get_online_cpus(); 492 spin_lock(&appldata_timer_lock); 493 if (appldata_timer_active) { 494 __appldata_vtimer_setup(APPLDATA_DEL_TIMER); 495 appldata_timer_suspended = 1; 496 } 497 spin_unlock(&appldata_timer_lock); 498 put_online_cpus(); 499 500 mutex_lock(&appldata_ops_mutex); 501 list_for_each(lh, &appldata_ops_list) { 502 ops = list_entry(lh, struct appldata_ops, list); 503 if (ops->active == 1) { 504 rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC, 505 (unsigned long) ops->data, ops->size, 506 ops->mod_lvl); 507 if (rc != 0) 508 pr_err("Stopping the data collection for %s " 509 "failed with rc=%d\n", ops->name, rc); 510 } 511 } 512 mutex_unlock(&appldata_ops_mutex); 513 return 0; 514 } 515 516 static int appldata_restore(struct device *dev) 517 { 518 struct appldata_ops *ops; 519 int rc; 520 struct list_head *lh; 521 522 get_online_cpus(); 523 spin_lock(&appldata_timer_lock); 524 if (appldata_timer_suspended) { 525 __appldata_vtimer_setup(APPLDATA_ADD_TIMER); 526 appldata_timer_suspended = 0; 527 } 528 spin_unlock(&appldata_timer_lock); 529 put_online_cpus(); 530 531 mutex_lock(&appldata_ops_mutex); 532 list_for_each(lh, &appldata_ops_list) { 533 ops = list_entry(lh, struct appldata_ops, list); 534 if (ops->active == 1) { 535 ops->callback(ops->data); // init record 536 rc = appldata_diag(ops->record_nr, 537 APPLDATA_START_INTERVAL_REC, 538 (unsigned long) ops->data, ops->size, 539 ops->mod_lvl); 540 if (rc != 0) { 541 pr_err("Starting the data collection for %s " 542 "failed with rc=%d\n", ops->name, rc); 543 } 544 } 545 } 546 mutex_unlock(&appldata_ops_mutex); 547 return 0; 548 } 549 550 static int appldata_thaw(struct device *dev) 551 { 552 return appldata_restore(dev); 553 } 554 555 static struct dev_pm_ops appldata_pm_ops = { 556 .freeze = appldata_freeze, 557 .thaw = appldata_thaw, 558 .restore = appldata_restore, 559 }; 560 561 static struct platform_driver appldata_pdrv = { 562 .driver = { 563 .name = "appldata", 564 .owner = THIS_MODULE, 565 .pm = &appldata_pm_ops, 566 }, 567 }; 568 /************************* suspend / resume <END> ****************************/ 569 570 571 /******************************* init / exit *********************************/ 572 573 static void __cpuinit appldata_online_cpu(int cpu) 574 { 575 init_virt_timer(&per_cpu(appldata_timer, cpu)); 576 per_cpu(appldata_timer, cpu).function = appldata_timer_function; 577 per_cpu(appldata_timer, cpu).data = (unsigned long) 578 &appldata_work; 579 atomic_inc(&appldata_expire_count); 580 spin_lock(&appldata_timer_lock); 581 __appldata_vtimer_setup(APPLDATA_MOD_TIMER); 582 spin_unlock(&appldata_timer_lock); 583 } 584 585 static void __cpuinit appldata_offline_cpu(int cpu) 586 { 587 del_virt_timer(&per_cpu(appldata_timer, cpu)); 588 if (atomic_dec_and_test(&appldata_expire_count)) { 589 atomic_set(&appldata_expire_count, num_online_cpus()); 590 queue_work(appldata_wq, &appldata_work); 591 } 592 spin_lock(&appldata_timer_lock); 593 __appldata_vtimer_setup(APPLDATA_MOD_TIMER); 594 spin_unlock(&appldata_timer_lock); 595 } 596 597 static int __cpuinit appldata_cpu_notify(struct notifier_block *self, 598 unsigned long action, 599 void *hcpu) 600 { 601 switch (action) { 602 case CPU_ONLINE: 603 case CPU_ONLINE_FROZEN: 604 appldata_online_cpu((long) hcpu); 605 break; 606 case CPU_DEAD: 607 case CPU_DEAD_FROZEN: 608 appldata_offline_cpu((long) hcpu); 609 break; 610 default: 611 break; 612 } 613 return NOTIFY_OK; 614 } 615 616 static struct notifier_block __cpuinitdata appldata_nb = { 617 .notifier_call = appldata_cpu_notify, 618 }; 619 620 /* 621 * appldata_init() 622 * 623 * init timer, register /proc entries 624 */ 625 static int __init appldata_init(void) 626 { 627 int i, rc; 628 629 rc = platform_driver_register(&appldata_pdrv); 630 if (rc) 631 return rc; 632 633 appldata_pdev = platform_device_register_simple("appldata", -1, NULL, 634 0); 635 if (IS_ERR(appldata_pdev)) { 636 rc = PTR_ERR(appldata_pdev); 637 goto out_driver; 638 } 639 appldata_wq = create_singlethread_workqueue("appldata"); 640 if (!appldata_wq) { 641 rc = -ENOMEM; 642 goto out_device; 643 } 644 645 get_online_cpus(); 646 for_each_online_cpu(i) 647 appldata_online_cpu(i); 648 put_online_cpus(); 649 650 /* Register cpu hotplug notifier */ 651 register_hotcpu_notifier(&appldata_nb); 652 653 appldata_sysctl_header = register_sysctl_table(appldata_dir_table); 654 return 0; 655 656 out_device: 657 platform_device_unregister(appldata_pdev); 658 out_driver: 659 platform_driver_unregister(&appldata_pdrv); 660 return rc; 661 } 662 663 __initcall(appldata_init); 664 665 /**************************** init / exit <END> ******************************/ 666 667 EXPORT_SYMBOL_GPL(appldata_register_ops); 668 EXPORT_SYMBOL_GPL(appldata_unregister_ops); 669 EXPORT_SYMBOL_GPL(appldata_diag); 670 671 #ifdef CONFIG_SWAP 672 EXPORT_SYMBOL_GPL(si_swapinfo); 673 #endif 674 EXPORT_SYMBOL_GPL(nr_threads); 675 EXPORT_SYMBOL_GPL(nr_running); 676 EXPORT_SYMBOL_GPL(nr_iowait); 677