From 47d696a99c502d7f75d3cf77ec1feb21ffc0ac9f Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 18 Aug 2003 01:31:59 -0700 Subject: [power] Improve suspend functions. - Implement pm_suspend(), which is callable from anywhere in the kernel, and takes one of PM_SUSPEND_STANDBY PM_SUSPEND_MEM PM_SUSPEND_DISK and enters the appropriate state. - Change sysfs file to look for "standby" "mem" "disk" for what state to enter (rather than 'suspend' and 'hibernate' for the latter two). - Add pm_sem to block multiple suspend sequences happening at once. - Allocate a console and stop processes from common code before entering state. - Add pm_power_down() callback for platform drivers to implement. Will be called to actually enter the low-power state. --- include/linux/pm.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'include/linux') diff --git a/include/linux/pm.h b/include/linux/pm.h index e4c795f71cea..a5e4d115d172 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -186,9 +186,31 @@ static inline void pm_dev_idle(struct pm_dev *dev) {} #endif /* CONFIG_PM */ + +/* + * Callbacks for platform drivers to implement. + */ extern void (*pm_idle)(void); extern void (*pm_power_off)(void); +enum { + PM_SUSPEND_ON, + PM_SUSPEND_STANDBY, + PM_SUSPEND_MEM, + PM_SUSPEND_DISK, + PM_SUSPEND_MAX, +}; + +extern int (*pm_power_down)(u32 state); + + +extern int pm_suspend(u32 state); + + +/* + * Device power management + */ + struct device; struct dev_pm_info { -- cgit v1.2.3 From e533deb559deeb04ca83c2612154682aa22ebbe9 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 18 Aug 2003 02:40:36 -0700 Subject: [power] Improve suspend sequence. - Expand pm_power_down() into struct pm_ops, with ->prepare(), ->enter() and ->finish() methods, so the platform drivers get called to do start and stop work during suspend sequence. - Make sure devices are suspended/resumed in enter_state(), and that they are powered down in pm_suspend_mem() and pm_suspend_standby(). - Call ->prepare() in suspend_prepare() and ->finish() in suspend_finish(). --- include/linux/pm.h | 7 ++- kernel/power/main.c | 126 +++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 110 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pm.h b/include/linux/pm.h index a5e4d115d172..15b3f5efa692 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -201,8 +201,13 @@ enum { PM_SUSPEND_MAX, }; -extern int (*pm_power_down)(u32 state); +struct pm_ops { + int (*prepare)(u32 state); + int (*enter)(u32 state); + int (*finish)(u32 state); +}; +extern void pm_set_ops(struct pm_ops *); extern int pm_suspend(u32 state); diff --git a/kernel/power/main.c b/kernel/power/main.c index 79301a45ea8a..12e2989ef9e1 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -16,20 +16,72 @@ #include -int (*pm_power_down)(u32 state) = NULL; +static DECLARE_MUTEX(pm_sem); +static struct pm_ops * pm_ops = NULL; + +/** + * pm_set_ops - Set the global power method table. + * @ops: Pointer to ops structure. + */ + +void pm_set_ops(struct pm_ops * ops) +{ + down(&pm_sem); + pm_ops = ops; + up(&pm_sem); +} -static DECLARE_MUTEX(pm_sem); +/** + * pm_suspend_standby - Enter 'standby' state. + * + * 'standby' is also known as 'Power-On Suspend'. Here, we power down + * devices, disable interrupts, and enter the state. + */ static int pm_suspend_standby(void) { - return 0; + int error = 0; + unsigned long flags; + + if (!pm_ops || !pm_ops->enter) + return -EPERM; + + if ((error = device_pm_power_down(PM_SUSPEND_STANDBY))) + goto Done; + local_irq_save(flags); + error = pm_ops->enter(PM_SUSPEND_STANDBY); + local_irq_restore(flags); + device_pm_power_up(); + Done: + return error; } + +/** + * pm_suspend_mem - Enter suspend-to-RAM state. + * + * Identical to pm_suspend_standby() - we power down devices, disable + * interrupts, and enter the low-power state. + */ + static int pm_suspend_mem(void) { - return 0; + int error = 0; + unsigned long flags; + + if (!pm_ops || !pm_ops->enter) + return -EPERM; + + if ((error = device_pm_power_down(PM_SUSPEND_STANDBY))) + goto Done; + local_irq_save(flags); + error = pm_ops->enter(PM_SUSPEND_STANDBY); + local_irq_restore(flags); + device_pm_power_up(); + Done: + return error; } static int pm_suspend_disk(void) @@ -51,25 +103,51 @@ struct pm_state { }; -static int suspend_prepare(void) +/** + * suspend_prepare - Do prep work before entering low-power state. + * @state: State we're entering. + * + * This is common code that is called for each state that we're + * entering. Allocate a console, stop all processes, then make sure + * the platform can enter the requested state. + */ + +static int suspend_prepare(u32 state) { int error = 0; pm_prepare_console(); if (freeze_processes()) { - thaw_processes(); error = -EAGAIN; - goto Done; + goto Thaw; } + if (pm_ops && pm_ops->prepare) { + if ((error = pm_ops->prepare(state))) + goto Thaw; + } Done: pm_restore_console(); return error; + Thaw: + thaw_processes(); + goto Done; } -static void suspend_finish(void) + +/** + * suspend_finish - Do final work before exiting suspend sequence. + * @state: State we're coming out of. + * + * Call platform code to clean up, restart processes, and free the + * console that we've allocated. + */ + +static void suspend_finish(u32 state) { + if (pm_ops && pm_ops->finish) + pm_ops->finish(state); thaw_processes(); pm_restore_console(); } @@ -86,23 +164,25 @@ static void suspend_finish(void) * we've woken up). */ -static int enter_state(struct pm_state * state) +static int enter_state(u32 state) { int error; + struct pm_state * s = &pm_states[state]; if (down_trylock(&pm_sem)) return -EBUSY; - if (!pm_power_down) { - error = -EPERM; + if ((error = suspend_prepare(state))) goto Unlock; - } - if ((error = suspend_prepare())) - return error; + if ((error = device_pm_suspend(state))) + goto Finish; - error = state->fn(); - suspend_finish(); + error = s->fn(); + + device_pm_resume(); + Finish: + suspend_finish(state); Unlock: up(&pm_sem); return error; @@ -120,7 +200,7 @@ static int enter_state(struct pm_state * state) int pm_suspend(u32 state) { if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX) - return enter_state(&pm_states[state]); + return enter_state(state); return -EINVAL; } @@ -160,20 +240,22 @@ static ssize_t state_show(struct subsystem * subsys, char * buf) return (s - buf); } -static ssize_t state_store(struct subsystem * s, const char * buf, size_t n) +static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n) { - struct pm_state * state; + u32 state; + struct pm_state * s; int error; char * end = strchr(buf,'\n'); if (end) *end = '\0'; - for (state = &pm_states[0]; state; state++) { - if (state->name && !strcmp(buf,state->name)) + for (state = 0; state < PM_SUSPEND_MAX; state++) { + s = &pm_states[state]; + if (s->name && !strcmp(buf,s->name)) break; } - if (state) + if (s) error = enter_state(state); else error = -EINVAL; -- cgit v1.2.3 From 4db335837b40105b914d6eab47785638dfa65059 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 19 Aug 2003 01:26:30 -0700 Subject: [power] Add flag to control suspend-to-disk behavior. Suspend-to-disk can be handled in numerous ways, some we have control over, and others we don't. The biggest difference is whether or not the firmware is responsible for entering a low-power state or if the platform driver is. The two modes are incompatible, so we enable the platform driver tell the PM core when they register their pm_ops (via the ->pm_disk_mode) field. If the firmware is responsible, then it will also write memory to disk, while the kernel is otherwise responsible. However, a user may choose to use the in-kernel suspend mechanism, even if the system supports only the firmware mechanism. Instead of entering a low-power state, the system will turn off (or reboot for testing). A sysfs file -- /sys/power/disk -- is available to set the mode to one of: 'firmware' 'platform' 'shutdown' 'reboot' The latter two are settable any time, and assume that one is using swsusp. The other two are only settable to what the platform supports. --- drivers/acpi/sleep/main.c | 10 ++++-- include/linux/pm.h | 10 ++++++ kernel/power/main.c | 78 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 91 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 92c6840f6c23..5011051e6a94 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c @@ -165,9 +165,13 @@ 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"); diff --git a/include/linux/pm.h b/include/linux/pm.h index 15b3f5efa692..70282a7943b1 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -201,7 +201,17 @@ enum { PM_SUSPEND_MAX, }; +enum { + PM_DISK_FIRMWARE = 1, + PM_DISK_PLATFORM, + PM_DISK_SHUTDOWN, + PM_DISK_REBOOT, + PM_DISK_MAX, +}; + + struct pm_ops { + u32 pm_disk_mode; int (*prepare)(u32 state); int (*enter)(u32 state); int (*finish)(u32 state); diff --git a/kernel/power/main.c b/kernel/power/main.c index 71648de7aa81..98c16b847144 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -20,6 +20,9 @@ static DECLARE_MUTEX(pm_sem); static struct pm_ops * pm_ops = NULL; +static u32 pm_disk_mode = PM_DISK_SHUTDOWN; + + /** * pm_set_ops - Set the global power method table. * @ops: Pointer to ops structure. @@ -29,6 +32,8 @@ void pm_set_ops(struct pm_ops * ops) { down(&pm_sem); pm_ops = ops; + if (ops->pm_disk_mode && ops->pm_disk_mode < PM_DISK_MAX) + pm_disk_mode = ops->pm_disk_mode; up(&pm_sem); } @@ -224,6 +229,74 @@ static struct subsys_attribute _name##_attr = { \ .store = _name##_store, \ } + +static char * pm_disk_modes[] = { + [PM_DISK_FIRMWARE] = "firmware", + [PM_DISK_PLATFORM] = "platform", + [PM_DISK_SHUTDOWN] = "shutdown", + [PM_DISK_REBOOT] = "reboot", +}; + +/** + * disk - Control suspend-to-disk mode + * + * Suspend-to-disk can be handled in several ways. The greatest + * distinction is who writes memory to disk - the firmware or the OS. + * If the firmware does it, we assume that it also handles suspending + * the system. + * If the OS does it, then we have three options for putting the system + * to sleep - using the platform driver (e.g. ACPI or other PM registers), + * powering off the system or rebooting the system (for testing). + * + * The system will support either 'firmware' or 'platform', and that is + * known a priori (and encoded in pm_ops). But, the user may choose + * 'shutdown' or 'reboot' as alternatives. + * + * show() will display what the mode is currently set to. + * store() will accept one of + * + * 'firmware' + * 'platform' + * 'shutdown' + * 'reboot' + * + * It will only change to 'firmware' or 'platform' if the system + * supports it (as determined from pm_ops->pm_disk_mode). + */ + +static ssize_t disk_show(struct subsystem * subsys, char * buf) +{ + return sprintf(buf,"%s\n",pm_disk_modes[pm_disk_mode]); +} + + +static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n) +{ + int i; + u32 mode = 0; + + for (i = PM_DISK_FIRMWARE; i < PM_DISK_MAX; i++) { + if (!strcmp(buf,pm_disk_modes[i])) { + mode = i; + break; + } + } + if (mode) { + if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT) + pm_disk_mode = mode; + else { + if (pm_ops && (mode == pm_ops->pm_disk_mode)) + pm_disk_mode = mode; + else + return -EINVAL; + } + return n; + } + return -EINVAL; +} + +power_attr(disk); + /** * state - control system power state. * @@ -251,10 +324,6 @@ static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n u32 state; struct pm_state * s; int error; - char * end = strchr(buf,'\n'); - - if (end) - *end = '\0'; for (state = 0; state < PM_SUSPEND_MAX; state++) { s = &pm_states[state]; @@ -272,6 +341,7 @@ power_attr(state); static struct attribute * g[] = { &state_attr.attr, + &disk_attr.attr, NULL, }; -- cgit v1.2.3 From 98256b561371e19539b68c631ef0dcc395e77908 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 19 Aug 2003 07:21:38 -0700 Subject: [acpi] Fix compilation when CONFIG_SMP=n A recent slew of ACPI "fixes" completely broke the build when one built without SMP, IO APICs, or Local APICs. Bad Intel, no cookie. --- arch/i386/kernel/acpi/boot.c | 22 +++++----------------- arch/i386/kernel/mpparse.c | 3 +-- arch/i386/kernel/setup.c | 10 ++++------ include/asm-i386/acpi.h | 38 +++++++++++++++++++++++++++----------- include/linux/acpi.h | 12 ++++++++++++ 5 files changed, 49 insertions(+), 36 deletions(-) (limited to 'include/linux') diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 336b2088b808..3bf5e36282f4 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,9 @@ extern int acpi_disabled; extern int acpi_ht; +int acpi_lapic = 0; +int acpi_ioapic = 0; + /* -------------------------------------------------------------------------- Boot-time Configuration -------------------------------------------------------------------------- */ @@ -90,8 +94,6 @@ char *__acpi_map_table(unsigned long phys, unsigned long size) #ifdef CONFIG_X86_LOCAL_APIC -int acpi_lapic; - static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; @@ -158,8 +160,6 @@ acpi_parse_lapic_addr_ovr ( return 0; } -#ifdef CONFIG_ACPI - static int __init acpi_parse_lapic_nmi ( acpi_table_entry_header *header) @@ -178,15 +178,11 @@ acpi_parse_lapic_nmi ( return 0; } -#endif /*CONFIG_ACPI*/ #endif /*CONFIG_X86_LOCAL_APIC*/ #ifdef CONFIG_X86_IO_APIC -int acpi_ioapic; - -#ifdef CONFIG_ACPI static int __init acpi_parse_ioapic ( @@ -248,7 +244,6 @@ acpi_parse_nmi_src ( return 0; } -#endif /*CONFIG_ACPI*/ #endif /*CONFIG_X86_IO_APIC*/ @@ -331,14 +326,12 @@ acpi_boot_init (void) if (result) return result; -#ifdef CONFIG_ACPI result = acpi_blacklisted(); if (result) { printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n"); acpi_disabled = 1; return result; } -#endif #ifdef CONFIG_X86_LOCAL_APIC @@ -389,21 +382,18 @@ acpi_boot_init (void) return result; } -#ifdef CONFIG_ACPI result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi); if (result < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* TBD: Cleanup to allow fallback to MPS */ return result; } -#endif /*CONFIG_ACPI*/ acpi_lapic = 1; #endif /*CONFIG_X86_LOCAL_APIC*/ #ifdef CONFIG_X86_IO_APIC -#ifdef CONFIG_ACPI /* * I/O APIC @@ -423,7 +413,7 @@ acpi_boot_init (void) /* * if "noapic" boot option, don't look for IO-APICs */ - if (skip_ioapic_setup) { + if (ioapic_setup_disabled()) { printk(KERN_INFO PREFIX "Skipping IOAPIC probe " "due to 'noapic' option.\n"); return 1; @@ -459,8 +449,6 @@ acpi_boot_init (void) acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; acpi_ioapic = 1; - -#endif /*CONFIG_ACPI*/ #endif /*CONFIG_X86_IO_APIC*/ #ifdef CONFIG_X86_LOCAL_APIC diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c index b57846ce7dbe..bd105ba58219 100644 --- a/arch/i386/kernel/mpparse.c +++ b/arch/i386/kernel/mpparse.c @@ -1013,7 +1013,6 @@ void __init mp_config_acpi_legacy_irqs (void) panic("Max # of irq sources exceeded!\n"); } } -#endif /* CONFIG_X86_IO_APIC */ #ifdef CONFIG_ACPI @@ -1150,5 +1149,5 @@ void __init mp_parse_prt (void) } #endif /*CONFIG_ACPI_PCI*/ - +#endif /* CONFIG_X86_IO_APIC */ #endif /*CONFIG_ACPI_BOOT*/ diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index ab2881128c35..f13a8ee9f67b 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -544,9 +544,8 @@ static void __init parse_cmdline_early (char ** cmdline_p) } /* disable IO-APIC */ - else if (!memcmp(from, "noapic", 6)) { - skip_ioapic_setup = 1; - } + else if (!memcmp(from, "noapic", 6)) + disable_ioapic_setup(); #endif /* @@ -1003,12 +1002,11 @@ void __init setup_arch(char **cmdline_p) generic_apic_probe(*cmdline_p); #endif -#ifdef CONFIG_ACPI_BOOT /* * Parse the ACPI tables for possible boot-time SMP configuration. */ - (void) acpi_boot_init(); -#endif + acpi_boot_init(); + #ifdef CONFIG_X86_LOCAL_APIC if (smp_found_config) get_smp_config(); diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h index 350048b1f39e..6b56aa3eaa39 100644 --- a/include/asm-i386/acpi.h +++ b/include/asm-i386/acpi.h @@ -106,21 +106,37 @@ :"0"(n_hi), "1"(n_lo)) -#if defined(CONFIG_ACPI_BOOT) && defined(CONFIG_X86_LOCAL_APIC) - extern int acpi_lapic; -#else - #define acpi_lapic 0 -#endif +#ifdef CONFIG_ACPI_BOOT +extern int acpi_lapic; +extern int acpi_ioapic; -#if defined(CONFIG_ACPI_BOOT) && defined(CONFIG_X86_IO_APIC) - extern int acpi_ioapic; -#else - #define acpi_ioapic 0 -#endif -#ifdef CONFIG_ACPI_BOOT /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */ #define FIX_ACPI_PAGES 4 + +#ifdef CONFIG_X86_IO_APIC +extern int skip_ioapic_setup; + +static inline void disable_ioapic_setup(void) +{ + skip_ioapic_setup = 1; +} + +static inline int ioapic_setup_disabled(void) +{ + return skip_ioapic_setup; +} + +#else +static inline void disable_ioapic_setup(void) +{ } + +#endif + +#else /* CONFIG_ACPI_BOOT */ +# define acpi_lapic 0 +# define acpi_ioapic 0 + #endif #ifdef CONFIG_ACPI_SLEEP diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 3fd526160f1a..94a0f27e331c 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -373,6 +373,11 @@ extern int acpi_mp_config; #define acpi_mp_config 0 +static inline int acpi_boot_init(void) +{ + return 0; +} + #endif /*!CONFIG_ACPI_BOOT*/ @@ -423,6 +428,13 @@ int ec_write(u8 addr, u8 val); int acpi_blacklisted(void); +#else + +static inline int acpi_blacklisted(void) +{ + return 0; +} + #endif /*CONFIG_ACPI*/ #endif /*_LINUX_ACPI_H*/ -- cgit v1.2.3 From f2a93dbd71db549d43e7bf9283918a83a5f5071d Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 19 Aug 2003 07:53:13 -0700 Subject: [power] Adapt swsusp to new PM core. Clean up heavily. - Split suspend/resume code into the four functions called from the PM core. - Remove now-duplicated code. - Make sure PM core frees memory and sync's disks before we shut down devices. - Remove software_suspend(), in favor of pm_suspend(). - Remove unused definitions from suspend.h --- include/linux/suspend.h | 24 +------ kernel/power/main.c | 28 ++++++++ kernel/power/power.h | 7 ++ kernel/power/swsusp.c | 171 ++++++------------------------------------------ kernel/sys.c | 7 +- 5 files changed, 59 insertions(+), 178 deletions(-) (limited to 'include/linux') diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 28788d8a65ff..da171766c8c8 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -8,8 +8,7 @@ #include #include #include - -extern unsigned char software_suspend_enabled; +#include #ifdef CONFIG_SOFTWARE_SUSPEND /* page backup entry */ @@ -46,12 +45,6 @@ extern int shrink_mem(void); /* mm/page_alloc.c */ extern void drain_local_pages(void); -/* kernel/suspend.c */ -extern int software_suspend(void); - -extern int register_suspend_notifier(struct notifier_block *); -extern int unregister_suspend_notifier(struct notifier_block *); - extern unsigned int nr_copy_pages __nosavedata; extern suspend_pagedir_t *pagedir_nosave __nosavedata; @@ -72,31 +65,16 @@ static inline int software_suspend(void) { return -EPERM; } -#define register_suspend_notifier(a) do { } while(0) -#define unregister_suspend_notifier(a) do { } while(0) #endif /* CONFIG_SOFTWARE_SUSPEND */ #ifdef CONFIG_PM extern void refrigerator(unsigned long); -extern int freeze_processes(void); -extern void thaw_processes(void); - -extern int pm_prepare_console(void); -extern void pm_restore_console(void); #else static inline void refrigerator(unsigned long flag) { -} -static inline int freeze_processes(void) -{ - return 0; -} -static inline void thaw_processes(void) -{ - } #endif /* CONFIG_PM */ diff --git a/kernel/power/main.c b/kernel/power/main.c index 063e98c6bceb..42bf7233a3a7 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -15,6 +15,8 @@ #include #include #include +#include + #include "power.h" @@ -30,6 +32,8 @@ static int have_swsusp = 1; static int have_swsusp = 0; #endif +extern long sys_sync(void); + /** * pm_set_ops - Set the global power method table. @@ -128,6 +132,25 @@ static int power_down(u32 mode) static int in_suspend __nosavedata = 0; +/** + * free_some_memory - Try to free as much memory as possible + * + * ... but do not OOM-kill anyone + * + * Notice: all userland should be stopped at this point, or + * livelock is possible. + */ + +static void free_some_memory(void) +{ + printk("Freeing memory: "); + while (shrink_all_memory(10000)) + printk("."); + printk("|\n"); + blk_run_queues(); +} + + /** * pm_suspend_disk - The granpappy of power management. * @@ -197,6 +220,7 @@ static int suspend_prepare(u32 state) pm_prepare_console(); + sys_sync(); if (freeze_processes()) { error = -EAGAIN; goto Thaw; @@ -207,6 +231,10 @@ static int suspend_prepare(u32 state) goto Thaw; } + /* Free memory before shutting down devices. */ + if (state == PM_SUSPEND_DISK) + free_some_memory(); + if ((error = device_pm_suspend(state))) goto Finish; diff --git a/kernel/power/power.h b/kernel/power/power.h index ae7bcbc37845..e98de640155d 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -37,3 +37,10 @@ static inline int swsusp_free(void) return 0; } #endif + + +extern int freeze_processes(void); +extern void thaw_processes(void); + +extern int pm_prepare_console(void); +extern void pm_restore_console(void); diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index d1b2a46de5fa..5c70937437d4 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -65,8 +65,6 @@ #include "power.h" -extern long sys_sync(void); - unsigned char software_suspend_enabled = 1; #define __ADDRESS(x) ((unsigned long) phys_to_virt(x)) @@ -439,29 +437,6 @@ static suspend_pagedir_t *create_suspend_pagedir(int nr_copy_pages) return pagedir; } -static int prepare_suspend_processes(void) -{ - sys_sync(); /* Syncing needs pdflushd, so do it before stopping processes */ - if (freeze_processes()) { - printk( KERN_ERR "Suspend failed: Not all processes stopped!\n" ); - thaw_processes(); - return 1; - } - return 0; -} - -/* - * Try to free as much memory as possible, but do not OOM-kill anyone - * - * Notice: all userland should be stopped at this point, or livelock is possible. - */ -static void free_some_memory(void) -{ - printk("Freeing memory: "); - while (shrink_all_memory(10000)) - printk("."); - printk("|\n"); -} /* Make disk drivers accept operations, again */ static void drivers_unsuspend(void) @@ -470,28 +445,6 @@ static void drivers_unsuspend(void) device_resume(RESUME_ENABLE); } -/* Called from process context */ -static int drivers_suspend(void) -{ - if (device_suspend(4, SUSPEND_NOTIFY)) - return -EIO; - if (device_suspend(4, SUSPEND_SAVE_STATE)) { - device_resume(RESUME_RESTORE_STATE); - return -EIO; - } - if (!pm_suspend_state) { - if(pm_send_all(PM_SUSPEND,(void *)3)) { - printk(KERN_WARNING "Problem while sending suspend event\n"); - return -EIO; - } - pm_suspend_state=1; - } else - printk(KERN_WARNING "PM suspend state already raised\n"); - device_suspend(4, SUSPEND_DISABLE); - - return 0; -} - #define RESUME_PHASE1 1 /* Called from interrupts disabled */ #define RESUME_PHASE2 2 /* Called with interrupts enabled */ #define RESUME_ALL_PHASES (RESUME_PHASE1 | RESUME_PHASE2) @@ -694,72 +647,6 @@ void do_magic_suspend_2(void) mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME); } -static int do_software_suspend(void) -{ - arch_prepare_suspend(); - if (pm_prepare_console()) - printk( "%sCan't allocate a console... proceeding\n", name_suspend); - if (!prepare_suspend_processes()) { - - /* At this point, all user processes and "dangerous" - kernel threads are stopped. Free some memory, as we - need half of memory free. */ - - free_some_memory(); - - /* No need to invalidate any vfsmnt list -- - * they will be valid after resume, anyway. - */ - blk_run_queues(); - - /* Save state of all device drivers, and stop them. */ - if (drivers_suspend()==0) - /* If stopping device drivers worked, we proceed basically into - * suspend_save_image. - * - * do_magic(0) returns after system is resumed. - * - * do_magic() copies all "used" memory to "free" memory, then - * unsuspends all device drivers, and writes memory to disk - * using normal kernel mechanism. - */ - do_magic(0); - thaw_processes(); - } - software_suspend_enabled = 1; - MDELAY(1000); - pm_restore_console(); - return 0; -} - - -/** - * software_suspend - initiate suspend-to-swap transition. - * - * This is main interface to the outside world. It needs to be - * called from process context. - */ - -int software_suspend(void) -{ - if(!software_suspend_enabled) - return -EINVAL; - - if (num_online_cpus() > 1) { - printk(KERN_WARNING "swsusp does not support SMP.\n"); - return -EPERM; - } - -#if defined (CONFIG_HIGHMEM) || defined (COFNIG_DISCONTIGMEM) - printk("swsusp is not supported with high- or discontig-mem.\n"); - return -EPERM; -#endif - - software_suspend_enabled = 0; - might_sleep(); - return do_software_suspend(); -} - /* More restore stuff */ /* FIXME: Why not memcpy(to, from, 1<version_code != LINUX_VERSION_CODE) return sanity_check_failed("Incorrect kernel version"); @@ -776,7 +701,8 @@ static int sanity_check(struct suspend_header *sh) return 0; } -static int bdev_read_page(struct block_device *bdev, long pos, void *buf) +static int __init bdev_read_page(struct block_device *bdev, + long pos, void *buf) { struct buffer_head *bh; BUG_ON (pos%PAGE_SIZE); @@ -792,7 +718,8 @@ static int bdev_read_page(struct block_device *bdev, long pos, void *buf) extern dev_t __init name_to_dev_t(const char *line); -static int __read_suspend_image(struct block_device *bdev, union diskpage *cur) +static int __init read_suspend_image(struct block_device *bdev, + union diskpage *cur) { swp_entry_t next; int i, nr_pgdir_pages; @@ -869,54 +796,6 @@ static int __read_suspend_image(struct block_device *bdev, union diskpage *cur) return 0; } -static int read_suspend_image(const char * specialfile) -{ - union diskpage *cur; - unsigned long scratch_page = 0; - int error; - char b[BDEVNAME_SIZE]; - - resume_device = name_to_dev_t(specialfile); - scratch_page = get_zeroed_page(GFP_ATOMIC); - cur = (void *) scratch_page; - if (cur) { - struct block_device *bdev; - printk("Resuming from device %s\n", - __bdevname(resume_device, b)); - bdev = open_by_devnum(resume_device, FMODE_READ, BDEV_RAW); - if (IS_ERR(bdev)) { - error = PTR_ERR(bdev); - } else { - set_blocksize(bdev, PAGE_SIZE); - error = __read_suspend_image(bdev, cur); - blkdev_put(bdev, BDEV_RAW); - } - } else error = -ENOMEM; - - if (scratch_page) - free_page(scratch_page); - switch (error) { - case 0: - PRINTK("Reading resume file was successful\n"); - break; - case -EINVAL: - break; - case -EIO: - printk( "%sI/O error\n", name_resume); - break; - case -ENOENT: - printk( "%s%s: No such file or directory\n", name_resume, specialfile); - break; - case -ENOMEM: - printk( "%sNot enough memory\n", name_resume); - break; - default: - printk( "%sError %d resuming\n", name_resume, error ); - } - MDELAY(1000); - return error; -} - /** * swsusp_save - Snapshot memory */ @@ -944,9 +823,7 @@ int swsusp_save(void) int swsusp_write(void) { arch_prepare_suspend(); - do_magic(0); - MDELAY(1000); - return 0; + return do_magic(0); } @@ -954,13 +831,39 @@ int swsusp_write(void) * swsusp_read - Read saved image from swap. */ -int swsusp_read(void) +int __init swsusp_read(void) { + union diskpage *cur; + int error; + char b[BDEVNAME_SIZE]; + if (!strlen(resume_file)) return -ENOENT; - printk("swsusp: %s\n", name_resume ); + + resume_device = name_to_dev_t(resume_file); + printk("swsusp: Resume From Partition: %s, Device: %s\n", + resume_file, __bdevname(resume_device, b)); + + cur = (union diskpage *)get_zeroed_page(GFP_ATOMIC); + if (cur) { + struct block_device *bdev; + bdev = open_by_devnum(resume_device, FMODE_READ, BDEV_RAW); + if (!IS_ERR(bdev)) { + set_blocksize(bdev, PAGE_SIZE); + error = read_suspend_image(bdev, cur); + blkdev_put(bdev, BDEV_RAW); + } else + error = PTR_ERR(bdev); + free_page((unsigned long)cur); + } else + error = -ENOMEM; + + if (!error) + PRINTK("Reading resume file was successful\n"); + else + printk( "%sError %d resuming\n", name_resume, error ); MDELAY(1000); - return read_suspend_image(resume_file); + return error; } @@ -968,10 +871,9 @@ int swsusp_read(void) * swsusp_restore - Replace running kernel with saved image. */ -int swsusp_restore(void) +int __init swsusp_restore(void) { - do_magic(1); - return 0; + return do_magic(1); } @@ -981,6 +883,12 @@ int swsusp_restore(void) int swsusp_free(void) { + PRINTK( "Freeing prev allocated pagedir\n" ); + free_suspend_pagedir((unsigned long) pagedir_save); + + PRINTK( "Fixing swap signatures... " ); + mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME); + PRINTK( "ok\n" ); return 0; } -- cgit v1.2.3 From 54050a4e1b5d6e97513237052c796ccb97fd90d9 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 19 Aug 2003 09:23:34 -0700 Subject: [power] Update device handling. - From conversations with Ben Herrenschmidt. Most devices should be able to handle powering down with interrupts enabled, which I already assume. But since suspending will stop I/O transactions before the call to power it off (making the device unusable anyway), there is no need to separate the calls - we may as well make it simpler for driver authors and require that driver authors do everything at the same time. There will always be devices that need to either power down or power up the device with interrupts disabled. They will get called with interrupts enabled, but may return -EAGAIN to be called again with interrupts disabled to do what they need to do. System devices are now always called only with interrupts disabled. Come on - they're system devices. Of course we need interrupts disabled. --- drivers/base/power/main.c | 1 - drivers/base/power/power.h | 4 -- drivers/base/power/resume.c | 78 ++++------------------- drivers/base/power/runtime.c | 12 +--- drivers/base/power/suspend.c | 148 ++++++++----------------------------------- drivers/base/sys.c | 111 ++------------------------------ include/linux/device.h | 2 - include/linux/sysdev.h | 4 -- kernel/power/main.c | 16 ++++- 9 files changed, 60 insertions(+), 316 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 5aabe5179fd1..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); 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 544104c6bbd1..a34f66a1b42c 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); /** @@ -30,37 +29,22 @@ int resume_device(struct device * dev) return 0; } + /** - * dpm_resume - Restore all device state. + * device_pm_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. + * Restore normal device state and release the dpm_sem. */ -int dpm_resume(void) +void device_pm_resume(void) { - while(!list_empty(&dpm_suspended)) { - struct list_head * entry = dpm_suspended.next; + 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); } @@ -89,65 +73,27 @@ 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); + 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) { 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. - */ - -void device_resume(u32 level) -{ - - printk("%s is deprecated. Called from:\n",__FUNCTION__); - dump_stack(); -} - 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 0747e409d0ec..8e5842521d4d 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -11,7 +11,6 @@ #include #include "power.h" -extern int sysdev_save(u32 state); extern int sysdev_suspend(u32 state); /* @@ -46,7 +45,10 @@ int suspend_device(struct device * dev, u32 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; } @@ -57,10 +59,13 @@ int suspend_device(struct device * dev, u32 state) * @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_pm_resume() + * above to bring the suspended devices back to life. * * Note this function leaves dpm_sem held to * a) block other devices from registering. @@ -83,153 +88,56 @@ int device_pm_suspend(u32 state) if ((error = suspend_device(dev,state))) goto Error; } - - if ((error = sysdev_save(state))) - goto Error; Done: return error; Error: - dpm_resume(); - up(&dpm_sem); + device_pm_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; -} - - -/** - * dpm_power_down_irq - Power down devices without interrupts. + * dpm_power_down - Power down devices without interrupts. * @state: State to enter. * - * Walk the dpm_off_irq list (built by dpm_power_down) and power + * Walk the dpm_off_irq list (built by device_pm_suspend) and power * down each device that requires the call to be made with interrupts * disabled. */ -static int dpm_power_down_irq(u32 state) +static int dpm_power_down(u32 state) { - struct device * dev; int error = 0; - list_for_each_entry_reverse(dev,&dpm_off_irq,power.entry) { - if ((error = power_down_device(dev,state))) - break; - } return error; } /** - * device_pm_power_down - Put all devices in low power state. + * device_pm_power_down - Shut down special devices. * @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. + * 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. */ int device_pm_power_down(u32 state) { int error = 0; + struct device * dev; - if ((error = dpm_power_down(state))) - goto ErrorIRQOn; - local_irq_disable(); - if ((error = dpm_power_down_irq(state))) - goto ErrorIRQOff; - - sysdev_suspend(state); + list_for_each_entry_reverse(dev,&dpm_off_irq,power.entry) { + if ((error = suspend_device(dev,state))) + break; + } + 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; } - - -/** - * 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; -} - 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 @@ -282,62 +282,17 @@ 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/include/linux/device.h b/include/linux/device.h index 7b49400adf31..c99ad50c6784 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -372,8 +372,6 @@ extern struct bus_type platform_bus_type; extern struct device legacy_bus; /* drivers/base/power.c */ -extern int device_suspend(u32 state, u32 level); -extern void device_resume(u32 level); extern void device_shutdown(void); diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h index 4bc3e22b5104..2a90db8d41de 100644 --- a/include/linux/sysdev.h +++ b/include/linux/sysdev.h @@ -31,10 +31,8 @@ struct sysdev_class { /* Default operations for these types of devices */ int (*shutdown)(struct sys_device *); - int (*save)(struct sys_device *, u32 state); int (*suspend)(struct sys_device *, u32 state); int (*resume)(struct sys_device *); - int (*restore)(struct sys_device *); struct kset kset; }; @@ -52,10 +50,8 @@ struct sysdev_driver { int (*add)(struct sys_device *); int (*remove)(struct sys_device *); int (*shutdown)(struct sys_device *); - int (*save)(struct sys_device *, u32 state); int (*suspend)(struct sys_device *, u32 state); int (*resume)(struct sys_device *); - int (*restore)(struct sys_device *); }; diff --git a/kernel/power/main.c b/kernel/power/main.c index 42bf7233a3a7..4d1476ba8156 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -65,9 +65,9 @@ static int pm_suspend_standby(void) if (!pm_ops || !pm_ops->enter) return -EPERM; + local_irq_save(flags); if ((error = device_pm_power_down(PM_SUSPEND_STANDBY))) goto Done; - local_irq_save(flags); error = pm_ops->enter(PM_SUSPEND_STANDBY); local_irq_restore(flags); device_pm_power_up(); @@ -91,9 +91,9 @@ static int pm_suspend_mem(void) if (!pm_ops || !pm_ops->enter) return -EPERM; + local_irq_save(flags); if ((error = device_pm_power_down(PM_SUSPEND_STANDBY))) goto Done; - local_irq_save(flags); error = pm_ops->enter(PM_SUSPEND_STANDBY); local_irq_restore(flags); device_pm_power_up(); @@ -114,9 +114,19 @@ static int pm_suspend_mem(void) static int power_down(u32 mode) { + unsigned long flags; + int error = 0; + + local_irq_save(flags); + device_pm_power_down(); switch(mode) { case PM_DISK_PLATFORM: - return pm_ops->enter(PM_SUSPEND_DISK); + error = pm_ops->enter(PM_SUSPEND_DISK); + if (error) { + device_pm_power_up(); + local_irq_restore(flags); + return error; + } case PM_DISK_SHUTDOWN: machine_power_off(); break; -- cgit v1.2.3 From 0d045e1fa51a9686c2a0aba434dd2b0039a9aa3d Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 19 Aug 2003 09:36:46 -0700 Subject: [power] Move suspend()/resume() methods. Instead of putting them in struct device_driver (which few, if any drivers use directly), put them in the controlling bus_type of the device (which are currently responsible for claiming the methods and forwarding the calls to the bus-specific driver anyway). This will save 8 bytes per driver instance, which isn't that much, but it's something. It also makes it more obvious to the reader what is going on. And, it makes for easier bus-level defaults in the case the device has no driver attached. The old calls remain until all instances have been fixed up. --- drivers/base/power/resume.c | 21 +++------------------ drivers/base/power/suspend.c | 22 ++-------------------- include/linux/device.h | 3 ++- kernel/power/main.c | 2 +- 4 files changed, 8 insertions(+), 40 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index a34f66a1b42c..a022a0cdedd5 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c @@ -22,10 +22,8 @@ extern int sysdev_resume(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; } @@ -49,19 +47,6 @@ void device_pm_resume(void) } -/** - * 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); -} - - /** * device_power_up_irq - Power on some devices. * @@ -78,7 +63,7 @@ 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)); + resume_device(to_device(entry)); list_add_tail(entry,&dpm_active); } } diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 8e5842521d4d..5e154218801e 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -37,11 +37,10 @@ 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); @@ -96,23 +95,6 @@ int device_pm_suspend(u32 state) } -/** - * dpm_power_down - Power down devices without interrupts. - * @state: State to enter. - * - * Walk the dpm_off_irq list (built by device_pm_suspend) and power - * down each device that requires the call to be made with interrupts - * disabled. - */ - -static int dpm_power_down(u32 state) -{ - int error = 0; - - return error; -} - - /** * device_pm_power_down - Shut down special devices. * @state: Power state to enter. diff --git a/include/linux/device.h b/include/linux/device.h index c99ad50c6784..8d6266f2e3c3 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -58,7 +58,8 @@ struct bus_type { struct device * (*add) (struct device * parent, char * bus_id); int (*hotplug) (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); - + int (*suspend)(struct device * dev, u32 state); + int (*resume)(struct device * dev); }; extern int bus_register(struct bus_type * bus); diff --git a/kernel/power/main.c b/kernel/power/main.c index 4d1476ba8156..422d5131fbf6 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -118,7 +118,7 @@ static int power_down(u32 mode) int error = 0; local_irq_save(flags); - device_pm_power_down(); + device_pm_power_down(PM_SUSPEND_DISK); switch(mode) { case PM_DISK_PLATFORM: error = pm_ops->enter(PM_SUSPEND_DISK); -- cgit v1.2.3 From 505f6a8832b7ac71135db6adcbefab270e5a047a Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 19 Aug 2003 19:01:05 -0700 Subject: [power] Update IDE to set suspend/resume methods in bus_type. Instead of having each driver set them in their own drivers. --- drivers/ide/ide-cd.c | 4 ---- drivers/ide/ide-disk.c | 4 ---- drivers/ide/ide.c | 16 ++++------------ include/linux/ide.h | 2 -- 4 files changed, 4 insertions(+), 22 deletions(-) (limited to 'include/linux') 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/include/linux/ide.h b/include/linux/ide.h index 82ca6da75b3f..a3ee36b438ca 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1241,8 +1241,6 @@ typedef struct ide_driver_s { #define DRIVER(drive) ((drive)->driver) extern int generic_ide_ioctl(struct block_device *, unsigned, unsigned long); -extern int generic_ide_suspend(struct device *dev, u32 state, u32 level); -extern int generic_ide_resume(struct device *dev, u32 level); /* * IDE modules. -- cgit v1.2.3 From 9234878aafa9a6e8f595fa259ea4fe267526714c Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Wed, 20 Aug 2003 21:47:37 -0700 Subject: [power] Fixup device suspend/resume function names. - Revert names of functions back to device_{suspend,resume} since at least APM are still using them. --- drivers/base/power/resume.c | 23 ++++++----------------- drivers/base/power/suspend.c | 38 +++++++++++--------------------------- include/linux/pm.h | 8 ++++---- kernel/power/main.c | 16 ++++++++-------- kernel/power/swsusp.c | 4 ++-- 5 files changed, 31 insertions(+), 58 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c index 0f68bf95beac..19c6387fec40 100644 --- a/drivers/base/power/resume.c +++ b/drivers/base/power/resume.c @@ -29,12 +29,12 @@ int resume_device(struct device * dev) /** - * device_pm_resume - Restore state of each device in system. + * device_resume - Restore state of each device in system. * * Restore normal device state and release the dpm_sem. */ -void device_pm_resume(void) +void device_resume(void) { while(!list_empty(&dpm_off)) { struct list_head * entry = dpm_off.next; @@ -46,6 +46,8 @@ void device_pm_resume(void) up(&dpm_sem); } +EXPORT_SYMBOL(device_resume); + /** * device_power_up_irq - Power on some devices. @@ -77,25 +79,12 @@ void dpm_power_up(void) * Called with interrupts disabled. */ -void device_pm_power_up(void) +void device_power_up(void) { sysdev_resume(); 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. - */ - -void device_resume(u32 level) -{ +EXPORT_SYMBOL(device_power_up); - printk("%s is deprecated. Called from:\n",__FUNCTION__); - dump_stack(); -} -EXPORT_SYMBOL(device_resume); diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 78b8e91f1e1a..e9ca633fc129 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -54,7 +54,7 @@ int suspend_device(struct device * dev, u32 state) /** - * 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 @@ -63,7 +63,7 @@ int suspend_device(struct device * dev, u32 state) * 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. * - * If we hit a failure with any of the devices, call device_pm_resume() + * 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 @@ -71,12 +71,12 @@ int suspend_device(struct device * dev, u32 state) * 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 + * device_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(). + * called device_suspend(). */ -int device_pm_suspend(u32 state) +int device_suspend(u32 state) { int error = 0; @@ -90,13 +90,15 @@ int device_pm_suspend(u32 state) Done: return error; Error: - device_pm_resume(); + device_resume(); goto Done; } +EXPORT_SYMBOL(device_suspend); + /** - * device_pm_power_down - Shut down special devices. + * device_power_down - Shut down special devices. * @state: Power state to enter. * * Walk the dpm_off_irq list, calling ->power_down() for each device that @@ -104,7 +106,7 @@ int device_pm_suspend(u32 state) * done, power down system devices. */ -int device_pm_power_down(u32 state) +int device_power_down(u32 state) { int error = 0; struct device * dev; @@ -124,23 +126,5 @@ int device_pm_power_down(u32 state) 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/include/linux/pm.h b/include/linux/pm.h index 70282a7943b1..3017bdef5f03 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -240,10 +240,10 @@ struct dev_pm_info { extern void device_pm_set_parent(struct device * dev, struct device * parent); -extern int device_pm_suspend(u32 state); -extern int device_pm_power_down(u32 state); -extern void device_pm_power_up(void); -extern void device_pm_resume(void); +extern int device_suspend(u32 state); +extern int device_power_down(u32 state); +extern void device_power_up(void); +extern void device_resume(void); #endif /* __KERNEL__ */ diff --git a/kernel/power/main.c b/kernel/power/main.c index 422d5131fbf6..1b92f13d9a77 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -66,11 +66,11 @@ static int pm_suspend_standby(void) return -EPERM; local_irq_save(flags); - if ((error = device_pm_power_down(PM_SUSPEND_STANDBY))) + if ((error = device_power_down(PM_SUSPEND_STANDBY))) goto Done; error = pm_ops->enter(PM_SUSPEND_STANDBY); local_irq_restore(flags); - device_pm_power_up(); + device_power_up(); Done: return error; } @@ -92,11 +92,11 @@ static int pm_suspend_mem(void) return -EPERM; local_irq_save(flags); - if ((error = device_pm_power_down(PM_SUSPEND_STANDBY))) + if ((error = device_power_down(PM_SUSPEND_STANDBY))) goto Done; error = pm_ops->enter(PM_SUSPEND_STANDBY); local_irq_restore(flags); - device_pm_power_up(); + device_power_up(); Done: return error; } @@ -118,12 +118,12 @@ static int power_down(u32 mode) int error = 0; local_irq_save(flags); - device_pm_power_down(PM_SUSPEND_DISK); + device_power_down(PM_SUSPEND_DISK); switch(mode) { case PM_DISK_PLATFORM: error = pm_ops->enter(PM_SUSPEND_DISK); if (error) { - device_pm_power_up(); + device_power_up(); local_irq_restore(flags); return error; } @@ -245,7 +245,7 @@ static int suspend_prepare(u32 state) if (state == PM_SUSPEND_DISK) free_some_memory(); - if ((error = device_pm_suspend(state))) + if ((error = device_suspend(state))) goto Finish; return 0; @@ -271,7 +271,7 @@ static int suspend_prepare(u32 state) static void suspend_finish(u32 state) { - device_pm_resume(); + device_resume(); if (pm_ops && pm_ops->finish) pm_ops->finish(state); thaw_processes(); diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 4ce75e5c23bb..2d6bac84469e 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -1,4 +1,4 @@ -/* +'/* * linux/kernel/suspend.c * * This file is to realize architecture-independent @@ -492,7 +492,7 @@ static int suspend_save_image(void) { int error; - device_pm_resume(); + device_resume(); lock_swapdevices(); error = write_suspend_image(); -- cgit v1.2.3 From 2b50fcaae095b81ee226a96ae708253532db8f27 Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Thu, 21 Aug 2003 01:09:09 -0700 Subject: [NET]: Make sure interval member of struct tc_estimator is signed. --- include/linux/pkt_sched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index fec8ad62b567..d97edad0effc 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -45,7 +45,7 @@ struct tc_stats struct tc_estimator { - char interval; + signed char interval; unsigned char ewma_log; }; -- cgit v1.2.3 From 46480a97d81e57150b8218ceeaae2c8ee5f4e9e7 Mon Sep 17 00:00:00 2001 From: John Levon Date: Thu, 21 Aug 2003 02:57:11 -0700 Subject: [PATCH] OProfile: export kernel pointer size in oprofilefs Tell user-space how big kernel pointers are, as preferable to sniffing /proc/kcore. Improve the oprofilefs_ulong_to_user() prototype. --- drivers/oprofile/oprofile_files.c | 14 +++++++++++++- drivers/oprofile/oprofilefs.c | 12 ++++++------ include/linux/oprofile.h | 2 +- 3 files changed, 20 insertions(+), 8 deletions(-) (limited to 'include/linux') 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/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/include/linux/oprofile.h b/include/linux/oprofile.h index c2b4fd735f40..9555dd4d69fc 100644 --- a/include/linux/oprofile.h +++ b/include/linux/oprofile.h @@ -92,7 +92,7 @@ ssize_t oprofilefs_str_to_user(char const * str, char * buf, size_t count, loff_ * Convert an unsigned long value into ASCII and copy it to the user buffer @buf, * updating *offset appropriately. Returns bytes written or -EFAULT. */ -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); /** * Read an ASCII string for a number from a userspace buffer and fill *val on success. -- cgit v1.2.3