x86: Constify a few items
[linux-3.10.git] / arch / x86 / kernel / apm_32.c
index 2467df7..66b5faf 100644 (file)
@@ -66,7 +66,7 @@
  *    1.5: Fix segment register reloading (in case of bad segments saved
  *         across BIOS call).
  *         Stephen Rothwell
- *    1.6: Cope with complier/assembler differences.
+ *    1.6: Cope with compiler/assembler differences.
  *         Only try to turn off the first display device.
  *         Fix OOPS at power off with no APM BIOS by Jan Echternach
  *                   <echter@informatik.uni-rostock.de>
  *         is now the way life works).
  *         Fix thinko in suspend() (wrong return).
  *         Notify drivers on critical suspend.
- *         Make kapmd absorb more idle time (Pavel Machek <pavel@suse.cz>
+ *         Make kapmd absorb more idle time (Pavel Machek <pavel@ucw.cz>
  *         modified by sfr).
  *         Disable interrupts while we are suspended (Andy Henroid
  *         <andy_henroid@yahoo.com> fixed by sfr).
  *         Work around byte swap bug in one of the Vaio's BIOS's
  *         (Marc Boucher <marc@mbsi.ca>).
  *         Exposed the disable flag to dmi so that we can handle known
- *         broken APM (Alan Cox <alan@redhat.com>).
+ *         broken APM (Alan Cox <alan@lxorguk.ukuu.org.uk>).
  *   1.14ac: If the BIOS says "I slowed the CPU down" then don't spin
- *         calling it - instead idle. (Alan Cox <alan@redhat.com>)
+ *         calling it - instead idle. (Alan Cox <alan@lxorguk.ukuu.org.uk>)
  *         If an APM idle fails log it and idle sensibly
  *   1.15: Don't queue events to clients who open the device O_WRONLY.
  *         Don't expect replies from clients who open the device O_RDONLY.
  *   Intel Order Number 241704-001.  Microsoft Part Number 781-110-X01.
  *
  * [This document is available free from Intel by calling 800.628.8686 (fax
- * 916.356.6100) or 800.548.4725; or via anonymous ftp from
- * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc.  It is also
+ * 916.356.6100) or 800.548.4725; or from
+ * http://www.microsoft.com/whdc/archive/amp_12.mspx  It is also
  * available from Microsoft by calling 206.882.8080.]
  *
  * APM 1.2 Reference:
  *    http://www.microsoft.com/whdc/archive/amp_12.mspx]
  */
 
+#define pr_fmt(fmt) "apm: " fmt
+
 #include <linux/module.h>
 
 #include <linux/poll.h>
 #include <linux/time.h>
 #include <linux/sched.h>
 #include <linux/pm.h>
-#include <linux/pm_legacy.h>
 #include <linux/capability.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/suspend.h>
 #include <linux/kthread.h>
 #include <linux/jiffies.h>
+#include <linux/acpi.h>
+#include <linux/syscore_ops.h>
+#include <linux/i8253.h>
+#include <linux/cpuidle.h>
 
-#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/desc.h>
-#include <asm/i8253.h>
+#include <asm/olpc.h>
 #include <asm/paravirt.h>
 #include <asm/reboot.h>
 
@@ -247,8 +251,6 @@ extern int (*console_blank_hook)(int);
 #define        APM_MINOR_DEV   134
 
 /*
- * See Documentation/Config.help for the configuration options.
- *
  * Various options can be changed at boot time as follows:
  * (We allow underscores for compatibility with the modules code)
  *     apm=on/off                      enable/disable APM
@@ -300,7 +302,7 @@ extern int (*console_blank_hook)(int);
  */
 #define APM_ZERO_SEGS
 
-#include "apm.h"
+#include <asm/apm.h>
 
 /*
  * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend.
@@ -323,7 +325,7 @@ extern int (*console_blank_hook)(int);
 /*
  * Ignore suspend events for this amount of time after a resume
  */
-#define DEFAULT_BOUNCE_INTERVAL                (3 * HZ)
+#define DEFAULT_BOUNCE_INTERVAL        (3 * HZ)
 
 /*
  * Maximum number of events stored
@@ -335,7 +337,7 @@ extern int (*console_blank_hook)(int);
  */
 struct apm_user {
        int             magic;
-       struct apm_user *       next;
+       struct apm_user *next;
        unsigned int    suser: 1;
        unsigned int    writer: 1;
        unsigned int    reader: 1;
@@ -365,50 +367,77 @@ struct apm_user {
 #endif
 #define DEFAULT_IDLE_PERIOD    (100 / 3)
 
+static int apm_cpu_idle(struct cpuidle_device *dev,
+                       struct cpuidle_driver *drv, int index);
+
+static struct cpuidle_driver apm_idle_driver = {
+       .name = "apm_idle",
+       .owner = THIS_MODULE,
+       .en_core_tk_irqen = 1,
+       .states = {
+               { /* entry 0 is for polling */ },
+               { /* entry 1 is for APM idle */
+                       .name = "APM",
+                       .desc = "APM idle",
+                       .flags = CPUIDLE_FLAG_TIME_VALID,
+                       .exit_latency = 250,    /* WAG */
+                       .target_residency = 500,        /* WAG */
+                       .enter = &apm_cpu_idle
+               },
+       },
+       .state_count = 2,
+};
+
+static struct cpuidle_device apm_cpuidle_device;
+
 /*
  * Local variables
  */
 static struct {
        unsigned long   offset;
        unsigned short  segment;
-}                              apm_bios_entry;
-static int                     clock_slowed;
-static int                     idle_threshold __read_mostly = DEFAULT_IDLE_THRESHOLD;
-static int                     idle_period __read_mostly = DEFAULT_IDLE_PERIOD;
-static int                     set_pm_idle;
-static int                     suspends_pending;
-static int                     standbys_pending;
-static int                     ignore_sys_suspend;
-static int                     ignore_normal_resume;
-static int                     bounce_interval __read_mostly = DEFAULT_BOUNCE_INTERVAL;
-
-static int                     debug __read_mostly;
-static int                     smp __read_mostly;
-static int                     apm_disabled = -1;
+} apm_bios_entry;
+static int clock_slowed;
+static int idle_threshold __read_mostly = DEFAULT_IDLE_THRESHOLD;
+static int idle_period __read_mostly = DEFAULT_IDLE_PERIOD;
+static int suspends_pending;
+static int standbys_pending;
+static int ignore_sys_suspend;
+static int ignore_normal_resume;
+static int bounce_interval __read_mostly = DEFAULT_BOUNCE_INTERVAL;
+
+static bool debug __read_mostly;
+static bool smp __read_mostly;
+static int apm_disabled = -1;
 #ifdef CONFIG_SMP
-static int                     power_off;
-#else
-static int                     power_off = 1;
-#endif
-#ifdef CONFIG_APM_REAL_MODE_POWER_OFF
-static int                     realmode_power_off = 1;
+static bool power_off;
 #else
-static int                     realmode_power_off;
+static bool power_off = 1;
 #endif
+static bool realmode_power_off;
 #ifdef CONFIG_APM_ALLOW_INTS
-static int                     allow_ints = 1;
+static bool allow_ints = 1;
 #else
-static int                     allow_ints;
+static bool allow_ints;
 #endif
-static int                     broken_psr;
+static bool broken_psr;
 
 static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
-static struct apm_user *       user_list;
+static struct apm_user *user_list;
 static DEFINE_SPINLOCK(user_list_lock);
-static const struct desc_struct        bad_bios_desc = { { { 0, 0x00409200 } } };
+static DEFINE_MUTEX(apm_mutex);
 
-static const char              driver_version[] = "1.16ac";    /* no spaces */
+/*
+ * Set up a segment that references the real mode segment 0x40
+ * that extends up to the end of page zero (that we have reserved).
+ * This is for buggy BIOS's that refer to (real mode) segment 0x40
+ * even though they are called in protected mode.
+ */
+static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092,
+                       (unsigned long)__va(0x400UL), PAGE_SIZE - 0x400 - 1);
+
+static const char driver_version[] = "1.16ac"; /* no spaces */
 
 static struct task_struct *kapmd_task;
 
@@ -416,7 +445,7 @@ static struct task_struct *kapmd_task;
  *     APM event names taken from the APM 1.2 specification. These are
  *     the message codes that the BIOS uses to tell us about events
  */
-static const char *    const apm_event_name[] = {
+static const char * const apm_event_name[] = {
        "system standby",
        "system suspend",
        "normal resume",
@@ -434,14 +463,14 @@ static const char *       const apm_event_name[] = {
 
 typedef struct lookup_t {
        int     key;
-       char *  msg;
+       char    *msg;
 } lookup_t;
 
 /*
  *     The BIOS returns a set of standard error codes in AX when the
  *     carry flag is set.
  */
+
 static const lookup_t error_table[] = {
 /* N/A { APM_SUCCESS,          "Operation succeeded" }, */
        { APM_DISABLED,         "Power management disabled" },
@@ -469,53 +498,25 @@ static const lookup_t error_table[] = {
  *     @err: APM BIOS return code
  *
  *     Write a meaningful log entry to the kernel log in the event of
- *     an APM error.
+ *     an APM error.  Note that this also handles (negative) kernel errors.
  */
+
 static void apm_error(char *str, int err)
 {
-       int     i;
+       int i;
 
        for (i = 0; i < ERROR_COUNT; i++)
-               if (error_table[i].key == err) break;
+               if (error_table[i].key == err)
+                       break;
        if (i < ERROR_COUNT)
-               printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg);
+               pr_notice("%s: %s\n", str, error_table[i].msg);
+       else if (err < 0)
+               pr_notice("%s: linux error code %i\n", str, err);
        else
-               printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n",
-                       str, err);
-}
-
-/*
- * Lock APM functionality to physical CPU 0
- */
-#ifdef CONFIG_SMP
-
-static cpumask_t apm_save_cpus(void)
-{
-       cpumask_t x = current->cpus_allowed;
-       /* Some bioses don't like being called from CPU != 0 */
-       set_cpus_allowed(current, cpumask_of_cpu(0));
-       BUG_ON(smp_processor_id() != 0);
-       return x;
+               pr_notice("%s: unknown error code %#2.2x\n",
+                      str, err);
 }
 
-static inline void apm_restore_cpus(cpumask_t mask)
-{
-       set_cpus_allowed(current, mask);
-}
-
-#else
-
-/*
- *     No CPU lockdown needed on a uniprocessor
- */
-#define apm_save_cpus()                (current->cpus_allowed)
-#define apm_restore_cpus(x)    (void)(x)
-
-#endif
-
 /*
  * These are the actual BIOS calls.  Depending on APM_ZERO_SEGS and
  * apm_info.allow_ints, we are being really paranoid here!  Not only
@@ -570,16 +571,23 @@ static inline void apm_irq_restore(unsigned long flags)
 #      define APM_DO_RESTORE_SEGS
 #endif
 
+struct apm_bios_call {
+       u32 func;
+       /* In and out */
+       u32 ebx;
+       u32 ecx;
+       /* Out only */
+       u32 eax;
+       u32 edx;
+       u32 esi;
+
+       /* Error: -ENOMEM, or bits 8-15 of eax */
+       int err;
+};
+
 /**
- *     apm_bios_call   -       Make an APM BIOS 32bit call
- *     @func: APM function to execute
- *     @ebx_in: EBX register for call entry
- *     @ecx_in: ECX register for call entry
- *     @eax: EAX register return
- *     @ebx: EBX register return
- *     @ecx: ECX register return
- *     @edx: EDX register return
- *     @esi: ESI register return
+ *     __apm_bios_call - Make an APM BIOS 32bit call
+ *     @_call: pointer to struct apm_bios_call.
  *
  *     Make an APM call using the 32bit protected mode interface. The
  *     caller is responsible for knowing if APM BIOS is configured and
@@ -588,80 +596,142 @@ static inline void apm_irq_restore(unsigned long flags)
  *     flag is loaded into AL.  If there is an error, then the error
  *     code is returned in AH (bits 8-15 of eax) and this function
  *     returns non-zero.
+ *
+ *     Note: this makes the call on the current CPU.
  */
-static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
-       u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi)
+static long __apm_bios_call(void *_call)
 {
        APM_DECL_SEGS
        unsigned long           flags;
-       cpumask_t               cpus;
        int                     cpu;
        struct desc_struct      save_desc_40;
        struct desc_struct      *gdt;
+       struct apm_bios_call    *call = _call;
 
-       cpus = apm_save_cpus();
-       
        cpu = get_cpu();
+       BUG_ON(cpu != 0);
        gdt = get_cpu_gdt_table(cpu);
        save_desc_40 = gdt[0x40 / 8];
        gdt[0x40 / 8] = bad_bios_desc;
 
        apm_irq_save(flags);
        APM_DO_SAVE_SEGS;
-       apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi);
+       apm_bios_call_asm(call->func, call->ebx, call->ecx,
+                         &call->eax, &call->ebx, &call->ecx, &call->edx,
+                         &call->esi);
        APM_DO_RESTORE_SEGS;
        apm_irq_restore(flags);
        gdt[0x40 / 8] = save_desc_40;
        put_cpu();
-       apm_restore_cpus(cpus);
-       
-       return *eax & 0xff;
+
+       return call->eax & 0xff;
+}
+
+/* Run __apm_bios_call or __apm_bios_call_simple on CPU 0 */
+static int on_cpu0(long (*fn)(void *), struct apm_bios_call *call)
+{
+       int ret;
+
+       /* Don't bother with work_on_cpu in the common case, so we don't
+        * have to worry about OOM or overhead. */
+       if (get_cpu() == 0) {
+               ret = fn(call);
+               put_cpu();
+       } else {
+               put_cpu();
+               ret = work_on_cpu(0, fn, call);
+       }
+
+       /* work_on_cpu can fail with -ENOMEM */
+       if (ret < 0)
+               call->err = ret;
+       else
+               call->err = (call->eax >> 8) & 0xff;
+
+       return ret;
 }
 
 /**
- *     apm_bios_call_simple    -       make a simple APM BIOS 32bit call
- *     @func: APM function to invoke
- *     @ebx_in: EBX register value for BIOS call
- *     @ecx_in: ECX register value for BIOS call
- *     @eax: EAX register on return from the BIOS call
+ *     apm_bios_call   -       Make an APM BIOS 32bit call (on CPU 0)
+ *     @call: the apm_bios_call registers.
+ *
+ *     If there is an error, it is returned in @call.err.
+ */
+static int apm_bios_call(struct apm_bios_call *call)
+{
+       return on_cpu0(__apm_bios_call, call);
+}
+
+/**
+ *     __apm_bios_call_simple - Make an APM BIOS 32bit call (on CPU 0)
+ *     @_call: pointer to struct apm_bios_call.
  *
  *     Make a BIOS call that returns one value only, or just status.
  *     If there is an error, then the error code is returned in AH
- *     (bits 8-15 of eax) and this function returns non-zero. This is
- *     used for simpler BIOS operations. This call may hold interrupts
- *     off for a long time on some laptops.
+ *     (bits 8-15 of eax) and this function returns non-zero (it can
+ *     also return -ENOMEM). This is used for simpler BIOS operations.
+ *     This call may hold interrupts off for a long time on some laptops.
+ *
+ *     Note: this makes the call on the current CPU.
  */
-
-static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
+static long __apm_bios_call_simple(void *_call)
 {
        u8                      error;
        APM_DECL_SEGS
        unsigned long           flags;
-       cpumask_t               cpus;
        int                     cpu;
        struct desc_struct      save_desc_40;
        struct desc_struct      *gdt;
+       struct apm_bios_call    *call = _call;
 
-       cpus = apm_save_cpus();
-       
        cpu = get_cpu();
+       BUG_ON(cpu != 0);
        gdt = get_cpu_gdt_table(cpu);
        save_desc_40 = gdt[0x40 / 8];
        gdt[0x40 / 8] = bad_bios_desc;
 
        apm_irq_save(flags);
        APM_DO_SAVE_SEGS;
-       error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax);
+       error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx,
+                                        &call->eax);
        APM_DO_RESTORE_SEGS;
        apm_irq_restore(flags);
        gdt[0x40 / 8] = save_desc_40;
        put_cpu();
-       apm_restore_cpus(cpus);
        return error;
 }
 
 /**
+ *     apm_bios_call_simple    -       make a simple APM BIOS 32bit call
+ *     @func: APM function to invoke
+ *     @ebx_in: EBX register value for BIOS call
+ *     @ecx_in: ECX register value for BIOS call
+ *     @eax: EAX register on return from the BIOS call
+ *     @err: bits
+ *
+ *     Make a BIOS call that returns one value only, or just status.
+ *     If there is an error, then the error code is returned in @err
+ *     and this function returns non-zero. This is used for simpler
+ *     BIOS operations.  This call may hold interrupts off for a long
+ *     time on some laptops.
+ */
+static int apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax,
+                               int *err)
+{
+       struct apm_bios_call call;
+       int ret;
+
+       call.func = func;
+       call.ebx = ebx_in;
+       call.ecx = ecx_in;
+
+       ret = on_cpu0(__apm_bios_call_simple, &call);
+       *eax = call.eax;
+       *err = call.err;
+       return ret;
+}
+
+/**
  *     apm_driver_version      -       APM driver version
  *     @val:   loaded with the APM version on return
  *
@@ -679,10 +749,11 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
 
 static int apm_driver_version(u_short *val)
 {
-       u32     eax;
+       u32 eax;
+       int err;
 
-       if (apm_bios_call_simple(APM_FUNC_VERSION, 0, *val, &eax))
-               return (eax >> 8) & 0xff;
+       if (apm_bios_call_simple(APM_FUNC_VERSION, 0, *val, &eax, &err))
+               return err;
        *val = eax;
        return APM_SUCCESS;
 }
@@ -703,22 +774,21 @@ static int apm_driver_version(u_short *val)
  *     that APM 1.2 is in use. If no messges are pending the value 0x80
  *     is returned (No power management events pending).
  */
 static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
 {
-       u32     eax;
-       u32     ebx;
-       u32     ecx;
-       u32     dummy;
+       struct apm_bios_call call;
 
-       if (apm_bios_call(APM_FUNC_GET_EVENT, 0, 0, &eax, &ebx, &ecx,
-                       &dummy, &dummy))
-               return (eax >> 8) & 0xff;
-       *event = ebx;
+       call.func = APM_FUNC_GET_EVENT;
+       call.ebx = call.ecx = 0;
+
+       if (apm_bios_call(&call))
+               return call.err;
+
+       *event = call.ebx;
        if (apm_info.connection_version < 0x0102)
                *info = ~0; /* indicate info not valid */
        else
-               *info = ecx;
+               *info = call.ecx;
        return APM_SUCCESS;
 }
 
@@ -735,13 +805,14 @@ static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
  *     The state holds the state to transition to, which may in fact
  *     be an acceptance of a BIOS requested state change.
  */
+
 static int set_power_state(u_short what, u_short state)
 {
-       u32     eax;
+       u32 eax;
+       int err;
 
-       if (apm_bios_call_simple(APM_FUNC_SET_STATE, what, state, &eax))
-               return (eax >> 8) & 0xff;
+       if (apm_bios_call_simple(APM_FUNC_SET_STATE, what, state, &eax, &err))
+               return err;
        return APM_SUCCESS;
 }
 
@@ -751,7 +822,7 @@ static int set_power_state(u_short what, u_short state)
  *
  *     Transition the entire system into a new APM power state.
  */
+
 static int set_system_power_state(u_short state)
 {
        return set_power_state(APM_DEVICE_ALL, state);
@@ -765,13 +836,14 @@ static int set_system_power_state(u_short state)
  *     to handle the idle request. On a success the function returns 1
  *     if the BIOS did clock slowing or 0 otherwise.
  */
+
 static int apm_do_idle(void)
 {
-       u32     eax;
-       u8      ret = 0;
-       int     idled = 0;
-       int     polling;
+       u32 eax;
+       u8 ret = 0;
+       int idled = 0;
+       int polling;
+       int err = 0;
 
        polling = !!(current_thread_info()->status & TS_POLLING);
        if (polling) {
@@ -784,7 +856,7 @@ static int apm_do_idle(void)
        }
        if (!need_resched()) {
                idled = 1;
-               ret = apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax);
+               ret = apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax, &err);
        }
        if (polling)
                current_thread_info()->status |= TS_POLLING;
@@ -798,10 +870,8 @@ static int apm_do_idle(void)
                /* This always fails on some SMP boards running UP kernels.
                 * Only report the failure the first 5 times.
                 */
