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/kernel | |
parent | 78fd82238d0e5716578c326404184a27ba67fd6e (diff) | |
download | linux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz |
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'arch/alpha/kernel')
-rw-r--r-- | arch/alpha/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/alpha/kernel/alpha_ksyms.c | 1 | ||||
-rw-r--r-- | arch/alpha/kernel/irq_alpha.c | 16 | ||||
-rw-r--r-- | arch/alpha/kernel/machvec_impl.h | 5 | ||||
-rw-r--r-- | arch/alpha/kernel/perf_event.c | 15 | ||||
-rw-r--r-- | arch/alpha/kernel/process.c | 17 | ||||
-rw-r--r-- | arch/alpha/kernel/proto.h | 6 | ||||
-rw-r--r-- | arch/alpha/kernel/rtc.c | 323 | ||||
-rw-r--r-- | arch/alpha/kernel/setup.c | 23 | ||||
-rw-r--r-- | arch/alpha/kernel/smp.c | 33 | ||||
-rw-r--r-- | arch/alpha/kernel/sys_jensen.c | 2 | ||||
-rw-r--r-- | arch/alpha/kernel/sys_marvel.c | 55 | ||||
-rw-r--r-- | arch/alpha/kernel/time.c | 405 | ||||
-rw-r--r-- | arch/alpha/kernel/traps.c | 15 |
14 files changed, 344 insertions, 573 deletions
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); } |