diff options
| -rw-r--r-- | arch/sparc64/kernel/irq.c | 1 | ||||
| -rw-r--r-- | arch/um/Makefile | 2 | ||||
| -rw-r--r-- | arch/um/drivers/cow.h | 39 | ||||
| -rw-r--r-- | arch/um/drivers/cow_user.c | 1 | ||||
| -rw-r--r-- | arch/um/os-Linux/start_up.c | 11 | ||||
| -rw-r--r-- | arch/um/scripts/Makefile.rules | 4 | ||||
| -rw-r--r-- | arch/um/sys-x86_64/stub_segv.c | 37 | ||||
| -rw-r--r-- | arch/x86_64/kernel/suspend.c | 127 | ||||
| -rw-r--r-- | arch/x86_64/kernel/suspend_asm.S | 17 | ||||
| -rw-r--r-- | drivers/pcmcia/cs.c | 3 | ||||
| -rw-r--r-- | include/linux/suspend.h | 2 | ||||
| -rw-r--r-- | kernel/power/swsusp.c | 7 |
12 files changed, 222 insertions, 29 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index c9b69167632a..233526ba3abe 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <asm/atomic.h> | 27 | #include <asm/atomic.h> |
| 28 | #include <asm/system.h> | 28 | #include <asm/system.h> |
| 29 | #include <asm/irq.h> | 29 | #include <asm/irq.h> |
| 30 | #include <asm/io.h> | ||
| 30 | #include <asm/sbus.h> | 31 | #include <asm/sbus.h> |
| 31 | #include <asm/iommu.h> | 32 | #include <asm/iommu.h> |
| 32 | #include <asm/upa.h> | 33 | #include <asm/upa.h> |
diff --git a/arch/um/Makefile b/arch/um/Makefile index 7af37e342e33..e1ffad224605 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile | |||
| @@ -152,7 +152,7 @@ archclean: | |||
| 152 | $(SYMLINK_HEADERS): | 152 | $(SYMLINK_HEADERS): |
| 153 | @echo ' SYMLINK $@' | 153 | @echo ' SYMLINK $@' |
| 154 | ifneq ($(KBUILD_SRC),) | 154 | ifneq ($(KBUILD_SRC),) |
| 155 | ln -fsn $(srctree)/include/asm-um/$(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $@ | 155 | $(Q)ln -fsn $(srctree)/include/asm-um/$(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $@ |
| 156 | else | 156 | else |
| 157 | $(Q)cd $(TOPDIR)/$(dir $@) ; \ | 157 | $(Q)cd $(TOPDIR)/$(dir $@) ; \ |
| 158 | ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@) | 158 | ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@) |
diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h index 4fcf3a8d13f4..dc36b222100b 100644 --- a/arch/um/drivers/cow.h +++ b/arch/um/drivers/cow.h | |||
| @@ -3,15 +3,40 @@ | |||
| 3 | 3 | ||
| 4 | #include <asm/types.h> | 4 | #include <asm/types.h> |
| 5 | 5 | ||
| 6 | #if defined(__BIG_ENDIAN) | 6 | #if defined(__KERNEL__) |
| 7 | # define ntohll(x) (x) | 7 | |
| 8 | # define htonll(x) (x) | 8 | # include <asm/byteorder.h> |
| 9 | #elif defined(__LITTLE_ENDIAN) | 9 | |
| 10 | # define ntohll(x) bswap_64(x) | 10 | # if defined(__BIG_ENDIAN) |
| 11 | # define htonll(x) bswap_64(x) | 11 | # define ntohll(x) (x) |
| 12 | # define htonll(x) (x) | ||
| 13 | # elif defined(__LITTLE_ENDIAN) | ||
| 14 | # define ntohll(x) be64_to_cpu(x) | ||
| 15 | # define htonll(x) cpu_to_be64(x) | ||
| 16 | # else | ||
| 17 | # error "Could not determine byte order" | ||
| 18 | # endif | ||
| 19 | |||
| 12 | #else | 20 | #else |
| 13 | #error "__BYTE_ORDER not defined" | 21 | /* For the definition of ntohl, htonl and __BYTE_ORDER */ |
| 22 | #include <endian.h> | ||
| 23 | #include <netinet/in.h> | ||
| 24 | #if defined(__BYTE_ORDER) | ||
| 25 | |||
| 26 | # if __BYTE_ORDER == __BIG_ENDIAN | ||
| 27 | # define ntohll(x) (x) | ||
| 28 | # define htonll(x) (x) | ||
| 29 | # elif __BYTE_ORDER == __LITTLE_ENDIAN | ||
| 30 | # define ntohll(x) bswap_64(x) | ||
| 31 | # define htonll(x) bswap_64(x) | ||
| 32 | # else | ||
| 33 | # error "Could not determine byte order: __BYTE_ORDER uncorrectly defined" | ||
| 34 | # endif | ||
| 35 | |||
| 36 | #else /* ! defined(__BYTE_ORDER) */ | ||
| 37 | # error "Could not determine byte order: __BYTE_ORDER not defined" | ||
| 14 | #endif | 38 | #endif |
| 39 | #endif /* ! defined(__KERNEL__) */ | ||
| 15 | 40 | ||
| 16 | extern int init_cow_file(int fd, char *cow_file, char *backing_file, | 41 | extern int init_cow_file(int fd, char *cow_file, char *backing_file, |
| 17 | int sectorsize, int alignment, int *bitmap_offset_out, | 42 | int sectorsize, int alignment, int *bitmap_offset_out, |
diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c index a8ce6fc3ef26..fbe2217db5dd 100644 --- a/arch/um/drivers/cow_user.c +++ b/arch/um/drivers/cow_user.c | |||
| @@ -9,7 +9,6 @@ | |||
| 9 | #include <sys/time.h> | 9 | #include <sys/time.h> |
| 10 | #include <sys/param.h> | 10 | #include <sys/param.h> |
| 11 | #include <sys/user.h> | 11 | #include <sys/user.h> |
| 12 | #include <netinet/in.h> | ||
| 13 | 12 | ||
| 14 | #include "os.h" | 13 | #include "os.h" |
| 15 | 14 | ||
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 6af83171ca4e..b99ab414542f 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c | |||
| @@ -143,11 +143,22 @@ static int __init skas0_cmd_param(char *str, int* add) | |||
| 143 | return 0; | 143 | return 0; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | /* The two __uml_setup would conflict, without this stupid alias. */ | ||
| 147 | |||
| 148 | static int __init mode_skas0_cmd_param(char *str, int* add) | ||
| 149 | __attribute__((alias("skas0_cmd_param"))); | ||
| 150 | |||
| 146 | __uml_setup("skas0", skas0_cmd_param, | 151 | __uml_setup("skas0", skas0_cmd_param, |
| 147 | "skas0\n" | 152 | "skas0\n" |
| 148 | " Disables SKAS3 usage, so that SKAS0 is used, unless \n" | 153 | " Disables SKAS3 usage, so that SKAS0 is used, unless \n" |
| 149 | " you specify mode=tt.\n\n"); | 154 | " you specify mode=tt.\n\n"); |
| 150 | 155 | ||
| 156 | __uml_setup("mode=skas0", mode_skas0_cmd_param, | ||
| 157 | "mode=skas0\n" | ||
| 158 | " Disables SKAS3 usage, so that SKAS0 is used, unless you \n" | ||
| 159 | " specify mode=tt. Note that this was recently added - on \n" | ||
| 160 | " older kernels you must use simply \"skas0\".\n\n"); | ||
| 161 | |||
| 151 | static int force_sysemu_disabled = 0; | 162 | static int force_sysemu_disabled = 0; |
| 152 | 163 | ||
| 153 | static int __init nosysemu_cmd_param(char *str, int* add) | 164 | static int __init nosysemu_cmd_param(char *str, int* add) |
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index 59a1291f477e..651d9d88b656 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules | |||
| @@ -7,8 +7,8 @@ USER_SINGLE_OBJS := \ | |||
| 7 | USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) | 7 | USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) |
| 8 | USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) | 8 | USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) |
| 9 | 9 | ||
| 10 | $(USER_OBJS) : c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) \ | 10 | $(USER_OBJS) $(USER_OBJS:.o=.i) $(USER_OBJS:.o=.s) $(USER_OBJS:.o=.lst): \ |
| 11 | $(CFLAGS_$(notdir $@)) | 11 | c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(notdir $@)) |
| 12 | $(USER_OBJS): cmd_checksrc = | 12 | $(USER_OBJS): cmd_checksrc = |
| 13 | $(USER_OBJS): quiet_cmd_checksrc = | 13 | $(USER_OBJS): quiet_cmd_checksrc = |
| 14 | $(USER_OBJS): cmd_force_checksrc = | 14 | $(USER_OBJS): cmd_force_checksrc = |
diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c index 65a131b362b6..d1e53bdf2e85 100644 --- a/arch/um/sys-x86_64/stub_segv.c +++ b/arch/um/sys-x86_64/stub_segv.c | |||
| @@ -10,6 +10,22 @@ | |||
| 10 | #include "uml-config.h" | 10 | #include "uml-config.h" |
| 11 | #include "sysdep/sigcontext.h" | 11 | #include "sysdep/sigcontext.h" |
| 12 | #include "sysdep/faultinfo.h" | 12 | #include "sysdep/faultinfo.h" |
| 13 | #include <stddef.h> | ||
| 14 | |||
| 15 | /* Copied from sys-x86_64/signal.c - Can't find an equivalent definition | ||
| 16 | * in the libc headers anywhere. | ||
| 17 | */ | ||
| 18 | struct rt_sigframe | ||
| 19 | { | ||
| 20 | char *pretcode; | ||
| 21 | struct ucontext uc; | ||
| 22 | struct siginfo info; | ||
| 23 | }; | ||
| 24 | |||
| 25 | /* Copied here from <linux/kernel.h> - we're userspace. */ | ||
| 26 | #define container_of(ptr, type, member) ({ \ | ||
| 27 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | ||
| 28 | (type *)( (char *)__mptr - offsetof(type,member) );}) | ||
| 13 | 29 | ||
| 14 | void __attribute__ ((__section__ (".__syscall_stub"))) | 30 | void __attribute__ ((__section__ (".__syscall_stub"))) |
| 15 | stub_segv_handler(int sig) | 31 | stub_segv_handler(int sig) |
| @@ -17,16 +33,19 @@ stub_segv_handler(int sig) | |||
| 17 | struct ucontext *uc; | 33 | struct ucontext *uc; |
| 18 | 34 | ||
| 19 | __asm__("movq %%rdx, %0" : "=g" (uc) :); | 35 | __asm__("movq %%rdx, %0" : "=g" (uc) :); |
| 20 | GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA), | 36 | GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA), |
| 21 | &uc->uc_mcontext); | 37 | &uc->uc_mcontext); |
| 22 | 38 | ||
| 23 | __asm__("movq %0, %%rax ; syscall": : "g" (__NR_getpid)); | 39 | __asm__("movq %0, %%rax ; syscall": : "g" (__NR_getpid)); |
| 24 | __asm__("movq %%rax, %%rdi ; movq %0, %%rax ; movq %1, %%rsi ;" | 40 | __asm__("movq %%rax, %%rdi ; movq %0, %%rax ; movq %1, %%rsi ;" |
| 25 | "syscall": : "g" (__NR_kill), "g" (SIGUSR1)); | 41 | "syscall": : "g" (__NR_kill), "g" (SIGUSR1) : |
| 26 | /* Two popqs to restore the stack to the state just before entering | 42 | "%rdi", "%rax", "%rsi"); |
| 27 | * the handler, one pops the return address, the other pops the frame | 43 | /* sys_sigreturn expects that the stack pointer will be 8 bytes into |
| 28 | * pointer. | 44 | * the signal frame. So, we use the ucontext pointer, which we know |
| 45 | * already, to get the signal frame pointer, and add 8 to that. | ||
| 29 | */ | 46 | */ |
| 30 | __asm__("popq %%rax ; popq %%rax ; movq %0, %%rax ; syscall" : : "g" | 47 | __asm__("movq %0, %%rsp": : |
| 31 | (__NR_rt_sigreturn)); | 48 | "g" ((unsigned long) container_of(uc, struct rt_sigframe, |
| 49 | uc) + 8)); | ||
| 50 | __asm__("movq %0, %%rax ; syscall" : : "g" (__NR_rt_sigreturn)); | ||
| 32 | } | 51 | } |
diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c index ebb9abf3ce6d..f066c6ab3618 100644 --- a/arch/x86_64/kernel/suspend.c +++ b/arch/x86_64/kernel/suspend.c | |||
| @@ -11,6 +11,8 @@ | |||
| 11 | #include <linux/smp.h> | 11 | #include <linux/smp.h> |
| 12 | #include <linux/suspend.h> | 12 | #include <linux/suspend.h> |
| 13 | #include <asm/proto.h> | 13 | #include <asm/proto.h> |
| 14 | #include <asm/page.h> | ||
| 15 | #include <asm/pgtable.h> | ||
| 14 | 16 | ||
| 15 | struct saved_context saved_context; | 17 | struct saved_context saved_context; |
| 16 | 18 | ||
| @@ -140,4 +142,129 @@ void fix_processor_context(void) | |||
| 140 | 142 | ||
| 141 | } | 143 | } |
| 142 | 144 | ||
| 145 | #ifdef CONFIG_SOFTWARE_SUSPEND | ||
| 146 | /* Defined in arch/x86_64/kernel/suspend_asm.S */ | ||
| 147 | extern int restore_image(void); | ||
| 143 | 148 | ||
| 149 | pgd_t *temp_level4_pgt; | ||
| 150 | |||
| 151 | static void **pages; | ||
| 152 | |||
| 153 | static inline void *__add_page(void) | ||
| 154 | { | ||
| 155 | void **c; | ||
| 156 | |||
| 157 | c = (void **)get_usable_page(GFP_ATOMIC); | ||
| 158 | if (c) { | ||
| 159 | *c = pages; | ||
| 160 | pages = c; | ||
| 161 | } | ||
| 162 | return c; | ||
| 163 | } | ||
| 164 | |||
| 165 | static inline void *__next_page(void) | ||
| 166 | { | ||
| 167 | void **c; | ||
| 168 | |||
| 169 | c = pages; | ||
| 170 | if (c) { | ||
| 171 | pages = *c; | ||
| 172 | *c = NULL; | ||
| 173 | } | ||
| 174 | return c; | ||
| 175 | } | ||
| 176 | |||
| 177 | /* | ||
| 178 | * Try to allocate as many usable pages as needed and daisy chain them. | ||
| 179 | * If one allocation fails, free the pages allocated so far | ||
| 180 | */ | ||
| 181 | static int alloc_usable_pages(unsigned long n) | ||
| 182 | { | ||
| 183 | void *p; | ||
| 184 | |||
| 185 | pages = NULL; | ||
| 186 | do | ||
| 187 | if (!__add_page()) | ||
| 188 | break; | ||
| 189 | while (--n); | ||
| 190 | if (n) { | ||
| 191 | p = __next_page(); | ||
| 192 | while (p) { | ||
| 193 | free_page((unsigned long)p); | ||
| 194 | p = __next_page(); | ||
| 195 | } | ||
| 196 | return -ENOMEM; | ||
| 197 | } | ||
| 198 | return 0; | ||
| 199 | } | ||
| 200 | |||
| 201 | static void res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long end) | ||
| 202 | { | ||
| 203 | long i, j; | ||
| 204 | |||
| 205 | i = pud_index(address); | ||
| 206 | pud = pud + i; | ||
| 207 | for (; i < PTRS_PER_PUD; pud++, i++) { | ||
| 208 | unsigned long paddr; | ||
| 209 | pmd_t *pmd; | ||
| 210 | |||
| 211 | paddr = address + i*PUD_SIZE; | ||
| 212 | if (paddr >= end) | ||
| 213 | break; | ||
| 214 | |||
| 215 | pmd = (pmd_t *)__next_page(); | ||
| 216 | set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE)); | ||
| 217 | for (j = 0; j < PTRS_PER_PMD; pmd++, j++, paddr += PMD_SIZE) { | ||
| 218 | unsigned long pe; | ||
| 219 | |||
| 220 | if (paddr >= end) | ||
| 221 | break; | ||
| 222 | pe = _PAGE_NX | _PAGE_PSE | _KERNPG_TABLE | paddr; | ||
| 223 | pe &= __supported_pte_mask; | ||
| 224 | set_pmd(pmd, __pmd(pe)); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | static void set_up_temporary_mappings(void) | ||
| 230 | { | ||
| 231 | unsigned long start, end, next; | ||
| 232 | |||
| 233 | temp_level4_pgt = (pgd_t *)__next_page(); | ||
| 234 | |||
| 235 | /* It is safe to reuse the original kernel mapping */ | ||
| 236 | set_pgd(temp_level4_pgt + pgd_index(__START_KERNEL_map), | ||
| 237 | init_level4_pgt[pgd_index(__START_KERNEL_map)]); | ||
| 238 | |||
| 239 | /* Set up the direct mapping from scratch */ | ||
| 240 | start = (unsigned long)pfn_to_kaddr(0); | ||
| 241 | end = (unsigned long)pfn_to_kaddr(end_pfn); | ||
| 242 | |||
| 243 | for (; start < end; start = next) { | ||
| 244 | pud_t *pud = (pud_t *)__next_page(); | ||
| 245 | next = start + PGDIR_SIZE; | ||
| 246 | if (next > end) | ||
| 247 | next = end; | ||
| 248 | res_phys_pud_init(pud, __pa(start), __pa(next)); | ||
| 249 | set_pgd(temp_level4_pgt + pgd_index(start), | ||
| 250 | mk_kernel_pgd(__pa(pud))); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | int swsusp_arch_resume(void) | ||
| 255 | { | ||
| 256 | unsigned long n; | ||
| 257 | |||
| 258 | n = ((end_pfn << PAGE_SHIFT) + PUD_SIZE - 1) >> PUD_SHIFT; | ||
| 259 | n += (n + PTRS_PER_PUD - 1) / PTRS_PER_PUD + 1; | ||
| 260 | pr_debug("swsusp_arch_resume(): pages needed = %lu\n", n); | ||
| 261 | if (alloc_usable_pages(n)) { | ||
| 262 | free_eaten_memory(); | ||
| 263 | return -ENOMEM; | ||
| 264 | } | ||
| 265 | /* We have got enough memory and from now on we cannot recover */ | ||
| 266 | set_up_temporary_mappings(); | ||
| 267 | restore_image(); | ||
| 268 | return 0; | ||
| 269 | } | ||
| 270 | #endif /* CONFIG_SOFTWARE_SUSPEND */ | ||
diff --git a/arch/x86_64/kernel/suspend_asm.S b/arch/x86_64/kernel/suspend_asm.S index 4d659e97df10..320b6fb00cca 100644 --- a/arch/x86_64/kernel/suspend_asm.S +++ b/arch/x86_64/kernel/suspend_asm.S | |||
| @@ -39,12 +39,13 @@ ENTRY(swsusp_arch_suspend) | |||
| 39 | call swsusp_save | 39 | call swsusp_save |
| 40 | ret | 40 | ret |
| 41 | 41 | ||
| 42 | ENTRY(swsusp_arch_resume) | 42 | ENTRY(restore_image) |
| 43 | /* set up cr3 */ | 43 | /* switch to temporary page tables */ |
| 44 | leaq init_level4_pgt(%rip),%rax | 44 | movq $__PAGE_OFFSET, %rdx |
| 45 | subq $__START_KERNEL_map,%rax | 45 | movq temp_level4_pgt(%rip), %rax |
| 46 | movq %rax,%cr3 | 46 | subq %rdx, %rax |
| 47 | 47 | movq %rax, %cr3 | |
| 48 | /* Flush TLB */ | ||
| 48 | movq mmu_cr4_features(%rip), %rax | 49 | movq mmu_cr4_features(%rip), %rax |
| 49 | movq %rax, %rdx | 50 | movq %rax, %rdx |
| 50 | andq $~(1<<7), %rdx # PGE | 51 | andq $~(1<<7), %rdx # PGE |
| @@ -69,6 +70,10 @@ loop: | |||
| 69 | movq pbe_next(%rdx), %rdx | 70 | movq pbe_next(%rdx), %rdx |
| 70 | jmp loop | 71 | jmp loop |
| 71 | done: | 72 | done: |
| 73 | /* go back to the original page tables */ | ||
| 74 | leaq init_level4_pgt(%rip), %rax | ||
| 75 | subq $__START_KERNEL_map, %rax | ||
| 76 | movq %rax, %cr3 | ||
| 72 | /* Flush TLB, including "global" things (vmalloc) */ | 77 | /* Flush TLB, including "global" things (vmalloc) */ |
| 73 | movq mmu_cr4_features(%rip), %rax | 78 | movq mmu_cr4_features(%rip), %rax |
| 74 | movq %rax, %rdx | 79 | movq %rax, %rdx |
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index fabd3529cebc..d5e76423a0ee 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c | |||
| @@ -689,6 +689,9 @@ static int pccardd(void *__skt) | |||
| 689 | schedule(); | 689 | schedule(); |
| 690 | try_to_freeze(); | 690 | try_to_freeze(); |
| 691 | } | 691 | } |
| 692 | /* make sure we are running before we exit */ | ||
| 693 | set_current_state(TASK_RUNNING); | ||
| 694 | |||
| 692 | remove_wait_queue(&skt->thread_wait, &wait); | 695 | remove_wait_queue(&skt->thread_wait, &wait); |
| 693 | 696 | ||
| 694 | /* remove from the device core */ | 697 | /* remove from the device core */ |
diff --git a/include/linux/suspend.h b/include/linux/suspend.h index f2e96fdfaae0..ad15a54806d8 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h | |||
| @@ -71,5 +71,7 @@ void restore_processor_state(void); | |||
| 71 | struct saved_context; | 71 | struct saved_context; |
| 72 | void __save_processor_state(struct saved_context *ctxt); | 72 | void __save_processor_state(struct saved_context *ctxt); |
| 73 | void __restore_processor_state(struct saved_context *ctxt); | 73 | void __restore_processor_state(struct saved_context *ctxt); |
| 74 | extern unsigned long get_usable_page(unsigned gfp_mask); | ||
| 75 | extern void free_eaten_memory(void); | ||
| 74 | 76 | ||
| 75 | #endif /* _LINUX_SWSUSP_H */ | 77 | #endif /* _LINUX_SWSUSP_H */ |
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index acf79ac1cb6d..2d5c45676442 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c | |||
| @@ -1095,7 +1095,7 @@ static inline void eat_page(void *page) | |||
| 1095 | *eaten_memory = c; | 1095 | *eaten_memory = c; |
| 1096 | } | 1096 | } |
| 1097 | 1097 | ||
| 1098 | static unsigned long get_usable_page(unsigned gfp_mask) | 1098 | unsigned long get_usable_page(unsigned gfp_mask) |
| 1099 | { | 1099 | { |
| 1100 | unsigned long m; | 1100 | unsigned long m; |
| 1101 | 1101 | ||
| @@ -1109,7 +1109,7 @@ static unsigned long get_usable_page(unsigned gfp_mask) | |||
| 1109 | return m; | 1109 | return m; |
| 1110 | } | 1110 | } |
| 1111 | 1111 | ||
| 1112 | static void free_eaten_memory(void) | 1112 | void free_eaten_memory(void) |
| 1113 | { | 1113 | { |
| 1114 | unsigned long m; | 1114 | unsigned long m; |
| 1115 | void **c; | 1115 | void **c; |
| @@ -1481,11 +1481,12 @@ static int read_suspend_image(void) | |||
| 1481 | /* Allocate memory for the image and read the data from swap */ | 1481 | /* Allocate memory for the image and read the data from swap */ |
| 1482 | 1482 | ||
| 1483 | error = check_pagedir(pagedir_nosave); | 1483 | error = check_pagedir(pagedir_nosave); |
| 1484 | free_eaten_memory(); | 1484 | |
| 1485 | if (!error) | 1485 | if (!error) |
| 1486 | error = data_read(pagedir_nosave); | 1486 | error = data_read(pagedir_nosave); |
| 1487 | 1487 | ||
| 1488 | if (error) { /* We fail cleanly */ | 1488 | if (error) { /* We fail cleanly */ |
| 1489 | free_eaten_memory(); | ||
| 1489 | for_each_pbe (p, pagedir_nosave) | 1490 | for_each_pbe (p, pagedir_nosave) |
| 1490 | if (p->address) { | 1491 | if (p->address) { |
| 1491 | free_page(p->address); | 1492 | free_page(p->address); |