-               if (++t < 5)
-               {
-                       printk(KERN_DEBUG "apm_do_idle failed (%d)\n",
-                                       (eax >> 8) & 0xff);
+               if (++t < 5) {
+                       printk(KERN_DEBUG "apm_do_idle failed (%d)\n", err);
                        t = jiffies;
                }
                return -1;
@@ -813,15 +883,16 @@ static int apm_do_idle(void)
 /**
  *     apm_do_busy     -       inform the BIOS the CPU is busy
  *
- *     Request that the BIOS brings the CPU back to full performance. 
+ *     Request that the BIOS brings the CPU back to full performance.
  */
+
 static void apm_do_busy(void)
 {
-       u32     dummy;
+       u32 dummy;
+       int err;
 
        if (clock_slowed || ALWAYS_CALL_BUSY) {
-               (void) apm_bios_call_simple(APM_FUNC_BUSY, 0, 0, &dummy);
+               (void)apm_bios_call_simple(APM_FUNC_BUSY, 0, 0, &dummy, &err);
                clock_slowed = 0;
        }
 }
@@ -832,47 +903,47 @@ static void apm_do_busy(void)
  * power management - we probably want
  * to conserve power.
  */
-#define IDLE_CALC_LIMIT   (HZ * 100)
-#define IDLE_LEAKY_MAX    16
-
-static void (*original_pm_idle)(void) __read_mostly;
+#define IDLE_CALC_LIMIT        (HZ * 100)
+#define IDLE_LEAKY_MAX 16
 
 /**
  * apm_cpu_idle                -       cpu idling for APM capable Linux
  *
- * This is the idling function the kernel executes when APM is available. It 
+ * This is the idling function the kernel executes when APM is available. It
  * tries to do BIOS powermanagement based on the average system idle time.
  * Furthermore it calls the system default idle routine.
  */
 
-static void apm_cpu_idle(void)
+static int apm_cpu_idle(struct cpuidle_device *dev,
+       struct cpuidle_driver *drv, int index)
 {
        static int use_apm_idle; /* = 0 */
        static unsigned int last_jiffies; /* = 0 */
        static unsigned int last_stime; /* = 0 */
+       cputime_t stime;
 
        int apm_idle_done = 0;
        unsigned int jiffies_since_last_check = jiffies - last_jiffies;
        unsigned int bucket;
 
 recalc:
+       task_cputime(current, NULL, &stime);
        if (jiffies_since_last_check > IDLE_CALC_LIMIT) {
                use_apm_idle = 0;
-               last_jiffies = jiffies;
-               last_stime = current->stime;
        } else if (jiffies_since_last_check > idle_period) {
                unsigned int idle_percentage;
 
-               idle_percentage = current->stime - last_stime;
+               idle_percentage = stime - last_stime;
                idle_percentage *= 100;
                idle_percentage /= jiffies_since_last_check;
                use_apm_idle = (idle_percentage > idle_threshold);
                if (apm_info.forbid_idle)
                        use_apm_idle = 0;
-               last_jiffies = jiffies;
-               last_stime = current->stime;
        }
 
+       last_jiffies = jiffies;
+       last_stime = stime;
+
        bucket = IDLE_LEAKY_MAX;
 
        while (!need_resched()) {
@@ -881,7 +952,8 @@ recalc:
 
                        t = jiffies;
                        switch (apm_do_idle()) {
-                       case 0: apm_idle_done = 1;
+                       case 0:
+                               apm_idle_done = 1;
                                if (t != jiffies) {
                                        if (bucket) {
                                                bucket = IDLE_LEAKY_MAX;
@@ -892,16 +964,15 @@ recalc:
                                        continue;
                                }
                                break;
-                       case 1: apm_idle_done = 1;
+                       case 1:
+                               apm_idle_done = 1;
                                break;
                        default: /* BIOS refused */
                                break;
                        }
                }
-               if (original_pm_idle)
-                       original_pm_idle();
-               else
-                       default_idle();
+               default_idle();
+               local_irq_disable();
                jiffies_since_last_check = jiffies - last_jiffies;
                if (jiffies_since_last_check > idle_period)
                        goto recalc;
@@ -909,6 +980,8 @@ recalc:
 
        if (apm_idle_done)
                apm_do_busy();
+
+       return index;
 }
 
 /**
@@ -920,27 +993,16 @@ recalc:
  *     the SMP call on CPU0 as some systems will only honour this call
  *     on their first cpu.
  */
+
 static void apm_power_off(void)
 {
-       unsigned char   po_bios_call[] = {
-               0xb8, 0x00, 0x10,       /* movw  $0x1000,ax  */
-               0x8e, 0xd0,             /* movw  ax,ss       */
-               0xbc, 0x00, 0xf0,       /* movw  $0xf000,sp  */
-               0xb8, 0x07, 0x53,       /* movw  $0x5307,ax  */
-               0xbb, 0x01, 0x00,       /* movw  $0x0001,bx  */
-               0xb9, 0x03, 0x00,       /* movw  $0x0003,cx  */
-               0xcd, 0x15              /* int   $0x15       */
-       };
-
        /* Some bioses don't like being called from CPU != 0 */
-       if (apm_info.realmode_power_off)
-       {
-               (void)apm_save_cpus();
-               machine_real_restart(po_bios_call, sizeof(po_bios_call));
+       if (apm_info.realmode_power_off) {
+               set_cpus_allowed_ptr(current, cpumask_of(0));
+               machine_real_restart(MRR_APM);
+       } else {
+               (void)set_system_power_state(APM_STATE_OFF);
        }
-       else
-               (void) set_system_power_state(APM_STATE_OFF);
 }
 
 #ifdef CONFIG_APM_DO_ENABLE
@@ -949,18 +1011,19 @@ static void apm_power_off(void)
  *     apm_enable_power_management - enable BIOS APM power management
  *     @enable: enable yes/no
  *
- *     Enable or disable the APM BIOS power services. 
+ *     Enable or disable the APM BIOS power services.
  */
+
 static int apm_enable_power_management(int enable)
 {
-       u32     eax;
+       u32 eax;
+       int err;
 
        if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED))
                return APM_NOT_ENGAGED;
        if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
-                       enable, &eax))
-               return (eax >> 8) & 0xff;
+                                enable, &eax, &err))
+               return err;
        if (enable)
                apm_info.bios.flags &= ~APM_BIOS_DISABLED;
        else
@@ -982,27 +1045,26 @@ static int apm_enable_power_management(int enable)
  *     if reported is a lifetime in secodnds/minutes at current powwer
  *     consumption.
  */
+
 static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
 {
-       u32     eax;
-       u32     ebx;
-       u32     ecx;
-       u32     edx;
-       u32     dummy;
+       struct apm_bios_call call;
+
+       call.func = APM_FUNC_GET_STATUS;
+       call.ebx = APM_DEVICE_ALL;
+       call.ecx = 0;
 
        if (apm_info.get_power_status_broken)
                return APM_32_UNSUPPORTED;
-       if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0,
-                       &eax, &ebx, &ecx, &edx, &dummy))
-               return (eax >> 8) & 0xff;
-       *status = ebx;
-       *bat = ecx;
+       if (apm_bios_call(&call))
+               return call.err;
+       *status = call.ebx;
+       *bat = call.ecx;
        if (apm_info.get_power_status_swabinminutes) {
-               *life = swab16((u16)edx);
+               *life = swab16((u16)call.edx);
                *life |= 0x8000;
        } else
-               *life = edx;
+               *life = call.edx;
        return APM_SUCCESS;
 }
 
@@ -1010,11 +1072,11 @@ static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
 static int apm_get_battery_status(u_short which, u_short *status,
                                  u_short *bat, u_short *life, u_short *nbat)
 {
-       u32     eax;
-       u32     ebx;
-       u32     ecx;
-       u32     edx;
-       u32     esi;
+       u32 eax;
+       u32 ebx;
+       u32 ecx;
+       u32 edx;
+       u32 esi;
 
        if (apm_info.connection_version < 0x0102) {
                /* pretend we only have one battery. */
@@ -1025,7 +1087,7 @@ static int apm_get_battery_status(u_short which, u_short *status,
        }
 
        if (apm_bios_call(APM_FUNC_GET_STATUS, (0x8000 | (which)), 0, &eax,
-                       &ebx, &ecx, &edx, &esi))
+                         &ebx, &ecx, &edx, &esi))
                return (eax >> 8) & 0xff;
        *status = ebx;
        *bat = ecx;
