aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kernel')
-rw-r--r--arch/x86_64/kernel/e820.c48
-rw-r--r--arch/x86_64/kernel/setup.c1
-rw-r--r--arch/x86_64/kernel/smpboot.c3
-rw-r--r--arch/x86_64/kernel/suspend_asm.S2
-rw-r--r--arch/x86_64/kernel/time.c37
5 files changed, 83 insertions, 8 deletions
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index d6d7f731f6f0..708a3cd9a27e 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -16,6 +16,7 @@
16#include <linux/string.h> 16#include <linux/string.h>
17#include <linux/kexec.h> 17#include <linux/kexec.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/mm.h>
19 20
20#include <asm/pgtable.h> 21#include <asm/pgtable.h>
21#include <asm/page.h> 22#include <asm/page.h>
@@ -297,6 +298,53 @@ void __init e820_reserve_resources(void)
297 } 298 }
298} 299}
299 300
301/* Mark pages corresponding to given address range as nosave */
302static void __init
303e820_mark_nosave_range(unsigned long start, unsigned long end)
304{
305 unsigned long pfn, max_pfn;
306
307 if (start >= end)
308 return;
309
310 printk("Nosave address range: %016lx - %016lx\n", start, end);
311 max_pfn = end >> PAGE_SHIFT;
312 for (pfn = start >> PAGE_SHIFT; pfn < max_pfn; pfn++)
313 if (pfn_valid(pfn))
314 SetPageNosave(pfn_to_page(pfn));
315}
316
317/*
318 * Find the ranges of physical addresses that do not correspond to
319 * e820 RAM areas and mark the corresponding pages as nosave for software
320 * suspend and suspend to RAM.
321 *
322 * This function requires the e820 map to be sorted and without any
323 * overlapping entries and assumes the first e820 area to be RAM.
324 */
325void __init e820_mark_nosave_regions(void)
326{
327 int i;
328 unsigned long paddr;
329
330 paddr = round_down(e820.map[0].addr + e820.map[0].size, PAGE_SIZE);
331 for (i = 1; i < e820.nr_map; i++) {
332 struct e820entry *ei = &e820.map[i];
333
334 if (paddr < ei->addr)
335 e820_mark_nosave_range(paddr,
336 round_up(ei->addr, PAGE_SIZE));
337
338 paddr = round_down(ei->addr + ei->size, PAGE_SIZE);
339 if (ei->type != E820_RAM)
340 e820_mark_nosave_range(round_up(ei->addr, PAGE_SIZE),
341 paddr);
342
343 if (paddr >= (end_pfn << PAGE_SHIFT))
344 break;
345 }
346}
347
300/* 348/*
301 * Add a memory region to the kernel e820 map. 349 * Add a memory region to the kernel e820 map.
302 */ 350 */
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index 34afad704824..4b39f0da17f3 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -689,6 +689,7 @@ void __init setup_arch(char **cmdline_p)
689 */ 689 */
690 probe_roms(); 690 probe_roms();
691 e820_reserve_resources(); 691 e820_reserve_resources();
692 e820_mark_nosave_regions();
692 693
693 request_resource(&iomem_resource, &video_ram_resource); 694 request_resource(&iomem_resource, &video_ram_resource);
694 695
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index 975380207b46..3ae9ffddddc0 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -46,9 +46,10 @@
46#include <linux/bootmem.h> 46#include <linux/bootmem.h>
47#include <linux/thread_info.h> 47#include <linux/thread_info.h>
48#include <linux/module.h> 48#include <linux/module.h>
49
50#include <linux/delay.h> 49#include <linux/delay.h>
51#include <linux/mc146818rtc.h> 50#include <linux/mc146818rtc.h>
51#include <linux/smp.h>
52
52#include <asm/mtrr.h> 53#include <asm/mtrr.h>
53#include <asm/pgalloc.h> 54#include <asm/pgalloc.h>
54#include <asm/desc.h> 55#include <asm/desc.h>
diff --git a/arch/x86_64/kernel/suspend_asm.S b/arch/x86_64/kernel/suspend_asm.S
index 320b6fb00cca..bfbe00763c68 100644
--- a/arch/x86_64/kernel/suspend_asm.S
+++ b/arch/x86_64/kernel/suspend_asm.S
@@ -54,7 +54,7 @@ ENTRY(restore_image)
54 movq %rcx, %cr3; 54 movq %rcx, %cr3;
55 movq %rax, %cr4; # turn PGE back on 55 movq %rax, %cr4; # turn PGE back on
56 56
57 movq pagedir_nosave(%rip), %rdx 57 movq restore_pblist(%rip), %rdx
58loop: 58loop:
59 testq %rdx, %rdx 59 testq %rdx, %rdx
60 jz done 60 jz done
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 7a9b18224182..7700e6cd2bd9 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -1148,23 +1148,25 @@ int hpet_rtc_timer_init(void)
1148 hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; 1148 hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
1149 1149
1150 local_irq_save(flags); 1150 local_irq_save(flags);
1151
1151 cnt = hpet_readl(HPET_COUNTER); 1152 cnt = hpet_readl(HPET_COUNTER);
1152 cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); 1153 cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq);
1153 hpet_writel(cnt, HPET_T1_CMP); 1154 hpet_writel(cnt, HPET_T1_CMP);
1154 hpet_t1_cmp = cnt; 1155 hpet_t1_cmp = cnt;
1155 local_irq_restore(flags);
1156 1156
1157 cfg = hpet_readl(HPET_T1_CFG); 1157 cfg = hpet_readl(HPET_T1_CFG);
1158 cfg &= ~HPET_TN_PERIODIC; 1158 cfg &= ~HPET_TN_PERIODIC;
1159 cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; 1159 cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
1160 hpet_writel(cfg, HPET_T1_CFG); 1160 hpet_writel(cfg, HPET_T1_CFG);
1161 1161
1162 local_irq_restore(flags);
1163
1162 return 1; 1164 return 1;
1163} 1165}
1164 1166
1165static void hpet_rtc_timer_reinit(void) 1167static void hpet_rtc_timer_reinit(void)
1166{ 1168{
1167 unsigned int cfg, cnt; 1169 unsigned int cfg, cnt, ticks_per_int, lost_ints;
1168 1170
1169 if (unlikely(!(PIE_on | AIE_on | UIE_on))) { 1171 if (unlikely(!(PIE_on | AIE_on | UIE_on))) {
1170 cfg = hpet_readl(HPET_T1_CFG); 1172 cfg = hpet_readl(HPET_T1_CFG);
@@ -1179,10 +1181,33 @@ static void hpet_rtc_timer_reinit(void)
1179 hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; 1181 hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
1180 1182
1181 /* It is more accurate to use the comparator value than current count.*/ 1183 /* It is more accurate to use the comparator value than current count.*/
1182 cnt = hpet_t1_cmp; 1184 ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq;
1183 cnt += hpet_tick*HZ/hpet_rtc_int_freq; 1185 hpet_t1_cmp += ticks_per_int;
1184 hpet_writel(cnt, HPET_T1_CMP); 1186 hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
1185 hpet_t1_cmp = cnt; 1187
1188 /*
1189 * If the interrupt handler was delayed too long, the write above tries
1190 * to schedule the next interrupt in the past and the hardware would
1191 * not interrupt until the counter had wrapped around.
1192 * So we have to check that the comparator wasn't set to a past time.
1193 */
1194 cnt = hpet_readl(HPET_COUNTER);
1195 if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) {
1196 lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1;
1197 /* Make sure that, even with the time needed to execute
1198 * this code, the next scheduled interrupt has been moved
1199 * back to the future: */
1200 lost_ints++;
1201
1202 hpet_t1_cmp += lost_ints * ticks_per_int;
1203 hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
1204
1205 if (PIE_on)
1206 PIE_count += lost_ints;
1207
1208 printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
1209 hpet_rtc_int_freq);
1210 }
1186} 1211}
1187 1212
1188/* 1213/*