sysctl: remove "struct file *" argument of ->proc_handler
[safe/jmp/linux-2.6] / arch / s390 / appldata / appldata_base.c
index c9da7d1..b55fd7e 100644 (file)
@@ -5,11 +5,14 @@
  * Exports appldata_register_ops() and appldata_unregister_ops() for the
  * data gathering modules.
  *
- * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Copyright IBM Corp. 2003, 2009
  *
  * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
+#define KMSG_COMPONENT "appldata"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -23,6 +26,8 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/workqueue.h>
+#include <linux/suspend.h>
+#include <linux/platform_device.h>
 #include <asm/appldata.h>
 #include <asm/timer.h>
 #include <asm/uaccess.h>
 #include "appldata.h"
 
 
-#define MY_PRINT_NAME  "appldata"              /* for debug messages, etc. */
 #define APPLDATA_CPU_INTERVAL  10000           /* default (CPU) time for
                                                   sampling interval in
                                                   milliseconds */
 
 #define TOD_MICRO      0x01000                 /* nr. of TOD clock units
                                                   for 1 microsecond */
+
+static struct platform_device *appldata_pdev;
+
 /*
  * /proc entries (sysctl)
  */
 static const char appldata_proc_name[APPLDATA_PROC_NAME_LENGTH] = "appldata";
-static int appldata_timer_handler(ctl_table *ctl, int write, struct file *filp,
+static int appldata_timer_handler(ctl_table *ctl, int write,
                                  void __user *buffer, size_t *lenp, loff_t *ppos);
 static int appldata_interval_handler(ctl_table *ctl, int write,
-                                        struct file *filp,
                                         void __user *buffer,
                                         size_t *lenp, loff_t *ppos);
 
 static struct ctl_table_header *appldata_sysctl_header;
 static struct ctl_table appldata_table[] = {
        {
-               .ctl_name       = CTL_APPLDATA_TIMER,
                .procname       = "timer",
                .mode           = S_IRUGO | S_IWUSR,
                .proc_handler   = &appldata_timer_handler,
        },
        {
-               .ctl_name       = CTL_APPLDATA_INTERVAL,
                .procname       = "interval",
                .mode           = S_IRUGO | S_IWUSR,
                .proc_handler   = &appldata_interval_handler,
        },
-       { .ctl_name = 0 }
+       { },
 };
 
 static struct ctl_table appldata_dir_table[] = {
        {
-               .ctl_name       = CTL_APPLDATA,
                .procname       = appldata_proc_name,
                .maxlen         = 0,
                .mode           = S_IRUGO | S_IXUGO,
                .child          = appldata_table,
        },
-       { .ctl_name = 0 }
+       { },
 };
 
 /*
@@ -87,6 +90,7 @@ static atomic_t appldata_expire_count = ATOMIC_INIT(0);
 static DEFINE_SPINLOCK(appldata_timer_lock);
 static int appldata_interval = APPLDATA_CPU_INTERVAL;
 static int appldata_timer_active;
+static int appldata_timer_suspended = 0;
 
 /*
  * Work queue
@@ -99,7 +103,7 @@ static DECLARE_WORK(appldata_work, appldata_work_fn);
 /*
  * Ops list
  */
-static DEFINE_SPINLOCK(appldata_ops_lock);
+static DEFINE_MUTEX(appldata_ops_mutex);
 static LIST_HEAD(appldata_ops_list);
 
 
@@ -111,9 +115,6 @@ static LIST_HEAD(appldata_ops_list);
  */
 static void appldata_timer_function(unsigned long data)
 {
-       P_DEBUG("   -= Timer =-\n");
-       P_DEBUG("CPU: %i, expire_count: %i\n", smp_processor_id(),
-               atomic_read(&appldata_expire_count));
        if (atomic_dec_and_test(&appldata_expire_count)) {
                atomic_set(&appldata_expire_count, num_online_cpus());
                queue_work(appldata_wq, (struct work_struct *) data);
@@ -131,18 +132,17 @@ static void appldata_work_fn(struct work_struct *work)
        struct appldata_ops *ops;
        int i;
 
-       P_DEBUG("  -= Work Queue =-\n");
        i = 0;
-       spin_lock(&appldata_ops_lock);
+       get_online_cpus();
+       mutex_lock(&appldata_ops_mutex);
        list_for_each(lh, &appldata_ops_list) {
                ops = list_entry(lh, struct appldata_ops, list);
-               P_DEBUG("list_for_each loop: %i) active = %u, name = %s\n",
-                       ++i, ops->active, ops->name);
                if (ops->active == 1) {
                        ops->callback(ops->data);
                }
        }
-       spin_unlock(&appldata_ops_lock);
+       mutex_unlock(&appldata_ops_mutex);
+       put_online_cpus();
 }
 
 /*
@@ -173,7 +173,7 @@ int appldata_diag(char record_nr, u16 function, unsigned long buffer,
 /*
  * appldata_mod_vtimer_wrap()
  *
- * wrapper function for mod_virt_timer(), because smp_call_function_on()
+ * wrapper function for mod_virt_timer(), because smp_call_function_single()
  * accepts only one parameter.
  */
 static void __appldata_mod_vtimer_wrap(void *p) {
@@ -181,7 +181,7 @@ static void __appldata_mod_vtimer_wrap(void *p) {
                struct vtimer_list *timer;
                u64    expires;
        } *args = p;
-       mod_virt_timer(args->timer, args->expires);
+       mod_virt_timer_periodic(args->timer, args->expires);
 }
 
 #define APPLDATA_ADD_TIMER     0
@@ -208,12 +208,11 @@ __appldata_vtimer_setup(int cmd)
                                          num_online_cpus()) * TOD_MICRO;
                for_each_online_cpu(i) {
                        per_cpu(appldata_timer, i).expires = per_cpu_interval;
-                       smp_call_function_on(add_virt_timer_periodic,
-                                            &per_cpu(appldata_timer, i),
-                                            0, 1, i);
+                       smp_call_function_single(i, add_virt_timer_periodic,
+                                                &per_cpu(appldata_timer, i),
+                                                1);
                }
                appldata_timer_active = 1;
-               P_INFO("Monitoring timer started.\n");
                break;
        case APPLDATA_DEL_TIMER:
                for_each_online_cpu(i)
@@ -222,7 +221,6 @@ __appldata_vtimer_setup(int cmd)
                        break;
                appldata_timer_active = 0;
                atomic_set(&appldata_expire_count, num_online_cpus());
-               P_INFO("Monitoring timer stopped.\n");
                break;
        case APPLDATA_MOD_TIMER:
                per_cpu_interval = (u64) (appldata_interval*1000 /
@@ -236,8 +234,8 @@ __appldata_vtimer_setup(int cmd)
                        } args;
                        args.timer = &per_cpu(appldata_timer, i);
                        args.expires = per_cpu_interval;
-                       smp_call_function_on(__appldata_mod_vtimer_wrap,
-                                            &args, 0, 1, i);
+                       smp_call_function_single(i, __appldata_mod_vtimer_wrap,
+                                                &args, 1);
                }
        }
 }
@@ -248,7 +246,7 @@ __appldata_vtimer_setup(int cmd)
  * Start/Stop timer, show status of timer (0 = not active, 1 = active)
  */
 static int
-appldata_timer_handler(ctl_table *ctl, int write, struct file *filp,
+appldata_timer_handler(ctl_table *ctl, int write,
                           void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        int len;
@@ -269,12 +267,14 @@ appldata_timer_handler(ctl_table *ctl, int write, struct file *filp,
        len = *lenp;
        if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len))
                return -EFAULT;
+       get_online_cpus();
        spin_lock(&appldata_timer_lock);
        if (buf[0] == '1')
                __appldata_vtimer_setup(APPLDATA_ADD_TIMER);
        else if (buf[0] == '0')
                __appldata_vtimer_setup(APPLDATA_DEL_TIMER);
        spin_unlock(&appldata_timer_lock);
+       put_online_cpus();
 out:
        *lenp = len;
        *ppos += len;
@@ -288,7 +288,7 @@ out:
  * current timer interval.
  */
 static int
-appldata_interval_handler(ctl_table *ctl, int write, struct file *filp,
+appldata_interval_handler(ctl_table *ctl, int write,
                           void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        int len, interval;
@@ -312,18 +312,15 @@ appldata_interval_handler(ctl_table *ctl, int write, struct file *filp,
        }
        interval = 0;
        sscanf(buf, "%i", &interval);
-       if (interval <= 0) {
-               P_ERROR("Timer CPU interval has to be > 0!\n");
+       if (interval <= 0)
                return -EINVAL;
-       }
 
+       get_online_cpus();
        spin_lock(&appldata_timer_lock);
        appldata_interval = interval;
        __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
        spin_unlock(&appldata_timer_lock);
-
-       P_INFO("Monitoring CPU interval set to %u milliseconds.\n",
-                interval);
+       put_online_cpus();
 out:
        *lenp = len;
        *ppos += len;
@@ -337,7 +334,7 @@ out:
  * monitoring (0 = not in process, 1 = in process)
  */
 static int
-appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
+appldata_generic_handler(ctl_table *ctl, int write,
                           void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        struct appldata_ops *ops = NULL, *tmp_ops;
@@ -346,7 +343,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
        struct list_head *lh;
 
        found = 0;
-       spin_lock(&appldata_ops_lock);
+       mutex_lock(&appldata_ops_mutex);
        list_for_each(lh, &appldata_ops_list) {
                tmp_ops = list_entry(lh, struct appldata_ops, list);
                if (&tmp_ops->ctl_table[2] == ctl) {
@@ -354,15 +351,15 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                }
        }
        if (!found) {
-               spin_unlock(&appldata_ops_lock);
+               mutex_unlock(&appldata_ops_mutex);
                return -ENODEV;
        }
        ops = ctl->data;
        if (!try_module_get(ops->owner)) {      // protect this function
-               spin_unlock(&appldata_ops_lock);
+               mutex_unlock(&appldata_ops_mutex);
                return -ENODEV;
        }
-       spin_unlock(&appldata_ops_lock);
+       mutex_unlock(&appldata_ops_mutex);
 
        if (!*lenp || *ppos) {
                *lenp = 0;
@@ -386,11 +383,11 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                return -EFAULT;
        }
 
-       spin_lock(&appldata_ops_lock);
+       mutex_lock(&appldata_ops_mutex);
        if ((buf[0] == '1') && (ops->active == 0)) {
                // protect work queue callback
                if (!try_module_get(ops->owner)) {
-                       spin_unlock(&appldata_ops_lock);
+                       mutex_unlock(&appldata_ops_mutex);
                        module_put(ops->owner);
                        return -ENODEV;
                }
@@ -400,29 +397,22 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
                                        (unsigned long) ops->data, ops->size,
                                        ops->mod_lvl);
                if (rc != 0) {
-                       P_ERROR("START DIAG 0xDC for %s failed, "
-                               "return code: %d\n", ops->name, rc);
+                       pr_err("Starting the data collection for %s "
+                              "failed with rc=%d\n", ops->name, rc);
                        module_put(ops->owner);
-               } else {
-                       P_INFO("Monitoring %s data enabled, "
-                               "DIAG 0xDC started.\n", ops->name);
+               } else
                        ops->active = 1;
-               }
        } else if ((buf[0] == '0') && (ops->active == 1)) {
                ops->active = 0;
                rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
                                (unsigned long) ops->data, ops->size,
                                ops->mod_lvl);
-               if (rc != 0) {
-                       P_ERROR("STOP DIAG 0xDC for %s failed, "
-                               "return code: %d\n", ops->name, rc);
-               } else {
-                       P_INFO("Monitoring %s data disabled, "
-                               "DIAG 0xDC stopped.\n", ops->name);
-               }
+               if (rc != 0)
+                       pr_err("Stopping the data collection for %s "
+                              "failed with rc=%d\n", ops->name, rc);
                module_put(ops->owner);
        }
-       spin_unlock(&appldata_ops_lock);
+       mutex_unlock(&appldata_ops_mutex);
 out:
        *lenp = len;
        *ppos += len;
@@ -441,75 +431,37 @@ out:
  */
 int appldata_register_ops(struct appldata_ops *ops)
 {
-       struct list_head *lh;
-       struct appldata_ops *tmp_ops;
-       int i;
-
-       i = 0;
+       if (ops->size > APPLDATA_MAX_REC_SIZE)
+               return -EINVAL;
 
-       if ((ops->size > APPLDATA_MAX_REC_SIZE) ||
-               (ops->size < 0)){
-               P_ERROR("Invalid size of %s record = %i, maximum = %i!\n",
-                       ops->name, ops->size, APPLDATA_MAX_REC_SIZE);
-               return -ENOMEM;
-       }
-       if ((ops->ctl_nr == CTL_APPLDATA) ||
-           (ops->ctl_nr == CTL_APPLDATA_TIMER) ||
-           (ops->ctl_nr == CTL_APPLDATA_INTERVAL)) {
-               P_ERROR("ctl_nr %i already in use!\n", ops->ctl_nr);
-               return -EBUSY;
-       }
-       ops->ctl_table = kzalloc(4*sizeof(struct ctl_table), GFP_KERNEL);
-       if (ops->ctl_table == NULL) {
-               P_ERROR("Not enough memory for %s ctl_table!\n", ops->name);
+       ops->ctl_table = kzalloc(4 * sizeof(struct ctl_table), GFP_KERNEL);
+       if (!ops->ctl_table)
                return -ENOMEM;
-       }
 
-       spin_lock(&appldata_ops_lock);
-       list_for_each(lh, &appldata_ops_list) {
-               tmp_ops = list_entry(lh, struct appldata_ops, list);
-               P_DEBUG("register_ops loop: %i) name = %s, ctl = %i\n",
-                       ++i, tmp_ops->name, tmp_ops->ctl_nr);
-               P_DEBUG("Comparing %s (ctl %i) with %s (ctl %i)\n",
-                       tmp_ops->name, tmp_ops->ctl_nr, ops->name,
-                       ops->ctl_nr);
-               if (strncmp(tmp_ops->name, ops->name,
-                               APPLDATA_PROC_NAME_LENGTH) == 0) {
-                       P_ERROR("Name \"%s\" already registered!\n", ops->name);
-                       kfree(ops->ctl_table);
-                       spin_unlock(&appldata_ops_lock);
-                       return -EBUSY;
-               }
-               if (tmp_ops->ctl_nr == ops->ctl_nr) {
-                       P_ERROR("ctl_nr %i already registered!\n", ops->ctl_nr);
-                       kfree(ops->ctl_table);
-                       spin_unlock(&appldata_ops_lock);
-                       return -EBUSY;
-               }
-       }
+       mutex_lock(&appldata_ops_mutex);
        list_add(&ops->list, &appldata_ops_list);
-       spin_unlock(&appldata_ops_lock);
+       mutex_unlock(&appldata_ops_mutex);
 
-       ops->ctl_table[0].ctl_name = CTL_APPLDATA;
        ops->ctl_table[0].procname = appldata_proc_name;
        ops->ctl_table[0].maxlen   = 0;
        ops->ctl_table[0].mode     = S_IRUGO | S_IXUGO;
        ops->ctl_table[0].child    = &ops->ctl_table[2];
 
-       ops->ctl_table[1].ctl_name = 0;
-
-       ops->ctl_table[2].ctl_name = ops->ctl_nr;
        ops->ctl_table[2].procname = ops->name;
        ops->ctl_table[2].mode     = S_IRUGO | S_IWUSR;
        ops->ctl_table[2].proc_handler = appldata_generic_handler;
        ops->ctl_table[2].data = ops;
 
-       ops->ctl_table[3].ctl_name = 0;
-
-       ops->sysctl_header = register_sysctl_table(ops->ctl_table,1);
-
-       P_INFO("%s-ops registered!\n", ops->name);
+       ops->sysctl_header = register_sysctl_table(ops->ctl_table);
+       if (!ops->sysctl_header)
+               goto out;
        return 0;
+out:
+       mutex_lock(&appldata_ops_mutex);
+       list_del(&ops->list);
+       mutex_unlock(&appldata_ops_mutex);
+       kfree(ops->ctl_table);
+       return -ENOMEM;
 }
 
 /*
@@ -519,24 +471,105 @@ int appldata_register_ops(struct appldata_ops *ops)
  */
 void appldata_unregister_ops(struct appldata_ops *ops)
 {
-       void *table;
-       spin_lock(&appldata_ops_lock);
+       mutex_lock(&appldata_ops_mutex);
        list_del(&ops->list);
-       /* at that point any incoming access will fail */
-       table = ops->ctl_table;
-       ops->ctl_table = NULL;
-       spin_unlock(&appldata_ops_lock);
+       mutex_unlock(&appldata_ops_mutex);
        unregister_sysctl_table(ops->sysctl_header);
-       kfree(table);
-       P_INFO("%s-ops unregistered!\n", ops->name);
+       kfree(ops->ctl_table);
 }
 /********************** module-ops management <END> **************************/
 
 
+/**************************** suspend / resume *******************************/
+static int appldata_freeze(struct device *dev)
+{
+       struct appldata_ops *ops;
+       int rc;
+       struct list_head *lh;
+
+       get_online_cpus();
+       spin_lock(&appldata_timer_lock);
+       if (appldata_timer_active) {
+               __appldata_vtimer_setup(APPLDATA_DEL_TIMER);
+               appldata_timer_suspended = 1;
+       }
+       spin_unlock(&appldata_timer_lock);
+       put_online_cpus();
+
+       mutex_lock(&appldata_ops_mutex);
+       list_for_each(lh, &appldata_ops_list) {
+               ops = list_entry(lh, struct appldata_ops, list);
+               if (ops->active == 1) {
+                       rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
+                                       (unsigned long) ops->data, ops->size,
+                                       ops->mod_lvl);
+                       if (rc != 0)
+                               pr_err("Stopping the data collection for %s "
+                                      "failed with rc=%d\n", ops->name, rc);
+               }
+       }
+       mutex_unlock(&appldata_ops_mutex);
+       return 0;
+}
+
+static int appldata_restore(struct device *dev)
+{
+       struct appldata_ops *ops;
+       int rc;
+       struct list_head *lh;
+
+       get_online_cpus();
+       spin_lock(&appldata_timer_lock);
+       if (appldata_timer_suspended) {
+               __appldata_vtimer_setup(APPLDATA_ADD_TIMER);
+               appldata_timer_suspended = 0;
+       }
+       spin_unlock(&appldata_timer_lock);
+       put_online_cpus();
+
+       mutex_lock(&appldata_ops_mutex);
+       list_for_each(lh, &appldata_ops_list) {
+               ops = list_entry(lh, struct appldata_ops, list);
+               if (ops->active == 1) {
+                       ops->callback(ops->data);       // init record
+                       rc = appldata_diag(ops->record_nr,
+                                       APPLDATA_START_INTERVAL_REC,
+                                       (unsigned long) ops->data, ops->size,
+                                       ops->mod_lvl);
+                       if (rc != 0) {
+                               pr_err("Starting the data collection for %s "
+                                      "failed with rc=%d\n", ops->name, rc);
+                       }
+               }
+       }
+       mutex_unlock(&appldata_ops_mutex);
+       return 0;
+}
+
+static int appldata_thaw(struct device *dev)
+{
+       return appldata_restore(dev);
+}
+
+static struct dev_pm_ops appldata_pm_ops = {
+       .freeze         = appldata_freeze,
+       .thaw           = appldata_thaw,
+       .restore        = appldata_restore,
+};
+
+static struct platform_driver appldata_pdrv = {
+       .driver = {
+               .name   = "appldata",
+               .owner  = THIS_MODULE,
+               .pm     = &appldata_pm_ops,
+       },
+};
+/************************* suspend / resume <END> ****************************/
+
+
 /******************************* init / exit *********************************/
 
