diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/acpi/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/acpi/sleep/main.c | 318 | ||||
| -rw-r--r-- | drivers/acpi/sleep/proc.c | 82 | ||||
| -rw-r--r-- | drivers/base/power/main.c | 2 | ||||
| -rw-r--r-- | drivers/base/power/power.h | 4 | ||||
| -rw-r--r-- | drivers/base/power/resume.c | 101 | ||||
| -rw-r--r-- | drivers/base/power/runtime.c | 12 | ||||
| -rw-r--r-- | drivers/base/power/suspend.c | 171 | ||||
| -rw-r--r-- | drivers/base/sys.c | 111 | ||||
| -rw-r--r-- | drivers/char/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/ide/ide-cd.c | 4 | ||||
| -rw-r--r-- | drivers/ide/ide-disk.c | 4 | ||||
| -rw-r--r-- | drivers/ide/ide.c | 16 | ||||
| -rw-r--r-- | drivers/isdn/hisax/sedlbauer_cs.c | 1 | ||||
| -rw-r--r-- | drivers/oprofile/buffer_sync.c | 4 | ||||
| -rw-r--r-- | drivers/oprofile/oprofile_files.c | 14 | ||||
| -rw-r--r-- | drivers/oprofile/oprofile_stats.c | 3 | ||||
| -rw-r--r-- | drivers/oprofile/oprofile_stats.h | 1 | ||||
| -rw-r--r-- | drivers/oprofile/oprofilefs.c | 12 | ||||
| -rw-r--r-- | drivers/pci/pci-driver.c | 31 |
20 files changed, 203 insertions, 692 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 99b9fa1f80e1..d9e1a83ab8ef 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -30,7 +30,7 @@ config ACPI bool "Full ACPI Support" depends on !X86_VISWS depends on !IA64_HP_SIM - depends on IA64 || (X86 && ACPI_HT) + depends on IA64 || (X86 || ACPI_HT) default y ---help--- Advanced Configuration and Power Interface (ACPI) support for diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index ba7294275354..d3f29ce924ae 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -1,11 +1,11 @@ /* * sleep.c - ACPI sleep support. - * - * Copyright (c) 2000-2003 Patrick Mochel * - * Portions are - * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> - * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> + * Copyright (c) 2000-2003 Patrick Mochel + * Copyright (c) 2003 Open Source Development Lab + * + * This file is released under the GPLv2. + * */ #include <linux/delay.h> @@ -16,274 +16,151 @@ #include <acpi/acpi_drivers.h> #include "sleep.h" -#define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME ("sleep") - u8 sleep_states[ACPI_S_STATE_COUNT]; +static struct pm_ops acpi_pm_ops; + extern void do_suspend_lowlevel_s4bios(int); extern void do_suspend_lowlevel(int); -/** - * acpi_system_restore_state - OS-specific restoration of state - * @state: sleep state we're exiting - * - * Note that if we're coming back from S4, the memory image should have already - * been loaded from the disk and is already in place. (Otherwise how else would we - * be here?). - */ -acpi_status -acpi_system_restore_state ( - u32 state) -{ - /* restore processor state - * We should only be here if we're coming back from STR or STD. - * And, in the case of the latter, the memory image should have already - * been loaded from disk. - */ - if (state > ACPI_STATE_S1) - acpi_restore_state_mem(); - - /* wait for power to come back */ - mdelay(10); - - /* turn all the devices back on */ - device_resume(RESUME_POWER_ON); - - /* enable interrupts once again */ - ACPI_ENABLE_IRQS(); - - /* restore device context */ - device_resume(RESUME_RESTORE_STATE); - - if (dmi_broken & BROKEN_INIT_AFTER_S1) { - printk("Broken toshiba laptop -> kicking interrupts\n"); - init_8259A(0); - } - - return AE_OK; -} +static u32 acpi_suspend_states[] = { + [PM_SUSPEND_ON] = ACPI_STATE_S0, + [PM_SUSPEND_STANDBY] = ACPI_STATE_S1, + [PM_SUSPEND_MEM] = ACPI_STATE_S3, + [PM_SUSPEND_DISK] = ACPI_STATE_S4, +}; /** - * acpi_system_save_state - save OS specific state and power down devices - * @state: sleep state we're entering. + * acpi_pm_prepare - Do preliminary suspend work. + * @state: suspend state we're entering. * - * This handles saving all context to memory, and possibly disk. - * First, we call to the device driver layer to save device state. - * Once we have that, we save whatevery processor and kernel state we - * need to memory. + * Make sure we support the state. If we do, and we need it, set the + * firmware waking vector and do arch-specific nastiness to get the + * wakeup code to the waking vector. */ -acpi_status -acpi_system_save_state( - u32 state) -{ - int error = 0; - /* Send notification to devices that they will be suspended. - * If any device or driver cannot make the transition, either up - * or down, we'll get an error back. - */ - error = device_suspend(state, SUSPEND_NOTIFY); - if (error) - return AE_ERROR; - - if (state < ACPI_STATE_S5) { - - /* Tell devices to stop I/O and actually save their state. - * It is theoretically possible that something could fail, - * so handle that gracefully.. - */ - error = device_suspend(state, SUSPEND_SAVE_STATE); - if (error) { - /* tell devices to restore state if they have - * it saved and to start taking I/O requests. - */ - device_resume(RESUME_RESTORE_STATE); - return error; - } - - /* flush caches */ - ACPI_FLUSH_CPU_CACHE(); - - /* Do arch specific saving of state. */ - if (state > ACPI_STATE_S1) { - error = acpi_save_state_mem(); +static int acpi_pm_prepare(u32 state) +{ + int error = 0; + u32 acpi_state = acpi_suspend_states[state]; - if (!error && (state == ACPI_STATE_S4)) - error = acpi_save_state_disk(); + if (!sleep_states[acpi_state]) + return -EPERM; - if (error) { - device_resume(RESUME_RESTORE_STATE); - return error; - } - } + /* do we have a wakeup address for S2 and S3? */ + /* Here, we support only S4BIOS, those we set the wakeup address */ + /* S4OS is only supported for now via swsusp.. */ + if (state == PM_SUSPEND_MEM || state == PM_SUSPEND_DISK) { + if (!acpi_wakeup_address) + return -EFAULT; + acpi_set_firmware_waking_vector( + (acpi_physical_address) acpi_wakeup_address); } - /* disable interrupts - * Note that acpi_suspend -- our caller -- will do this once we return. - * But, we want it done early, so we don't get any suprises during - * the device suspend sequence. - */ - ACPI_DISABLE_IRQS(); + ACPI_FLUSH_CPU_CACHE(); - /* Unconditionally turn off devices. - * Obvious if we enter a sleep state. - * If entering S5 (soft off), this should put devices in a - * quiescent state. - */ - error = device_suspend(state, SUSPEND_POWER_DOWN); + /* Do arch specific saving of state. */ + if (state > PM_SUSPEND_STANDBY) { + if ((error = acpi_save_state_mem())) + goto Err; + } - /* We're pretty screwed if we got an error from this. - * We try to recover by simply calling our own restore_state - * function; see above for definition. - * - * If it's S5 though, go through with it anyway.. - */ - if (error && state != ACPI_STATE_S5) - acpi_system_restore_state(state); + acpi_enter_sleep_state_prep(acpi_state); - return error ? AE_ERROR : AE_OK; + return 0; + Err: + acpi_set_firmware_waking_vector(0); + return error; } -/**************************************************************************** - * - * FUNCTION: acpi_system_suspend - * - * PARAMETERS: %state: Sleep state to enter. - * - * RETURN: acpi_status, whether or not we successfully entered and - * exited sleep. - * - * DESCRIPTION: Perform OS-specific action to enter sleep state. - * This is the final step in going to sleep, per spec. If we - * know we're coming back (i.e. not entering S5), we save the - * processor flags. [ We'll have to save and restore them anyway, - * so we use the arch-agnostic save_flags and restore_flags - * here.] We then set the place to return to in arch-specific - * globals using arch_set_return_point. Finally, we call the - * ACPI function to write the proper values to I/O ports. +/** + * acpi_pm_enter - Actually enter a sleep state. + * @state: State we're entering. * - ****************************************************************************/ + * Flush caches and go to sleep. For STR or STD, we have to call + * arch-specific assembly, which in turn call acpi_enter_sleep_state(). + * It's unfortunate, but it works. Please fix if you're feeling frisky. + */ -acpi_status -acpi_system_suspend( - u32 state) +static int acpi_pm_enter(u32 state) { - acpi_status status = AE_ERROR; - unsigned long flags = 0; + acpi_status status = AE_OK; + unsigned long flags = 0; + u32 acpi_state = acpi_suspend_states[state]; + ACPI_FLUSH_CPU_CACHE(); local_irq_save(flags); - switch (state) { - case ACPI_STATE_S1: + case PM_SUSPEND_STANDBY: barrier(); - status = acpi_enter_sleep_state(state); + status = acpi_enter_sleep_state(acpi_state); break; - case ACPI_STATE_S2: - case ACPI_STATE_S3: + case PM_SUSPEND_MEM: do_suspend_lowlevel(0); break; - case ACPI_STATE_S4: - do_suspend_lowlevel_s4bios(0); + case PM_SUSPEND_DISK: + if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM) + status = acpi_enter_sleep_state(acpi_state); + else + do_suspend_lowlevel_s4bios(0); break; default: - printk(KERN_WARNING PREFIX "don't know how to handle %d state.\n", state); - break; + return -EINVAL; } local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); - return status; + return ACPI_SUCCESS(status) ? 0 : -EFAULT; } /** - * acpi_suspend - OS-agnostic system suspend/resume support (S? states) - * @state: state we're entering + * acpi_pm_finish - Finish up suspend sequence. + * @state: State we're coming out of. * + * This is called after we wake back up (or if entering the sleep state + * failed). */ -acpi_status -acpi_suspend ( - u32 state) -{ - acpi_status status; - - /* Suspend is hard to get right on SMP. */ - if (num_online_cpus() != 1) - return AE_ERROR; - - /* get out if state is invalid */ - if (state < ACPI_STATE_S1 || state > ACPI_STATE_S5) - return AE_ERROR; - - /* Since we handle S4OS via a different path (swsusp), give up if no s4bios. */ - if (state == ACPI_STATE_S4 && !acpi_gbl_FACS->S4bios_f) - return AE_ERROR; - - pm_prepare_console(); - - /* - * TBD: S1 can be done without device_suspend. Make a CONFIG_XX - * to handle however when S1 failed without device_suspend. - */ - if (freeze_processes()) { - status = AE_ERROR; - goto Done; - } - - /* do we have a wakeup address for S2 and S3? */ - /* Here, we support only S4BIOS, those we set the wakeup address */ - /* S4OS is only supported for now via swsusp.. */ - if (state == ACPI_STATE_S2 || state == ACPI_STATE_S3 || state == ACPI_STATE_S4) { - if (!acpi_wakeup_address) - return AE_ERROR; - acpi_set_firmware_waking_vector((acpi_physical_address) acpi_wakeup_address); - } - - status = acpi_system_save_state(state); - if (!ACPI_SUCCESS(status)) - return status; - acpi_enter_sleep_state_prep(state); - - /* disable interrupts and flush caches */ - ACPI_DISABLE_IRQS(); - ACPI_FLUSH_CPU_CACHE(); - - /* perform OS-specific sleep actions */ - status = acpi_system_suspend(state); - - /* Even if we failed to go to sleep, all of the devices are in an suspended - * mode. So, we run these unconditionaly to make sure we have a usable system - * no matter what. - */ +static int acpi_pm_finish(u32 state) +{ acpi_leave_sleep_state(state); - acpi_system_restore_state(state); - /* make sure interrupts are enabled */ - ACPI_ENABLE_IRQS(); + /* restore processor state + * We should only be here if we're coming back from STR or STD. + * And, in the case of the latter, the memory image should have already + * been loaded from disk. + */ + if (state > ACPI_STATE_S1) + acpi_restore_state_mem(); /* reset firmware waking vector */ acpi_set_firmware_waking_vector((acpi_physical_address) 0); - Done: - thaw_processes(); - pm_restore_console(); - return status; + if (dmi_broken & BROKEN_INIT_AFTER_S1) { + printk("Broken toshiba laptop -> kicking interrupts\n"); + init_8259A(0); + } + return 0; } + +static struct pm_ops acpi_pm_ops = { + .prepare = acpi_pm_prepare, + .enter = acpi_pm_enter, + .finish = acpi_pm_finish, +}; + static int __init acpi_sleep_init(void) { int i = 0; - ACPI_FUNCTION_TRACE("acpi_system_add_fs"); - if (acpi_disabled) - return_VALUE(0); + return 0; printk(KERN_INFO PREFIX "(supports"); for (i=0; i<ACPI_S_STATE_COUNT; i++) { @@ -294,14 +171,19 @@ static int __init acpi_sleep_init(void) sleep_states[i] = 1; printk(" S%d", i); } - if (i == ACPI_STATE_S4 && acpi_gbl_FACS->S4bios_f) { - sleep_states[i] = 1; - printk(" S4bios"); + if (i == ACPI_STATE_S4) { + if (acpi_gbl_FACS->S4bios_f) { + sleep_states[i] = 1; + printk(" S4bios"); + acpi_pm_ops.pm_disk_mode = PM_DISK_FIRMWARE; + } else if (sleep_states[i]) + acpi_pm_ops.pm_disk_mode = PM_DISK_PLATFORM; } } printk(")\n"); - return_VALUE(0); + pm_set_ops(&acpi_pm_ops); + return 0; } late_initcall(acpi_sleep_init); diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index 50f0bdfd0992..41cbde00b785 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -13,80 +13,12 @@ #include "sleep.h" -#define ACPI_SYSTEM_FILE_SLEEP "sleep" #define ACPI_SYSTEM_FILE_ALARM "alarm" #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME ("sleep") -static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset) -{ - int i; - - ACPI_FUNCTION_TRACE("acpi_system_sleep_seq_show"); - - for (i = 0; i <= ACPI_STATE_S5; i++) { - if (sleep_states[i]) { - seq_printf(seq,"S%d ", i); - if (i == ACPI_STATE_S4 && acpi_gbl_FACS->S4bios_f) - seq_printf(seq, "S4bios "); - } - } - - seq_puts(seq, "\n"); - - return 0; -} - -static int acpi_system_sleep_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_system_sleep_seq_show, PDE(inode)->data); -} - -static int -acpi_system_write_sleep ( - struct file *file, - const char *buffer, - size_t count, - loff_t *ppos) -{ - acpi_status status = AE_ERROR; - char state_string[12] = {'\0'}; - u32 state = 0; - - ACPI_FUNCTION_TRACE("acpi_system_write_sleep"); - - if (count > sizeof(state_string) - 1) - goto Done; - - if (copy_from_user(state_string, buffer, count)) - return_VALUE(-EFAULT); - - state_string[count] = '\0'; - - state = simple_strtoul(state_string, NULL, 0); - - if (state < 1 || state > 4) - goto Done; - - if (!sleep_states[state]) - goto Done; - -#ifdef CONFIG_SOFTWARE_SUSPEND - if (state == 4) { - software_suspend(); - goto Done; - } -#endif - status = acpi_suspend(state); - Done: - if (ACPI_FAILURE(status)) - return_VALUE(-EINVAL); - else - return_VALUE(count); -} - static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) { u32 sec, min, hr; @@ -362,14 +294,6 @@ end: } -static struct file_operations acpi_system_sleep_fops = { - .open = acpi_system_sleep_open_fs, - .read = seq_read, - .write = acpi_system_write_sleep, - .llseek = seq_lseek, - .release = single_release, -}; - static struct file_operations acpi_system_alarm_fops = { .open = acpi_system_alarm_open_fs, .read = seq_read, @@ -383,12 +307,6 @@ static int acpi_sleep_proc_init(void) { struct proc_dir_entry *entry = NULL; - /* 'sleep' [R/W]*/ - entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP, - S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_sleep_fops; - /* 'alarm' [R/W] */ entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM, S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 6f53840c6b39..611a69accdd0 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -25,7 +25,6 @@ #include "power.h" LIST_HEAD(dpm_active); -LIST_HEAD(dpm_suspended); LIST_HEAD(dpm_off); LIST_HEAD(dpm_off_irq); @@ -76,6 +75,7 @@ int device_pm_add(struct device * dev) pr_debug("PM: Adding info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", dev->kobj.name); + atomic_set(&dev->power.pm_users,0); down(&dpm_sem); list_add_tail(&dev->power.entry,&dpm_active); device_pm_set_parent(dev,dev->parent); diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 8130b04ffe5f..fde72b37f938 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -31,7 +31,6 @@ extern struct semaphore dpm_sem; * The PM lists. */ extern struct list_head dpm_active; -extern struct list_head dpm_suspended; extern struct list_head dpm_off; extern struct list_head dpm_off_irq; @@ -61,15 +60,12 @@ extern void dpm_sysfs_remove(struct device *); */ extern int dpm_resume(void); extern void dpm_power_up(void); -extern void dpm_power_up_irq(void); -extern void power_up_device(struct device *); extern int resume_device(struct device *); /* * suspend.c */ extern int suspend_device(struct device *, u32); -extern int power_down_device(struct device *, u32); /* diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 6c8653205128..9db84a9e41e3 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c @@ -12,7 +12,6 @@ #include "power.h" extern int sysdev_resume(void); -extern int sysdev_restore(void); /** @@ -23,59 +22,33 @@ extern int sysdev_restore(void); int resume_device(struct device * dev) { - struct device_driver * drv = dev->driver; - - if (drv && drv->resume) - return drv->resume(dev,RESUME_RESTORE_STATE); + if (dev->bus && dev->bus->resume) + return dev->bus->resume(dev); return 0; } + /** - * dpm_resume - Restore all device state. + * device_resume - Restore state of each device in system. * - * Walk the dpm_suspended list and restore each device. As they are - * resumed, move the devices to the dpm_active list. + * Walk the dpm_off list, remove each entry, resume the device, + * then add it to the dpm_active list. */ -int dpm_resume(void) +void device_resume(void) { - while(!list_empty(&dpm_suspended)) { - struct list_head * entry = dpm_suspended.next; + down(&dpm_sem); + while(!list_empty(&dpm_off)) { + struct list_head * entry = dpm_off.next; struct device * dev = to_device(entry); list_del_init(entry); resume_device(dev); list_add_tail(entry,&dpm_active); } - return 0; -} - - -/** - * device_pm_resume - Restore state of each device in system. - * - * Restore system device state, then common device state. Finally, - * release dpm_sem, as we're done with device PM. - */ - -void device_pm_resume(void) -{ - sysdev_restore(); - dpm_resume(); up(&dpm_sem); } - -/** - * power_up_device - Power one device on. - * @dev: Device. - */ - -void power_up_device(struct device * dev) -{ - struct device_driver * drv = dev->driver; - if (drv && drv->resume) - drv->resume(dev,RESUME_POWER_ON); -} +EXPORT_SYMBOL(device_resume); /** @@ -89,65 +62,31 @@ void power_up_device(struct device * dev) * Interrupts must be disabled when calling this. */ -void dpm_power_up_irq(void) +void dpm_power_up(void) { while(!list_empty(&dpm_off_irq)) { struct list_head * entry = dpm_off_irq.next; list_del_init(entry); - power_up_device(to_device(entry)); - list_add_tail(entry,&dpm_suspended); - } -} - - -/** - * dpm_power_up - Power on most devices. - * - * Walk the dpm_off list and power each device up. This is used - * to power on devices that were able to power down with interrupts - * enabled. - */ - -void dpm_power_up(void) -{ - while (!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.next; - list_del_init(entry); - power_up_device(to_device(entry)); - list_add_tail(entry,&dpm_suspended); + resume_device(to_device(entry)); + list_add_tail(entry,&dpm_active); } } /** - * device_pm_power_up - Turn on all devices. + * device_pm_power_up - Turn on all devices that need special attention. * - * First, power on system devices, which must happen with interrupts - * disbled. Then, power on devices that also require interrupts disabled. - * Turn interrupts back on, and finally power up the rest of the normal - * devices. + * Power on system devices then devices that required we shut them down + * with interrupts disabled. + * Called with interrupts disabled. */ -void device_pm_power_up(void) +void device_power_up(void) { sysdev_resume(); - dpm_power_up_irq(); - local_irq_enable(); dpm_power_up(); } -/** - * device_resume - resume all the devices in the system - * @level: stage of resume process we're at - * - * This function is deprecated, and should be replaced with appropriate - * calls to device_pm_power_up() and device_pm_resume() above. - */ +EXPORT_SYMBOL(device_power_up); -void device_resume(u32 level) -{ - printk("%s is deprecated. Called from:\n",__FUNCTION__); - dump_stack(); -} -EXPORT_SYMBOL(device_resume); diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 4a4ac9f7764d..05ef979a3791 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -14,8 +14,6 @@ static void runtime_resume(struct device * dev) { if (!dev->power.power_state) return; - - power_up_device(dev); resume_device(dev); } @@ -55,19 +53,11 @@ int dpm_runtime_suspend(struct device * dev, u32 state) if (dev->power.power_state) dpm_runtime_resume(dev); - error = suspend_device(dev,state); - if (!error) { - error = power_down_device(dev,state); - if (error) - goto ErrResume; + if (!(error = suspend_device(dev,state))) dev->power.power_state = state; - } Done: up(&dpm_sem); return error; - ErrResume: - resume_device(dev); - goto Done; } diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index cf1f6c0b7b0e..6da8cdd69dce 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -11,7 +11,6 @@ #include <linux/device.h> #include "power.h" -extern int sysdev_save(u32 state); extern int sysdev_suspend(u32 state); /* @@ -38,41 +37,43 @@ extern int sysdev_suspend(u32 state); int suspend_device(struct device * dev, u32 state) { - struct device_driver * drv = dev->driver; int error = 0; - if (drv && drv->suspend) - error = drv->suspend(dev,state,SUSPEND_SAVE_STATE); + if (dev->bus && dev->bus->suspend) + error = dev->bus->suspend(dev,state); if (!error) { list_del(&dev->power.entry); - list_add(&dev->power.entry,&dpm_suspended); + list_add(&dev->power.entry,&dpm_off); + } else if (error == -EAGAIN) { + list_del(&dev->power.entry); + list_add(&dev->power.entry,&dpm_off_irq); } return error; } /** - * device_pm_suspend - Save state and stop all devices in system. + * device_suspend - Save state and stop all devices in system. * @state: Power state to put each device in. * * Walk the dpm_active list, call ->suspend() for each device, and move - * it to dpm_suspended. If we hit a failure with any of the devices, call - * dpm_resume() above to bring the suspended devices back to life. + * it to dpm_off. + * Check the return value for each. If it returns 0, then we move the + * the device to the dpm_off list. If it returns -EAGAIN, we move it to + * the dpm_off_irq list. If we get a different error, try and back out. * - * Have system devices save state last. + * If we hit a failure with any of the devices, call device_resume() + * above to bring the suspended devices back to life. * * Note this function leaves dpm_sem held to * a) block other devices from registering. * b) prevent other PM operations from happening after we've begun. * c) make sure we're exclusive when we disable interrupts. * - * device_pm_resume() will release dpm_sem after restoring state to - * all devices (as will this on error). You must call it once you've - * called device_pm_suspend(). */ -int device_pm_suspend(u32 state) +int device_suspend(u32 state) { int error = 0; @@ -83,153 +84,45 @@ int device_pm_suspend(u32 state) if ((error = suspend_device(dev,state))) goto Error; } - - if ((error = sysdev_save(state))) - goto Error; Done: + up(&dpm_sem); return error; Error: - dpm_resume(); - up(&dpm_sem); + device_resume(); goto Done; } - -/** - * power_down_device - Put one device in low power state. - * @dev: Device. - * @state: Power state to enter. - */ - -int power_down_device(struct device * dev, u32 state) -{ - struct device_driver * drv = dev->driver; - int error = 0; - - if (drv && drv->suspend) - error = drv->suspend(dev,state,SUSPEND_POWER_DOWN); - if (!error) { - list_del(&dev->power.entry); - list_add(&dev->power.entry,&dpm_off); - } - return error; -} - - -/** - * dpm_power_down - Put all devices in low power state. - * @state: Power state to enter. - * - * Walk the dpm_suspended list (with interrupts enabled) and try - * to power down each each. If any fail with -EAGAIN, they require - * the call to be done with interrupts disabled. So, we move them to - * the dpm_off_irq list. - * - * If the call succeeds, we move each device to the dpm_off list. - */ - -static int dpm_power_down(u32 state) -{ - while(!list_empty(&dpm_suspended)) { - struct list_head * entry = dpm_suspended.prev; - int error; - error = power_down_device(to_device(entry),state); - if (error) { - if (error == -EAGAIN) { - list_del(entry); - list_add(entry,&dpm_off_irq); - continue; - } - return error; - } - } - return 0; -} +EXPORT_SYMBOL(device_suspend); /** - * dpm_power_down_irq - Power down devices without interrupts. - * @state: State to enter. + * device_power_down - Shut down special devices. + * @state: Power state to enter. * - * Walk the dpm_off_irq list (built by dpm_power_down) and power - * down each device that requires the call to be made with interrupts - * disabled. + * Walk the dpm_off_irq list, calling ->power_down() for each device that + * couldn't power down the device with interrupts enabled. When we're + * done, power down system devices. */ -static int dpm_power_down_irq(u32 state) +int device_power_down(u32 state) { - struct device * dev; int error = 0; + struct device * dev; list_for_each_entry_reverse(dev,&dpm_off_irq,power.entry) { - if ((error = power_down_device(dev,state))) + if ((error = suspend_device(dev,state))) break; - } - return error; -} - - -/** - * device_pm_power_down - Put all devices in low power state. - * @state: Power state to enter. - * - * Walk the dpm_suspended list, calling ->power_down() for each device. - * Check the return value for each. If it returns 0, then we move the - * the device to the dpm_off list. If it returns -EAGAIN, we move it to - * the dpm_off_irq list. If we get a different error, try and back out. - * - * dpm_irq_off is for devices that require interrupts to be disabled to - * either to power down the device or power it back on. - * - * When we're done, we disable interrrupts (!!) and walk the dpm_off_irq - * list to shut down the devices that need interrupts disabled. - * - * This function leaves interrupts disabled on exit, since powering down - * devices should be the very last thing before the system is put into a - * low-power state. - * - * device_pm_power_on() should be called to re-enable interrupts and power - * the devices back on. - */ - -int device_pm_power_down(u32 state) -{ - int error = 0; - - if ((error = dpm_power_down(state))) - goto ErrorIRQOn; - local_irq_disable(); - if ((error = dpm_power_down_irq(state))) - goto ErrorIRQOff; - - sysdev_suspend(state); + } + if (error) + goto Error; + if ((error = sysdev_suspend(state))) + goto Error; Done: return error; - - ErrorIRQOff: - dpm_power_up_irq(); - local_irq_enable(); - ErrorIRQOn: + Error: dpm_power_up(); goto Done; } +EXPORT_SYMBOL(device_power_down); -/** - * device_suspend - suspend all devices on the device ree - * @state: state we're entering - * @level: Stage of suspend sequence we're in. - * - * - * This function is deprecated. Calls should be replaced with - * appropriate calls to device_pm_suspend() and device_pm_power_down(). - */ - -int device_suspend(u32 state, u32 level) -{ - - printk("%s Called from:\n",__FUNCTION__); - dump_stack(); - return -EFAULT; -} -EXPORT_SYMBOL(device_suspend); diff --git a/drivers/base/sys.c b/drivers/base/sys.c index e306d2e26363..299b390e243b 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -283,61 +283,16 @@ void sysdev_shutdown(void) /** - * sysdev_save - Save system device state - * @state: Power state we're entering. - * - * This is called when the system is going to sleep, but before interrupts - * have been disabled. This allows system device drivers to allocate and - * save device state, including sleeping during the process.. - */ - -int sysdev_save(u32 state) -{ - struct sysdev_class * cls; - - pr_debug("Saving System Device State\n"); - - down_write(&system_subsys.rwsem); - - list_for_each_entry_reverse(cls,&system_subsys.kset.list, - kset.kobj.entry) { - struct sys_device * sysdev; - pr_debug("Saving state for type '%s':\n",cls->kset.kobj.name); - - list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { - struct sysdev_driver * drv; - - pr_debug(" %s\n",sysdev->kobj.name); - - list_for_each_entry(drv,&global_drivers,entry) { - if (drv->save) - drv->save(sysdev,state); - } - - list_for_each_entry(drv,&cls->drivers,entry) { - if (drv->save) - drv->save(sysdev,state); - } - - if (cls->save) - cls->save(sysdev,state); - } - } - up_write(&system_subsys.rwsem); - return 0; -} - - -/** * sysdev_suspend - Suspend all system devices. * @state: Power state to enter. * * We perform an almost identical operation as sys_device_shutdown() - * above, though calling ->suspend() instead. + * above, though calling ->suspend() instead. Interrupts are disabled + * when this called. Devices are responsible for both saving state and + * quiescing or powering down the device. * - * Note: Interrupts are disabled when called, so we can't sleep when - * trying to get the subsystem's rwsem. If that happens, print a nasty - * warning and return an error. + * This is only called by the device PM core, so we let them handle + * all synchronization. */ int sysdev_suspend(u32 state) @@ -346,11 +301,6 @@ int sysdev_suspend(u32 state) pr_debug("Suspending System Devices\n"); - if (!down_write_trylock(&system_subsys.rwsem)) { - printk("%s: Cannot acquire semaphore; Failing\n",__FUNCTION__); - return -EFAULT; - } - list_for_each_entry_reverse(cls,&system_subsys.kset.list, kset.kobj.entry) { struct sys_device * sysdev; @@ -378,8 +328,6 @@ int sysdev_suspend(u32 state) cls->suspend(sysdev,state); } } - up_write(&system_subsys.rwsem); - return 0; } @@ -390,7 +338,7 @@ int sysdev_suspend(u32 state) * Similar to sys_device_suspend(), but we iterate the list forwards * to guarantee that parent devices are resumed before their children. * - * Note: Interrupts are disabled when called. + * Note: Interrupts are disabled when called. */ int sysdev_resume(void) @@ -399,9 +347,6 @@ int sysdev_resume(void) pr_debug("Resuming System Devices\n"); - if(!down_write_trylock(&system_subsys.rwsem)) - return -EFAULT; - list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) { struct sys_device * sysdev; @@ -429,50 +374,6 @@ int sysdev_resume(void) } } - up_write(&system_subsys.rwsem); - return 0; -} - - -/** - * sysdev_restore - Restore system device state - * - * This is called during a suspend/resume cycle last, after interrupts - * have been re-enabled. This is intended for auxillary drivers, etc, - * that may sleep when restoring state. - */ - -int sysdev_restore(void) -{ - struct sysdev_class * cls; - - down_write(&system_subsys.rwsem); - pr_debug("Restoring System Device State\n"); - - list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) { - struct sys_device * sysdev; - - pr_debug("Restoring state for type '%s':\n",cls->kset.kobj.name); - list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { - struct sysdev_driver * drv; - pr_debug(" %s\n",sysdev->kobj.name); - - if (cls->restore) - cls->restore(sysdev); - - list_for_each_entry(drv,&cls->drivers,entry) { - if (drv->restore) - drv->restore(sysdev); - } - - list_for_each_entry(drv,&global_drivers,entry) { - if (drv->restore) - drv->restore(sysdev); - } - } - } - - up_write(&system_subsys.rwsem); return 0; } diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index d16c54b65102..60f1508b24ab 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -6,7 +6,7 @@ menu "Character devices" config VT bool "Virtual terminal" if EMBEDDED - requires INPUT=y + select INPUT default y ---help--- If you say Y here, you will get support for terminal devices with diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index cf0b5307a8de..4e7a197f6611 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -3330,10 +3330,6 @@ static ide_driver_t ide_cdrom_driver = { .drives = LIST_HEAD_INIT(ide_cdrom_driver.drives), .start_power_step = ide_cdrom_start_power_step, .complete_power_step = ide_cdrom_complete_power_step, - .gen_driver = { - .suspend = generic_ide_suspend, - .resume = generic_ide_resume, - } }; static int idecd_open(struct inode * inode, struct file * file) diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 30865145af3e..1217e840ac02 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -1732,10 +1732,6 @@ static ide_driver_t idedisk_driver = { .drives = LIST_HEAD_INIT(idedisk_driver.drives), .start_power_step = idedisk_start_power_step, .complete_power_step = idedisk_complete_power_step, - .gen_driver = { - .suspend = generic_ide_suspend, - .resume = generic_ide_resume, - } }; static int idedisk_open(struct inode *inode, struct file *filp) diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 5d19aa20abcd..dd0ad3ff074c 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -1534,16 +1534,13 @@ int ata_attach(ide_drive_t *drive) EXPORT_SYMBOL(ata_attach); -int generic_ide_suspend(struct device *dev, u32 state, u32 level) +static int generic_ide_suspend(struct device *dev, u32 state) { ide_drive_t *drive = dev->driver_data; struct request rq; struct request_pm_state rqpm; ide_task_t args; - if (level == dev->power_state || level != SUSPEND_SAVE_STATE) - return 0; - memset(&rq, 0, sizeof(rq)); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); @@ -1556,18 +1553,13 @@ int generic_ide_suspend(struct device *dev, u32 state, u32 level) return ide_do_drive_cmd(drive, &rq, ide_wait); } -EXPORT_SYMBOL(generic_ide_suspend); - -int generic_ide_resume(struct device *dev, u32 level) +static int generic_ide_resume(struct device *dev) { ide_drive_t *drive = dev->driver_data; struct request rq; struct request_pm_state rqpm; ide_task_t args; - if (level == dev->power_state || level != RESUME_RESTORE_STATE) - return 0; - memset(&rq, 0, sizeof(rq)); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); @@ -1580,8 +1572,6 @@ int generic_ide_resume(struct device *dev, u32 level) return ide_do_drive_cmd(drive, &rq, ide_head_wait); } -EXPORT_SYMBOL(generic_ide_resume); - int generic_ide_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg) { @@ -2594,6 +2584,8 @@ EXPORT_SYMBOL(ide_probe); struct bus_type ide_bus_type = { .name = "ide", + .suspend = generic_ide_suspend, + .resume = generic_ide_resume, }; /* diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 63ceffd78748..a73b16eefd58 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -647,7 +647,6 @@ static void __exit exit_sedlbauer_cs(void) /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) { - del_timer(&dev_list->release); if (dev_list->state & DEV_CONFIG) sedlbauer_release(dev_list); sedlbauer_detach(dev_list); diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index ad105b881410..2dac57b618a3 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -308,8 +308,10 @@ static void add_us_sample(struct mm_struct * mm, struct op_sample * s) cookie = lookup_dcookie(mm, s->eip, &offset); - if (!cookie) + if (!cookie) { + atomic_inc(&oprofile_stats.sample_lost_no_mapping); return; + } if (cookie != last_cookie) { add_cookie_switch(cookie); diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 21ae41a54e90..b7466377afd4 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -19,6 +19,17 @@ unsigned long fs_cpu_buffer_size = 8192; unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */ +static ssize_t pointer_size_read(struct file * file, char * buf, size_t count, loff_t * offset) +{ + return oprofilefs_ulong_to_user((unsigned long)sizeof(void *), buf, count, offset); +} + + +static struct file_operations pointer_size_fops = { + .read = pointer_size_read, +}; + + static ssize_t cpu_type_read(struct file * file, char * buf, size_t count, loff_t * offset) { return oprofilefs_str_to_user(oprofile_ops->cpu_type, buf, count, offset); @@ -32,7 +43,7 @@ static struct file_operations cpu_type_fops = { static ssize_t enable_read(struct file * file, char * buf, size_t count, loff_t * offset) { - return oprofilefs_ulong_to_user(&oprofile_started, buf, count, offset); + return oprofilefs_ulong_to_user(oprofile_started, buf, count, offset); } @@ -85,6 +96,7 @@ void oprofile_create_files(struct super_block * sb, struct dentry * root) oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed); oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &fs_cpu_buffer_size); oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); + oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops); oprofile_create_stats_files(sb, root); if (oprofile_ops->create_files) oprofile_ops->create_files(sb, root); diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c index 5624c1e017e0..f01e1935072c 100644 --- a/drivers/oprofile/oprofile_stats.c +++ b/drivers/oprofile/oprofile_stats.c @@ -32,6 +32,7 @@ void oprofile_reset_stats(void) } atomic_set(&oprofile_stats.sample_lost_no_mm, 0); + atomic_set(&oprofile_stats.sample_lost_no_mapping, 0); atomic_set(&oprofile_stats.event_lost_overflow, 0); } @@ -70,6 +71,8 @@ void oprofile_create_stats_files(struct super_block * sb, struct dentry * root) oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mm", &oprofile_stats.sample_lost_no_mm); + oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mapping", + &oprofile_stats.sample_lost_no_mapping); oprofilefs_create_ro_atomic(sb, dir, "event_lost_overflow", &oprofile_stats.event_lost_overflow); } diff --git a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h index e3f67d5c0910..9f4d4d2046db 100644 --- a/drivers/oprofile/oprofile_stats.h +++ b/drivers/oprofile/oprofile_stats.h @@ -14,6 +14,7 @@ struct oprofile_stat_struct { atomic_t sample_lost_no_mm; + atomic_t sample_lost_no_mapping; atomic_t event_lost_overflow; }; diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index c82630ec1819..ed1efe61f6e3 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -69,7 +69,7 @@ ssize_t oprofilefs_str_to_user(char const * str, char * buf, size_t count, loff_ #define TMPBUFSIZE 50 -ssize_t oprofilefs_ulong_to_user(unsigned long * val, char * buf, size_t count, loff_t * offset) +ssize_t oprofilefs_ulong_to_user(unsigned long val, char * buf, size_t count, loff_t * offset) { char tmpbuf[TMPBUFSIZE]; size_t maxlen; @@ -78,7 +78,7 @@ ssize_t oprofilefs_ulong_to_user(unsigned long * val, char * buf, size_t count, return 0; spin_lock(&oprofilefs_lock); - maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", *val); + maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val); spin_unlock(&oprofilefs_lock); if (maxlen > TMPBUFSIZE) maxlen = TMPBUFSIZE; @@ -122,7 +122,8 @@ int oprofilefs_ulong_from_user(unsigned long * val, char const * buf, size_t cou static ssize_t ulong_read_file(struct file * file, char * buf, size_t count, loff_t * offset) { - return oprofilefs_ulong_to_user(file->private_data, buf, count, offset); + unsigned long * val = file->private_data; + return oprofilefs_ulong_to_user(*val, buf, count, offset); } @@ -212,9 +213,8 @@ int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root, static ssize_t atomic_read_file(struct file * file, char * buf, size_t count, loff_t * offset) { - atomic_t * aval = file->private_data; - unsigned long val = atomic_read(aval); - return oprofilefs_ulong_to_user(&val, buf, count, offset); + atomic_t * val = file->private_data; + return oprofilefs_ulong_to_user(atomic_read(val), buf, count, offset); } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index f0f3d80ce60d..640681c93bdc 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -158,32 +158,23 @@ static int pci_device_remove(struct device * dev) return 0; } -static int pci_device_suspend(struct device * dev, u32 state, u32 level) +static int pci_device_suspend(struct device * dev, u32 state) { struct pci_dev * pci_dev = to_pci_dev(dev); - int error = 0; + struct pci_driver * drv = pci_dev->driver; - if (pci_dev->driver) { - if (level == SUSPEND_SAVE_STATE && pci_dev->driver->save_state) - error = pci_dev->driver->save_state(pci_dev,state); - else if (level == SUSPEND_POWER_DOWN && pci_dev->driver->suspend) - error = pci_dev->driver->suspend(pci_dev,state); - } - return error; + if (drv && drv->suspend) + return drv->suspend(pci_dev,state); + return 0; } -static int pci_device_resume(struct device * dev, u32 level) +static int pci_device_resume(struct device * dev) { struct pci_dev * pci_dev = to_pci_dev(dev); + struct pci_driver * drv = pci_dev->driver; - if (pci_dev->driver) { - /* We may not call PCI drivers resume at - RESUME_POWER_ON because interrupts are not yet - working at that point. Calling resume at - RESUME_RESTORE_STATE seems like solution. */ - if (level == RESUME_RESTORE_STATE && pci_dev->driver->resume) - pci_dev->driver->resume(pci_dev); - } + if (drv && drv->resume) + drv->resume(pci_dev); return 0; } @@ -349,8 +340,6 @@ pci_register_driver(struct pci_driver *drv) drv->driver.name = drv->name; drv->driver.bus = &pci_bus_type; drv->driver.probe = pci_device_probe; - drv->driver.resume = pci_device_resume; - drv->driver.suspend = pci_device_suspend; drv->driver.remove = pci_device_remove; drv->driver.kobj.ktype = &pci_driver_kobj_type; pci_init_dynids(&drv->dynids); @@ -496,6 +485,8 @@ struct bus_type pci_bus_type = { .name = "pci", .match = pci_bus_match, .hotplug = pci_hotplug, + .suspend = pci_device_suspend, + .resume = pci_device_resume, }; static int __init pci_driver_init(void) |
