From f80aabb03a33702d934fbc3c02fd96471816d82e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 21 Oct 2005 03:21:43 -0400 Subject: [PATCH] gfp_t: dma-mapping (amd64) Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/pci-gart.c | 4 ++-- arch/x86_64/kernel/pci-nommu.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/x86_64/kernel') diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c index cf0a0315d58..88be97c9698 100644 --- a/arch/x86_64/kernel/pci-gart.c +++ b/arch/x86_64/kernel/pci-gart.c @@ -187,7 +187,7 @@ static void flush_gart(struct device *dev) /* Allocate DMA memory on node near device */ noinline -static void *dma_alloc_pages(struct device *dev, unsigned gfp, unsigned order) +static void *dma_alloc_pages(struct device *dev, gfp_t gfp, unsigned order) { struct page *page; int node; @@ -204,7 +204,7 @@ static void *dma_alloc_pages(struct device *dev, unsigned gfp, unsigned order) */ void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - unsigned gfp) + gfp_t gfp) { void *memory; unsigned long dma_mask = 0; diff --git a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c index 67d90b89af0..5a981dca87f 100644 --- a/arch/x86_64/kernel/pci-nommu.c +++ b/arch/x86_64/kernel/pci-nommu.c @@ -24,7 +24,7 @@ EXPORT_SYMBOL(iommu_sac_force); */ void *dma_alloc_coherent(struct device *hwdev, size_t size, - dma_addr_t *dma_handle, unsigned gfp) + dma_addr_t *dma_handle, gfp_t gfp) { void *ret; u64 mask; -- cgit v1.2.3-70-g09d2 From dacb16b1a034fa7a0b868ee30758119fbfd90bc1 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Sun, 30 Oct 2005 14:59:25 -0800 Subject: [PATCH] i386 and x86_64 TSC set_cyc2ns_scale imprecision I just found out that some precision is unnecessarily lost in the arch/i386/kernel/timers/timer_tsc.c:set_cyc2ns_scale function. It uses a cpu_mhz parameter when it could use a cpu_khz. In the specific case of an Intel P4 running at 3001.171 Mhz, the truncation to 3001 Mhz leads to an imprecision of 19 microseconds per second : this is very sad for a timer with nearly nanosecond accuracy. Fix the x86_64 architecture too. Cc: george anzinger Cc: john stultz Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/timers/timer_hpet.c | 17 +++++++++++------ arch/i386/kernel/timers/timer_tsc.c | 21 +++++++++++++-------- arch/x86_64/kernel/time.c | 8 ++++---- 3 files changed, 28 insertions(+), 18 deletions(-) (limited to 'arch/x86_64/kernel') diff --git a/arch/i386/kernel/timers/timer_hpet.c b/arch/i386/kernel/timers/timer_hpet.c index d973a8b681f..be242723c33 100644 --- a/arch/i386/kernel/timers/timer_hpet.c +++ b/arch/i386/kernel/timers/timer_hpet.c @@ -30,23 +30,28 @@ static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED; * basic equation: * ns = cycles / (freq / ns_per_sec) * ns = cycles * (ns_per_sec / freq) - * ns = cycles * (10^9 / (cpu_mhz * 10^6)) - * ns = cycles * (10^3 / cpu_mhz) + * ns = cycles * (10^9 / (cpu_khz * 10^3)) + * ns = cycles * (10^6 / cpu_khz) * * Then we use scaling math (suggested by george@mvista.com) to get: - * ns = cycles * (10^3 * SC / cpu_mhz) / SC + * ns = cycles * (10^6 * SC / cpu_khz) / SC * ns = cycles * cyc2ns_scale / SC * * And since SC is a constant power of two, we can convert the div * into a shift. + * + * We can use khz divisor instead of mhz to keep a better percision, since + * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits. + * (mathieu.desnoyers@polymtl.ca) + * * -johnstul@us.ibm.com "math is hard, lets go shopping!" */ static unsigned long cyc2ns_scale; #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ -static inline void set_cyc2ns_scale(unsigned long cpu_mhz) +static inline void set_cyc2ns_scale(unsigned long cpu_khz) { - cyc2ns_scale = (1000 << CYC2NS_SCALE_FACTOR)/cpu_mhz; + cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz; } static inline unsigned long long cycles_2_ns(unsigned long long cyc) @@ -163,7 +168,7 @@ static int __init init_hpet(char* override) printk("Detected %u.%03u MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); } - set_cyc2ns_scale(cpu_khz/1000); + set_cyc2ns_scale(cpu_khz); } /* set this only when cpu_has_tsc */ timer_hpet.read_timer = read_timer_tsc; diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c index 6dd470cc9f7..d395e3b4248 100644 --- a/arch/i386/kernel/timers/timer_tsc.c +++ b/arch/i386/kernel/timers/timer_tsc.c @@ -49,23 +49,28 @@ static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED; * basic equation: * ns = cycles / (freq / ns_per_sec) * ns = cycles * (ns_per_sec / freq) - * ns = cycles * (10^9 / (cpu_mhz * 10^6)) - * ns = cycles * (10^3 / cpu_mhz) + * ns = cycles * (10^9 / (cpu_khz * 10^3)) + * ns = cycles * (10^6 / cpu_khz) * * Then we use scaling math (suggested by george@mvista.com) to get: - * ns = cycles * (10^3 * SC / cpu_mhz) / SC + * ns = cycles * (10^6 * SC / cpu_khz) / SC * ns = cycles * cyc2ns_scale / SC * * And since SC is a constant power of two, we can convert the div - * into a shift. + * into a shift. + * + * We can use khz divisor instead of mhz to keep a better percision, since + * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits. + * (mathieu.desnoyers@polymtl.ca) + * * -johnstul@us.ibm.com "math is hard, lets go shopping!" */ static unsigned long cyc2ns_scale; #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ -static inline void set_cyc2ns_scale(unsigned long cpu_mhz) +static inline void set_cyc2ns_scale(unsigned long cpu_khz) { - cyc2ns_scale = (1000 << CYC2NS_SCALE_FACTOR)/cpu_mhz; + cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz; } static inline unsigned long long cycles_2_ns(unsigned long long cyc) @@ -286,7 +291,7 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, if (use_tsc) { if (!(freq->flags & CPUFREQ_CONST_LOOPS)) { fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq); - set_cyc2ns_scale(cpu_khz/1000); + set_cyc2ns_scale(cpu_khz); } } #endif @@ -536,7 +541,7 @@ static int __init init_tsc(char* override) printk("Detected %u.%03u MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); } - set_cyc2ns_scale(cpu_khz/1000); + set_cyc2ns_scale(cpu_khz); return 0; } } diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 703acde2a1a..47d25ad0816 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -481,9 +481,9 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) static unsigned int cyc2ns_scale; #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ -static inline void set_cyc2ns_scale(unsigned long cpu_mhz) +static inline void set_cyc2ns_scale(unsigned long cpu_khz) { - cyc2ns_scale = (1000 << CYC2NS_SCALE_FACTOR)/cpu_mhz; + cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz; } static inline unsigned long long cycles_2_ns(unsigned long long cyc) @@ -655,7 +655,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, vxtime.tsc_quot = (1000L << 32) / cpu_khz; } - set_cyc2ns_scale(cpu_khz_ref / 1000); + set_cyc2ns_scale(cpu_khz_ref); return 0; } @@ -939,7 +939,7 @@ void __init time_init(void) rdtscll_sync(&vxtime.last_tsc); setup_irq(0, &irq0); - set_cyc2ns_scale(cpu_khz / 1000); + set_cyc2ns_scale(cpu_khz); #ifndef CONFIG_SMP time_init_gtod(); -- cgit v1.2.3-70-g09d2 From 08967f941ad897b2f7c2f99e886c75d6319e5087 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Sun, 30 Oct 2005 14:59:28 -0800 Subject: [PATCH] FPU context corrupted after resume mxcsr_feature_mask_init isn't needed in suspend/resume time (we can use boot time mask). And actually it's harmful, as it clear task's saved fxsave in resume. This bug is widely seen by users using zsh. (akpm: my eyes. Fixed some surrounding whitespace mess) Signed-off-by: Shaohua Li Cc: Pavel Machek Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/power/cpu.c | 12 +++++------- arch/x86_64/kernel/suspend.c | 11 +++++------ 2 files changed, 10 insertions(+), 13 deletions(-) (limited to 'arch/x86_64/kernel') diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c index b27c5acc79d..1f1572692e0 100644 --- a/arch/i386/power/cpu.c +++ b/arch/i386/power/cpu.c @@ -51,16 +51,14 @@ void save_processor_state(void) __save_processor_state(&saved_context); } -static void -do_fpu_end(void) +static void do_fpu_end(void) { - /* restore FPU regs if necessary */ - /* Do it out of line so that gcc does not move cr0 load to some stupid place */ - kernel_fpu_end(); - mxcsr_feature_mask_init(); + /* + * Restore FPU regs if necessary. + */ + kernel_fpu_end(); } - static void fix_processor_context(void) { int cpu = smp_processor_id(); diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c index f066c6ab361..02516823f51 100644 --- a/arch/x86_64/kernel/suspend.c +++ b/arch/x86_64/kernel/suspend.c @@ -63,13 +63,12 @@ void save_processor_state(void) __save_processor_state(&saved_context); } -static void -do_fpu_end(void) +static void do_fpu_end(void) { - /* restore FPU regs if necessary */ - /* Do it out of line so that gcc does not move cr0 load to some stupid place */ - kernel_fpu_end(); - mxcsr_feature_mask_init(); + /* + * Restore FPU regs if necessary + */ + kernel_fpu_end(); } void __restore_processor_state(struct saved_context *ctxt) -- cgit v1.2.3-70-g09d2 From daedb82d6b54e58a66ad1dce3509e699a5bd1b18 Mon Sep 17 00:00:00 2001 From: "Kamble, Nitin A" Date: Sun, 30 Oct 2005 14:59:43 -0800 Subject: [PATCH] x86: vmx cpu feature detection If VMX feature is available in the CPU, this patch will make it visible in the /proc/cpuinfo with the cpuid detection. Signed-Off-By: Nitin A Kamble Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/proc.c | 2 +- arch/x86_64/kernel/setup.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/kernel') diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c index 8bd77d948a8..41b871ecf4b 100644 --- a/arch/i386/kernel/cpu/proc.c +++ b/arch/i386/kernel/cpu/proc.c @@ -44,7 +44,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Intel-defined (#2) */ - "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "est", + "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", NULL, "est", "tm2", NULL, "cid", NULL, NULL, "cx16", "xtpr", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index cb28df14ff6..da0bc3e7bdf 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -1213,7 +1213,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Intel-defined (#2) */ - "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "est", + "pni", NULL, NULL, "monitor", "ds_cpl", "vmx", NULL, "est", "tm2", NULL, "cid", NULL, NULL, "cx16", "xtpr", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -- cgit v1.2.3-70-g09d2 From 2c1b4a5ca48831595979a850f40ced8e7da026f8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 30 Oct 2005 14:59:58 -0800 Subject: [PATCH] swsusp: rework memory freeing on resume The following patch makes swsusp use the PG_nosave and PG_nosave_free flags to mark pages that should be freed in case of an error during resume. This allows us to simplify the code and to use swsusp_free() in all of the swsusp's resume error paths, which makes them actually work. Signed-off-by: Rafael J. Wysocki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/suspend.c | 84 ++++++++------------------------- include/linux/suspend.h | 3 +- kernel/power/disk.c | 14 +++--- kernel/power/power.h | 2 +- kernel/power/snapshot.c | 2 +- kernel/power/swsusp.c | 110 ++++++++++++++----------------------------- 6 files changed, 65 insertions(+), 150 deletions(-) (limited to 'arch/x86_64/kernel') diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c index 02516823f51..fd2bef78088 100644 --- a/arch/x86_64/kernel/suspend.c +++ b/arch/x86_64/kernel/suspend.c @@ -147,57 +147,7 @@ extern int restore_image(void); pgd_t *temp_level4_pgt; -static void **pages; - -static inline void *__add_page(void) -{ - void **c; - - c = (void **)get_usable_page(GFP_ATOMIC); - if (c) { - *c = pages; - pages = c; - } - return c; -} - -static inline void *__next_page(void) -{ - void **c; - - c = pages; - if (c) { - pages = *c; - *c = NULL; - } - return c; -} - -/* - * Try to allocate as many usable pages as needed and daisy chain them. - * If one allocation fails, free the pages allocated so far - */ -static int alloc_usable_pages(unsigned long n) -{ - void *p; - - pages = NULL; - do - if (!__add_page()) - break; - while (--n); - if (n) { - p = __next_page(); - while (p) { - free_page((unsigned long)p); - p = __next_page(); - } - return -ENOMEM; - } - return 0; -} - -static void res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long end) +static int res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long end) { long i, j; @@ -211,7 +161,9 @@ static void res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long e if (paddr >= end) break; - pmd = (pmd_t *)__next_page(); + pmd = (pmd_t *)get_safe_page(GFP_ATOMIC); + if (!pmd) + return -ENOMEM; set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE)); for (j = 0; j < PTRS_PER_PMD; pmd++, j++, paddr += PMD_SIZE) { unsigned long pe; @@ -223,13 +175,17 @@ static void res_phys_pud_init(pud_t *pud, unsigned long address, unsigned long e set_pmd(pmd, __pmd(pe)); } } + return 0; } -static void set_up_temporary_mappings(void) +static int set_up_temporary_mappings(void) { unsigned long start, end, next; + int error; - temp_level4_pgt = (pgd_t *)__next_page(); + temp_level4_pgt = (pgd_t *)get_safe_page(GFP_ATOMIC); + if (!temp_level4_pgt) + return -ENOMEM; /* It is safe to reuse the original kernel mapping */ set_pgd(temp_level4_pgt + pgd_index(__START_KERNEL_map), @@ -240,29 +196,27 @@ static void set_up_temporary_mappings(void) end = (unsigned long)pfn_to_kaddr(end_pfn); for (; start < end; start = next) { - pud_t *pud = (pud_t *)__next_page(); + pud_t *pud = (pud_t *)get_safe_page(GFP_ATOMIC); + if (!pud) + return -ENOMEM; next = start + PGDIR_SIZE; if (next > end) next = end; - res_phys_pud_init(pud, __pa(start), __pa(next)); + if ((error = res_phys_pud_init(pud, __pa(start), __pa(next)))) + return error; set_pgd(temp_level4_pgt + pgd_index(start), mk_kernel_pgd(__pa(pud))); } + return 0; } int swsusp_arch_resume(void) { - unsigned long n; + int error; - n = ((end_pfn << PAGE_SHIFT) + PUD_SIZE - 1) >> PUD_SHIFT; - n += (n + PTRS_PER_PUD - 1) / PTRS_PER_PUD + 1; - pr_debug("swsusp_arch_resume(): pages needed = %lu\n", n); - if (alloc_usable_pages(n)) { - free_eaten_memory(); - return -ENOMEM; - } /* We have got enough memory and from now on we cannot recover */ - set_up_temporary_mappings(); + if ((error = set_up_temporary_mappings())) + return error; restore_image(); return 0; } diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 380915e9563..a61c04f804b 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -71,8 +71,7 @@ void restore_processor_state(void); struct saved_context; void __save_processor_state(struct saved_context *ctxt); void __restore_processor_state(struct saved_context *ctxt); -extern unsigned long get_usable_page(gfp_t gfp_mask); -extern void free_eaten_memory(void); +unsigned long get_safe_page(gfp_t gfp_mask); /* * XXX: We try to keep some more pages free so that I/O operations succeed diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 761956e813f..44ef5e799df 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -30,7 +30,6 @@ extern int swsusp_check(void); extern int swsusp_read(void); extern void swsusp_close(void); extern int swsusp_resume(void); -extern int swsusp_free(void); static int noresume = 0; @@ -252,14 +251,17 @@ static int software_resume(void) pr_debug("PM: Reading swsusp image.\n"); - if ((error = swsusp_read())) - goto Cleanup; + if ((error = swsusp_read())) { + swsusp_free(); + goto Thaw; + } pr_debug("PM: Preparing devices for restore.\n"); if ((error = device_suspend(PMSG_FREEZE))) { printk("Some devices failed to suspend\n"); - goto Free; + swsusp_free(); + goto Thaw; } mb(); @@ -268,9 +270,7 @@ static int software_resume(void) swsusp_resume(); pr_debug("PM: Restore failed, recovering.n"); device_resume(); - Free: - swsusp_free(); - Cleanup: + Thaw: unprepare_processes(); Done: /* For success case, the suspend path will release the lock */ diff --git a/kernel/power/power.h b/kernel/power/power.h index 28afcb09014..d4fd96a135a 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -66,7 +66,7 @@ extern asmlinkage int swsusp_arch_suspend(void); extern asmlinkage int swsusp_arch_resume(void); extern int restore_highmem(void); -extern void free_pagedir(struct pbe *pblist); extern struct pbe * alloc_pagedir(unsigned nr_pages); extern void create_pbe_list(struct pbe *pblist, unsigned nr_pages); +extern void swsusp_free(void); extern int enough_swap(unsigned nr_pages); diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 03916cf3ff0..84e686bdb40 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -240,7 +240,7 @@ static void copy_data_pages(struct pbe *pblist) * free_pagedir - free pages allocated with alloc_pagedir() */ -void free_pagedir(struct pbe *pblist) +static void free_pagedir(struct pbe *pblist) { struct pbe *pbe; diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index f6abfdb0a02..50667f4f3a2 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -629,6 +629,11 @@ int swsusp_resume(void) * execution continues at place where swsusp_arch_suspend was called */ BUG_ON(!error); + /* The only reason why swsusp_arch_resume() can fail is memory being + * very tight, so we have to free it as soon as we can to avoid + * subsequent failures + */ + swsusp_free(); restore_processor_state(); restore_highmem(); touch_softlockup_watchdog(); @@ -644,54 +649,28 @@ int swsusp_resume(void) * * We don't know which pages are usable until we allocate them. * - * Allocated but unusable (ie eaten) memory pages are linked together - * to create a list, so that we can free them easily - * - * We could have used a type other than (void *) - * for this purpose, but ... + * Allocated but unusable (ie eaten) memory pages are marked so that + * swsusp_free() can release them */ -static void **eaten_memory = NULL; -static inline void eat_page(void *page) -{ - void **c; - - c = eaten_memory; - eaten_memory = page; - *eaten_memory = c; -} - -unsigned long get_usable_page(gfp_t gfp_mask) +unsigned long get_safe_page(gfp_t gfp_mask) { unsigned long m; - m = get_zeroed_page(gfp_mask); - while (!PageNosaveFree(virt_to_page(m))) { - eat_page((void *)m); + do { m = get_zeroed_page(gfp_mask); - if (!m) - break; + if (m && PageNosaveFree(virt_to_page(m))) + /* This is for swsusp_free() */ + SetPageNosave(virt_to_page(m)); + } while (m && PageNosaveFree(virt_to_page(m))); + if (m) { + /* This is for swsusp_free() */ + SetPageNosave(virt_to_page(m)); + SetPageNosaveFree(virt_to_page(m)); } return m; } -void free_eaten_memory(void) -{ - unsigned long m; - void **c; - int i = 0; - - c = eaten_memory; - while (c) { - m = (unsigned long)c; - c = *c; - free_page(m); - i++; - } - eaten_memory = NULL; - pr_debug("swsusp: %d unused pages freed\n", i); -} - /** * check_pagedir - We ensure here that pages that the PBEs point to * won't collide with pages where we're going to restore from the loaded @@ -709,7 +688,7 @@ static int check_pagedir(struct pbe *pblist) p->address = 0UL; for_each_pbe (p, pblist) { - p->address = get_usable_page(GFP_ATOMIC); + p->address = get_safe_page(GFP_ATOMIC); if (!p->address) return -ENOMEM; } @@ -728,7 +707,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) unsigned long zone_pfn; struct pbe *pbpage, *tail, *p; void *m; - int rel = 0, error = 0; + int rel = 0; if (!pblist) /* a sanity check */ return NULL; @@ -736,41 +715,37 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) pr_debug("swsusp: Relocating pagedir (%lu pages to check)\n", swsusp_info.pagedir_pages); - /* Set page flags */ + /* Clear page flags */ for_each_zone (zone) { for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) - SetPageNosaveFree(pfn_to_page(zone_pfn + + if (pfn_valid(zone_pfn + zone->zone_start_pfn)) + ClearPageNosaveFree(pfn_to_page(zone_pfn + zone->zone_start_pfn)); } - /* Clear orig addresses */ + /* Mark orig addresses */ for_each_pbe (p, pblist) - ClearPageNosaveFree(virt_to_page(p->orig_address)); + SetPageNosaveFree(virt_to_page(p->orig_address)); tail = pblist + PB_PAGE_SKIP; /* Relocate colliding pages */ for_each_pb_page (pbpage, pblist) { - if (!PageNosaveFree(virt_to_page((unsigned long)pbpage))) { - m = (void *)get_usable_page(GFP_ATOMIC | __GFP_COLD); - if (!m) { - error = -ENOMEM; - break; - } + if (PageNosaveFree(virt_to_page((unsigned long)pbpage))) { + m = (void *)get_safe_page(GFP_ATOMIC | __GFP_COLD); + if (!m) + return NULL; memcpy(m, (void *)pbpage, PAGE_SIZE); if (pbpage == pblist) pblist = (struct pbe *)m; else tail->next = (struct pbe *)m; - - eat_page((void *)pbpage); pbpage = (struct pbe *)m; /* We have to link the PBEs again */ - for (p = pbpage; p < pbpage + PB_PAGE_SKIP; p++) if (p->next) /* needed to save the end */ p->next = p + 1; @@ -780,15 +755,13 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) tail = pbpage + PB_PAGE_SKIP; } - if (error) { - printk("\nswsusp: Out of memory\n\n"); - free_pagedir(pblist); - free_eaten_memory(); - pblist = NULL; - /* Is this even worth handling? It should never ever happen, and we - have just lost user's state, anyway... */ - } else - printk("swsusp: Relocated %d pages\n", rel); + /* This is for swsusp_free() */ + for_each_pb_page (pbpage, pblist) { + SetPageNosave(virt_to_page(pbpage)); + SetPageNosaveFree(virt_to_page(pbpage)); + } + + printk("swsusp: Relocated %d pages\n", rel); return pblist; } @@ -1006,9 +979,7 @@ static int read_pagedir(struct pbe *pblist) break; } - if (error) - free_pagedir(pblist); - else + if (!error) BUG_ON(i != swsusp_info.pagedir_pages); return error; @@ -1051,15 +1022,6 @@ static int read_suspend_image(void) if (!error) error = data_read(pagedir_nosave); - if (error) { /* We fail cleanly */ - free_eaten_memory(); - for_each_pbe (p, pagedir_nosave) - if (p->address) { - free_page(p->address); - p->address = 0UL; - } - free_pagedir(pagedir_nosave); - } return error; } -- cgit v1.2.3-70-g09d2 From a8db2db1e6a8d323d87a67c5391d48fe2b97faf5 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 30 Oct 2005 15:01:38 -0800 Subject: [PATCH] introduce setup_timer() helper Every user of init_timer() also needs to initialize ->function and ->data fields. This patch adds a simple setup_timer() helper for that. The schedule_timeout() is patched as an example of usage. Signed-off-by: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/i8259.c | 8 ++++---- include/linux/timer.h | 9 +++++++++ kernel/timer.c | 8 ++------ 3 files changed, 15 insertions(+), 10 deletions(-) (limited to 'arch/x86_64/kernel') diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index b2a238b5a17..c6c9791d77c 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -494,7 +494,7 @@ void invalidate_interrupt7(void); void thermal_interrupt(void); void i8254_timer_resume(void); -static void setup_timer(void) +static void setup_timer_hardware(void) { outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ udelay(10); @@ -505,13 +505,13 @@ static void setup_timer(void) static int timer_resume(struct sys_device *dev) { - setup_timer(); + setup_timer_hardware(); return 0; } void i8254_timer_resume(void) { - setup_timer(); + setup_timer_hardware(); } static struct sysdev_class timer_sysclass = { @@ -594,7 +594,7 @@ void __init init_IRQ(void) * Set the clock to HZ Hz, we already have a valid * vector now: */ - setup_timer(); + setup_timer_hardware(); if (!acpi_ioapic) setup_irq(2, &irq2); diff --git a/include/linux/timer.h b/include/linux/timer.h index 3340f3bd135..ddd5bbe1fc8 100644 --- a/include/linux/timer.h +++ b/include/linux/timer.h @@ -38,6 +38,15 @@ extern struct timer_base_s __init_timer_base; void fastcall init_timer(struct timer_list * timer); +static inline void setup_timer(struct timer_list * timer, + void (*function)(unsigned long), + unsigned long data) +{ + timer->function = function; + timer->data = data; + init_timer(timer); +} + /*** * timer_pending - is a timer pending? * @timer: the timer in question diff --git a/kernel/timer.c b/kernel/timer.c index 6a2e5f8dc72..6ed1a826e5c 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1146,12 +1146,8 @@ fastcall signed long __sched schedule_timeout(signed long timeout) expire = timeout + jiffies; - init_timer(&timer); - timer.expires = expire; - timer.data = (unsigned long) current; - timer.function = process_timeout; - - add_timer(&timer); + setup_timer(&timer, process_timeout, (unsigned long)current); + __mod_timer(&timer, expire); schedule(); del_singleshot_timer_sync(&timer); -- cgit v1.2.3-70-g09d2 From ecea8d19c9f0ebd62ddaa07fc919ff4e4b820d99 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 30 Oct 2005 15:03:00 -0800 Subject: [PATCH] jiffies_64 cleanup Define jiffies_64 in kernel/timer.c rather than having 24 duplicated defines in each architecture. Signed-off-by: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/kernel/time.c | 4 ---- arch/arm/kernel/time.c | 4 ---- arch/arm26/kernel/time.c | 4 ---- arch/cris/kernel/time.c | 4 ---- arch/frv/kernel/time.c | 3 --- arch/h8300/kernel/time.c | 4 ---- arch/i386/kernel/time.c | 4 ---- arch/ia64/kernel/time.c | 4 ---- arch/m32r/kernel/time.c | 4 ---- arch/m68k/kernel/time.c | 4 ---- arch/m68knommu/kernel/time.c | 4 ---- arch/mips/kernel/time.c | 4 ---- arch/parisc/kernel/time.c | 4 ---- arch/ppc/kernel/time.c | 5 ----- arch/ppc64/kernel/time.c | 4 ---- arch/s390/kernel/time.c | 4 ---- arch/sh/kernel/time.c | 4 ---- arch/sh64/kernel/time.c | 2 -- arch/sparc/kernel/time.c | 4 ---- arch/sparc64/kernel/time.c | 4 ---- arch/um/kernel/time_kern.c | 4 ---- arch/v850/kernel/time.c | 4 ---- arch/x86_64/kernel/time.c | 4 ---- arch/xtensa/kernel/time.c | 3 --- kernel/timer.c | 4 ++++ 25 files changed, 4 insertions(+), 93 deletions(-) (limited to 'arch/x86_64/kernel') diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index 67be50b7d80..6b2921be190 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -55,10 +55,6 @@ #include "proto.h" #include "irq_impl.h" -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - extern unsigned long wall_jiffies; /* kernel/timer.c */ static int set_rtc_mmss(unsigned long); diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 69449a818dc..fc4729106a3 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -36,10 +36,6 @@ #include #include -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - /* * Our system timer. */ diff --git a/arch/arm26/kernel/time.c b/arch/arm26/kernel/time.c index e66aedd02fa..335525339ad 100644 --- a/arch/arm26/kernel/time.c +++ b/arch/arm26/kernel/time.c @@ -34,10 +34,6 @@ #include #include -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - extern unsigned long wall_jiffies; /* this needs a better home */ diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c index a2d99b4aedc..b863815de78 100644 --- a/arch/cris/kernel/time.c +++ b/arch/cris/kernel/time.c @@ -32,10 +32,6 @@ #include #include -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - int have_rtc; /* used to remember if we have an RTC or not */; #define TICK_SIZE tick diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c index f43b734482e..2e9741227b7 100644 --- a/arch/frv/kernel/time.c +++ b/arch/frv/kernel/time.c @@ -34,9 +34,6 @@ extern unsigned long wall_jiffies; -u64 jiffies_64 = INITIAL_JIFFIES; -EXPORT_SYMBOL(jiffies_64); - unsigned long __nongprelbss __clkin_clock_speed_HZ; unsigned long __nongprelbss __ext_bus_clock_speed_HZ; unsigned long __nongprelbss __res_bus_clock_speed_HZ; diff --git a/arch/h8300/kernel/time.c b/arch/h8300/kernel/time.c index af8c5d2057d..688a5100604 100644 --- a/arch/h8300/kernel/time.c +++ b/arch/h8300/kernel/time.c @@ -32,10 +32,6 @@ #define TICK_SIZE (tick_nsec / 1000) -u64 jiffies_64; - -EXPORT_SYMBOL(jiffies_64); - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 46c35ec9137..07471bba2dc 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -74,10 +74,6 @@ int pit_latch_buggy; /* extern */ #include "do_timer.h" -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - unsigned int cpu_khz; /* Detected as we calibrate the TSC */ EXPORT_SYMBOL(cpu_khz); diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 8b8a5a45b62..5b7e736f3b4 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -32,10 +32,6 @@ extern unsigned long wall_jiffies; -u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - #define TIME_KEEPER_ID 0 /* smp_processor_id() of time-keeper */ #ifdef CONFIG_IA64_DEBUG_IRQ diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c index 539c562cd54..2ebce2063fe 100644 --- a/arch/m32r/kernel/time.c +++ b/arch/m32r/kernel/time.c @@ -39,10 +39,6 @@ extern void send_IPI_allbutself(int, int); extern void smp_local_timer_interrupt(struct pt_regs *); #endif -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - extern unsigned long wall_jiffies; #define TICK_SIZE (tick_nsec / 1000) diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index 4ec95e3cb87..98e4b1adfa2 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -27,10 +27,6 @@ #include #include -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - static inline int set_rtc_mmss(unsigned long nowtime) { if (mach_set_clock_mmss) diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c index b17c1ecba96..b9d8abb4543 100644 --- a/arch/m68knommu/kernel/time.c +++ b/arch/m68knommu/kernel/time.c @@ -27,10 +27,6 @@ #define TICK_SIZE (tick_nsec / 1000) -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - extern unsigned long wall_jiffies; diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index a24651dfaab..787ed541d44 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -45,10 +45,6 @@ #define TICK_SIZE (tick_nsec / 1000) -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - /* * forward reference */ diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index bc979e1abde..cded2568078 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -33,10 +33,6 @@ #include -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - /* xtime and wall_jiffies keep wall-clock time */ extern unsigned long wall_jiffies; diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index 22d7fd1e0ae..67797184f4e 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -66,11 +66,6 @@ #include -/* XXX false sharing with below? */ -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - unsigned long disarm_decr[NR_CPUS]; extern struct timezone sys_tz; diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index b56c6a324e1..ab565468578 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c @@ -68,10 +68,6 @@ #include #include -u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - /* keep track of when we need to update the rtc */ time_t last_rtc_update; extern int piranha_simulator; diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 2fd75da1549..9a1d95894f3 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -49,10 +49,6 @@ #define TICK_SIZE tick -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - static ext_int_info_t ext_int_info_cc; static u64 init_timer_cc; static u64 jiffies_timer_cc; diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 02ca69918d7..671b876416b 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c @@ -56,10 +56,6 @@ extern unsigned long wall_jiffies; #define TICK_SIZE (tick_nsec / 1000) DEFINE_SPINLOCK(tmu0_lock); -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - /* XXX: Can we initialize this in a routine somewhere? Dreamcast doesn't want * these routines anywhere... */ #ifdef CONFIG_SH_RTC diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c index 43e395a14f4..870fe5327e0 100644 --- a/arch/sh64/kernel/time.c +++ b/arch/sh64/kernel/time.c @@ -116,8 +116,6 @@ extern unsigned long wall_jiffies; -u64 jiffies_64 = INITIAL_JIFFIES; - static unsigned long tmu_base, rtc_base; unsigned long cprc_base; diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 279a62627c1..24814d58f9e 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -45,10 +45,6 @@ extern unsigned long wall_jiffies; -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - DEFINE_SPINLOCK(rtc_lock); enum sparc_clock_type sp_clock_typ; DEFINE_SPINLOCK(mostek_lock); diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 3f08a32f51a..38c5525087a 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -55,10 +55,6 @@ unsigned long ds1287_regs = 0UL; extern unsigned long wall_jiffies; -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - static void __iomem *mstk48t08_regs; static void __iomem *mstk48t59_regs; diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c index 4e08f7545d6..020ca79b8d3 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c @@ -22,10 +22,6 @@ #include "mode.h" #include "os.h" -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - int hz(void) { return(HZ); diff --git a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c index ea3fd8844ff..c1e85c2aef6 100644 --- a/arch/v850/kernel/time.c +++ b/arch/v850/kernel/time.c @@ -26,10 +26,6 @@ #include "mach.h" -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - #define TICK_SIZE (tick_nsec / 1000) /* diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 47d25ad0816..bd5ea09bfdf 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -42,10 +42,6 @@ #include #endif -u64 jiffies_64 = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - #ifdef CONFIG_CPU_FREQ static void cpufreq_delayed_get(void); #endif diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c index 8e423d1335c..cb6e38ed2b1 100644 --- a/arch/xtensa/kernel/time.c +++ b/arch/xtensa/kernel/time.c @@ -29,9 +29,6 @@ extern volatile unsigned long wall_jiffies; -u64 jiffies_64 = INITIAL_JIFFIES; -EXPORT_SYMBOL(jiffies_64); - spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; EXPORT_SYMBOL(rtc_lock); diff --git a/kernel/timer.c b/kernel/timer.c index 562d53eabb4..fd74268d866 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -46,6 +46,10 @@ static void time_interpolator_update(long delta_nsec); #define time_interpolator_update(x) #endif +u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; + +EXPORT_SYMBOL(jiffies_64); + /* * per-CPU timer vector definitions: */ -- cgit v1.2.3-70-g09d2 From f00c96f313b07d2eb2845305b9a3395e14385767 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 30 Oct 2005 15:03:35 -0800 Subject: [PATCH] hpet-RTC: disable interrupt when no longer needed When the emulated RTC interrupt is no longer needed, we better disable it; otherwise, we get a spurious interrupt whenever the timer has rolled over and reaches the same comparator value. Having a superfluous interrupt every five minutes doesn't hurt much, but it's bad style anyway. ;-) Signed-off-by: Clemens Ladisch Acked-by: "Pallipadi, Venkatesh" Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/time_hpet.c | 6 +++++- arch/x86_64/kernel/time.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/kernel') diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c index 658c0629ba6..23e81fcbeae 100644 --- a/arch/i386/kernel/time_hpet.c +++ b/arch/i386/kernel/time_hpet.c @@ -319,8 +319,12 @@ static void hpet_rtc_timer_reinit(void) { unsigned int cfg, cnt; - if (!(PIE_on | AIE_on | UIE_on)) + if (unlikely(!(PIE_on | AIE_on | UIE_on))) { + cfg = hpet_readl(HPET_T1_CFG); + cfg &= ~HPET_TN_ENABLE; + hpet_writel(cfg, HPET_T1_CFG); return; + } if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) hpet_rtc_int_freq = PIE_freq; diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index bd5ea09bfdf..7037ca668c6 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -1138,8 +1138,12 @@ static void hpet_rtc_timer_reinit(void) { unsigned int cfg, cnt; - if (!(PIE_on | AIE_on | UIE_on)) + if (unlikely(!(PIE_on | AIE_on | UIE_on))) { + cfg = hpet_readl(HPET_T1_CFG); + cfg &= ~HPET_TN_ENABLE; + hpet_writel(cfg, HPET_T1_CFG); return; + } if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ)) hpet_rtc_int_freq = PIE_freq; -- cgit v1.2.3-70-g09d2 From 5f819949ee4e5a06c2e0054cbb42f3f0d170d779 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 30 Oct 2005 15:03:36 -0800 Subject: [PATCH] hpet-RTC: fix timer config register accesses Make sure that the RTC timer is in non-periodic mode; some stupid BIOS might have initialized it to periodic mode. Furthermore, don't set the SETVAL bit in the config register. This wouldn't have any effect unless the timer was in period mode (which it isn't), and then the actual timer frequency would be half that of the desired one because incrementing the comparator in the interrupt handler would be done after the hardware has already incremented it itself. Signed-off-by: Clemens Ladisch Acked-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/time_hpet.c | 9 ++------- arch/x86_64/kernel/time.c | 9 ++------- 2 files changed, 4 insertions(+), 14 deletions(-) (limited to 'arch/x86_64/kernel') diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c index 23e81fcbeae..cb1f313858e 100644 --- a/arch/i386/kernel/time_hpet.c +++ b/arch/i386/kernel/time_hpet.c @@ -309,7 +309,8 @@ int hpet_rtc_timer_init(void) local_irq_restore(flags); cfg = hpet_readl(HPET_T1_CFG); - cfg |= HPET_TN_ENABLE | HPET_TN_SETVAL | HPET_TN_32BIT; + cfg &= ~HPET_TN_PERIODIC; + cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; hpet_writel(cfg, HPET_T1_CFG); return 1; @@ -335,12 +336,6 @@ static void hpet_rtc_timer_reinit(void) cnt = hpet_readl(HPET_T1_CMP); cnt += hpet_tick*HZ/hpet_rtc_int_freq; hpet_writel(cnt, HPET_T1_CMP); - - cfg = hpet_readl(HPET_T1_CFG); - cfg |= HPET_TN_ENABLE | HPET_TN_SETVAL | HPET_TN_32BIT; - hpet_writel(cfg, HPET_T1_CFG); - - return; } /* diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 7037ca668c6..35a896ef4c3 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -1128,7 +1128,8 @@ int hpet_rtc_timer_init(void) local_irq_restore(flags); cfg = hpet_readl(HPET_T1_CFG); - cfg |= HPET_TN_ENABLE | HPET_TN_SETVAL | HPET_TN_32BIT; + cfg &= ~HPET_TN_PERIODIC; + cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; hpet_writel(cfg, HPET_T1_CFG); return 1; @@ -1154,12 +1155,6 @@ static void hpet_rtc_timer_reinit(void) cnt = hpet_readl(HPET_T1_CMP); cnt += hpet_tick*HZ/hpet_rtc_int_freq; hpet_writel(cnt, HPET_T1_CMP); - - cfg = hpet_readl(HPET_T1_CFG); - cfg |= HPET_TN_ENABLE | HPET_TN_SETVAL | HPET_TN_32BIT; - hpet_writel(cfg, HPET_T1_CFG); - - return; } /* -- cgit v1.2.3-70-g09d2 From 7811fb8f400a3dbfa027d86bb583a31c66fddfc3 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 30 Oct 2005 15:03:36 -0800 Subject: [PATCH] hpet-RTC: cache the comparator register Reads from an HPET register require a round trip to the south bridge and are almost as slow as PCI reads. By caching the last value we've written to the comparator register, we can eliminate all HPET reads from the fast path in the emulated RTC interrupt handler. Signed-off-by: Clemens Ladisch Acked-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/time_hpet.c | 5 ++++- arch/x86_64/kernel/time.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'arch/x86_64/kernel') diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c index cb1f313858e..9caeaa315cd 100644 --- a/arch/i386/kernel/time_hpet.c +++ b/arch/i386/kernel/time_hpet.c @@ -275,6 +275,7 @@ static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ; static unsigned long PIE_count; static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */ +static unsigned int hpet_t1_cmp; /* cached comparator register */ /* * Timer 1 for RTC, we do not use periodic interrupt feature, @@ -306,6 +307,7 @@ int hpet_rtc_timer_init(void) cnt = hpet_readl(HPET_COUNTER); cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); hpet_writel(cnt, HPET_T1_CMP); + hpet_t1_cmp = cnt; local_irq_restore(flags); cfg = hpet_readl(HPET_T1_CFG); @@ -333,9 +335,10 @@ static void hpet_rtc_timer_reinit(void) hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; /* It is more accurate to use the comparator value than current count.*/ - cnt = hpet_readl(HPET_T1_CMP); + cnt = hpet_t1_cmp; cnt += hpet_tick*HZ/hpet_rtc_int_freq; hpet_writel(cnt, HPET_T1_CMP); + hpet_t1_cmp = cnt; } /* diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 35a896ef4c3..fdaddc4e528 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -1089,6 +1089,7 @@ static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ; static unsigned long PIE_count; static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */ +static unsigned int hpet_t1_cmp; /* cached comparator register */ int is_hpet_enabled(void) { @@ -1125,6 +1126,7 @@ int hpet_rtc_timer_init(void) cnt = hpet_readl(HPET_COUNTER); cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq); hpet_writel(cnt, HPET_T1_CMP); + hpet_t1_cmp = cnt; local_irq_restore(flags); cfg = hpet_readl(HPET_T1_CFG); @@ -1152,9 +1154,10 @@ static void hpet_rtc_timer_reinit(void) hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ; /* It is more accurate to use the comparator value than current count.*/ - cnt = hpet_readl(HPET_T1_CMP); + cnt = hpet_t1_cmp; cnt += hpet_tick*HZ/hpet_rtc_int_freq; hpet_writel(cnt, HPET_T1_CMP); + hpet_t1_cmp = cnt; } /* -- cgit v1.2.3-70-g09d2