-static void
-appldata_online_cpu(int cpu)
+static void __cpuinit appldata_online_cpu(int cpu)
 {
        init_virt_timer(&per_cpu(appldata_timer, cpu));
        per_cpu(appldata_timer, cpu).function = appldata_timer_function;
@@ -548,8 +581,7 @@ appldata_online_cpu(int cpu)
        spin_unlock(&appldata_timer_lock);
 }
 
-static void
-appldata_offline_cpu(int cpu)
+static void __cpuinit appldata_offline_cpu(int cpu)
 {
        del_virt_timer(&per_cpu(appldata_timer, cpu));
        if (atomic_dec_and_test(&appldata_expire_count)) {
@@ -561,15 +593,17 @@ appldata_offline_cpu(int cpu)
        spin_unlock(&appldata_timer_lock);
 }
 
-static int __cpuinit
-appldata_cpu_notify(struct notifier_block *self,
-                   unsigned long action, void *hcpu)
+static int __cpuinit appldata_cpu_notify(struct notifier_block *self,
+                                        unsigned long action,
+                                        void *hcpu)
 {
        switch (action) {
        case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
                appldata_online_cpu((long) hcpu);
                break;
        case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
                appldata_offline_cpu((long) hcpu);
                break;
        default:
@@ -578,7 +612,7 @@ appldata_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static struct notifier_block appldata_nb = {
+static struct notifier_block __cpuinitdata appldata_nb = {
        .notifier_call = appldata_cpu_notify,
 };
 
@@ -589,124 +623,53 @@ static struct notifier_block appldata_nb = {
  */
 static int __init appldata_init(void)
 {
-       int i;
+       int i, rc;
 
-       P_DEBUG("sizeof(parameter_list) = %lu\n",
-               sizeof(struct appldata_parameter_list));
+       rc = platform_driver_register(&appldata_pdrv);
+       if (rc)
+               return rc;
 
+       appldata_pdev = platform_device_register_simple("appldata", -1, NULL,
+                                                       0);
+       if (IS_ERR(appldata_pdev)) {
+               rc = PTR_ERR(appldata_pdev);
+               goto out_driver;
+       }
        appldata_wq = create_singlethread_workqueue("appldata");
        if (!appldata_wq) {
-               P_ERROR("Could not create work queue\n");
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto out_device;
        }
 
+       get_online_cpus();
        for_each_online_cpu(i)
                appldata_online_cpu(i);
+       put_online_cpus();
 
        /* Register cpu hotplug notifier */
        register_hotcpu_notifier(&appldata_nb);
 
-       appldata_sysctl_header = register_sysctl_table(appldata_dir_table, 1);
-#ifdef MODULE
-       appldata_dir_table[0].de->owner = THIS_MODULE;
-       appldata_table[0].de->owner = THIS_MODULE;
-       appldata_table[1].de->owner = THIS_MODULE;
-#endif
-
-       P_DEBUG("Base interface initialized.\n");
+       appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
        return 0;
-}
 
-/*
- * appldata_exit()
- *
- * stop timer, unregister /proc entries
- */
-static void __exit appldata_exit(void)
-{
-       struct list_head *lh;
-       struct appldata_ops *ops;
-       int rc, i;
-
-       P_DEBUG("Unloading module ...\n");
-       /*
-        * ops list should be empty, but just in case something went wrong...
-        */
-       spin_lock(&appldata_ops_lock);
-       list_for_each(lh, &appldata_ops_list) {
-               ops = list_entry(lh, struct appldata_ops, list);
-               rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
-                               (unsigned long) ops->data, ops->size,
-                               ops->mod_lvl);
-               if (rc != 0) {
-                       P_ERROR("STOP DIAG 0xDC for %s failed, "
-                               "return code: %d\n", ops->name, rc);
-               }
-       }
-       spin_unlock(&appldata_ops_lock);
-
-       for_each_online_cpu(i)
-               appldata_offline_cpu(i);
-
-       appldata_timer_active = 0;
-
-       unregister_sysctl_table(appldata_sysctl_header);
-
-       destroy_workqueue(appldata_wq);
-       P_DEBUG("... module unloaded!\n");
+out_device:
+       platform_device_unregister(appldata_pdev);
+out_driver:
+       platform_driver_unregister(&appldata_pdrv);
+       return rc;
 }
-/**************************** init / exit <END> ******************************/
 
+__initcall(appldata_init);
 
-module_init(appldata_init);
-module_exit(appldata_exit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Gerald Schaefer");
-MODULE_DESCRIPTION("Linux-VM Monitor Stream, base infrastructure");
+/**************************** init / exit <END> ******************************/
 
 EXPORT_SYMBOL_GPL(appldata_register_ops);
 EXPORT_SYMBOL_GPL(appldata_unregister_ops);
 EXPORT_SYMBOL_GPL(appldata_diag);
 
-#ifdef MODULE
-/*
- * Kernel symbols needed by appldata_mem and appldata_os modules.
- * However, if this file is compiled as a module (for testing only), these
- * symbols are not exported. In this case, we define them locally and export
- * those.
- */
-void si_swapinfo(struct sysinfo *val)
-{
-       val->freeswap = -1ul;
-       val->totalswap = -1ul;
-}
-
-unsigned long avenrun[3] = {-1 - FIXED_1/200, -1 - FIXED_1/200,
-                               -1 - FIXED_1/200};
-int nr_threads = -1;
-
-void get_full_page_state(struct page_state *ps)
-{
-       memset(ps, -1, sizeof(struct page_state));
-}
-
-unsigned long nr_running(void)
-{
-       return -1;
-}
-
-unsigned long nr_iowait(void)
-{
-       return -1;
-}
-
-/*unsigned long nr_context_switches(void)
-{
-       return -1;
-}*/
-#endif /* MODULE */
+#ifdef CONFIG_SWAP
 EXPORT_SYMBOL_GPL(si_swapinfo);
+#endif
 EXPORT_SYMBOL_GPL(nr_threads);
 EXPORT_SYMBOL_GPL(nr_running);
 EXPORT_SYMBOL_GPL(nr_iowait);
-//EXPORT_SYMBOL_GPL(nr_context_switches);