Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
3cc8a5f4
Commit
3cc8a5f4
authored
Jan 09, 2009
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'suspend' into release
parents
d0302bc6
ada9cfdd
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
446 additions
and
201 deletions
+446
-201
Documentation/kernel-parameters.txt
Documentation/kernel-parameters.txt
+26
-19
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/acpi/sleep.c
+2
-0
arch/x86/kernel/e820.c
arch/x86/kernel/e820.c
+21
-0
drivers/acpi/main.c
drivers/acpi/main.c
+59
-8
include/linux/acpi.h
include/linux/acpi.h
+1
-0
include/linux/suspend.h
include/linux/suspend.h
+13
-0
kernel/power/disk.c
kernel/power/disk.c
+3
-3
kernel/power/snapshot.c
kernel/power/snapshot.c
+199
-171
kernel/power/swsusp.c
kernel/power/swsusp.c
+122
-0
No files found.
Documentation/kernel-parameters.txt
View file @
3cc8a5f4
...
@@ -150,16 +150,20 @@ and is between 256 and 4096 characters. It is defined in the file
...
@@ -150,16 +150,20 @@ and is between 256 and 4096 characters. It is defined in the file
default: 0
default: 0
acpi_sleep= [HW,ACPI] Sleep options
acpi_sleep= [HW,ACPI] Sleep options
Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig, old_ordering }
Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig,
See Documentation/power/video.txt for s3_bios and s3_mode.
old_ordering, s4_nonvs }
See Documentation/power/video.txt for information on
s3_bios and s3_mode.
s3_beep is for debugging; it makes the PC's speaker beep
s3_beep is for debugging; it makes the PC's speaker beep
as soon as the kernel's real-mode entry point is called.
as soon as the kernel's real-mode entry point is called.
s4_nohwsig prevents ACPI hardware signature from being
s4_nohwsig prevents ACPI hardware signature from being
used during resume from hibernation.
used during resume from hibernation.
old_ordering causes the ACPI 1.0 ordering of the _PTS
old_ordering causes the ACPI 1.0 ordering of the _PTS
control method, wrt putting devices into low power
control method, with respect to putting devices into
states, to be enforced (the ACPI 2.0 ordering of _PTS is
low power states, to be enforced (the ACPI 2.0 ordering
used by default).
of _PTS is used by default).
s4_nonvs prevents the kernel from saving/restoring the
ACPI NVS memory during hibernation.
acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode
acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode
Format: { level | edge | high | low }
Format: { level | edge | high | low }
...
@@ -194,7 +198,7 @@ and is between 256 and 4096 characters. It is defined in the file
...
@@ -194,7 +198,7 @@ and is between 256 and 4096 characters. It is defined in the file
acpi_skip_timer_override [HW,ACPI]
acpi_skip_timer_override [HW,ACPI]
Recognize and ignore IRQ0/pin2 Interrupt Override.
Recognize and ignore IRQ0/pin2 Interrupt Override.
For broken nForce2 BIOS resulting in XT-PIC timer.
For broken nForce2 BIOS resulting in XT-PIC timer.
acpi_use_timer_override [HW,ACPI
}
acpi_use_timer_override [HW,ACPI
]
Use timer override. For some broken Nvidia NF5 boards
Use timer override. For some broken Nvidia NF5 boards
that require a timer override, but don't have
that require a timer override, but don't have
HPET
HPET
...
@@ -861,17 +865,19 @@ and is between 256 and 4096 characters. It is defined in the file
...
@@ -861,17 +865,19 @@ and is between 256 and 4096 characters. It is defined in the file
See Documentation/ide/ide.txt.
See Documentation/ide/ide.txt.
idle= [X86]
idle= [X86]
Format: idle=poll or idle=mwait, idle=halt, idle=nomwait
Format: idle=poll, idle=mwait, idle=halt, idle=nomwait
Poll forces a polling idle loop that can slightly improves the performance
Poll forces a polling idle loop that can slightly
of waking up a idle CPU, but will use a lot of power and make the system
improve the performance of waking up a idle CPU, but
run hot. Not recommended.
will use a lot of power and make the system run hot.
idle=mwait. On systems which support MONITOR/MWAIT but the kernel chose
Not recommended.
to not use it because it doesn't save as much power as a normal idle
idle=mwait: On systems which support MONITOR/MWAIT but
loop use the MONITOR/MWAIT idle loop anyways. Performance should be the same
the kernel chose to not use it because it doesn't save
as idle=poll.
as much power as a normal idle loop, use the
idle=halt. Halt is forced to be used for CPU idle.
MONITOR/MWAIT idle loop anyways. Performance should be
the same as idle=poll.
idle=halt: Halt is forced to be used for CPU idle.
In such case C2/C3 won't be used again.
In such case C2/C3 won't be used again.
idle=nomwait
.
Disable mwait for CPU C-states
idle=nomwait
:
Disable mwait for CPU C-states
ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem
ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem
Claim all unknown PCI IDE storage controllers.
Claim all unknown PCI IDE storage controllers.
...
@@ -1053,8 +1059,8 @@ and is between 256 and 4096 characters. It is defined in the file
...
@@ -1053,8 +1059,8 @@ and is between 256 and 4096 characters. It is defined in the file
lapic [X86-32,APIC] Enable the local APIC even if BIOS
lapic [X86-32,APIC] Enable the local APIC even if BIOS
disabled it.
disabled it.
lapic_timer_c2_ok [X86-32,x86-64,APIC] trust the local apic timer
in
lapic_timer_c2_ok [X86-32,x86-64,APIC] trust the local apic timer
C2 power state.
in
C2 power state.
libata.dma= [LIBATA] DMA control
libata.dma= [LIBATA] DMA control
libata.dma=0 Disable all PATA and SATA DMA
libata.dma=0 Disable all PATA and SATA DMA
...
@@ -2242,7 +2248,8 @@ and is between 256 and 4096 characters. It is defined in the file
...
@@ -2242,7 +2248,8 @@ and is between 256 and 4096 characters. It is defined in the file
thermal.psv= [HW,ACPI]
thermal.psv= [HW,ACPI]
-1: disable all passive trip points
-1: disable all passive trip points
<degrees C>: override all passive trip points to this value
<degrees C>: override all passive trip points to this
value
thermal.tzp= [HW,ACPI]
thermal.tzp= [HW,ACPI]
Specify global default ACPI thermal zone polling rate
Specify global default ACPI thermal zone polling rate
...
...
arch/x86/kernel/acpi/sleep.c
View file @
3cc8a5f4
...
@@ -159,6 +159,8 @@ static int __init acpi_sleep_setup(char *str)
...
@@ -159,6 +159,8 @@ static int __init acpi_sleep_setup(char *str)
#endif
#endif
if
(
strncmp
(
str
,
"old_ordering"
,
12
)
==
0
)
if
(
strncmp
(
str
,
"old_ordering"
,
12
)
==
0
)
acpi_old_suspend_ordering
();
acpi_old_suspend_ordering
();
if
(
strncmp
(
str
,
"s4_nonvs"
,
8
)
==
0
)
acpi_s4_no_nvs
();
str
=
strchr
(
str
,
','
);
str
=
strchr
(
str
,
','
);
if
(
str
!=
NULL
)
if
(
str
!=
NULL
)
str
+=
strspn
(
str
,
",
\t
"
);
str
+=
strspn
(
str
,
",
\t
"
);
...
...
arch/x86/kernel/e820.c
View file @
3cc8a5f4
...
@@ -665,6 +665,27 @@ void __init e820_mark_nosave_regions(unsigned long limit_pfn)
...
@@ -665,6 +665,27 @@ void __init e820_mark_nosave_regions(unsigned long limit_pfn)
}
}
#endif
#endif
#ifdef CONFIG_HIBERNATION
/**
* Mark ACPI NVS memory region, so that we can save/restore it during
* hibernation and the subsequent resume.
*/
static
int
__init
e820_mark_nvs_memory
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
e820
.
nr_map
;
i
++
)
{
struct
e820entry
*
ei
=
&
e820
.
map
[
i
];
if
(
ei
->
type
==
E820_NVS
)
hibernate_nvs_register
(
ei
->
addr
,
ei
->
size
);
}
return
0
;
}
core_initcall
(
e820_mark_nvs_memory
);
#endif
/*
/*
* Early reserved memory areas.
* Early reserved memory areas.
*/
*/
...
...
drivers/acpi/main.c
View file @
3cc8a5f4
...
@@ -101,6 +101,19 @@ void __init acpi_old_suspend_ordering(void)
...
@@ -101,6 +101,19 @@ void __init acpi_old_suspend_ordering(void)
* cases.
* cases.
*/
*/
static
bool
set_sci_en_on_resume
;
static
bool
set_sci_en_on_resume
;
/*
* The ACPI specification wants us to save NVS memory regions during hibernation
* and to restore them during the subsequent resume. However, it is not certain
* if this mechanism is going to work on all machines, so we allow the user to
* disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line
* option.
*/
static
bool
s4_no_nvs
;
void
__init
acpi_s4_no_nvs
(
void
)
{
s4_no_nvs
=
true
;
}
/**
/**
* acpi_pm_disable_gpes - Disable the GPEs.
* acpi_pm_disable_gpes - Disable the GPEs.
...
@@ -394,9 +407,25 @@ void __init acpi_no_s4_hw_signature(void)
...
@@ -394,9 +407,25 @@ void __init acpi_no_s4_hw_signature(void)
static
int
acpi_hibernation_begin
(
void
)
static
int
acpi_hibernation_begin
(
void
)
{
{
acpi_target_sleep_state
=
ACPI_STATE_S4
;
int
error
;
acpi_sleep_tts_switch
(
acpi_target_sleep_state
);
return
0
;
error
=
s4_no_nvs
?
0
:
hibernate_nvs_alloc
();
if
(
!
error
)
{
acpi_target_sleep_state
=
ACPI_STATE_S4
;
acpi_sleep_tts_switch
(
acpi_target_sleep_state
);
}
return
error
;
}
static
int
acpi_hibernation_pre_snapshot
(
void
)
{
int
error
=
acpi_pm_prepare
();
if
(
!
error
)
hibernate_nvs_save
();
return
error
;
}
}
static
int
acpi_hibernation_enter
(
void
)
static
int
acpi_hibernation_enter
(
void
)
...
@@ -417,6 +446,12 @@ static int acpi_hibernation_enter(void)
...
@@ -417,6 +446,12 @@ static int acpi_hibernation_enter(void)
return
ACPI_SUCCESS
(
status
)
?
0
:
-
EFAULT
;
return
ACPI_SUCCESS
(
status
)
?
0
:
-
EFAULT
;
}
}
static
void
acpi_hibernation_finish
(
void
)
{
hibernate_nvs_free
();
acpi_pm_finish
();
}
static
void
acpi_hibernation_leave
(
void
)
static
void
acpi_hibernation_leave
(
void
)
{
{
/*
/*
...
@@ -432,6 +467,8 @@ static void acpi_hibernation_leave(void)
...
@@ -432,6 +467,8 @@ static void acpi_hibernation_leave(void)
"cannot resume!
\n
"
);
"cannot resume!
\n
"
);
panic
(
"ACPI S4 hardware signature mismatch"
);
panic
(
"ACPI S4 hardware signature mismatch"
);
}
}
/* Restore the NVS memory area */
hibernate_nvs_restore
();
}
}
static
void
acpi_pm_enable_gpes
(
void
)
static
void
acpi_pm_enable_gpes
(
void
)
...
@@ -442,8 +479,8 @@ static void acpi_pm_enable_gpes(void)
...
@@ -442,8 +479,8 @@ static void acpi_pm_enable_gpes(void)
static
struct
platform_hibernation_ops
acpi_hibernation_ops
=
{
static
struct
platform_hibernation_ops
acpi_hibernation_ops
=
{
.
begin
=
acpi_hibernation_begin
,
.
begin
=
acpi_hibernation_begin
,
.
end
=
acpi_pm_end
,
.
end
=
acpi_pm_end
,
.
pre_snapshot
=
acpi_
pm_prepare
,
.
pre_snapshot
=
acpi_
hibernation_pre_snapshot
,
.
finish
=
acpi_
pm
_finish
,
.
finish
=
acpi_
hibernation
_finish
,
.
prepare
=
acpi_pm_prepare
,
.
prepare
=
acpi_pm_prepare
,
.
enter
=
acpi_hibernation_enter
,
.
enter
=
acpi_hibernation_enter
,
.
leave
=
acpi_hibernation_leave
,
.
leave
=
acpi_hibernation_leave
,
...
@@ -469,8 +506,22 @@ static int acpi_hibernation_begin_old(void)
...
@@ -469,8 +506,22 @@ static int acpi_hibernation_begin_old(void)
error
=
acpi_sleep_prepare
(
ACPI_STATE_S4
);
error
=
acpi_sleep_prepare
(
ACPI_STATE_S4
);
if
(
!
error
)
{
if
(
!
s4_no_nvs
)
error
=
hibernate_nvs_alloc
();
if
(
!
error
)
acpi_target_sleep_state
=
ACPI_STATE_S4
;
}
return
error
;
}
static
int
acpi_hibernation_pre_snapshot_old
(
void
)
{
int
error
=
acpi_pm_disable_gpes
();
if
(
!
error
)
if
(
!
error
)
acpi_target_sleep_state
=
ACPI_STATE_S4
;
hibernate_nvs_save
();
return
error
;
return
error
;
}
}
...
@@ -481,8 +532,8 @@ static int acpi_hibernation_begin_old(void)
...
@@ -481,8 +532,8 @@ static int acpi_hibernation_begin_old(void)
static
struct
platform_hibernation_ops
acpi_hibernation_ops_old
=
{
static
struct
platform_hibernation_ops
acpi_hibernation_ops_old
=
{
.
begin
=
acpi_hibernation_begin_old
,
.
begin
=
acpi_hibernation_begin_old
,
.
end
=
acpi_pm_end
,
.
end
=
acpi_pm_end
,
.
pre_snapshot
=
acpi_
pm_disable_gpes
,
.
pre_snapshot
=
acpi_
hibernation_pre_snapshot_old
,
.
finish
=
acpi_
pm
_finish
,
.
finish
=
acpi_
hibernation
_finish
,
.
prepare
=
acpi_pm_disable_gpes
,
.
prepare
=
acpi_pm_disable_gpes
,
.
enter
=
acpi_hibernation_enter
,
.
enter
=
acpi_hibernation_enter
,
.
leave
=
acpi_hibernation_leave
,
.
leave
=
acpi_hibernation_leave
,
...
...
include/linux/acpi.h
View file @
3cc8a5f4
...
@@ -270,6 +270,7 @@ int acpi_check_mem_region(resource_size_t start, resource_size_t n,
...
@@ -270,6 +270,7 @@ int acpi_check_mem_region(resource_size_t start, resource_size_t n,
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_PM_SLEEP
void
__init
acpi_no_s4_hw_signature
(
void
);
void
__init
acpi_no_s4_hw_signature
(
void
);
void
__init
acpi_old_suspend_ordering
(
void
);
void
__init
acpi_old_suspend_ordering
(
void
);
void
__init
acpi_s4_no_nvs
(
void
);
#endif
/* CONFIG_PM_SLEEP */
#endif
/* CONFIG_PM_SLEEP */
#else
/* CONFIG_ACPI */
#else
/* CONFIG_ACPI */
...
...
include/linux/suspend.h
View file @
3cc8a5f4
...
@@ -232,6 +232,11 @@ extern unsigned long get_safe_page(gfp_t gfp_mask);
...
@@ -232,6 +232,11 @@ extern unsigned long get_safe_page(gfp_t gfp_mask);
extern
void
hibernation_set_ops
(
struct
platform_hibernation_ops
*
ops
);
extern
void
hibernation_set_ops
(
struct
platform_hibernation_ops
*
ops
);
extern
int
hibernate
(
void
);
extern
int
hibernate
(
void
);
extern
int
hibernate_nvs_register
(
unsigned
long
start
,
unsigned
long
size
);
extern
int
hibernate_nvs_alloc
(
void
);
extern
void
hibernate_nvs_free
(
void
);
extern
void
hibernate_nvs_save
(
void
);
extern
void
hibernate_nvs_restore
(
void
);
#else
/* CONFIG_HIBERNATION */
#else
/* CONFIG_HIBERNATION */
static
inline
int
swsusp_page_is_forbidden
(
struct
page
*
p
)
{
return
0
;
}
static
inline
int
swsusp_page_is_forbidden
(
struct
page
*
p
)
{
return
0
;
}
static
inline
void
swsusp_set_page_free
(
struct
page
*
p
)
{}
static
inline
void
swsusp_set_page_free
(
struct
page
*
p
)
{}
...
@@ -239,6 +244,14 @@ static inline void swsusp_unset_page_free(struct page *p) {}
...
@@ -239,6 +244,14 @@ static inline void swsusp_unset_page_free(struct page *p) {}
static
inline
void
hibernation_set_ops
(
struct
platform_hibernation_ops
*
ops
)
{}
static
inline
void
hibernation_set_ops
(
struct
platform_hibernation_ops
*
ops
)
{}
static
inline
int
hibernate
(
void
)
{
return
-
ENOSYS
;
}
static
inline
int
hibernate
(
void
)
{
return
-
ENOSYS
;
}
static
inline
int
hibernate_nvs_register
(
unsigned
long
a
,
unsigned
long
b
)
{
return
0
;
}
static
inline
int
hibernate_nvs_alloc
(
void
)
{
return
0
;
}
static
inline
void
hibernate_nvs_free
(
void
)
{}
static
inline
void
hibernate_nvs_save
(
void
)
{}
static
inline
void
hibernate_nvs_restore
(
void
)
{}
#endif
/* CONFIG_HIBERNATION */
#endif
/* CONFIG_HIBERNATION */
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_PM_SLEEP
...
...
kernel/power/disk.c
View file @
3cc8a5f4
...
@@ -259,12 +259,12 @@ int hibernation_snapshot(int platform_mode)
...
@@ -259,12 +259,12 @@ int hibernation_snapshot(int platform_mode)
{
{
int
error
,
ftrace_save
;
int
error
,
ftrace_save
;
/* Free memory before shutting down devices. */
error
=
platform_begin
(
platform_mode
);
error
=
swsusp_shrink_memory
();
if
(
error
)
if
(
error
)
return
error
;
return
error
;
error
=
platform_begin
(
platform_mode
);
/* Free memory before shutting down devices. */
error
=
swsusp_shrink_memory
();
if
(
error
)
if
(
error
)
goto
Close
;
goto
Close
;
...
...
kernel/power/snapshot.c
View file @
3cc8a5f4
This diff is collapsed.
Click to expand it.
kernel/power/swsusp.c
View file @
3cc8a5f4
...
@@ -262,3 +262,125 @@ int swsusp_shrink_memory(void)
...
@@ -262,3 +262,125 @@ int swsusp_shrink_memory(void)
return
0
;
return
0
;
}
}
/*
* Platforms, like ACPI, may want us to save some memory used by them during
* hibernation and to restore the contents of this memory during the subsequent
* resume. The code below implements a mechanism allowing us to do that.
*/
struct
nvs_page
{
unsigned
long
phys_start
;
unsigned
int
size
;
void
*
kaddr
;
void
*
data
;
struct
list_head
node
;
};
static
LIST_HEAD
(
nvs_list
);
/**
* hibernate_nvs_register - register platform NVS memory region to save
* @start - physical address of the region
* @size - size of the region
*
* The NVS region need not be page-aligned (both ends) and we arrange
* things so that the data from page-aligned addresses in this region will
* be copied into separate RAM pages.
*/
int
hibernate_nvs_register
(
unsigned
long
start
,
unsigned
long
size
)
{
struct
nvs_page
*
entry
,
*
next
;
while
(
size
>
0
)
{
unsigned
int
nr_bytes
;
entry
=
kzalloc
(
sizeof
(
struct
nvs_page
),
GFP_KERNEL
);
if
(
!
entry
)
goto
Error
;
list_add_tail
(
&
entry
->
node
,
&
nvs_list
);
entry
->
phys_start
=
start
;
nr_bytes
=
PAGE_SIZE
-
(
start
&
~
PAGE_MASK
);
entry
->
size
=
(
size
<
nr_bytes
)
?
size
:
nr_bytes
;
start
+=
entry
->
size
;
size
-=
entry
->
size
;
}
return
0
;
Error:
list_for_each_entry_safe
(
entry
,
next
,
&
nvs_list
,
node
)
{
list_del
(
&
entry
->
node
);
kfree
(
entry
);
}
return
-
ENOMEM
;
}
/**
* hibernate_nvs_free - free data pages allocated for saving NVS regions
*/
void
hibernate_nvs_free
(
void
)
{
struct
nvs_page
*
entry
;
list_for_each_entry
(
entry
,
&
nvs_list
,
node
)
if
(
entry
->
data
)
{
free_page
((
unsigned
long
)
entry
->
data
);
entry
->
data
=
NULL
;
if
(
entry
->
kaddr
)
{
iounmap
(
entry
->
kaddr
);
entry
->
kaddr
=
NULL
;
}
}
}
/**
* hibernate_nvs_alloc - allocate memory necessary for saving NVS regions
*/
int
hibernate_nvs_alloc
(
void
)
{
struct
nvs_page
*
entry
;
list_for_each_entry
(
entry
,
&
nvs_list
,
node
)
{
entry
->
data
=
(
void
*
)
__get_free_page
(
GFP_KERNEL
);
if
(
!
entry
->
data
)
{
hibernate_nvs_free
();
return
-
ENOMEM
;
}
}
return
0
;
}
/**
* hibernate_nvs_save - save NVS memory regions
*/
void
hibernate_nvs_save
(
void
)
{
struct
nvs_page
*
entry
;
printk
(
KERN_INFO
"PM: Saving platform NVS memory
\n
"
);
list_for_each_entry
(
entry
,
&
nvs_list
,
node
)
if
(
entry
->
data
)
{
entry
->
kaddr
=
ioremap
(
entry
->
phys_start
,
entry
->
size
);
memcpy
(
entry
->
data
,
entry
->
kaddr
,
entry
->
size
);
}
}
/**
* hibernate_nvs_restore - restore NVS memory regions
*
* This function is going to be called with interrupts disabled, so it
* cannot iounmap the virtual addresses used to access the NVS region.
*/
void
hibernate_nvs_restore
(
void
)
{
struct
nvs_page
*
entry
;
printk
(
KERN_INFO
"PM: Restoring platform NVS memory
\n
"
);
list_for_each_entry
(
entry
,
&
nvs_list
,
node
)
if
(
entry
->
data
)
memcpy
(
entry
->
kaddr
,
entry
->
data
,
entry
->
size
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment