diff options
author | Scott Wood <scottwood@freescale.com> | 2014-04-07 23:49:35 (GMT) |
---|---|---|
committer | Scott Wood <scottwood@freescale.com> | 2014-04-07 23:49:35 (GMT) |
commit | 62b8c978ee6b8d135d9e7953221de58000dba986 (patch) | |
tree | 683b04b2e627f6710c22c151b23c8cc9a165315e /arch/alpha | |
parent | 78fd82238d0e5716578c326404184a27ba67fd6e (diff) | |
download | linux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz |
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'arch/alpha')
28 files changed, 393 insertions, 778 deletions
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index d39dc9b..35a300d 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -1,7 +1,6 @@ config ALPHA bool default y - select ARCH_MIGHT_HAVE_PC_PARPORT select HAVE_AOUT select HAVE_IDE select HAVE_OPROFILE @@ -16,8 +15,8 @@ config ALPHA select ARCH_WANT_IPC_PARSE_VERSION select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE - select GENERIC_CLOCKEVENTS select GENERIC_SMP_IDLE_THREAD + select GENERIC_CMOS_UPDATE select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER select HAVE_MOD_ARCH_SPECIFIC @@ -488,20 +487,6 @@ config VGA_HOSE which always have multiple hoses, and whose consoles support it. -config ALPHA_QEMU - bool "Run under QEMU emulation" - depends on !ALPHA_GENERIC - ---help--- - Assume the presence of special features supported by QEMU PALcode - that reduce the overhead of system emulation. - - Generic kernels will auto-detect QEMU. But when building a - system-specific kernel, the assumption is that we want to - elimiate as many runtime tests as possible. - - If unsure, say N. - - config ALPHA_SRM bool "Use SRM as bootloader" if ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_NAUTILUS || ALPHA_NONAME depends on TTY @@ -537,6 +522,7 @@ config ARCH_MAY_HAVE_PC_FDC config SMP bool "Symmetric multi-processing support" depends on ALPHA_SABLE || ALPHA_LYNX || ALPHA_RAWHIDE || ALPHA_DP264 || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_GENERIC || ALPHA_SHARK || ALPHA_MARVEL + select USE_GENERIC_SMP_HELPERS ---help--- This enables support for systems with more than one CPU. If you have a system with only one CPU, like most personal computers, say N. If @@ -586,30 +572,6 @@ config NUMA Access). This option is for configuring high-end multiprocessor server machines. If in doubt, say N. -config ALPHA_WTINT - bool "Use WTINT" if ALPHA_SRM || ALPHA_GENERIC - default y if ALPHA_QEMU - default n if ALPHA_EV5 || ALPHA_EV56 || (ALPHA_EV4 && !ALPHA_LCA) - default n if !ALPHA_SRM && !ALPHA_GENERIC - default y if SMP - ---help--- - The Wait for Interrupt (WTINT) PALcall attempts to place the CPU - to sleep until the next interrupt. This may reduce the power - consumed, and the heat produced by the computer. However, it has - the side effect of making the cycle counter unreliable as a timing - device across the sleep. - - For emulation under QEMU, definitely say Y here, as we have other - mechanisms for measuring time than the cycle counter. - - For EV4 (but not LCA), EV5 and EV56 systems, or for systems running - MILO, sleep mode is not supported so you might as well say N here. - - For SMP systems we cannot use the cycle counter for timing anyway, - so you might as well say Y here. - - If unsure, say N. - config NODES_SHIFT int default "7" @@ -651,41 +613,9 @@ config VERBOSE_MCHECK_ON Take the default (1) unless you want more control or more info. -choice - prompt "Timer interrupt frequency (HZ)?" - default HZ_128 if ALPHA_QEMU - default HZ_1200 if ALPHA_RAWHIDE - default HZ_1024 - ---help--- - The frequency at which timer interrupts occur. A high frequency - minimizes latency, whereas a low frequency minimizes overhead of - process accounting. The later effect is especially significant - when being run under QEMU. - - Note that some Alpha hardware cannot change the interrupt frequency - of the timer. If unsure, say 1024 (or 1200 for Rawhide). - - config HZ_32 - bool "32 Hz" - config HZ_64 - bool "64 Hz" - config HZ_128 - bool "128 Hz" - config HZ_256 - bool "256 Hz" - config HZ_1024 - bool "1024 Hz" - config HZ_1200 - bool "1200 Hz" -endchoice - config HZ - int - default 32 if HZ_32 - default 64 if HZ_64 - default 128 if HZ_128 - default 256 if HZ_256 - default 1200 if HZ_1200 + int + default 1200 if ALPHA_RAWHIDE default 1024 source "drivers/pci/Kconfig" diff --git a/arch/alpha/include/asm/Kbuild b/arch/alpha/include/asm/Kbuild index f01fb50..a6e85f44 100644 --- a/arch/alpha/include/asm/Kbuild +++ b/arch/alpha/include/asm/Kbuild @@ -3,4 +3,3 @@ generic-y += clkdev.h generic-y += exec.h generic-y += trace_clock.h -generic-y += preempt.h diff --git a/arch/alpha/include/asm/machvec.h b/arch/alpha/include/asm/machvec.h index 75cb364..72dbf23 100644 --- a/arch/alpha/include/asm/machvec.h +++ b/arch/alpha/include/asm/machvec.h @@ -33,7 +33,6 @@ struct alpha_machine_vector int nr_irqs; int rtc_port; - int rtc_boot_cpu_only; unsigned int max_asn; unsigned long max_isa_dma_address; unsigned long irq_probe_mask; @@ -96,6 +95,9 @@ struct alpha_machine_vector struct _alpha_agp_info *(*agp_info)(void); + unsigned int (*rtc_get_time)(struct rtc_time *); + int (*rtc_set_time)(struct rtc_time *); + const char *vector_name; /* NUMA information */ @@ -124,19 +126,13 @@ extern struct alpha_machine_vector alpha_mv; #ifdef CONFIG_ALPHA_GENERIC extern int alpha_using_srm; -extern int alpha_using_qemu; #else -# ifdef CONFIG_ALPHA_SRM -# define alpha_using_srm 1 -# else -# define alpha_using_srm 0 -# endif -# ifdef CONFIG_ALPHA_QEMU -# define alpha_using_qemu 1 -# else -# define alpha_using_qemu 0 -# endif +#ifdef CONFIG_ALPHA_SRM +#define alpha_using_srm 1 +#else +#define alpha_using_srm 0 +#endif #endif /* GENERIC */ -#endif /* __KERNEL__ */ +#endif #endif /* __ALPHA_MACHVEC_H */ diff --git a/arch/alpha/include/asm/pal.h b/arch/alpha/include/asm/pal.h index 5422a47..6fcd2b5 100644 --- a/arch/alpha/include/asm/pal.h +++ b/arch/alpha/include/asm/pal.h @@ -89,7 +89,6 @@ __CALL_PAL_W1(wrmces, unsigned long); __CALL_PAL_RW2(wrperfmon, unsigned long, unsigned long, unsigned long); __CALL_PAL_W1(wrusp, unsigned long); __CALL_PAL_W1(wrvptptr, unsigned long); -__CALL_PAL_RW1(wtint, unsigned long, unsigned long); /* * TB routines.. @@ -112,75 +111,5 @@ __CALL_PAL_RW1(wtint, unsigned long, unsigned long); #define tbiap() __tbi(-1, /* no second argument */) #define tbia() __tbi(-2, /* no second argument */) -/* - * QEMU Cserv routines.. - */ - -static inline unsigned long -qemu_get_walltime(void) -{ - register unsigned long v0 __asm__("$0"); - register unsigned long a0 __asm__("$16") = 3; - - asm("call_pal %2 # cserve get_time" - : "=r"(v0), "+r"(a0) - : "i"(PAL_cserve) - : "$17", "$18", "$19", "$20", "$21"); - - return v0; -} - -static inline unsigned long -qemu_get_alarm(void) -{ - register unsigned long v0 __asm__("$0"); - register unsigned long a0 __asm__("$16") = 4; - - asm("call_pal %2 # cserve get_alarm" - : "=r"(v0), "+r"(a0) - : "i"(PAL_cserve) - : "$17", "$18", "$19", "$20", "$21"); - - return v0; -} - -static inline void -qemu_set_alarm_rel(unsigned long expire) -{ - register unsigned long a0 __asm__("$16") = 5; - register unsigned long a1 __asm__("$17") = expire; - - asm volatile("call_pal %2 # cserve set_alarm_rel" - : "+r"(a0), "+r"(a1) - : "i"(PAL_cserve) - : "$0", "$18", "$19", "$20", "$21"); -} - -static inline void -qemu_set_alarm_abs(unsigned long expire) -{ - register unsigned long a0 __asm__("$16") = 6; - register unsigned long a1 __asm__("$17") = expire; - - asm volatile("call_pal %2 # cserve set_alarm_abs" - : "+r"(a0), "+r"(a1) - : "i"(PAL_cserve) - : "$0", "$18", "$19", "$20", "$21"); -} - -static inline unsigned long -qemu_get_vmtime(void) -{ - register unsigned long v0 __asm__("$0"); - register unsigned long a0 __asm__("$16") = 7; - - asm("call_pal %2 # cserve get_time" - : "=r"(v0), "+r"(a0) - : "i"(PAL_cserve) - : "$17", "$18", "$19", "$20", "$21"); - - return v0; -} - #endif /* !__ASSEMBLY__ */ #endif /* __ALPHA_PAL_H */ diff --git a/arch/alpha/include/asm/pgalloc.h b/arch/alpha/include/asm/pgalloc.h index aab14a0..bc2a0da 100644 --- a/arch/alpha/include/asm/pgalloc.h +++ b/arch/alpha/include/asm/pgalloc.h @@ -72,10 +72,7 @@ pte_alloc_one(struct mm_struct *mm, unsigned long address) if (!pte) return NULL; page = virt_to_page(pte); - if (!pgtable_page_ctor(page)) { - __free_page(page); - return NULL; - } + pgtable_page_ctor(page); return page; } diff --git a/arch/alpha/include/asm/rtc.h b/arch/alpha/include/asm/rtc.h index f71c3b0..d70408d 100644 --- a/arch/alpha/include/asm/rtc.h +++ b/arch/alpha/include/asm/rtc.h @@ -1 +1,12 @@ +#ifndef _ALPHA_RTC_H +#define _ALPHA_RTC_H + +#if defined(CONFIG_ALPHA_MARVEL) && defined(CONFIG_SMP) \ + || defined(CONFIG_ALPHA_GENERIC) +# define get_rtc_time alpha_mv.rtc_get_time +# define set_rtc_time alpha_mv.rtc_set_time +#endif + #include <asm-generic/rtc.h> + +#endif diff --git a/arch/alpha/include/asm/string.h b/arch/alpha/include/asm/string.h index c2911f5..b02b8a2 100644 --- a/arch/alpha/include/asm/string.h +++ b/arch/alpha/include/asm/string.h @@ -22,27 +22,15 @@ extern void * __memcpy(void *, const void *, size_t); #define __HAVE_ARCH_MEMSET extern void * __constant_c_memset(void *, unsigned long, size_t); -extern void * ___memset(void *, int, size_t); extern void * __memset(void *, int, size_t); extern void * memset(void *, int, size_t); -/* For gcc 3.x, we cannot have the inline function named "memset" because - the __builtin_memset will attempt to resolve to the inline as well, - leading to a "sorry" about unimplemented recursive inlining. */ -extern inline void *__memset(void *s, int c, size_t n) -{ - if (__builtin_constant_p(c)) { - if (__builtin_constant_p(n)) { - return __builtin_memset(s, c, n); - } else { - unsigned long c8 = (c & 0xff) * 0x0101010101010101UL; - return __constant_c_memset(s, c8, n); - } - } - return ___memset(s, c, n); -} - -#define memset __memset +#define memset(s, c, n) \ +(__builtin_constant_p(c) \ + ? (__builtin_constant_p(n) && (c) == 0 \ + ? __builtin_memset((s),0,(n)) \ + : __constant_c_memset((s),0x0101010101010101UL*(unsigned char)(c),(n))) \ + : __memset((s),(c),(n))) #define __HAVE_ARCH_STRCPY extern char * strcpy(char *,const char *); diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h index 453597b..52cd2a4 100644 --- a/arch/alpha/include/asm/thread_info.h +++ b/arch/alpha/include/asm/thread_info.h @@ -58,6 +58,8 @@ register struct thread_info *__current_thread_info __asm__("$8"); #define THREAD_SIZE_ORDER 1 #define THREAD_SIZE (2*PAGE_SIZE) +#define PREEMPT_ACTIVE 0x40000000 + /* * Thread information flags: * - these are process state flags and used from assembly diff --git a/arch/alpha/include/uapi/asm/errno.h b/arch/alpha/include/uapi/asm/errno.h index 17f92aa..e5f29ca 100644 --- a/arch/alpha/include/uapi/asm/errno.h +++ b/arch/alpha/include/uapi/asm/errno.h @@ -43,7 +43,7 @@ #define EUSERS 68 /* Too many users */ #define EDQUOT 69 /* Quota exceeded */ -#define ESTALE 70 /* Stale file handle */ +#define ESTALE 70 /* Stale NFS file handle */ #define EREMOTE 71 /* Object is remote */ #define ENOLCK 77 /* No record locks available */ diff --git a/arch/alpha/include/uapi/asm/pal.h b/arch/alpha/include/uapi/asm/pal.h index dfc8140..3c0ce08 100644 --- a/arch/alpha/include/uapi/asm/pal.h +++ b/arch/alpha/include/uapi/asm/pal.h @@ -46,7 +46,6 @@ #define PAL_rdusp 58 #define PAL_whami 60 #define PAL_retsys 61 -#define PAL_wtint 62 #define PAL_rti 63 diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h index e3a1491..467de01 100644 --- a/arch/alpha/include/uapi/asm/socket.h +++ b/arch/alpha/include/uapi/asm/socket.h @@ -81,8 +81,6 @@ #define SO_SELECT_ERR_QUEUE 45 -#define SO_BUSY_POLL 46 - -#define SO_MAX_PACING_RATE 47 +#define SO_BUSY_POLL 46 #endif /* _UAPI_ASM_SOCKET_H */ diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 0d54650..84ec46b 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_PCI) += pci.o pci_iommu.o pci-sysfs.o obj-$(CONFIG_SRM_ENV) += srm_env.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o -obj-$(CONFIG_RTC_DRV_ALPHA) += rtc.o ifdef CONFIG_ALPHA_GENERIC diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index f4c7ab6..89566b3 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -40,7 +40,6 @@ EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memset); -EXPORT_SYMBOL(___memset); EXPORT_SYMBOL(__memsetw); EXPORT_SYMBOL(__constant_c_memset); EXPORT_SYMBOL(copy_page); diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c index 1c8625c..28e4429 100644 --- a/arch/alpha/kernel/irq_alpha.c +++ b/arch/alpha/kernel/irq_alpha.c @@ -66,7 +66,21 @@ do_entInt(unsigned long type, unsigned long vector, break; case 1: old_regs = set_irq_regs(regs); +#ifdef CONFIG_SMP + { + long cpu; + + smp_percpu_timer_interrupt(regs); + cpu = smp_processor_id(); + if (cpu != boot_cpuid) { + kstat_incr_irqs_this_cpu(RTC_IRQ, irq_to_desc(RTC_IRQ)); + } else { + handle_irq(RTC_IRQ); + } + } +#else handle_irq(RTC_IRQ); +#endif set_irq_regs(old_regs); return; case 2: @@ -214,7 +228,7 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr, */ struct irqaction timer_irqaction = { - .handler = rtc_timer_interrupt, + .handler = timer_interrupt, .name = "timer", }; diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h index f54bdf6..7fa6248 100644 --- a/arch/alpha/kernel/machvec_impl.h +++ b/arch/alpha/kernel/machvec_impl.h @@ -43,7 +43,10 @@ #define CAT1(x,y) x##y #define CAT(x,y) CAT1(x,y) -#define DO_DEFAULT_RTC .rtc_port = 0x70 +#define DO_DEFAULT_RTC \ + .rtc_port = 0x70, \ + .rtc_get_time = common_get_rtc_time, \ + .rtc_set_time = common_set_rtc_time #define DO_EV4_MMU \ .max_asn = EV4_MAX_ASN, \ diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c index c52e7f0..d821b17 100644 --- a/arch/alpha/kernel/perf_event.c +++ b/arch/alpha/kernel/perf_event.c @@ -83,8 +83,6 @@ struct alpha_pmu_t { long pmc_left[3]; /* Subroutine for allocation of PMCs. Enforces constraints. */ int (*check_constraints)(struct perf_event **, unsigned long *, int); - /* Subroutine for checking validity of a raw event for this PMU. */ - int (*raw_event_valid)(u64 config); }; /* @@ -205,12 +203,6 @@ success: } -static int ev67_raw_event_valid(u64 config) -{ - return config >= EV67_CYCLES && config < EV67_LAST_ET; -}; - - static const struct alpha_pmu_t ev67_pmu = { .event_map = ev67_perfmon_event_map, .max_events = ARRAY_SIZE(ev67_perfmon_event_map), @@ -219,8 +211,7 @@ static const struct alpha_pmu_t ev67_pmu = { .pmc_count_mask = {EV67_PCTR_0_COUNT_MASK, EV67_PCTR_1_COUNT_MASK, 0}, .pmc_max_period = {(1UL<<20) - 1, (1UL<<20) - 1, 0}, .pmc_left = {16, 4, 0}, - .check_constraints = ev67_check_constraints, - .raw_event_valid = ev67_raw_event_valid, + .check_constraints = ev67_check_constraints }; @@ -618,9 +609,7 @@ static int __hw_perf_event_init(struct perf_event *event) } else if (attr->type == PERF_TYPE_HW_CACHE) { return -EOPNOTSUPP; } else if (attr->type == PERF_TYPE_RAW) { - if (!alpha_pmu->raw_event_valid(attr->config)) - return -EINVAL; - ev = attr->config; + ev = attr->config & 0xff; } else { return -EOPNOTSUPP; } diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 1941a07..f2360a7 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -46,23 +46,6 @@ void (*pm_power_off)(void) = machine_power_off; EXPORT_SYMBOL(pm_power_off); -#ifdef CONFIG_ALPHA_WTINT -/* - * Sleep the CPU. - * EV6, LCA45 and QEMU know how to power down, skipping N timer interrupts. - */ -void arch_cpu_idle(void) -{ - wtint(0); - local_irq_enable(); -} - -void arch_cpu_idle_dead(void) -{ - wtint(INT_MAX); -} -#endif /* ALPHA_WTINT */ - struct halt_info { int mode; char *restart_cmd; diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index da2d6ec..d3e52d3 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -135,15 +135,17 @@ extern void unregister_srm_console(void); /* smp.c */ extern void setup_smp(void); extern void handle_ipi(struct pt_regs *); +extern void smp_percpu_timer_interrupt(struct pt_regs *); /* bios32.c */ /* extern void reset_for_srm(void); */ /* time.c */ -extern irqreturn_t rtc_timer_interrupt(int irq, void *dev); -extern void init_clockevent(void); +extern irqreturn_t timer_interrupt(int irq, void *dev); extern void common_init_rtc(void); extern unsigned long est_cycle_freq; +extern unsigned int common_get_rtc_time(struct rtc_time *time); +extern int common_set_rtc_time(struct rtc_time *time); /* smc37c93x.c */ extern void SMC93x_Init(void); diff --git a/arch/alpha/kernel/rtc.c b/arch/alpha/kernel/rtc.c deleted file mode 100644 index c8d284d..0000000 --- a/arch/alpha/kernel/rtc.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * linux/arch/alpha/kernel/rtc.c - * - * Copyright (C) 1991, 1992, 1995, 1999, 2000 Linus Torvalds - * - * This file contains date handling. - */ -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/mc146818rtc.h> -#include <linux/bcd.h> -#include <linux/rtc.h> -#include <linux/platform_device.h> - -#include <asm/rtc.h> - -#include "proto.h" - - -/* - * Support for the RTC device. - * - * We don't want to use the rtc-cmos driver, because we don't want to support - * alarms, as that would be indistinguishable from timer interrupts. - * - * Further, generic code is really, really tied to a 1900 epoch. This is - * true in __get_rtc_time as well as the users of struct rtc_time e.g. - * rtc_tm_to_time. Thankfully all of the other epochs in use are later - * than 1900, and so it's easy to adjust. - */ - -static unsigned long rtc_epoch; - -static int __init -specifiy_epoch(char *str) -{ - unsigned long epoch = simple_strtoul(str, NULL, 0); - if (epoch < 1900) - printk("Ignoring invalid user specified epoch %lu\n", epoch); - else - rtc_epoch = epoch; - return 1; -} -__setup("epoch=", specifiy_epoch); - -static void __init -init_rtc_epoch(void) -{ - int epoch, year, ctrl; - - if (rtc_epoch != 0) { - /* The epoch was specified on the command-line. */ - return; - } - - /* Detect the epoch in use on this computer. */ - ctrl = CMOS_READ(RTC_CONTROL); - year = CMOS_READ(RTC_YEAR); - if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - year = bcd2bin(year); - - /* PC-like is standard; used for year >= 70 */ - epoch = 1900; - if (year < 20) { - epoch = 2000; - } else if (year >= 20 && year < 48) { - /* NT epoch */ - epoch = 1980; - } else if (year >= 48 && year < 70) { - /* Digital UNIX epoch */ - epoch = 1952; - } - rtc_epoch = epoch; - - printk(KERN_INFO "Using epoch %d for rtc year %d\n", epoch, year); -} - -static int -alpha_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - __get_rtc_time(tm); - - /* Adjust for non-default epochs. It's easier to depend on the - generic __get_rtc_time and adjust the epoch here than create - a copy of __get_rtc_time with the edits we need. */ - if (rtc_epoch != 1900) { - int year = tm->tm_year; - /* Undo the century adjustment made in __get_rtc_time. */ - if (year >= 100) - year -= 100; - year += rtc_epoch - 1900; - /* Redo the century adjustment with the epoch in place. */ - if (year <= 69) - year += 100; - tm->tm_year = year; - } - - return rtc_valid_tm(tm); -} - -static int -alpha_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - struct rtc_time xtm; - - if (rtc_epoch != 1900) { - xtm = *tm; - xtm.tm_year -= rtc_epoch - 1900; - tm = &xtm; - } - - return __set_rtc_time(tm); -} - -static int -alpha_rtc_set_mmss(struct device *dev, unsigned long nowtime) -{ - int retval = 0; - int real_seconds, real_minutes, cmos_minutes; - unsigned char save_control, save_freq_select; - - /* Note: This code only updates minutes and seconds. Comments - indicate this was to avoid messing with unknown time zones, - and with the epoch nonsense described above. In order for - this to work, the existing clock cannot be off by more than - 15 minutes. - - ??? This choice is may be out of date. The x86 port does - not have problems with timezones, and the epoch processing has - now been fixed in alpha_set_rtc_time. - - In either case, one can always force a full rtc update with - the userland hwclock program, so surely 15 minute accuracy - is no real burden. */ - - /* In order to set the CMOS clock precisely, we have to be called - 500 ms after the second nowtime has started, because when - nowtime is written into the registers of the CMOS clock, it will - jump to the next second precisely 500 ms later. Check the Motorola - MC146818A or Dallas DS12887 data sheet for details. */ - - /* irq are locally disabled here */ - spin_lock(&rtc_lock); - /* Tell the clock it's being set */ - save_control = CMOS_READ(RTC_CONTROL); - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - - /* Stop and reset prescaler */ - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - cmos_minutes = CMOS_READ(RTC_MINUTES); - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - cmos_minutes = bcd2bin(cmos_minutes); - - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) { - /* correct for half hour time zone */ - real_minutes += 30; - } - real_minutes %= 60; - - if (abs(real_minutes - cmos_minutes) < 30) { - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - real_seconds = bin2bcd(real_seconds); - real_minutes = bin2bcd(real_minutes); - } - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); - } else { - printk_once(KERN_NOTICE - "set_rtc_mmss: can't update from %d to %d\n", - cmos_minutes, real_minutes); - retval = -1; - } - - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - spin_unlock(&rtc_lock); - - return retval; -} - -static int -alpha_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case RTC_EPOCH_READ: - return put_user(rtc_epoch, (unsigned long __user *)arg); - case RTC_EPOCH_SET: - if (arg < 1900) - return -EINVAL; - rtc_epoch = arg; - return 0; - default: - return -ENOIOCTLCMD; - } -} - -static const struct rtc_class_ops alpha_rtc_ops = { - .read_time = alpha_rtc_read_time, - .set_time = alpha_rtc_set_time, - .set_mmss = alpha_rtc_set_mmss, - .ioctl = alpha_rtc_ioctl, -}; - -/* - * Similarly, except do the actual CMOS access on the boot cpu only. - * This requires marshalling the data across an interprocessor call. - */ - -#if defined(CONFIG_SMP) && \ - (defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_MARVEL)) -# define HAVE_REMOTE_RTC 1 - -union remote_data { - struct rtc_time *tm; - unsigned long now; - long retval; -}; - -static void -do_remote_read(void *data) -{ - union remote_data *x = data; - x->retval = alpha_rtc_read_time(NULL, x->tm); -} - -static int -remote_read_time(struct device *dev, struct rtc_time *tm) -{ - union remote_data x; - if (smp_processor_id() != boot_cpuid) { - x.tm = tm; - smp_call_function_single(boot_cpuid, do_remote_read, &x, 1); - return x.retval; - } - return alpha_rtc_read_time(NULL, tm); -} - -static void -do_remote_set(void *data) -{ - union remote_data *x = data; - x->retval = alpha_rtc_set_time(NULL, x->tm); -} - -static int -remote_set_time(struct device *dev, struct rtc_time *tm) -{ - union remote_data x; - if (smp_processor_id() != boot_cpuid) { - x.tm = tm; - smp_call_function_single(boot_cpuid, do_remote_set, &x, 1); - return x.retval; - } - return alpha_rtc_set_time(NULL, tm); -} - -static void -do_remote_mmss(void *data) -{ - union remote_data *x = data; - x->retval = alpha_rtc_set_mmss(NULL, x->now); -} - -static int -remote_set_mmss(struct device *dev, unsigned long now) -{ - union remote_data x; - if (smp_processor_id() != boot_cpuid) { - x.now = now; - smp_call_function_single(boot_cpuid, do_remote_mmss, &x, 1); - return x.retval; - } - return alpha_rtc_set_mmss(NULL, now); -} - -static const struct rtc_class_ops remote_rtc_ops = { - .read_time = remote_read_time, - .set_time = remote_set_time, - .set_mmss = remote_set_mmss, - .ioctl = alpha_rtc_ioctl, -}; -#endif - -static int __init -alpha_rtc_init(void) -{ - const struct rtc_class_ops *ops; - struct platform_device *pdev; - struct rtc_device *rtc; - const char *name; - - init_rtc_epoch(); - name = "rtc-alpha"; - ops = &alpha_rtc_ops; - -#ifdef HAVE_REMOTE_RTC - if (alpha_mv.rtc_boot_cpu_only) - ops = &remote_rtc_ops; -#endif - - pdev = platform_device_register_simple(name, -1, NULL, 0); - rtc = devm_rtc_device_register(&pdev->dev, name, ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - - platform_set_drvdata(pdev, rtc); - return 0; -} -device_initcall(alpha_rtc_init); diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index b20af76..9e3107cc5 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -115,17 +115,10 @@ unsigned long alpha_agpgart_size = DEFAULT_AGP_APER_SIZE; #ifdef CONFIG_ALPHA_GENERIC struct alpha_machine_vector alpha_mv; -#endif - -#ifndef alpha_using_srm int alpha_using_srm; EXPORT_SYMBOL(alpha_using_srm); #endif -#ifndef alpha_using_qemu -int alpha_using_qemu; -#endif - static struct alpha_machine_vector *get_sysvec(unsigned long, unsigned long, unsigned long); static struct alpha_machine_vector *get_sysvec_byname(const char *); @@ -536,15 +529,11 @@ setup_arch(char **cmdline_p) atomic_notifier_chain_register(&panic_notifier_list, &alpha_panic_block); -#ifndef alpha_using_srm +#ifdef CONFIG_ALPHA_GENERIC /* Assume that we've booted from SRM if we haven't booted from MILO. Detect the later by looking for "MILO" in the system serial nr. */ alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; #endif -#ifndef alpha_using_qemu - /* Similarly, look for QEMU. */ - alpha_using_qemu = strstr((const char *)hwrpb->ssn, "QEMU") != 0; -#endif /* If we are using SRM, we want to allow callbacks as early as possible, so do this NOW, and then @@ -1218,7 +1207,6 @@ show_cpuinfo(struct seq_file *f, void *slot) char *systype_name; char *sysvariation_name; int nr_processors; - unsigned long timer_freq; cpu_index = (unsigned) (cpu->type - 1); cpu_name = "Unknown"; @@ -1230,12 +1218,6 @@ show_cpuinfo(struct seq_file *f, void *slot) nr_processors = get_nr_processors(cpu, hwrpb->nr_processors); -#if CONFIG_HZ == 1024 || CONFIG_HZ == 1200 - timer_freq = (100UL * hwrpb->intr_freq) / 4096; -#else - timer_freq = 100UL * CONFIG_HZ; -#endif - seq_printf(f, "cpu\t\t\t: Alpha\n" "cpu model\t\t: %s\n" "cpu variation\t\t: %ld\n" @@ -1261,7 +1243,8 @@ show_cpuinfo(struct seq_file *f, void *slot) (char*)hwrpb->ssn, est_cycle_freq ? : hwrpb->cycle_freq, est_cycle_freq ? "est." : "", - timer_freq / 100, timer_freq % 100, + hwrpb->intr_freq / 4096, + (100 * hwrpb->intr_freq / 4096) % 100, hwrpb->pagesize, hwrpb->pa_bits, hwrpb->max_asn, diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 99ac36d..9dbbcb3 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -138,11 +138,9 @@ smp_callin(void) /* Get our local ticker going. */ smp_setup_percpu_timer(cpuid); - init_clockevent(); /* Call platform-specific callin, if specified */ - if (alpha_mv.smp_callin) - alpha_mv.smp_callin(); + if (alpha_mv.smp_callin) alpha_mv.smp_callin(); /* All kernel threads share the same mm context. */ atomic_inc(&init_mm.mm_count); @@ -500,6 +498,35 @@ smp_cpus_done(unsigned int max_cpus) ((bogosum + 2500) / (5000/HZ)) % 100); } + +void +smp_percpu_timer_interrupt(struct pt_regs *regs) +{ + struct pt_regs *old_regs; + int cpu = smp_processor_id(); + unsigned long user = user_mode(regs); + struct cpuinfo_alpha *data = &cpu_data[cpu]; + + old_regs = set_irq_regs(regs); + + /* Record kernel PC. */ + profile_tick(CPU_PROFILING); + + if (!--data->prof_counter) { + /* We need to make like a normal interrupt -- otherwise + timer interrupts ignore the global interrupt lock, + which would be a Bad Thing. */ + irq_enter(); + + update_process_times(user); + + data->prof_counter = data->prof_multiplier; + + irq_exit(); + } + set_irq_regs(old_regs); +} + int setup_profiling_timer(unsigned int multiplier) { diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c index 608f2a7..5a0af11 100644 --- a/arch/alpha/kernel/sys_jensen.c +++ b/arch/alpha/kernel/sys_jensen.c @@ -224,6 +224,8 @@ struct alpha_machine_vector jensen_mv __initmv = { .machine_check = jensen_machine_check, .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, .rtc_port = 0x170, + .rtc_get_time = common_get_rtc_time, + .rtc_set_time = common_set_rtc_time, .nr_irqs = 16, .device_interrupt = jensen_device_interrupt, diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c index f21d61f..c92e389 100644 --- a/arch/alpha/kernel/sys_marvel.c +++ b/arch/alpha/kernel/sys_marvel.c @@ -22,6 +22,7 @@ #include <asm/hwrpb.h> #include <asm/tlbflush.h> #include <asm/vga.h> +#include <asm/rtc.h> #include "proto.h" #include "err_impl.h" @@ -399,6 +400,57 @@ marvel_init_rtc(void) init_rtc_irq(); } +struct marvel_rtc_time { + struct rtc_time *time; + int retval; +}; + +#ifdef CONFIG_SMP +static void +smp_get_rtc_time(void *data) +{ + struct marvel_rtc_time *mrt = data; + mrt->retval = __get_rtc_time(mrt->time); +} + +static void +smp_set_rtc_time(void *data) +{ + struct marvel_rtc_time *mrt = data; + mrt->retval = __set_rtc_time(mrt->time); +} +#endif + +static unsigned int +marvel_get_rtc_time(struct rtc_time *time) +{ +#ifdef CONFIG_SMP + struct marvel_rtc_time mrt; + + if (smp_processor_id() != boot_cpuid) { + mrt.time = time; + smp_call_function_single(boot_cpuid, smp_get_rtc_time, &mrt, 1); + return mrt.retval; + } +#endif + return __get_rtc_time(time); +} + +static int +marvel_set_rtc_time(struct rtc_time *time) +{ +#ifdef CONFIG_SMP + struct marvel_rtc_time mrt; + + if (smp_processor_id() != boot_cpuid) { + mrt.time = time; + smp_call_function_single(boot_cpuid, smp_set_rtc_time, &mrt, 1); + return mrt.retval; + } +#endif + return __set_rtc_time(time); +} + static void marvel_smp_callin(void) { @@ -440,7 +492,8 @@ struct alpha_machine_vector marvel_ev7_mv __initmv = { .vector_name = "MARVEL/EV7", DO_EV7_MMU, .rtc_port = 0x70, - .rtc_boot_cpu_only = 1, + .rtc_get_time = marvel_get_rtc_time, + .rtc_set_time = marvel_set_rtc_time, DO_MARVEL_IO, .machine_check = marvel_machine_check, .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index ee39cee..ea33950 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -3,7 +3,13 @@ * * Copyright (C) 1991, 1992, 1995, 1999, 2000 Linus Torvalds * - * This file contains the clocksource time handling. + * This file contains the PC-specific time handling details: + * reading the RTC at bootup, etc.. + * 1994-07-02 Alan Modra + * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime + * 1995-03-26 Markus Kuhn + * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 + * precision CMOS clock update * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 * "A Kernel Model for Precision Timekeeping" by Dave Mills * 1997-01-09 Adrian Sun @@ -15,6 +21,9 @@ * 1999-04-16 Thorsten Kranzkowski (dl8bcu@gmx.net) * fixed algorithm in do_gettimeofday() for calculating the precise time * from processor cycle counter (now taking lost_ticks into account) + * 2000-08-13 Jan-Benedict Glaw <jbglaw@lug-owl.de> + * Fixed time_init to be aware of epoches != 1900. This prevents + * booting up in 2048 for me;) Code is stolen from rtc.c. * 2003-06-03 R. Scott Bailey <scott.bailey@eds.com> * Tighten sanity in time_init from 1% (10,000 PPM) to 250 PPM */ @@ -37,19 +46,40 @@ #include <asm/uaccess.h> #include <asm/io.h> #include <asm/hwrpb.h> +#include <asm/rtc.h> #include <linux/mc146818rtc.h> #include <linux/time.h> #include <linux/timex.h> #include <linux/clocksource.h> -#include <linux/clockchips.h> #include "proto.h" #include "irq_impl.h" +static int set_rtc_mmss(unsigned long); + DEFINE_SPINLOCK(rtc_lock); EXPORT_SYMBOL(rtc_lock); +#define TICK_SIZE (tick_nsec / 1000) + +/* + * Shift amount by which scaled_ticks_per_cycle is scaled. Shifting + * by 48 gives us 16 bits for HZ while keeping the accuracy good even + * for large CPU clock rates. + */ +#define FIX_SHIFT 48 + +/* lump static variables together for more efficient access: */ +static struct { + /* cycle counter last time it got invoked */ + __u32 last_time; + /* ticks/cycle * 2^48 */ + unsigned long scaled_ticks_per_cycle; + /* partial unused tick */ + unsigned long partial_tick; +} state; + unsigned long est_cycle_freq; #ifdef CONFIG_IRQ_WORK @@ -78,156 +108,109 @@ static inline __u32 rpcc(void) return __builtin_alpha_rpcc(); } - - -/* - * The RTC as a clock_event_device primitive. - */ - -static DEFINE_PER_CPU(struct clock_event_device, cpu_ce); - -irqreturn_t -rtc_timer_interrupt(int irq, void *dev) +int update_persistent_clock(struct timespec now) { - int cpu = smp_processor_id(); - struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); - - /* Don't run the hook for UNUSED or SHUTDOWN. */ - if (likely(ce->mode == CLOCK_EVT_MODE_PERIODIC)) - ce->event_handler(ce); - - if (test_irq_work_pending()) { - clear_irq_work_pending(); - irq_work_run(); - } - - return IRQ_HANDLED; + return set_rtc_mmss(now.tv_sec); } -static void -rtc_ce_set_mode(enum clock_event_mode mode, struct clock_event_device *ce) -{ - /* The mode member of CE is updated in generic code. - Since we only support periodic events, nothing to do. */ -} - -static int -rtc_ce_set_next_event(unsigned long evt, struct clock_event_device *ce) +void read_persistent_clock(struct timespec *ts) { - /* This hook is for oneshot mode, which we don't support. */ - return -EINVAL; -} + unsigned int year, mon, day, hour, min, sec, epoch; + + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + sec = bcd2bin(sec); + min = bcd2bin(min); + hour = bcd2bin(hour); + day = bcd2bin(day); + mon = bcd2bin(mon); + year = bcd2bin(year); + } -static void __init -init_rtc_clockevent(void) -{ - int cpu = smp_processor_id(); - struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); - - *ce = (struct clock_event_device){ - .name = "rtc", - .features = CLOCK_EVT_FEAT_PERIODIC, - .rating = 100, - .cpumask = cpumask_of(cpu), - .set_mode = rtc_ce_set_mode, - .set_next_event = rtc_ce_set_next_event, - }; + /* PC-like is standard; used for year >= 70 */ + epoch = 1900; + if (year < 20) + epoch = 2000; + else if (year >= 20 && year < 48) + /* NT epoch */ + epoch = 1980; + else if (year >= 48 && year < 70) + /* Digital UNIX epoch */ + epoch = 1952; - clockevents_config_and_register(ce, CONFIG_HZ, 0, 0); -} + printk(KERN_INFO "Using epoch = %d\n", epoch); - -/* - * The QEMU clock as a clocksource primitive. - */ + if ((year += epoch) < 1970) + year += 100; -static cycle_t -qemu_cs_read(struct clocksource *cs) -{ - return qemu_get_vmtime(); + ts->tv_sec = mktime(year, mon, day, hour, min, sec); + ts->tv_nsec = 0; } -static struct clocksource qemu_cs = { - .name = "qemu", - .rating = 400, - .read = qemu_cs_read, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, - .max_idle_ns = LONG_MAX -}; /* - * The QEMU alarm as a clock_event_device primitive. + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "xtime_update()" routine every clocktick */ - -static void -qemu_ce_set_mode(enum clock_event_mode mode, struct clock_event_device *ce) +irqreturn_t timer_interrupt(int irq, void *dev) { - /* The mode member of CE is updated for us in generic code. - Just make sure that the event is disabled. */ - qemu_set_alarm_abs(0); -} + unsigned long delta; + __u32 now; + long nticks; -static int -qemu_ce_set_next_event(unsigned long evt, struct clock_event_device *ce) -{ - qemu_set_alarm_rel(evt); - return 0; -} +#ifndef CONFIG_SMP + /* Not SMP, do kernel PC profiling here. */ + profile_tick(CPU_PROFILING); +#endif -static irqreturn_t -qemu_timer_interrupt(int irq, void *dev) -{ - int cpu = smp_processor_id(); - struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); + /* + * Calculate how many ticks have passed since the last update, + * including any previous partial leftover. Save any resulting + * fraction for the next pass. + */ + now = rpcc(); + delta = now - state.last_time; + state.last_time = now; + delta = delta * state.scaled_ticks_per_cycle + state.partial_tick; + state.partial_tick = delta & ((1UL << FIX_SHIFT) - 1); + nticks = delta >> FIX_SHIFT; - ce->event_handler(ce); - return IRQ_HANDLED; -} + if (nticks) + xtime_update(nticks); -static void __init -init_qemu_clockevent(void) -{ - int cpu = smp_processor_id(); - struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); - - *ce = (struct clock_event_device){ - .name = "qemu", - .features = CLOCK_EVT_FEAT_ONESHOT, - .rating = 400, - .cpumask = cpumask_of(cpu), - .set_mode = qemu_ce_set_mode, - .set_next_event = qemu_ce_set_next_event, - }; + if (test_irq_work_pending()) { + clear_irq_work_pending(); + irq_work_run(); + } - clockevents_config_and_register(ce, NSEC_PER_SEC, 1000, LONG_MAX); +#ifndef CONFIG_SMP + while (nticks--) + update_process_times(user_mode(get_irq_regs())); +#endif + + return IRQ_HANDLED; } - void __init common_init_rtc(void) { - unsigned char x, sel = 0; + unsigned char x; /* Reset periodic interrupt frequency. */ -#if CONFIG_HZ == 1024 || CONFIG_HZ == 1200 - x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f; - /* Test includes known working values on various platforms - where 0x26 is wrong; we refuse to change those. */ - if (x != 0x26 && x != 0x25 && x != 0x19 && x != 0x06) { - sel = RTC_REF_CLCK_32KHZ + 6; + x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f; + /* Test includes known working values on various platforms + where 0x26 is wrong; we refuse to change those. */ + if (x != 0x26 && x != 0x25 && x != 0x19 && x != 0x06) { + printk("Setting RTC_FREQ to 1024 Hz (%x)\n", x); + CMOS_WRITE(0x26, RTC_FREQ_SELECT); } -#elif CONFIG_HZ == 256 || CONFIG_HZ == 128 || CONFIG_HZ == 64 || CONFIG_HZ == 32 - sel = RTC_REF_CLCK_32KHZ + __builtin_ffs(32768 / CONFIG_HZ); -#else -# error "Unknown HZ from arch/alpha/Kconfig" -#endif - if (sel) { - printk(KERN_INFO "Setting RTC_FREQ to %d Hz (%x)\n", - CONFIG_HZ, sel); - CMOS_WRITE(sel, RTC_FREQ_SELECT); - } /* Turn on periodic interrupts. */ x = CMOS_READ(RTC_CONTROL); @@ -250,37 +233,16 @@ common_init_rtc(void) init_rtc_irq(); } - -#ifndef CONFIG_ALPHA_WTINT -/* - * The RPCC as a clocksource primitive. - * - * While we have free-running timecounters running on all CPUs, and we make - * a half-hearted attempt in init_rtc_rpcc_info to sync the timecounter - * with the wall clock, that initialization isn't kept up-to-date across - * different time counters in SMP mode. Therefore we can only use this - * method when there's only one CPU enabled. - * - * When using the WTINT PALcall, the RPCC may shift to a lower frequency, - * or stop altogether, while waiting for the interrupt. Therefore we cannot - * use this method when WTINT is in use. - */ - -static cycle_t read_rpcc(struct clocksource *cs) +unsigned int common_get_rtc_time(struct rtc_time *time) { - return rpcc(); + return __get_rtc_time(time); } -static struct clocksource clocksource_rpcc = { - .name = "rpcc", - .rating = 300, - .read = read_rpcc, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS -}; -#endif /* ALPHA_WTINT */ +int common_set_rtc_time(struct rtc_time *time) +{ + return __set_rtc_time(time); +} - /* Validate a computed cycle counter result against the known bounds for the given processor core. There's too much brokenness in the way of timing hardware for any one method to work everywhere. :-( @@ -391,6 +353,33 @@ rpcc_after_update_in_progress(void) return rpcc(); } +#ifndef CONFIG_SMP +/* Until and unless we figure out how to get cpu cycle counters + in sync and keep them there, we can't use the rpcc. */ +static cycle_t read_rpcc(struct clocksource *cs) +{ + cycle_t ret = (cycle_t)rpcc(); + return ret; +} + +static struct clocksource clocksource_rpcc = { + .name = "rpcc", + .rating = 300, + .read = read_rpcc, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS +}; + +static inline void register_rpcc_clocksource(long cycle_freq) +{ + clocksource_register_hz(&clocksource_rpcc, cycle_freq); +} +#else /* !CONFIG_SMP */ +static inline void register_rpcc_clocksource(long cycle_freq) +{ +} +#endif /* !CONFIG_SMP */ + void __init time_init(void) { @@ -398,15 +387,6 @@ time_init(void) unsigned long cycle_freq, tolerance; long diff; - if (alpha_using_qemu) { - clocksource_register_hz(&qemu_cs, NSEC_PER_SEC); - init_qemu_clockevent(); - - timer_irqaction.handler = qemu_timer_interrupt; - init_rtc_irq(); - return; - } - /* Calibrate CPU clock -- attempt #1. */ if (!est_cycle_freq) est_cycle_freq = validate_cc_value(calibrate_cc_with_pit()); @@ -441,25 +421,100 @@ time_init(void) "and unable to estimate a proper value!\n"); } - /* See above for restrictions on using clocksource_rpcc. */ -#ifndef CONFIG_ALPHA_WTINT - if (hwrpb->nr_processors == 1) - clocksource_register_hz(&clocksource_rpcc, cycle_freq); -#endif + /* From John Bowman <bowman@math.ualberta.ca>: allow the values + to settle, as the Update-In-Progress bit going low isn't good + enough on some hardware. 2ms is our guess; we haven't found + bogomips yet, but this is close on a 500Mhz box. */ + __delay(1000000); + + + if (HZ > (1<<16)) { + extern void __you_loose (void); + __you_loose(); + } + + register_rpcc_clocksource(cycle_freq); + + state.last_time = cc1; + state.scaled_ticks_per_cycle + = ((unsigned long) HZ << FIX_SHIFT) / cycle_freq; + state.partial_tick = 0L; /* Startup the timer source. */ alpha_mv.init_rtc(); - init_rtc_clockevent(); } -/* Initialize the clock_event_device for secondary cpus. */ -#ifdef CONFIG_SMP -void __init -init_clockevent(void) +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you won't notice until after reboot! + */ + + +static int +set_rtc_mmss(unsigned long nowtime) { - if (alpha_using_qemu) - init_qemu_clockevent(); - else - init_rtc_clockevent(); + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + /* irq are locally disabled here */ + spin_lock(&rtc_lock); + /* Tell the clock it's being set */ + save_control = CMOS_READ(RTC_CONTROL); + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + /* Stop and reset prescaler */ + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + cmos_minutes = bcd2bin(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) { + /* correct for half hour time zone */ + real_minutes += 30; + } + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + real_seconds = bin2bcd(real_seconds); + real_minutes = bin2bcd(real_minutes); + } + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk_once(KERN_NOTICE + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); + + return retval; } -#endif diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 9c4c189..bd0665c 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -241,21 +241,6 @@ do_entIF(unsigned long type, struct pt_regs *regs) (const char *)(data[1] | (long)data[2] << 32), data[0]); } -#ifdef CONFIG_ALPHA_WTINT - if (type == 4) { - /* If CALL_PAL WTINT is totally unsupported by the - PALcode, e.g. MILO, "emulate" it by overwriting - the insn. */ - unsigned int *pinsn - = (unsigned int *) regs->pc - 1; - if (*pinsn == PAL_wtint) { - *pinsn = 0x47e01400; /* mov 0,$0 */ - imb(); - regs->r0 = 0; - return; - } - } -#endif /* ALPHA_WTINT */ die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"), regs, type, NULL); } diff --git a/arch/alpha/lib/csum_partial_copy.c b/arch/alpha/lib/csum_partial_copy.c index ff3c107..ffb19b7 100644 --- a/arch/alpha/lib/csum_partial_copy.c +++ b/arch/alpha/lib/csum_partial_copy.c @@ -130,7 +130,7 @@ csum_partial_cfu_aligned(const unsigned long __user *src, unsigned long *dst, *dst = word | tmp; checksum += carry; } - if (err && errp) *errp = err; + if (err) *errp = err; return checksum; } @@ -185,7 +185,7 @@ csum_partial_cfu_dest_aligned(const unsigned long __user *src, *dst = word | tmp; checksum += carry; } - if (err && errp) *errp = err; + if (err) *errp = err; return checksum; } @@ -242,7 +242,7 @@ csum_partial_cfu_src_aligned(const unsigned long __user *src, stq_u(partial_dest | second_dest, dst); out: checksum += carry; - if (err && errp) *errp = err; + if (err) *errp = err; return checksum; } @@ -325,7 +325,7 @@ csum_partial_cfu_unaligned(const unsigned long __user * src, stq_u(partial_dest | word | second_dest, dst); checksum += carry; } - if (err && errp) *errp = err; + if (err) *errp = err; return checksum; } @@ -339,7 +339,7 @@ csum_partial_copy_from_user(const void __user *src, void *dst, int len, if (len) { if (!access_ok(VERIFY_READ, src, len)) { - if (errp) *errp = -EFAULT; + *errp = -EFAULT; memset(dst, 0, len); return sum; } diff --git a/arch/alpha/lib/ev6-memset.S b/arch/alpha/lib/ev6-memset.S index 356bb2f..d8b94e1 100644 --- a/arch/alpha/lib/ev6-memset.S +++ b/arch/alpha/lib/ev6-memset.S @@ -30,15 +30,14 @@ .set noat .set noreorder .text - .globl memset .globl __memset - .globl ___memset .globl __memsetw .globl __constant_c_memset + .globl memset - .ent ___memset + .ent __memset .align 5 -___memset: +__memset: .frame $30,0,$26,0 .prologue 0 @@ -228,7 +227,7 @@ end_b: nop nop ret $31,($26),1 # L0 : - .end ___memset + .end __memset /* * This is the original body of code, prior to replication and @@ -595,5 +594,4 @@ end_w: .end __memsetw -memset = ___memset -__memset = ___memset +memset = __memset diff --git a/arch/alpha/lib/memset.S b/arch/alpha/lib/memset.S index 76ccc6d..311b8cf 100644 --- a/arch/alpha/lib/memset.S +++ b/arch/alpha/lib/memset.S @@ -19,13 +19,11 @@ .text .globl memset .globl __memset - .globl ___memset .globl __memsetw .globl __constant_c_memset - - .ent ___memset + .ent __memset .align 5 -___memset: +__memset: .frame $30,0,$26,0 .prologue 0 @@ -105,7 +103,7 @@ within_one_quad: end: ret $31,($26),1 /* E1 */ - .end ___memset + .end __memset .align 5 .ent __memsetw @@ -123,5 +121,4 @@ __memsetw: .end __memsetw -memset = ___memset -__memset = ___memset +memset = __memset |