summaryrefslogtreecommitdiff
path: root/arch/alpha/kernel
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
committerScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
commit62b8c978ee6b8d135d9e7953221de58000dba986 (patch)
tree683b04b2e627f6710c22c151b23c8cc9a165315e /arch/alpha/kernel
parent78fd82238d0e5716578c326404184a27ba67fd6e (diff)
downloadlinux-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/Makefile1
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c1
-rw-r--r--arch/alpha/kernel/irq_alpha.c16
-rw-r--r--arch/alpha/kernel/machvec_impl.h5
-rw-r--r--arch/alpha/kernel/perf_event.c15
-rw-r--r--arch/alpha/kernel/process.c17
-rw-r--r--arch/alpha/kernel/proto.h6
-rw-r--r--arch/alpha/kernel/rtc.c323
-rw-r--r--arch/alpha/kernel/setup.c23
-rw-r--r--arch/alpha/kernel/smp.c33
-rw-r--r--arch/alpha/kernel/sys_jensen.c2
-rw-r--r--arch/alpha/kernel/sys_marvel.c55
-rw-r--r--arch/alpha/kernel/time.c405
-rw-r--r--arch/alpha/kernel/traps.c15
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);
}