@@ -1043,16 +1105,18 @@ static int apm_get_battery_status(u_short which, u_short *status,
  *     Activate or deactive power management on either a specific device
  *     or the entire system (%APM_DEVICE_ALL).
  */
+
 static int apm_engage_power_management(u_short device, int enable)
 {
-       u32     eax;
+       u32 eax;
+       int err;
 
        if ((enable == 0) && (device == APM_DEVICE_ALL)
            && (apm_info.bios.flags & APM_BIOS_DISABLED))
                return APM_DISABLED;
-       if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax))
-               return (eax >> 8) & 0xff;
+       if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable,
+                                &eax, &err))
+               return err;
        if (device == APM_DEVICE_ALL) {
                if (enable)
                        apm_info.bios.flags &= ~APM_BIOS_DISENGAGED;
@@ -1073,7 +1137,7 @@ static int apm_engage_power_management(u_short device, int enable)
  *     all video devices. Typically the BIOS will do laptop backlight and
  *     monitor powerdown for us.
  */
+
 static int apm_console_blank(int blank)
 {
        int error = APM_NOT_ENGAGED; /* silence gcc */
@@ -1125,7 +1189,7 @@ static apm_event_t get_queued_event(struct apm_user *as)
 
 static void queue_event(apm_event_t event, struct apm_user *sender)
 {
-       struct apm_user *       as;
+       struct apm_user *as;
 
        spin_lock(&user_list_lock);
        if (user_list == NULL)
@@ -1140,12 +1204,12 @@ static void queue_event(apm_event_t event, struct apm_user *sender)
                        static int notified;
 
                        if (notified++ == 0)
-                           printk(KERN_ERR "apm: an event queue overflowed\n");
+                               pr_err("an event queue overflowed\n");
                        if (++as->event_tail >= APM_MAX_EVENTS)
                                as->event_tail = 0;
                }
                as->events[as->event_head] = event;
-               if ((!as->suser) || (!as->writer))
+               if (!as->suser || !as->writer)
                        continue;
                switch (event) {
                case APM_SYS_SUSPEND:
@@ -1171,39 +1235,28 @@ static void reinit_timer(void)
 #ifdef INIT_TIMER_AFTER_SUSPEND
        unsigned long flags;
 
-       spin_lock_irqsave(&i8253_lock, flags);
+       raw_spin_lock_irqsave(&i8253_lock, flags);
        /* set the clock to HZ */
        outb_p(0x34, PIT_MODE);         /* binary, mode 2, LSB/MSB, ch 0 */
        udelay(10);
        outb_p(LATCH & 0xff, PIT_CH0);  /* LSB */
        udelay(10);
-       outb(LATCH >> 8, PIT_CH0);      /* MSB */
+       outb_p(LATCH >> 8, PIT_CH0);    /* MSB */
        udelay(10);
-       spin_unlock_irqrestore(&i8253_lock, flags);
+       raw_spin_unlock_irqrestore(&i8253_lock, flags);
 #endif
 }
 
 static int suspend(int vetoable)
 {
-       int             err;
+       int err;
        struct apm_user *as;
 
-       if (pm_send_all(PM_SUSPEND, (void *)3)) {
-               /* Vetoed */
-               if (vetoable) {
-                       if (apm_info.connection_version > 0x100)
-                               set_system_power_state(APM_STATE_REJECT);
-                       err = -EBUSY;
-                       ignore_sys_suspend = 0;
-                       printk(KERN_WARNING "apm: suspend was vetoed.\n");
-                       goto out;
-               }
-               printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n");
-       }
+       dpm_suspend_start(PMSG_SUSPEND);
+       dpm_suspend_end(PMSG_SUSPEND);
 
-       device_suspend(PMSG_SUSPEND);
        local_irq_disable();
-       device_power_down(PMSG_SUSPEND);
+       syscore_suspend();
 
        local_irq_enable();
 
@@ -1220,12 +1273,14 @@ static int suspend(int vetoable)
        if (err != APM_SUCCESS)
                apm_error("suspend", err);
        err = (err == APM_SUCCESS) ? 0 : -EIO;
-       device_power_up();
+
+       syscore_resume();
        local_irq_enable();
-       device_resume();
-       pm_send_all(PM_RESUME, (void *)0);
+
+       dpm_resume_start(PMSG_RESUME);
+       dpm_resume_end(PMSG_RESUME);
+
        queue_event(APM_NORMAL_RESUME, NULL);
- out:
        spin_lock(&user_list_lock);
        for (as = user_list; as != NULL; as = as->next) {
                as->suspend_wait = 0;
@@ -1238,10 +1293,12 @@ static int suspend(int vetoable)
 
 static void standby(void)
 {
-       int     err;
+       int err;
+
+       dpm_suspend_end(PMSG_SUSPEND);
 
        local_irq_disable();
-       device_power_down(PMSG_SUSPEND);
+       syscore_suspend();
        local_irq_enable();
 
        err = set_system_power_state(APM_STATE_STANDBY);
@@ -1249,14 +1306,16 @@ static void standby(void)
                apm_error("standby", err);
 
        local_irq_disable();
-       device_power_up();
+       syscore_resume();
        local_irq_enable();
+
+       dpm_resume_start(PMSG_RESUME);
 }
 
 static apm_event_t get_event(void)
 {
-       int             error;
-       apm_event_t     event = APM_NO_EVENTS; /* silence gcc */
+       int error;
+       apm_event_t event = APM_NO_EVENTS; /* silence gcc */
        apm_eventinfo_t info;
 
        static int notified;
@@ -1274,9 +1333,9 @@ static apm_event_t get_event(void)
 
 static void check_events(void)
 {
-       apm_event_t             event;
-       static unsigned long    last_resume;
-       static int              ignore_bounce;
+       apm_event_t event;
+       static unsigned long last_resume;
+       static int ignore_bounce;
 
        while ((event = get_event()) != 0) {
                if (debug) {
@@ -1335,8 +1394,7 @@ static void check_events(void)
                        ignore_bounce = 1;
                        if ((event != APM_NORMAL_RESUME)
                            || (ignore_normal_resume == 0)) {
-                               device_resume();
-                               pm_send_all(PM_RESUME, (void *)0);
+                               dpm_resume_end(PMSG_RESUME);
                                queue_event(event, NULL);
                        }
                        ignore_normal_resume = 0;
@@ -1356,7 +1414,7 @@ static void check_events(void)
                        /*
                         * We are not allowed to reject a critical suspend.
                         */
-                       (void) suspend(0);
+                       (void)suspend(0);
                        break;
                }
        }
@@ -1364,12 +1422,12 @@ static void check_events(void)
 
 static void apm_event_handler(void)
 {
-       static int      pending_count = 4;
-       int             err;
+       static int pending_count = 4;
+       int err;
 
        if ((standbys_pending > 0) || (suspends_pending > 0)) {
                if ((apm_info.connection_version > 0x100) &&
-                               (pending_count-- <= 0)) {
+                   (pending_count-- <= 0)) {
                        pending_count = 4;
                        if (debug)
                                printk(KERN_DEBUG "apm: setting state busy\n");
@@ -1408,8 +1466,8 @@ static void apm_mainloop(void)
 
 static int check_apm_user(struct apm_user *as, const char *func)
 {
-       if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
-               printk(KERN_ERR "apm: %s passed bad filp\n", func);
+       if (as == NULL || as->magic != APM_BIOS_MAGIC) {
+               pr_err("%s passed bad filp\n", func);
                return 1;
        }
        return 0;
@@ -1417,9 +1475,9 @@ static int check_apm_user(struct apm_user *as, const char *func)
 
 static ssize_t do_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
 {
-       struct apm_user *       as;
-       int                     i;
-       apm_event_t             event;
+       struct apm_user *as;
+       int i;
+       apm_event_t event;
 
        as = fp->private_data;
        if (check_apm_user(as, "read"))
@@ -1458,9 +1516,9 @@ static ssize_t do_read(struct file *fp, char __user *buf, size_t count, loff_t *
        return 0;
 }
 
-static unsigned int do_poll(struct file *fp, poll_table * wait)
+static unsigned int do_poll(struct file *fp, poll_table *wait)
 {
-       struct apm_user * as;
+       struct apm_user *as;
 
        as = fp->private_data;
        if (check_apm_user(as, "poll"))
@@ -1471,18 +1529,19 @@ static unsigned int do_poll(struct file *fp, poll_table * wait)
        return 0;
 }
 
-static int do_ioctl(struct inode * inode, struct file *filp,
-                   u_int cmd, u_long arg)
+static long do_ioctl(struct file *filp, u_int cmd, u_long arg)
 {
-       struct apm_user *       as;
+       struct apm_user *as;
+       int ret;
 
        as = filp->private_data;
        if (check_apm_user(as, "ioctl"))
                return -EIO;
-       if ((!as->suser) || (!as->writer))
+       if (!as->suser || !as->writer)
                return -EPERM;
        switch (cmd) {
        case APM_IOC_STANDBY:
+               mutex_lock(&apm_mutex);
                if (as->standbys_read > 0) {
                        as->standbys_read--;
                        as->standbys_pending--;
@@ -1491,8 +1550,10 @@ static int do_ioctl(struct inode * inode, struct file *filp,
                        queue_event(APM_USER_STANDBY, as);
                if (standbys_pending <= 0)
                        standby();
+               mutex_unlock(&apm_mutex);
                break;
        case APM_IOC_SUSPEND:
+               mutex_lock(&apm_mutex);
                if (as->suspends_read > 0) {
                        as->suspends_read--;
                        as->suspends_pending--;
@@ -1500,23 +1561,25 @@ static int do_ioctl(struct inode * inode, struct file *filp,
                } else
                        queue_event(APM_USER_SUSPEND, as);
                if (suspends_pending <= 0) {
-                       return suspend(1);
+                       ret = suspend(1);
+                       mutex_unlock(&apm_mutex);
                } else {
                        as->suspend_wait = 1;
+                       mutex_unlock(&apm_mutex);
                        wait_event_interruptible(apm_suspend_waitqueue,
                                        as->suspend_wait == 0);
-                       return as->suspend_result;
+                       ret = as->suspend_result;
                }
-               break;
+               return ret;
        default:
-               return -EINVAL;
+               return -ENOTTY;
        }
        return 0;
 }
 
-static int do_release(struct inode * inode, struct file * filp)
+static int do_release(struct inode *inode, struct file *filp)
 {
-       struct apm_user *       as;
+       struct apm_user *as;
 
        as = filp->private_data;
        if (check_apm_user(as, "release"))
@@ -1532,18 +1595,18 @@ static int do_release(struct inode * inode, struct file * filp)
                if (suspends_pending <= 0)
                        (void) suspend(1);
        }
-       spin_lock(&user_list_lock);
+       spin_lock(&user_list_lock);
        if (user_list == as)
                user_list = as->next;
        else {
-               struct apm_user *       as1;
+               struct apm_user *as1;
 
                for (as1 = user_list;
                     (as1 != NULL) && (as1->next != as);
                     as1 = as1->next)
                        ;
                if (as1 == NULL)
-                       printk(KERN_ERR "apm: filp not in user list\n");
+                       pr_err("filp not in user list\n");
                else
                        as1->next = as->next;
        }
@@ -1552,23 +1615,21 @@ static int do_release(struct inode * inode, struct file * filp)
        return 0;
 }
 
-static int do_open(struct inode * inode, struct file * filp)
+static int do_open(struct inode *inode, struct file *filp)
 {
-       struct apm_user *       as;
+       struct apm_user *as;
 
        as = kmalloc(sizeof(*as), GFP_KERNEL);
-       if (as == NULL) {
-               printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
-                      sizeof(*as));
+       if (as == NULL)
                return -ENOMEM;
-       }
+
        as->magic = APM_BIOS_MAGIC;
        as->event_tail = as->event_head = 0;
        as->suspends_pending = as->standbys_pending = 0;
        as->suspends_read = as->standbys_read = 0;
        /*
         * XXX - this is a tiny bit broken, when we consider BSD
-         * process accounting. If the device is opened by root, we
+        * process accounting. If the device is opened by root, we
         * instantly flag that we used superuser privs. Who knows,
         * we might close the device immediately without doing a
         * privileged operation -- cevans
@@ -1651,16 +1712,16 @@ static int proc_apm_show(struct seq_file *m, void *v)
           8) min = minutes; sec = seconds */
 
        seq_printf(m, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
-                    driver_version,
-                    (apm_info.bios.version >> 8) & 0xff,
-                    apm_info.bios.version & 0xff,
-                    apm_info.bios.flags,
-                    ac_line_status,
-                    battery_status,
-                    battery_flag,
-                    percentage,
-                    time_units,
-                    units);
+                  driver_version,
+                  (apm_info.bios.version >> 8) & 0xff,
+                  apm_info.bios.version & 0xff,
+                  apm_info.bios.flags,
+                  ac_line_status,
+                  battery_status,
+                  battery_flag,
+                  percentage,
+                  time_units,
+                  units);
        return 0;
 }
 
@@ -1683,19 +1744,17 @@ static int apm(void *unused)
        unsigned short  cx;
        unsigned short  dx;
        int             error;
-       char *          power_stat;
-       char *          bat_stat;
+       char            *power_stat;
+       char            *bat_stat;
 
-#ifdef CONFIG_SMP
        /* 2002/08/01 - WT
         * This is to avoid random crashes at boot time during initialization
         * on SMP systems in case of "apm=power-off" mode. Seen on ASUS A7M266D.
         * Some bioses don't like being called from CPU != 0.
         * Method suggested by Ingo Molnar.
         */
-       set_cpus_allowed(current, cpumask_of_cpu(0));
+       set_cpus_allowed_ptr(current, cpumask_of(0));
        BUG_ON(smp_processor_id() != 0);
-#endif
 
        if (apm_info.connection_version == 0) {
                apm_info.connection_version = apm_info.bios.version;
@@ -1743,23 +1802,41 @@ static int apm(void *unused)
                }
        }
 
-       if (debug && (num_online_cpus() == 1 || smp )) {
+       if (debug && (num_online_cpus() == 1 || smp)) {
                error = apm_get_power_status(&bx, &cx, &dx);
                if (error)
                        printk(KERN_INFO "apm: power status not available\n");
                else {
                        switch ((bx >> 8) & 0xff) {
-                       case 0: power_stat = "off line"; break;
-                       case 1: power_stat = "on line"; break;
-                       case 2: power_stat = "on backup power"; break;
-                       default: power_stat = "unknown"; break;
+                       case 0:
+                               power_stat = "off line";
+                               break;
+                       case 1:
+                               power_stat = "on line";
+                               break;
+                       case 2:
+                               power_stat = "on backup power";
+                               break;
+                       default:
+                               power_stat = "unknown";
+                               break;
                        }
                        switch (bx & 0xff) {
-                       case 0: bat_stat = "high"; break;
-                       case 1: bat_stat = "low"; break;
-                       case 2: bat_stat = "critical"; break;
-                       case 3: bat_stat = "charging"; break;
-                       default: bat_stat = "unknown"; break;
+                       case 0:
+                               bat_stat = "high";
+                               break;
+                       case 1:
+                               bat_stat = "low";
+                               break;
+                       case 2:
+                               bat_stat = "critical";
+                               break;
+                       case 3:
+                               bat_stat = "charging";
+                               break;
+                       default:
+                               bat_stat = "unknown";
+                               break;
                        }
                        printk(KERN_INFO
                               "apm: AC %s, battery status %s, battery life ",
@@ -1776,8 +1853,8 @@ static int apm(void *unused)
                                        printk("unknown\n");
                                else
                                        printk("%d %s\n", dx & 0x7fff,
-                                               (dx & 0x8000) ?
-                                               "minutes" : "seconds");
+                                              (dx & 0x8000) ?
+                                              "minutes" : "seconds");
                        }
                }
        }
@@ -1802,7 +1879,7 @@ static int apm(void *unused)
 #ifndef MODULE
 static int __init apm_setup(char *str)
 {
-       int     invert;
+       int invert;
 
        while ((str != NULL) && (*str != '\0')) {
                if (strncmp(str, "off", 3) == 0)
@@ -1827,14 +1904,13 @@ static int __init apm_setup(char *str)
                if ((strncmp(str, "power-off", 9) == 0) ||
                    (strncmp(str, "power_off", 9) == 0))
                        power_off = !invert;
-               if (strncmp(str, "smp", 3) == 0)
-               {
+               if (strncmp(str, "smp", 3) == 0) {
                        smp = !invert;
                        idle_threshold = 100;
                }
                if ((strncmp(str, "allow-ints", 10) == 0) ||
                    (strncmp(str, "allow_ints", 10) == 0))
-                       apm_info.allow_ints = !invert;
+                       apm_info.allow_ints = !invert;
                if ((strncmp(str, "broken-psr", 10) == 0) ||
                    (strncmp(str, "broken_psr", 10) == 0))
                        apm_info.get_power_status_broken = !invert;
@@ -1855,9 +1931,10 @@ static const struct file_operations apm_bios_fops = {
        .owner          = THIS_MODULE,
        .read           = do_read,
        .poll           = do_poll,
-       .ioctl          = do_ioctl,
+       .unlocked_ioctl = do_ioctl,
        .open           = do_open,
        .release        = do_release,
+       .llseek         = noop_llseek,
 };
 
 static struct miscdevice apm_device = {
@@ -1880,7 +1957,8 @@ static int __init print_if_true(const struct dmi_system_id *d)
  */
 static int __init broken_ps2_resume(const struct dmi_system_id *d)
 {
-       printk(KERN_INFO "%s machine detected. Mousepad Resume Bug workaround hopefully not needed.\n", d->ident);
+       printk(KERN_INFO "%s machine detected. Mousepad Resume Bug "
+              "workaround hopefully not needed.\n", d->ident);
        return 0;
 }
 
@@ -1889,7 +1967,8 @@ static int __init set_realmode_power_off(const struct dmi_system_id *d)
 {
        if (apm_info.realmode_power_off == 0) {
                apm_info.realmode_power_off = 1;
-               printk(KERN_INFO "%s bios detected. Using realmode poweroff only.\n", d->ident);
+               printk(KERN_INFO "%s bios detected. "
+                      "Using realmode poweroff only.\n", d->ident);
        }
        return 0;
 }
@@ -1899,7 +1978,8 @@ static int __init set_apm_ints(const struct dmi_system_id *d)
 {
        if (apm_info.allow_ints == 0) {
                apm_info.allow_ints = 1;
-               printk(KERN_INFO "%s machine detected. Enabling interrupts during APM calls.\n", d->ident);
+               printk(KERN_INFO "%s machine detected. "
+                      "Enabling interrupts during APM calls.\n", d->ident);
        }
        return 0;
 }
@@ -1909,7 +1989,8 @@ static int __init apm_is_horked(const struct dmi_system_id *d)
 {
        if (apm_info.disabled == 0) {
                apm_info.disabled = 1;
-               printk(KERN_INFO "%s machine detected. Disabling APM.\n", d->ident);
+               printk(KERN_INFO "%s machine detected. "
+                      "Disabling APM.\n", d->ident);
        }
        return 0;
 }
@@ -1918,9 +1999,10 @@ static int __init apm_is_horked_d850md(const struct dmi_system_id *d)
 {
        if (apm_info.disabled == 0) {
                apm_info.disabled = 1;
-               printk(KERN_INFO "%s machine detected. Disabling APM.\n", d->ident);
-               printk(KERN_INFO "This bug is fixed in bios P15 which is available for \n");
-               printk(KERN_INFO "download from support.intel.com \n");
+               printk(KERN_INFO "%s machine detected. "
+                      "Disabling APM.\n", d->ident);
+               printk(KERN_INFO "This bug is fixed in bios P15 which is available for\n");
+               printk(KERN_INFO "download from support.intel.com\n");
        }
        return 0;
 }
@@ -1930,7 +2012,8 @@ static int __init apm_likes_to_melt(const struct dmi_system_id *d)
 {
        if (apm_info.forbid_idle == 0) {
                apm_info.forbid_idle = 1;
-               printk(KERN_INFO "%s machine detected. Disabling APM idle calls.\n", d->ident);
+               printk(KERN_INFO "%s machine detected. "
+                      "Disabling APM idle calls.\n", d->ident);
        }
        return 0;
 }
@@ -1953,7 +2036,8 @@ static int __init apm_likes_to_melt(const struct dmi_system_id *d)
 static int __init broken_apm_power(const struct dmi_system_id *d)
 {
        apm_info.get_power_status_broken = 1;
-       printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n");
+       printk(KERN_WARNING "BIOS strings suggest APM bugs, "
+              "disabling power status reporting.\n");
        return 0;
 }
 
@@ -1964,7 +2048,8 @@ static int __init broken_apm_power(const struct dmi_system_id *d)
 static int __init swab_apm_power_in_minutes(const struct dmi_system_id *d)
 {
        apm_info.get_power_status_swabinminutes = 1;
-       printk(KERN_WARNING "BIOS strings suggest APM reports battery life in minutes and wrong byte order.\n");
+       printk(KERN_WARNING "BIOS strings suggest APM reports battery life "
+              "in minutes and wrong byte order.\n");
        return 0;
 }
 
@@ -1989,8 +2074,8 @@ static struct dmi_system_id __initdata apm_dmi_table[] = {
                apm_is_horked, "Dell Inspiron 2500",
                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 2500"),
-                       DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
-                       DMI_MATCH(DMI_BIOS_VERSION,"A11"), },
+                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "A11"), },
        },
        {       /* Allow interrupts during suspend on Dell Inspiron laptops*/
                set_apm_ints, "Dell Inspiron", {
@@ -2013,15 +2098,15 @@ static struct dmi_system_id __initdata apm_dmi_table[] = {
                apm_is_horked, "Dell Dimension 4100",
                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "XPS-Z"),
-                       DMI_MATCH(DMI_BIOS_VENDOR,"Intel Corp."),
-                       DMI_MATCH(DMI_BIOS_VERSION,"A11"), },
+                       DMI_MATCH(DMI_BIOS_VENDOR, "Intel Corp."),
+                       DMI_MATCH(DMI_BIOS_VERSION, "A11"), },
        },
        {       /* Allow interrupts during suspend on Compaq Laptops*/
                set_apm_ints, "Compaq 12XL125",
                {       DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Compaq PC"),
                        DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
-                       DMI_MATCH(DMI_BIOS_VERSION,"4.06"), },
+                       DMI_MATCH(DMI_BIOS_VERSION, "4.06"), },
        },
        {       /* Allow interrupts during APM or the clock goes slow */
                set_apm_ints, "ASUSTeK",
@@ -2063,15 +2148,15 @@ static struct dmi_system_id __initdata apm_dmi_table[] = {
                apm_is_horked, "Sharp PC-PJ/AX",
                {       DMI_MATCH(DMI_SYS_VENDOR, "SHARP"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"),
-                       DMI_MATCH(DMI_BIOS_VENDOR,"SystemSoft"),
-                       DMI_MATCH(DMI_BIOS_VERSION,"Version R2.08"), },
+                       DMI_MATCH(DMI_BIOS_VENDOR, "SystemSoft"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "Version R2.08"), },
        },
        {       /* APM crashes */
                apm_is_horked, "Dell Inspiron 2500",
                {       DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 2500"),
-                       DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
-                       DMI_MATCH(DMI_BIOS_VERSION,"A11"), },
+                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "A11"), },
        },
        {       /* APM idle hangs */
                apm_likes_to_melt, "Jabil AMD",
@@ -2191,22 +2276,21 @@ static struct dmi_system_id __initdata apm_dmi_table[] = {
  */
 static int __init apm_init(void)
 {
-       struct proc_dir_entry *apm_proc;
        struct desc_struct *gdt;
        int err;
 
        dmi_check_system(apm_dmi_table);
 
-       if (apm_info.bios.version == 0 || paravirt_enabled()) {
+       if (apm_info.bios.version == 0 || paravirt_enabled() || machine_is_olpc()) {
                printk(KERN_INFO "apm: BIOS not found.\n");
                return -ENODEV;
        }
        printk(KERN_INFO
-               "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
-               ((apm_info.bios.version >> 8) & 0xff),
-               (apm_info.bios.version & 0xff),
-               apm_info.bios.flags,
-               driver_version);
+              "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
+              ((apm_info.bios.version >> 8) & 0xff),
+              (apm_info.bios.version & 0xff),
+              apm_info.bios.flags,
+              driver_version);
        if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) {
                printk(KERN_INFO "apm: no 32 bit BIOS support\n");
                return -ENODEV;
@@ -2247,29 +2331,19 @@ static int __init apm_init(void)
        }
 
        if (apm_info.disabled) {
-               printk(KERN_NOTICE "apm: disabled on user request.\n");
+               pr_notice("disabled on user request.\n");
                return -ENODEV;
        }
        if ((num_online_cpus() > 1) && !power_off && !smp) {
-               printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
+               pr_notice("disabled - APM is not SMP safe.\n");
                apm_info.disabled = 1;
                return -ENODEV;
        }
-       if (pm_flags & PM_ACPI) {
-               printk(KERN_NOTICE "apm: overridden by ACPI.\n");
+       if (!acpi_disabled) {
+               pr_notice("overridden by ACPI.\n");
                apm_info.disabled = 1;
                return -ENODEV;
        }
-       pm_flags |= PM_APM;
-
-       /*
-        * Set up a segment that references the real mode segment 0x40
-        * that extends up to the end of page zero (that we have reserved).
-        * This is for buggy BIOS's that refer to (real mode) segment 0x40
-        * even though they are called in protected mode.
-        */
-       set_base(bad_bios_desc, __va((unsigned long)0x40 << 4));
-       _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
 
        /*
         * Set up the long jump entry point to the APM BIOS, which is called
@@ -2289,21 +2363,18 @@ static int __init apm_init(void)
         * code to that CPU.
         */
        gdt = get_cpu_gdt_table(0);
-       set_base(gdt[APM_CS >> 3],
-                __va((unsigned long)apm_info.bios.cseg << 4));
-       set_base(gdt[APM_CS_16 >> 3],
-                __va((unsigned long)apm_info.bios.cseg_16 << 4));
-       set_base(gdt[APM_DS >> 3],
-                __va((unsigned long)apm_info.bios.dseg << 4));
+       set_desc_base(&gdt[APM_CS >> 3],
+                (unsigned long)__va((unsigned long)apm_info.bios.cseg << 4));
+       set_desc_base(&gdt[APM_CS_16 >> 3],
+                (unsigned long)__va((unsigned long)apm_info.bios.cseg_16 << 4));
+       set_desc_base(&gdt[APM_DS >> 3],
+                (unsigned long)__va((unsigned long)apm_info.bios.dseg << 4));
 
-       apm_proc = create_proc_entry("apm", 0, NULL);
-       if (apm_proc)
-               apm_proc->proc_fops = &apm_file_ops;
+       proc_create("apm", 0, NULL, &apm_file_ops);
 
        kapmd_task = kthread_create(apm, NULL, "kapmd");
        if (IS_ERR(kapmd_task)) {
-               printk(KERN_ERR "apm: disabled - Unable to start kernel "
-                               "thread.\n");
+               pr_err("disabled - Unable to start kernel thread\n");
                err = PTR_ERR(kapmd_task);
                kapmd_task = NULL;
                remove_proc_entry("apm", NULL);
@@ -2311,9 +2382,9 @@ static int __init apm_init(void)
        }
        wake_up_process(kapmd_task);
 
-       if (num_online_cpus() > 1 && !smp ) {
+       if (num_online_cpus() > 1 && !smp) {
                printk(KERN_NOTICE
-                  "apm: disabled - APM is not SMP safe (power off active).\n");
+                      "apm: disabled - APM is not SMP safe (power off active).\n");
                return 0;
        }
 
@@ -2328,9 +2399,9 @@ static int __init apm_init(void)
        if (HZ != 100)
                idle_period = (idle_period * HZ) / 100;
        if (idle_threshold < 100) {
-               original_pm_idle = pm_idle;
-               pm_idle  = apm_cpu_idle;
-               set_pm_idle = 1;
+               if (!cpuidle_register_driver(&apm_idle_driver))
+                       if (cpuidle_register_device(&apm_cpuidle_device))
+                               cpuidle_unregister_driver(&apm_idle_driver);
        }
 
        return 0;
@@ -2338,17 +2409,11 @@ static int __init apm_init(void)
 
 static void __exit apm_exit(void)
 {
-       int     error;
+       int error;
+
+       cpuidle_unregister_device(&apm_cpuidle_device);
+       cpuidle_unregister_driver(&apm_idle_driver);
 
-       if (set_pm_idle) {
-               pm_idle = original_pm_idle;
-               /*
-                * We are about to unload the current idle thread pm callback
-                * (pm_idle), Wait for all processors to update cached/local
-                * copies of pm_idle before proceeding.
-                */
-               cpu_idle_wait();
-       }
        if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
            && (apm_info.connection_version > 0x0100)) {
                error = apm_engage_power_management(APM_DEVICE_ALL, 0);
@@ -2363,7 +2428,6 @@ static void __exit apm_exit(void)
                kthread_stop(kapmd_task);
                kapmd_task = NULL;
        }
-       pm_flags &= ~PM_APM;
 }
 
 module_init(apm_init);