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