diff options
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, 573 insertions, 344 deletions
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 84ec46b38f7d..0d54650e78fc 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile | |||
| @@ -16,6 +16,7 @@ obj-$(CONFIG_PCI) += pci.o pci_iommu.o pci-sysfs.o | |||
| 16 | obj-$(CONFIG_SRM_ENV) += srm_env.o | 16 | obj-$(CONFIG_SRM_ENV) += srm_env.o |
| 17 | obj-$(CONFIG_MODULES) += module.o | 17 | obj-$(CONFIG_MODULES) += module.o |
| 18 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o | 18 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o |
| 19 | obj-$(CONFIG_RTC_DRV_ALPHA) += rtc.o | ||
| 19 | 20 | ||
| 20 | ifdef CONFIG_ALPHA_GENERIC | 21 | ifdef CONFIG_ALPHA_GENERIC |
| 21 | 22 | ||
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index 89566b346c0f..f4c7ab6f43b0 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c | |||
| @@ -40,6 +40,7 @@ EXPORT_SYMBOL(strrchr); | |||
| 40 | EXPORT_SYMBOL(memmove); | 40 | EXPORT_SYMBOL(memmove); |
| 41 | EXPORT_SYMBOL(__memcpy); | 41 | EXPORT_SYMBOL(__memcpy); |
| 42 | EXPORT_SYMBOL(__memset); | 42 | EXPORT_SYMBOL(__memset); |
| 43 | EXPORT_SYMBOL(___memset); | ||
| 43 | EXPORT_SYMBOL(__memsetw); | 44 | EXPORT_SYMBOL(__memsetw); |
| 44 | EXPORT_SYMBOL(__constant_c_memset); | 45 | EXPORT_SYMBOL(__constant_c_memset); |
| 45 | EXPORT_SYMBOL(copy_page); | 46 | EXPORT_SYMBOL(copy_page); |
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c index 28e4429596f3..1c8625cb0e25 100644 --- a/arch/alpha/kernel/irq_alpha.c +++ b/arch/alpha/kernel/irq_alpha.c | |||
| @@ -66,21 +66,7 @@ do_entInt(unsigned long type, unsigned long vector, | |||
| 66 | break; | 66 | break; |
| 67 | case 1: | 67 | case 1: |
| 68 | old_regs = set_irq_regs(regs); | 68 | old_regs = set_irq_regs(regs); |
| 69 | #ifdef CONFIG_SMP | ||
| 70 | { | ||
| 71 | long cpu; | ||
| 72 | |||
| 73 | smp_percpu_timer_interrupt(regs); | ||
| 74 | cpu = smp_processor_id(); | ||
| 75 | if (cpu != boot_cpuid) { | ||
| 76 | kstat_incr_irqs_this_cpu(RTC_IRQ, irq_to_desc(RTC_IRQ)); | ||
| 77 | } else { | ||
| 78 | handle_irq(RTC_IRQ); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | #else | ||
| 82 | handle_irq(RTC_IRQ); | 69 | handle_irq(RTC_IRQ); |
| 83 | #endif | ||
| 84 | set_irq_regs(old_regs); | 70 | set_irq_regs(old_regs); |
| 85 | return; | 71 | return; |
| 86 | case 2: | 72 | case 2: |
| @@ -228,7 +214,7 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr, | |||
| 228 | */ | 214 | */ |
| 229 | 215 | ||
| 230 | struct irqaction timer_irqaction = { | 216 | struct irqaction timer_irqaction = { |
| 231 | .handler = timer_interrupt, | 217 | .handler = rtc_timer_interrupt, |
| 232 | .name = "timer", | 218 | .name = "timer", |
| 233 | }; | 219 | }; |
| 234 | 220 | ||
diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h index 7fa62488bd16..f54bdf658cd0 100644 --- a/arch/alpha/kernel/machvec_impl.h +++ b/arch/alpha/kernel/machvec_impl.h | |||
| @@ -43,10 +43,7 @@ | |||
| 43 | #define CAT1(x,y) x##y | 43 | #define CAT1(x,y) x##y |
| 44 | #define CAT(x,y) CAT1(x,y) | 44 | #define CAT(x,y) CAT1(x,y) |
| 45 | 45 | ||
| 46 | #define DO_DEFAULT_RTC \ | 46 | #define DO_DEFAULT_RTC .rtc_port = 0x70 |
| 47 | .rtc_port = 0x70, \ | ||
| 48 | .rtc_get_time = common_get_rtc_time, \ | ||
| 49 | .rtc_set_time = common_set_rtc_time | ||
| 50 | 47 | ||
| 51 | #define DO_EV4_MMU \ | 48 | #define DO_EV4_MMU \ |
| 52 | .max_asn = EV4_MAX_ASN, \ | 49 | .max_asn = EV4_MAX_ASN, \ |
diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c index d821b17047e0..c52e7f0ee5f6 100644 --- a/arch/alpha/kernel/perf_event.c +++ b/arch/alpha/kernel/perf_event.c | |||
| @@ -83,6 +83,8 @@ struct alpha_pmu_t { | |||
| 83 | long pmc_left[3]; | 83 | long pmc_left[3]; |
| 84 | /* Subroutine for allocation of PMCs. Enforces constraints. */ | 84 | /* Subroutine for allocation of PMCs. Enforces constraints. */ |
| 85 | int (*check_constraints)(struct perf_event **, unsigned long *, int); | 85 | int (*check_constraints)(struct perf_event **, unsigned long *, int); |
| 86 | /* Subroutine for checking validity of a raw event for this PMU. */ | ||
| 87 | int (*raw_event_valid)(u64 config); | ||
| 86 | }; | 88 | }; |
| 87 | 89 | ||
| 88 | /* | 90 | /* |
| @@ -203,6 +205,12 @@ success: | |||
| 203 | } | 205 | } |
| 204 | 206 | ||
| 205 | 207 | ||
| 208 | static int ev67_raw_event_valid(u64 config) | ||
| 209 | { | ||
| 210 | return config >= EV67_CYCLES && config < EV67_LAST_ET; | ||
| 211 | }; | ||
| 212 | |||
| 213 | |||
| 206 | static const struct alpha_pmu_t ev67_pmu = { | 214 | static const struct alpha_pmu_t ev67_pmu = { |
| 207 | .event_map = ev67_perfmon_event_map, | 215 | .event_map = ev67_perfmon_event_map, |
| 208 | .max_events = ARRAY_SIZE(ev67_perfmon_event_map), | 216 | .max_events = ARRAY_SIZE(ev67_perfmon_event_map), |
| @@ -211,7 +219,8 @@ static const struct alpha_pmu_t ev67_pmu = { | |||
| 211 | .pmc_count_mask = {EV67_PCTR_0_COUNT_MASK, EV67_PCTR_1_COUNT_MASK, 0}, | 219 | .pmc_count_mask = {EV67_PCTR_0_COUNT_MASK, EV67_PCTR_1_COUNT_MASK, 0}, |
| 212 | .pmc_max_period = {(1UL<<20) - 1, (1UL<<20) - 1, 0}, | 220 | .pmc_max_period = {(1UL<<20) - 1, (1UL<<20) - 1, 0}, |
| 213 | .pmc_left = {16, 4, 0}, | 221 | .pmc_left = {16, 4, 0}, |
| 214 | .check_constraints = ev67_check_constraints | 222 | .check_constraints = ev67_check_constraints, |
| 223 | .raw_event_valid = ev67_raw_event_valid, | ||
| 215 | }; | 224 | }; |
| 216 | 225 | ||
| 217 | 226 | ||
| @@ -609,7 +618,9 @@ static int __hw_perf_event_init(struct perf_event *event) | |||
| 609 | } else if (attr->type == PERF_TYPE_HW_CACHE) { | 618 | } else if (attr->type == PERF_TYPE_HW_CACHE) { |
| 610 | return -EOPNOTSUPP; | 619 | return -EOPNOTSUPP; |
| 611 | } else if (attr->type == PERF_TYPE_RAW) { | 620 | } else if (attr->type == PERF_TYPE_RAW) { |
| 612 | ev = attr->config & 0xff; | 621 | if (!alpha_pmu->raw_event_valid(attr->config)) |
| 622 | return -EINVAL; | ||
| 623 | ev = attr->config; | ||
| 613 | } else { | 624 | } else { |
| 614 | return -EOPNOTSUPP; | 625 | return -EOPNOTSUPP; |
| 615 | } | 626 | } |
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index f2360a74e5d5..1941a07b5811 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c | |||
| @@ -46,6 +46,23 @@ | |||
| 46 | void (*pm_power_off)(void) = machine_power_off; | 46 | void (*pm_power_off)(void) = machine_power_off; |
| 47 | EXPORT_SYMBOL(pm_power_off); | 47 | EXPORT_SYMBOL(pm_power_off); |
| 48 | 48 | ||
| 49 | #ifdef CONFIG_ALPHA_WTINT | ||
| 50 | /* | ||
| 51 | * Sleep the CPU. | ||
| 52 | * EV6, LCA45 and QEMU know how to power down, skipping N timer interrupts. | ||
| 53 | */ | ||
| 54 | void arch_cpu_idle(void) | ||
| 55 | { | ||
| 56 | wtint(0); | ||
| 57 | local_irq_enable(); | ||
| 58 | } | ||
| 59 | |||
| 60 | void arch_cpu_idle_dead(void) | ||
| 61 | { | ||
| 62 | wtint(INT_MAX); | ||
| 63 | } | ||
| 64 | #endif /* ALPHA_WTINT */ | ||
| 65 | |||
| 49 | struct halt_info { | 66 | struct halt_info { |
| 50 | int mode; | 67 | int mode; |
| 51 | char *restart_cmd; | 68 | char *restart_cmd; |
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index d3e52d3fd592..da2d6ec9c370 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h | |||
| @@ -135,17 +135,15 @@ extern void unregister_srm_console(void); | |||
| 135 | /* smp.c */ | 135 | /* smp.c */ |
| 136 | extern void setup_smp(void); | 136 | extern void setup_smp(void); |
| 137 | extern void handle_ipi(struct pt_regs *); | 137 | extern void handle_ipi(struct pt_regs *); |
| 138 | extern void smp_percpu_timer_interrupt(struct pt_regs *); | ||
| 139 | 138 | ||
| 140 | /* bios32.c */ | 139 | /* bios32.c */ |
| 141 | /* extern void reset_for_srm(void); */ | 140 | /* extern void reset_for_srm(void); */ |
| 142 | 141 | ||
| 143 | /* time.c */ | 142 | /* time.c */ |
| 144 | extern irqreturn_t timer_interrupt(int irq, void *dev); | 143 | extern irqreturn_t rtc_timer_interrupt(int irq, void *dev); |
| 144 | extern void init_clockevent(void); | ||
| 145 | extern void common_init_rtc(void); | 145 | extern void common_init_rtc(void); |
| 146 | extern unsigned long est_cycle_freq; | 146 | extern unsigned long est_cycle_freq; |
| 147 | extern unsigned int common_get_rtc_time(struct rtc_time *time); | ||
| 148 | extern int common_set_rtc_time(struct rtc_time *time); | ||
| 149 | 147 | ||
| 150 | /* smc37c93x.c */ | 148 | /* smc37c93x.c */ |
| 151 | extern void SMC93x_Init(void); | 149 | extern void SMC93x_Init(void); |
diff --git a/arch/alpha/kernel/rtc.c b/arch/alpha/kernel/rtc.c new file mode 100644 index 000000000000..c8d284d8521f --- /dev/null +++ b/arch/alpha/kernel/rtc.c | |||
| @@ -0,0 +1,323 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/alpha/kernel/rtc.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1991, 1992, 1995, 1999, 2000 Linus Torvalds | ||
| 5 | * | ||
| 6 | * This file contains date handling. | ||
| 7 | */ | ||
| 8 | #include <linux/errno.h> | ||
| 9 | #include <linux/init.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/param.h> | ||
| 12 | #include <linux/string.h> | ||
| 13 | #include <linux/mc146818rtc.h> | ||
| 14 | #include <linux/bcd.h> | ||
| 15 | #include <linux/rtc.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | |||
| 18 | #include <asm/rtc.h> | ||
| 19 | |||
| 20 | #include "proto.h" | ||
| 21 | |||
| 22 | |||
| 23 | /* | ||
| 24 | * Support for the RTC device. | ||
| 25 | * | ||
| 26 | * We don't want to use the rtc-cmos driver, because we don't want to support | ||
| 27 | * alarms, as that would be indistinguishable from timer interrupts. | ||
| 28 | * | ||
| 29 | * Further, generic code is really, really tied to a 1900 epoch. This is | ||
| 30 | * true in __get_rtc_time as well as the users of struct rtc_time e.g. | ||
| 31 | * rtc_tm_to_time. Thankfully all of the other epochs in use are later | ||
| 32 | * than 1900, and so it's easy to adjust. | ||
| 33 | */ | ||
| 34 | |||
| 35 | static unsigned long rtc_epoch; | ||
| 36 | |||
| 37 | static int __init | ||
| 38 | specifiy_epoch(char *str) | ||
| 39 | { | ||
| 40 | unsigned long epoch = simple_strtoul(str, NULL, 0); | ||
| 41 | if (epoch < 1900) | ||
| 42 | printk("Ignoring invalid user specified epoch %lu\n", epoch); | ||
| 43 | else | ||
| 44 | rtc_epoch = epoch; | ||
| 45 | return 1; | ||
| 46 | } | ||
| 47 | __setup("epoch=", specifiy_epoch); | ||
| 48 | |||
| 49 | static void __init | ||
| 50 | init_rtc_epoch(void) | ||
| 51 | { | ||
| 52 | int epoch, year, ctrl; | ||
| 53 | |||
| 54 | if (rtc_epoch != 0) { | ||
| 55 | /* The epoch was specified on the command-line. */ | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | |||
| 59 | /* Detect the epoch in use on this computer. */ | ||
| 60 | ctrl = CMOS_READ(RTC_CONTROL); | ||
| 61 | year = CMOS_READ(RTC_YEAR); | ||
| 62 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
| 63 | year = bcd2bin(year); | ||
| 64 | |||
| 65 | /* PC-like is standard; used for year >= 70 */ | ||
| 66 | epoch = 1900; | ||
| 67 | if (year < 20) { | ||
| 68 | epoch = 2000; | ||
| 69 | } else if (year >= 20 && year < 48) { | ||
| 70 | /* NT epoch */ | ||
| 71 | epoch = 1980; | ||
| 72 | } else if (year >= 48 && year < 70) { | ||
| 73 | /* Digital UNIX epoch */ | ||
| 74 | epoch = 1952; | ||
| 75 | } | ||
| 76 | rtc_epoch = epoch; | ||
| 77 | |||
| 78 | printk(KERN_INFO "Using epoch %d for rtc year %d\n", epoch, year); | ||
| 79 | } | ||
| 80 | |||
| 81 | static int | ||
| 82 | alpha_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 83 | { | ||
| 84 | __get_rtc_time(tm); | ||
| 85 | |||
| 86 | /* Adjust for non-default epochs. It's easier to depend on the | ||
| 87 | generic __get_rtc_time and adjust the epoch here than create | ||
| 88 | a copy of __get_rtc_time with the edits we need. */ | ||
| 89 | if (rtc_epoch != 1900) { | ||
| 90 | int year = tm->tm_year; | ||
| 91 | /* Undo the century adjustment made in __get_rtc_time. */ | ||
| 92 | if (year >= 100) | ||
| 93 | year -= 100; | ||
| 94 | year += rtc_epoch - 1900; | ||
| 95 | /* Redo the century adjustment with the epoch in place. */ | ||
| 96 | if (year <= 69) | ||
| 97 | year += 100; | ||
| 98 | tm->tm_year = year; | ||
| 99 | } | ||
| 100 | |||
| 101 | return rtc_valid_tm(tm); | ||
| 102 | } | ||
| 103 | |||
| 104 | static int | ||
| 105 | alpha_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 106 | { | ||
| 107 | struct rtc_time xtm; | ||
| 108 | |||
| 109 | if (rtc_epoch != 1900) { | ||
| 110 | xtm = *tm; | ||
| 111 | xtm.tm_year -= rtc_epoch - 1900; | ||
| 112 | tm = &xtm; | ||
| 113 | } | ||
| 114 | |||
| 115 | return __set_rtc_time(tm); | ||
| 116 | } | ||
| 117 | |||
| 118 | static int | ||
| 119 | alpha_rtc_set_mmss(struct device *dev, unsigned long nowtime) | ||
| 120 | { | ||
| 121 | int retval = 0; | ||
| 122 | int real_seconds, real_minutes, cmos_minutes; | ||
| 123 | unsigned char save_control, save_freq_select; | ||
| 124 | |||
| 125 | /* Note: This code only updates minutes and seconds. Comments | ||
| 126 | indicate this was to avoid messing with unknown time zones, | ||
| 127 | and with the epoch nonsense described above. In order for | ||
| 128 | this to work, the existing clock cannot be off by more than | ||
| 129 | 15 minutes. | ||
| 130 | |||
| 131 | ??? This choice is may be out of date. The x86 port does | ||
| 132 | not have problems with timezones, and the epoch processing has | ||
| 133 | now been fixed in alpha_set_rtc_time. | ||
| 134 | |||
| 135 | In either case, one can always force a full rtc update with | ||
| 136 | the userland hwclock program, so surely 15 minute accuracy | ||
| 137 | is no real burden. */ | ||
| 138 | |||
| 139 | /* In order to set the CMOS clock precisely, we have to be called | ||
| 140 | 500 ms after the second nowtime has started, because when | ||
| 141 | nowtime is written into the registers of the CMOS clock, it will | ||
| 142 | jump to the next second precisely 500 ms later. Check the Motorola | ||
| 143 | MC146818A or Dallas DS12887 data sheet for details. */ | ||
| 144 | |||
| 145 | /* irq are locally disabled here */ | ||
| 146 | spin_lock(&rtc_lock); | ||
| 147 | /* Tell the clock it's being set */ | ||
| 148 | save_control = CMOS_READ(RTC_CONTROL); | ||
| 149 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | ||
| 150 | |||
| 151 | /* Stop and reset prescaler */ | ||
| 152 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | ||
| 153 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | ||
| 154 | |||
| 155 | cmos_minutes = CMOS_READ(RTC_MINUTES); | ||
| 156 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
| 157 | cmos_minutes = bcd2bin(cmos_minutes); | ||
| 158 | |||
| 159 | real_seconds = nowtime % 60; | ||
| 160 | real_minutes = nowtime / 60; | ||
| 161 | if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) { | ||
| 162 | /* correct for half hour time zone */ | ||
| 163 | real_minutes += 30; | ||
| 164 | } | ||
| 165 | real_minutes %= 60; | ||
| 166 | |||
| 167 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
| 168 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
| 169 | real_seconds = bin2bcd(real_seconds); | ||
| 170 | real_minutes = bin2bcd(real_minutes); | ||
| 171 | } | ||
| 172 | CMOS_WRITE(real_seconds,RTC_SECONDS); | ||
| 173 | CMOS_WRITE(real_minutes,RTC_MINUTES); | ||
| 174 | } else { | ||
| 175 | printk_once(KERN_NOTICE | ||
| 176 | "set_rtc_mmss: can't update from %d to %d\n", | ||
| 177 | cmos_minutes, real_minutes); | ||
| 178 | retval = -1; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* The following flags have to be released exactly in this order, | ||
| 182 | * otherwise the DS12887 (popular MC146818A clone with integrated | ||
| 183 | * battery and quartz) will not reset the oscillator and will not | ||
| 184 | * update precisely 500 ms later. You won't find this mentioned in | ||
| 185 | * the Dallas Semiconductor data sheets, but who believes data | ||
| 186 | * sheets anyway ... -- Markus Kuhn | ||
| 187 | */ | ||
| 188 | CMOS_WRITE(save_control, RTC_CONTROL); | ||
| 189 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | ||
| 190 | spin_unlock(&rtc_lock); | ||
| 191 | |||
| 192 | return retval; | ||
| 193 | } | ||
| 194 | |||
| 195 | static int | ||
| 196 | alpha_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | ||
| 197 | { | ||
| 198 | switch (cmd) { | ||
| 199 | case RTC_EPOCH_READ: | ||
| 200 | return put_user(rtc_epoch, (unsigned long __user *)arg); | ||
| 201 | case RTC_EPOCH_SET: | ||
| 202 | if (arg < 1900) | ||
| 203 | return -EINVAL; | ||
| 204 | rtc_epoch = arg; | ||
| 205 | return 0; | ||
| 206 | default: | ||
| 207 | return -ENOIOCTLCMD; | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | static const struct rtc_class_ops alpha_rtc_ops = { | ||
| 212 | .read_time = alpha_rtc_read_time, | ||
| 213 | .set_time = alpha_rtc_set_time, | ||
| 214 | .set_mmss = alpha_rtc_set_mmss, | ||
| 215 | .ioctl = alpha_rtc_ioctl, | ||
| 216 | }; | ||
| 217 | |||
| 218 | /* | ||
| 219 | * Similarly, except do the actual CMOS access on the boot cpu only. | ||
| 220 | * This requires marshalling the data across an interprocessor call. | ||
| 221 | */ | ||
| 222 | |||
| 223 | #if defined(CONFIG_SMP) && \ | ||
| 224 | (defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_MARVEL)) | ||
| 225 | # define HAVE_REMOTE_RTC 1 | ||
| 226 | |||
| 227 | union remote_data { | ||
| 228 | struct rtc_time *tm; | ||
| 229 | unsigned long now; | ||
| 230 | long retval; | ||
| 231 | }; | ||
| 232 | |||
| 233 | static void | ||
| 234 | do_remote_read(void *data) | ||
| 235 | { | ||
| 236 | union remote_data *x = data; | ||
| 237 | x->retval = alpha_rtc_read_time(NULL, x->tm); | ||
| 238 | } | ||
| 239 | |||
| 240 | static int | ||
| 241 | remote_read_time(struct device *dev, struct rtc_time *tm) | ||
| 242 | { | ||
| 243 | union remote_data x; | ||
| 244 | if (smp_processor_id() != boot_cpuid) { | ||
| 245 | x.tm = tm; | ||
| 246 | smp_call_function_single(boot_cpuid, do_remote_read, &x, 1); | ||
| 247 | return x.retval; | ||
| 248 | } | ||
| 249 | return alpha_rtc_read_time(NULL, tm); | ||
| 250 | } | ||
| 251 | |||
| 252 | static void | ||
| 253 | do_remote_set(void *data) | ||
| 254 | { | ||
| 255 | union remote_data *x = data; | ||
| 256 | x->retval = alpha_rtc_set_time(NULL, x->tm); | ||
| 257 | } | ||
| 258 | |||
| 259 | static int | ||
| 260 | remote_set_time(struct device *dev, struct rtc_time *tm) | ||
| 261 | { | ||
| 262 | union remote_data x; | ||
| 263 | if (smp_processor_id() != boot_cpuid) { | ||
| 264 | x.tm = tm; | ||
| 265 | smp_call_function_single(boot_cpuid, do_remote_set, &x, 1); | ||
| 266 | return x.retval; | ||
| 267 | } | ||
| 268 | return alpha_rtc_set_time(NULL, tm); | ||
| 269 | } | ||
| 270 | |||
| 271 | static void | ||
| 272 | do_remote_mmss(void *data) | ||
| 273 | { | ||
| 274 | union remote_data *x = data; | ||
| 275 | x->retval = alpha_rtc_set_mmss(NULL, x->now); | ||
| 276 | } | ||
| 277 | |||
| 278 | static int | ||
| 279 | remote_set_mmss(struct device *dev, unsigned long now) | ||
| 280 | { | ||
| 281 | union remote_data x; | ||
| 282 | if (smp_processor_id() != boot_cpuid) { | ||
| 283 | x.now = now; | ||
| 284 | smp_call_function_single(boot_cpuid, do_remote_mmss, &x, 1); | ||
| 285 | return x.retval; | ||
| 286 | } | ||
| 287 | return alpha_rtc_set_mmss(NULL, now); | ||
| 288 | } | ||
| 289 | |||
| 290 | static const struct rtc_class_ops remote_rtc_ops = { | ||
| 291 | .read_time = remote_read_time, | ||
| 292 | .set_time = remote_set_time, | ||
| 293 | .set_mmss = remote_set_mmss, | ||
| 294 | .ioctl = alpha_rtc_ioctl, | ||
| 295 | }; | ||
| 296 | #endif | ||
| 297 | |||
| 298 | static int __init | ||
| 299 | alpha_rtc_init(void) | ||
| 300 | { | ||
| 301 | const struct rtc_class_ops *ops; | ||
| 302 | struct platform_device *pdev; | ||
| 303 | struct rtc_device *rtc; | ||
| 304 | const char *name; | ||
| 305 | |||
| 306 | init_rtc_epoch(); | ||
| 307 | name = "rtc-alpha"; | ||
| 308 | ops = &alpha_rtc_ops; | ||
| 309 | |||
| 310 | #ifdef HAVE_REMOTE_RTC | ||
| 311 | if (alpha_mv.rtc_boot_cpu_only) | ||
| 312 | ops = &remote_rtc_ops; | ||
| 313 | #endif | ||
| 314 | |||
| 315 | pdev = platform_device_register_simple(name, -1, NULL, 0); | ||
| 316 | rtc = devm_rtc_device_register(&pdev->dev, name, ops, THIS_MODULE); | ||
| 317 | if (IS_ERR(rtc)) | ||
| 318 | return PTR_ERR(rtc); | ||
| 319 | |||
| 320 | platform_set_drvdata(pdev, rtc); | ||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | device_initcall(alpha_rtc_init); | ||
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 9e3107cc5ebb..b20af76f12c1 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c | |||
| @@ -115,10 +115,17 @@ unsigned long alpha_agpgart_size = DEFAULT_AGP_APER_SIZE; | |||
| 115 | 115 | ||
| 116 | #ifdef CONFIG_ALPHA_GENERIC | 116 | #ifdef CONFIG_ALPHA_GENERIC |
| 117 | struct alpha_machine_vector alpha_mv; | 117 | struct alpha_machine_vector alpha_mv; |
| 118 | #endif | ||
| 119 | |||
| 120 | #ifndef alpha_using_srm | ||
| 118 | int alpha_using_srm; | 121 | int alpha_using_srm; |
| 119 | EXPORT_SYMBOL(alpha_using_srm); | 122 | EXPORT_SYMBOL(alpha_using_srm); |
| 120 | #endif | 123 | #endif |
| 121 | 124 | ||
| 125 | #ifndef alpha_using_qemu | ||
| 126 | int alpha_using_qemu; | ||
| 127 | #endif | ||
| 128 | |||
| 122 | static struct alpha_machine_vector *get_sysvec(unsigned long, unsigned long, | 129 | static struct alpha_machine_vector *get_sysvec(unsigned long, unsigned long, |
| 123 | unsigned long); | 130 | unsigned long); |
| 124 | static struct alpha_machine_vector *get_sysvec_byname(const char *); | 131 | static struct alpha_machine_vector *get_sysvec_byname(const char *); |
| @@ -529,11 +536,15 @@ setup_arch(char **cmdline_p) | |||
| 529 | atomic_notifier_chain_register(&panic_notifier_list, | 536 | atomic_notifier_chain_register(&panic_notifier_list, |
| 530 | &alpha_panic_block); | 537 | &alpha_panic_block); |
| 531 | 538 | ||
| 532 | #ifdef CONFIG_ALPHA_GENERIC | 539 | #ifndef alpha_using_srm |
| 533 | /* Assume that we've booted from SRM if we haven't booted from MILO. | 540 | /* Assume that we've booted from SRM if we haven't booted from MILO. |
| 534 | Detect the later by looking for "MILO" in the system serial nr. */ | 541 | Detect the later by looking for "MILO" in the system serial nr. */ |
| 535 | alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; | 542 | alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; |
| 536 | #endif | 543 | #endif |
| 544 | #ifndef alpha_using_qemu | ||
| 545 | /* Similarly, look for QEMU. */ | ||
| 546 | alpha_using_qemu = strstr((const char *)hwrpb->ssn, "QEMU") != 0; | ||
| 547 | #endif | ||
| 537 | 548 | ||
| 538 | /* If we are using SRM, we want to allow callbacks | 549 | /* If we are using SRM, we want to allow callbacks |
| 539 | as early as possible, so do this NOW, and then | 550 | as early as possible, so do this NOW, and then |
| @@ -1207,6 +1218,7 @@ show_cpuinfo(struct seq_file *f, void *slot) | |||
| 1207 | char *systype_name; | 1218 | char *systype_name; |
| 1208 | char *sysvariation_name; | 1219 | char *sysvariation_name; |
| 1209 | int nr_processors; | 1220 | int nr_processors; |
| 1221 | unsigned long timer_freq; | ||
| 1210 | 1222 | ||
| 1211 | cpu_index = (unsigned) (cpu->type - 1); | 1223 | cpu_index = (unsigned) (cpu->type - 1); |
| 1212 | cpu_name = "Unknown"; | 1224 | cpu_name = "Unknown"; |
| @@ -1218,6 +1230,12 @@ show_cpuinfo(struct seq_file *f, void *slot) | |||
| 1218 | 1230 | ||
| 1219 | nr_processors = get_nr_processors(cpu, hwrpb->nr_processors); | 1231 | nr_processors = get_nr_processors(cpu, hwrpb->nr_processors); |
| 1220 | 1232 | ||
| 1233 | #if CONFIG_HZ == 1024 || CONFIG_HZ == 1200 | ||
| 1234 | timer_freq = (100UL * hwrpb->intr_freq) / 4096; | ||
| 1235 | #else | ||
| 1236 | timer_freq = 100UL * CONFIG_HZ; | ||
| 1237 | #endif | ||
| 1238 | |||
| 1221 | seq_printf(f, "cpu\t\t\t: Alpha\n" | 1239 | seq_printf(f, "cpu\t\t\t: Alpha\n" |
| 1222 | "cpu model\t\t: %s\n" | 1240 | "cpu model\t\t: %s\n" |
| 1223 | "cpu variation\t\t: %ld\n" | 1241 | "cpu variation\t\t: %ld\n" |
| @@ -1243,8 +1261,7 @@ show_cpuinfo(struct seq_file *f, void *slot) | |||
| 1243 | (char*)hwrpb->ssn, | 1261 | (char*)hwrpb->ssn, |
| 1244 | est_cycle_freq ? : hwrpb->cycle_freq, | 1262 | est_cycle_freq ? : hwrpb->cycle_freq, |
| 1245 | est_cycle_freq ? "est." : "", | 1263 | est_cycle_freq ? "est." : "", |
| 1246 | hwrpb->intr_freq / 4096, | 1264 | timer_freq / 100, timer_freq % 100, |
| 1247 | (100 * hwrpb->intr_freq / 4096) % 100, | ||
| 1248 | hwrpb->pagesize, | 1265 | hwrpb->pagesize, |
| 1249 | hwrpb->pa_bits, | 1266 | hwrpb->pa_bits, |
| 1250 | hwrpb->max_asn, | 1267 | hwrpb->max_asn, |
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 9dbbcb3b9146..99ac36d5de4e 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c | |||
| @@ -138,9 +138,11 @@ smp_callin(void) | |||
| 138 | 138 | ||
| 139 | /* Get our local ticker going. */ | 139 | /* Get our local ticker going. */ |
| 140 | smp_setup_percpu_timer(cpuid); | 140 | smp_setup_percpu_timer(cpuid); |
| 141 | init_clockevent(); | ||
| 141 | 142 | ||
| 142 | /* Call platform-specific callin, if specified */ | 143 | /* Call platform-specific callin, if specified */ |
| 143 | if (alpha_mv.smp_callin) alpha_mv.smp_callin(); | 144 | if (alpha_mv.smp_callin) |
| 145 | alpha_mv.smp_callin(); | ||
| 144 | 146 | ||
| 145 | /* All kernel threads share the same mm context. */ | 147 | /* All kernel threads share the same mm context. */ |
| 146 | atomic_inc(&init_mm.mm_count); | 148 | atomic_inc(&init_mm.mm_count); |
| @@ -498,35 +500,6 @@ smp_cpus_done(unsigned int max_cpus) | |||
| 498 | ((bogosum + 2500) / (5000/HZ)) % 100); | 500 | ((bogosum + 2500) / (5000/HZ)) % 100); |
| 499 | } | 501 | } |
| 500 | 502 | ||
| 501 | |||
| 502 | void | ||
| 503 | smp_percpu_timer_interrupt(struct pt_regs *regs) | ||
| 504 | { | ||
| 505 | struct pt_regs *old_regs; | ||
| 506 | int cpu = smp_processor_id(); | ||
| 507 | unsigned long user = user_mode(regs); | ||
| 508 | struct cpuinfo_alpha *data = &cpu_data[cpu]; | ||
| 509 | |||
| 510 | old_regs = set_irq_regs(regs); | ||
| 511 | |||
| 512 | /* Record kernel PC. */ | ||
| 513 | profile_tick(CPU_PROFILING); | ||
| 514 | |||
| 515 | if (!--data->prof_counter) { | ||
| 516 | /* We need to make like a normal interrupt -- otherwise | ||
| 517 | timer interrupts ignore the global interrupt lock, | ||
| 518 | which would be a Bad Thing. */ | ||
| 519 | irq_enter(); | ||
| 520 | |||
| 521 | update_process_times(user); | ||
| 522 | |||
| 523 | data->prof_counter = data->prof_multiplier; | ||
| 524 | |||
| 525 | irq_exit(); | ||
| 526 | } | ||
| 527 | set_irq_regs(old_regs); | ||
| 528 | } | ||
| 529 | |||
| 530 | int | 503 | int |
| 531 | setup_profiling_timer(unsigned int multiplier) | 504 | setup_profiling_timer(unsigned int multiplier) |
| 532 | { | 505 | { |
diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c index 5a0af11b3a61..608f2a7fa0a3 100644 --- a/arch/alpha/kernel/sys_jensen.c +++ b/arch/alpha/kernel/sys_jensen.c | |||
| @@ -224,8 +224,6 @@ struct alpha_machine_vector jensen_mv __initmv = { | |||
| 224 | .machine_check = jensen_machine_check, | 224 | .machine_check = jensen_machine_check, |
| 225 | .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, | 225 | .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, |
| 226 | .rtc_port = 0x170, | 226 | .rtc_port = 0x170, |
| 227 | .rtc_get_time = common_get_rtc_time, | ||
| 228 | .rtc_set_time = common_set_rtc_time, | ||
| 229 | 227 | ||
| 230 | .nr_irqs = 16, | 228 | .nr_irqs = 16, |
| 231 | .device_interrupt = jensen_device_interrupt, | 229 | .device_interrupt = jensen_device_interrupt, |
diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c index c92e389ff219..f21d61fab678 100644 --- a/arch/alpha/kernel/sys_marvel.c +++ b/arch/alpha/kernel/sys_marvel.c | |||
| @@ -22,7 +22,6 @@ | |||
| 22 | #include <asm/hwrpb.h> | 22 | #include <asm/hwrpb.h> |
| 23 | #include <asm/tlbflush.h> | 23 | #include <asm/tlbflush.h> |
| 24 | #include <asm/vga.h> | 24 | #include <asm/vga.h> |
| 25 | #include <asm/rtc.h> | ||
| 26 | 25 | ||
| 27 | #include "proto.h" | 26 | #include "proto.h" |
| 28 | #include "err_impl.h" | 27 | #include "err_impl.h" |
| @@ -400,57 +399,6 @@ marvel_init_rtc(void) | |||
| 400 | init_rtc_irq(); | 399 | init_rtc_irq(); |
| 401 | } | 400 | } |
| 402 | 401 | ||
| 403 | struct marvel_rtc_time { | ||
| 404 | struct rtc_time *time; | ||
| 405 | int retval; | ||
| 406 | }; | ||
| 407 | |||
| 408 | #ifdef CONFIG_SMP | ||
| 409 | static void | ||
| 410 | smp_get_rtc_time(void *data) | ||
| 411 | { | ||
| 412 | struct marvel_rtc_time *mrt = data; | ||
| 413 | mrt->retval = __get_rtc_time(mrt->time); | ||
| 414 | } | ||
| 415 | |||
| 416 | static void | ||
| 417 | smp_set_rtc_time(void *data) | ||
| 418 | { | ||
| 419 | struct marvel_rtc_time *mrt = data; | ||
| 420 | mrt->retval = __set_rtc_time(mrt->time); | ||
| 421 | } | ||
| 422 | #endif | ||
| 423 | |||
| 424 | static unsigned int | ||
| 425 | marvel_get_rtc_time(struct rtc_time *time) | ||
| 426 | { | ||
| 427 | #ifdef CONFIG_SMP | ||
| 428 | struct marvel_rtc_time mrt; | ||
| 429 | |||
| 430 | if (smp_processor_id() != boot_cpuid) { | ||
| 431 | mrt.time = time; | ||
| 432 | smp_call_function_single(boot_cpuid, smp_get_rtc_time, &mrt, 1); | ||
| 433 | return mrt.retval; | ||
| 434 | } | ||
| 435 | #endif | ||
| 436 | return __get_rtc_time(time); | ||
| 437 | } | ||
| 438 | |||
| 439 | static int | ||
| 440 | marvel_set_rtc_time(struct rtc_time *time) | ||
| 441 | { | ||
| 442 | #ifdef CONFIG_SMP | ||
| 443 | struct marvel_rtc_time mrt; | ||
| 444 | |||
| 445 | if (smp_processor_id() != boot_cpuid) { | ||
| 446 | mrt.time = time; | ||
| 447 | smp_call_function_single(boot_cpuid, smp_set_rtc_time, &mrt, 1); | ||
| 448 | return mrt.retval; | ||
| 449 | } | ||
| 450 | #endif | ||
| 451 | return __set_rtc_time(time); | ||
| 452 | } | ||
| 453 | |||
| 454 | static void | 402 | static void |
| 455 | marvel_smp_callin(void) | 403 | marvel_smp_callin(void) |
| 456 | { | 404 | { |
| @@ -492,8 +440,7 @@ struct alpha_machine_vector marvel_ev7_mv __initmv = { | |||
| 492 | .vector_name = "MARVEL/EV7", | 440 | .vector_name = "MARVEL/EV7", |
| 493 | DO_EV7_MMU, | 441 | DO_EV7_MMU, |
| 494 | .rtc_port = 0x70, | 442 | .rtc_port = 0x70, |
| 495 | .rtc_get_time = marvel_get_rtc_time, | 443 | .rtc_boot_cpu_only = 1, |
| 496 | .rtc_set_time = marvel_set_rtc_time, | ||
| 497 | DO_MARVEL_IO, | 444 | DO_MARVEL_IO, |
| 498 | .machine_check = marvel_machine_check, | 445 | .machine_check = marvel_machine_check, |
| 499 | .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, | 446 | .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, |
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index ea3395036556..ee39cee8064c 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c | |||
| @@ -3,13 +3,7 @@ | |||
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1991, 1992, 1995, 1999, 2000 Linus Torvalds | 4 | * Copyright (C) 1991, 1992, 1995, 1999, 2000 Linus Torvalds |
| 5 | * | 5 | * |
| 6 | * This file contains the PC-specific time handling details: | 6 | * This file contains the clocksource time handling. |
| 7 | * reading the RTC at bootup, etc.. | ||
| 8 | * 1994-07-02 Alan Modra | ||
| 9 | * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime | ||
| 10 | * 1995-03-26 Markus Kuhn | ||
| 11 | * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 | ||
| 12 | * precision CMOS clock update | ||
| 13 | * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 | 7 | * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 |
| 14 | * "A Kernel Model for Precision Timekeeping" by Dave Mills | 8 | * "A Kernel Model for Precision Timekeeping" by Dave Mills |
| 15 | * 1997-01-09 Adrian Sun | 9 | * 1997-01-09 Adrian Sun |
| @@ -21,9 +15,6 @@ | |||
| 21 | * 1999-04-16 Thorsten Kranzkowski (dl8bcu@gmx.net) | 15 | * 1999-04-16 Thorsten Kranzkowski (dl8bcu@gmx.net) |
| 22 | * fixed algorithm in do_gettimeofday() for calculating the precise time | 16 | * fixed algorithm in do_gettimeofday() for calculating the precise time |
| 23 | * from processor cycle counter (now taking lost_ticks into account) | 17 | * from processor cycle counter (now taking lost_ticks into account) |
| 24 | * 2000-08-13 Jan-Benedict Glaw <jbglaw@lug-owl.de> | ||
| 25 | * Fixed time_init to be aware of epoches != 1900. This prevents | ||
| 26 | * booting up in 2048 for me;) Code is stolen from rtc.c. | ||
| 27 | * 2003-06-03 R. Scott Bailey <scott.bailey@eds.com> | 18 | * 2003-06-03 R. Scott Bailey <scott.bailey@eds.com> |
| 28 | * Tighten sanity in time_init from 1% (10,000 PPM) to 250 PPM | 19 | * Tighten sanity in time_init from 1% (10,000 PPM) to 250 PPM |
| 29 | */ | 20 | */ |
| @@ -46,40 +37,19 @@ | |||
| 46 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
| 47 | #include <asm/io.h> | 38 | #include <asm/io.h> |
| 48 | #include <asm/hwrpb.h> | 39 | #include <asm/hwrpb.h> |
| 49 | #include <asm/rtc.h> | ||
| 50 | 40 | ||
| 51 | #include <linux/mc146818rtc.h> | 41 | #include <linux/mc146818rtc.h> |
| 52 | #include <linux/time.h> | 42 | #include <linux/time.h> |
| 53 | #include <linux/timex.h> | 43 | #include <linux/timex.h> |
| 54 | #include <linux/clocksource.h> | 44 | #include <linux/clocksource.h> |
| 45 | #include <linux/clockchips.h> | ||
| 55 | 46 | ||
| 56 | #include "proto.h" | 47 | #include "proto.h" |
| 57 | #include "irq_impl.h" | 48 | #include "irq_impl.h" |
| 58 | 49 | ||
| 59 | static int set_rtc_mmss(unsigned long); | ||
| 60 | |||
| 61 | DEFINE_SPINLOCK(rtc_lock); | 50 | DEFINE_SPINLOCK(rtc_lock); |
| 62 | EXPORT_SYMBOL(rtc_lock); | 51 | EXPORT_SYMBOL(rtc_lock); |
| 63 | 52 | ||
| 64 | #define TICK_SIZE (tick_nsec / 1000) | ||
| 65 | |||
| 66 | /* | ||
| 67 | * Shift amount by which scaled_ticks_per_cycle is scaled. Shifting | ||
| 68 | * by 48 gives us 16 bits for HZ while keeping the accuracy good even | ||
| 69 | * for large CPU clock rates. | ||
| 70 | */ | ||
| 71 | #define FIX_SHIFT 48 | ||
| 72 | |||
| 73 | /* lump static variables together for more efficient access: */ | ||
| 74 | static struct { | ||
| 75 | /* cycle counter last time it got invoked */ | ||
| 76 | __u32 last_time; | ||
| 77 | /* ticks/cycle * 2^48 */ | ||
| 78 | unsigned long scaled_ticks_per_cycle; | ||
| 79 | /* partial unused tick */ | ||
| 80 | unsigned long partial_tick; | ||
| 81 | } state; | ||
| 82 | |||
| 83 | unsigned long est_cycle_freq; | 53 | unsigned long est_cycle_freq; |
| 84 | 54 | ||
| 85 | #ifdef CONFIG_IRQ_WORK | 55 | #ifdef CONFIG_IRQ_WORK |
| @@ -108,109 +78,156 @@ static inline __u32 rpcc(void) | |||
| 108 | return __builtin_alpha_rpcc(); | 78 | return __builtin_alpha_rpcc(); |
| 109 | } | 79 | } |
| 110 | 80 | ||
| 111 | int update_persistent_clock(struct timespec now) | ||
| 112 | { | ||
| 113 | return set_rtc_mmss(now.tv_sec); | ||
| 114 | } | ||
| 115 | 81 | ||
| 116 | void read_persistent_clock(struct timespec *ts) | 82 | |
| 83 | /* | ||
| 84 | * The RTC as a clock_event_device primitive. | ||
| 85 | */ | ||
| 86 | |||
| 87 | static DEFINE_PER_CPU(struct clock_event_device, cpu_ce); | ||
| 88 | |||
| 89 | irqreturn_t | ||
| 90 | rtc_timer_interrupt(int irq, void *dev) | ||
| 117 | { | 91 | { |
| 118 | unsigned int year, mon, day, hour, min, sec, epoch; | 92 | int cpu = smp_processor_id(); |
| 119 | 93 | struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); | |
| 120 | sec = CMOS_READ(RTC_SECONDS); | ||
| 121 | min = CMOS_READ(RTC_MINUTES); | ||
| 122 | hour = CMOS_READ(RTC_HOURS); | ||
| 123 | day = CMOS_READ(RTC_DAY_OF_MONTH); | ||
| 124 | mon = CMOS_READ(RTC_MONTH); | ||
| 125 | year = CMOS_READ(RTC_YEAR); | ||
| 126 | |||
| 127 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
| 128 | sec = bcd2bin(sec); | ||
| 129 | min = bcd2bin(min); | ||
| 130 | hour = bcd2bin(hour); | ||
| 131 | day = bcd2bin(day); | ||
| 132 | mon = bcd2bin(mon); | ||
| 133 | year = bcd2bin(year); | ||
| 134 | } | ||
| 135 | 94 | ||
| 136 | /* PC-like is standard; used for year >= 70 */ | 95 | /* Don't run the hook for UNUSED or SHUTDOWN. */ |
| 137 | epoch = 1900; | 96 | if (likely(ce->mode == CLOCK_EVT_MODE_PERIODIC)) |
| 138 | if (year < 20) | 97 | ce->event_handler(ce); |
| 139 | epoch = 2000; | ||
| 140 | else if (year >= 20 && year < 48) | ||
| 141 | /* NT epoch */ | ||
| 142 | epoch = 1980; | ||
| 143 | else if (year >= 48 && year < 70) | ||
| 144 | /* Digital UNIX epoch */ | ||
| 145 | epoch = 1952; | ||
| 146 | 98 | ||
| 147 | printk(KERN_INFO "Using epoch = %d\n", epoch); | 99 | if (test_irq_work_pending()) { |
| 100 | clear_irq_work_pending(); | ||
| 101 | irq_work_run(); | ||
| 102 | } | ||
| 148 | 103 | ||
| 149 | if ((year += epoch) < 1970) | 104 | return IRQ_HANDLED; |
| 150 | year += 100; | 105 | } |
| 151 | 106 | ||
| 152 | ts->tv_sec = mktime(year, mon, day, hour, min, sec); | 107 | static void |
| 153 | ts->tv_nsec = 0; | 108 | rtc_ce_set_mode(enum clock_event_mode mode, struct clock_event_device *ce) |
| 109 | { | ||
| 110 | /* The mode member of CE is updated in generic code. | ||
| 111 | Since we only support periodic events, nothing to do. */ | ||
| 112 | } | ||
| 113 | |||
| 114 | static int | ||
| 115 | rtc_ce_set_next_event(unsigned long evt, struct clock_event_device *ce) | ||
| 116 | { | ||
| 117 | /* This hook is for oneshot mode, which we don't support. */ | ||
| 118 | return -EINVAL; | ||
| 154 | } | 119 | } |
| 155 | 120 | ||
| 121 | static void __init | ||
| 122 | init_rtc_clockevent(void) | ||
| 123 | { | ||
| 124 | int cpu = smp_processor_id(); | ||
| 125 | struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); | ||
| 126 | |||
| 127 | *ce = (struct clock_event_device){ | ||
| 128 | .name = "rtc", | ||
| 129 | .features = CLOCK_EVT_FEAT_PERIODIC, | ||
| 130 | .rating = 100, | ||
| 131 | .cpumask = cpumask_of(cpu), | ||
| 132 | .set_mode = rtc_ce_set_mode, | ||
| 133 | .set_next_event = rtc_ce_set_next_event, | ||
| 134 | }; | ||
| 156 | 135 | ||
| 136 | clockevents_config_and_register(ce, CONFIG_HZ, 0, 0); | ||
| 137 | } | ||
| 157 | 138 | ||
| 139 | |||
| 158 | /* | 140 | /* |
| 159 | * timer_interrupt() needs to keep up the real-time clock, | 141 | * The QEMU clock as a clocksource primitive. |
| 160 | * as well as call the "xtime_update()" routine every clocktick | ||
| 161 | */ | 142 | */ |
| 162 | irqreturn_t timer_interrupt(int irq, void *dev) | 143 | |
| 144 | static cycle_t | ||
| 145 | qemu_cs_read(struct clocksource *cs) | ||
| 163 | { | 146 | { |
| 164 | unsigned long delta; | 147 | return qemu_get_vmtime(); |
| 165 | __u32 now; | 148 | } |
| 166 | long nticks; | ||
| 167 | 149 | ||
| 168 | #ifndef CONFIG_SMP | 150 | static struct clocksource qemu_cs = { |
| 169 | /* Not SMP, do kernel PC profiling here. */ | 151 | .name = "qemu", |
| 170 | profile_tick(CPU_PROFILING); | 152 | .rating = 400, |
| 171 | #endif | 153 | .read = qemu_cs_read, |
| 154 | .mask = CLOCKSOURCE_MASK(64), | ||
| 155 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
| 156 | .max_idle_ns = LONG_MAX | ||
| 157 | }; | ||
| 172 | 158 | ||
| 173 | /* | ||
| 174 | * Calculate how many ticks have passed since the last update, | ||
| 175 | * including any previous partial leftover. Save any resulting | ||
| 176 | * fraction for the next pass. | ||
| 177 | */ | ||
| 178 | now = rpcc(); | ||
| 179 | delta = now - state.last_time; | ||
| 180 | state.last_time = now; | ||
| 181 | delta = delta * state.scaled_ticks_per_cycle + state.partial_tick; | ||
| 182 | state.partial_tick = delta & ((1UL << FIX_SHIFT) - 1); | ||
| 183 | nticks = delta >> FIX_SHIFT; | ||
| 184 | 159 | ||
| 185 | if (nticks) | 160 | /* |
| 186 | xtime_update(nticks); | 161 | * The QEMU alarm as a clock_event_device primitive. |
| 162 | */ | ||
| 187 | 163 | ||
| 188 | if (test_irq_work_pending()) { | 164 | static void |
| 189 | clear_irq_work_pending(); | 165 | qemu_ce_set_mode(enum clock_event_mode mode, struct clock_event_device *ce) |
| 190 | irq_work_run(); | 166 | { |
| 191 | } | 167 | /* The mode member of CE is updated for us in generic code. |
| 168 | Just make sure that the event is disabled. */ | ||
| 169 | qemu_set_alarm_abs(0); | ||
| 170 | } | ||
| 192 | 171 | ||
| 193 | #ifndef CONFIG_SMP | 172 | static int |
| 194 | while (nticks--) | 173 | qemu_ce_set_next_event(unsigned long evt, struct clock_event_device *ce) |
| 195 | update_process_times(user_mode(get_irq_regs())); | 174 | { |
| 196 | #endif | 175 | qemu_set_alarm_rel(evt); |
| 176 | return 0; | ||
| 177 | } | ||
| 197 | 178 | ||
| 179 | static irqreturn_t | ||
| 180 | qemu_timer_interrupt(int irq, void *dev) | ||
| 181 | { | ||
| 182 | int cpu = smp_processor_id(); | ||
| 183 | struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); | ||
| 184 | |||
| 185 | ce->event_handler(ce); | ||
| 198 | return IRQ_HANDLED; | 186 | return IRQ_HANDLED; |
| 199 | } | 187 | } |
| 200 | 188 | ||
| 189 | static void __init | ||
| 190 | init_qemu_clockevent(void) | ||
| 191 | { | ||
| 192 | int cpu = smp_processor_id(); | ||
| 193 | struct clock_event_device *ce = &per_cpu(cpu_ce, cpu); | ||
| 194 | |||
| 195 | *ce = (struct clock_event_device){ | ||
| 196 | .name = "qemu", | ||
| 197 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
| 198 | .rating = 400, | ||
| 199 | .cpumask = cpumask_of(cpu), | ||
| 200 | .set_mode = qemu_ce_set_mode, | ||
| 201 | .set_next_event = qemu_ce_set_next_event, | ||
| 202 | }; | ||
| 203 | |||
| 204 | clockevents_config_and_register(ce, NSEC_PER_SEC, 1000, LONG_MAX); | ||
| 205 | } | ||
| 206 | |||
| 207 | |||
| 201 | void __init | 208 | void __init |
| 202 | common_init_rtc(void) | 209 | common_init_rtc(void) |
| 203 | { | 210 | { |
| 204 | unsigned char x; | 211 | unsigned char x, sel = 0; |
| 205 | 212 | ||
| 206 | /* Reset periodic interrupt frequency. */ | 213 | /* Reset periodic interrupt frequency. */ |
| 207 | x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f; | 214 | #if CONFIG_HZ == 1024 || CONFIG_HZ == 1200 |
| 208 | /* Test includes known working values on various platforms | 215 | x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f; |
| 209 | where 0x26 is wrong; we refuse to change those. */ | 216 | /* Test includes known working values on various platforms |
| 210 | if (x != 0x26 && x != 0x25 && x != 0x19 && x != 0x06) { | 217 | where 0x26 is wrong; we refuse to change those. */ |
| 211 | printk("Setting RTC_FREQ to 1024 Hz (%x)\n", x); | 218 | if (x != 0x26 && x != 0x25 && x != 0x19 && x != 0x06) { |
| 212 | CMOS_WRITE(0x26, RTC_FREQ_SELECT); | 219 | sel = RTC_REF_CLCK_32KHZ + 6; |
| 213 | } | 220 | } |
| 221 | #elif CONFIG_HZ == 256 || CONFIG_HZ == 128 || CONFIG_HZ == 64 || CONFIG_HZ == 32 | ||
| 222 | sel = RTC_REF_CLCK_32KHZ + __builtin_ffs(32768 / CONFIG_HZ); | ||
| 223 | #else | ||
| 224 | # error "Unknown HZ from arch/alpha/Kconfig" | ||
| 225 | #endif | ||
| 226 | if (sel) { | ||
| 227 | printk(KERN_INFO "Setting RTC_FREQ to %d Hz (%x)\n", | ||
| 228 | CONFIG_HZ, sel); | ||
| 229 | CMOS_WRITE(sel, RTC_FREQ_SELECT); | ||
| 230 | } | ||
| 214 | 231 | ||
| 215 | /* Turn on periodic interrupts. */ | 232 | /* Turn on periodic interrupts. */ |
| 216 | x = CMOS_READ(RTC_CONTROL); | 233 | x = CMOS_READ(RTC_CONTROL); |
| @@ -233,16 +250,37 @@ common_init_rtc(void) | |||
| 233 | init_rtc_irq(); | 250 | init_rtc_irq(); |
| 234 | } | 251 | } |
| 235 | 252 | ||
| 236 | unsigned int common_get_rtc_time(struct rtc_time *time) | 253 | |
| 237 | { | 254 | #ifndef CONFIG_ALPHA_WTINT |
| 238 | return __get_rtc_time(time); | 255 | /* |
| 239 | } | 256 | * The RPCC as a clocksource primitive. |
| 257 | * | ||
| 258 | * While we have free-running timecounters running on all CPUs, and we make | ||
| 259 | * a half-hearted attempt in init_rtc_rpcc_info to sync the timecounter | ||
| 260 | * with the wall clock, that initialization isn't kept up-to-date across | ||
| 261 | * different time counters in SMP mode. Therefore we can only use this | ||
| 262 | * method when there's only one CPU enabled. | ||
| 263 | * | ||
| 264 | * When using the WTINT PALcall, the RPCC may shift to a lower frequency, | ||
| 265 | * or stop altogether, while waiting for the interrupt. Therefore we cannot | ||
| 266 | * use this method when WTINT is in use. | ||
| 267 | */ | ||
| 240 | 268 | ||
| 241 | int common_set_rtc_time(struct rtc_time *time) | 269 | static cycle_t read_rpcc(struct clocksource *cs) |
| 242 | { | 270 | { |
| 243 | return __set_rtc_time(time); | 271 | return rpcc(); |
| 244 | } | 272 | } |
| 245 | 273 | ||
| 274 | static struct clocksource clocksource_rpcc = { | ||
| 275 | .name = "rpcc", | ||
| 276 | .rating = 300, | ||
| 277 | .read = read_rpcc, | ||
| 278 | .mask = CLOCKSOURCE_MASK(32), | ||
| 279 | .flags = CLOCK_SOURCE_IS_CONTINUOUS | ||
| 280 | }; | ||
| 281 | #endif /* ALPHA_WTINT */ | ||
| 282 | |||
| 283 | |||
| 246 | /* Validate a computed cycle counter result against the known bounds for | 284 | /* Validate a computed cycle counter result against the known bounds for |
| 247 | the given processor core. There's too much brokenness in the way of | 285 | the given processor core. There's too much brokenness in the way of |
| 248 | timing hardware for any one method to work everywhere. :-( | 286 | timing hardware for any one method to work everywhere. :-( |
| @@ -353,33 +391,6 @@ rpcc_after_update_in_progress(void) | |||
| 353 | return rpcc(); | 391 | return rpcc(); |
| 354 | } | 392 | } |
| 355 | 393 | ||
| 356 | #ifndef CONFIG_SMP | ||
| 357 | /* Until and unless we figure out how to get cpu cycle counters | ||
| 358 | in sync and keep them there, we can't use the rpcc. */ | ||
| 359 | static cycle_t read_rpcc(struct clocksource *cs) | ||
| 360 | { | ||
| 361 | cycle_t ret = (cycle_t)rpcc(); | ||
| 362 | return ret; | ||
| 363 | } | ||
| 364 | |||
| 365 | static struct clocksource clocksource_rpcc = { | ||
| 366 | .name = "rpcc", | ||
| 367 | .rating = 300, | ||
| 368 | .read = read_rpcc, | ||
| 369 | .mask = CLOCKSOURCE_MASK(32), | ||
| 370 | .flags = CLOCK_SOURCE_IS_CONTINUOUS | ||
| 371 | }; | ||
| 372 | |||
| 373 | static inline void register_rpcc_clocksource(long cycle_freq) | ||
| 374 | { | ||
| 375 | clocksource_register_hz(&clocksource_rpcc, cycle_freq); | ||
| 376 | } | ||
| 377 | #else /* !CONFIG_SMP */ | ||
| 378 | static inline void register_rpcc_clocksource(long cycle_freq) | ||
| 379 | { | ||
| 380 | } | ||
| 381 | #endif /* !CONFIG_SMP */ | ||
| 382 | |||
| 383 | void __init | 394 | void __init |
| 384 | time_init(void) | 395 | time_init(void) |
| 385 | { | 396 | { |
| @@ -387,6 +398,15 @@ time_init(void) | |||
| 387 | unsigned long cycle_freq, tolerance; | 398 | unsigned long cycle_freq, tolerance; |
| 388 | long diff; | 399 | long diff; |
| 389 | 400 | ||
| 401 | if (alpha_using_qemu) { | ||
| 402 | clocksource_register_hz(&qemu_cs, NSEC_PER_SEC); | ||
| 403 | init_qemu_clockevent(); | ||
| 404 | |||
| 405 | timer_irqaction.handler = qemu_timer_interrupt; | ||
| 406 | init_rtc_irq(); | ||
| 407 | return; | ||
| 408 | } | ||
| 409 | |||
| 390 | /* Calibrate CPU clock -- attempt #1. */ | 410 | /* Calibrate CPU clock -- attempt #1. */ |
| 391 | if (!est_cycle_freq) | 411 | if (!est_cycle_freq) |
| 392 | est_cycle_freq = validate_cc_value(calibrate_cc_with_pit()); | 412 | est_cycle_freq = validate_cc_value(calibrate_cc_with_pit()); |
| @@ -421,100 +441,25 @@ time_init(void) | |||
| 421 | "and unable to estimate a proper value!\n"); | 441 | "and unable to estimate a proper value!\n"); |
| 422 | } | 442 | } |
| 423 | 443 | ||
| 424 | /* From John Bowman <bowman@math.ualberta.ca>: allow the values | 444 | /* See above for restrictions on using clocksource_rpcc. */ |
| 425 | to settle, as the Update-In-Progress bit going low isn't good | 445 | #ifndef CONFIG_ALPHA_WTINT |
| 426 | enough on some hardware. 2ms is our guess; we haven't found | 446 | if (hwrpb->nr_processors == 1) |
| 427 | bogomips yet, but this is close on a 500Mhz box. */ | 447 | clocksource_register_hz(&clocksource_rpcc, cycle_freq); |
| 428 | __delay(1000000); | 448 | #endif |
| 429 | |||
| 430 | |||
| 431 | if (HZ > (1<<16)) { | ||
| 432 | extern void __you_loose (void); | ||
| 433 | __you_loose(); | ||
| 434 | } | ||
| 435 | |||
| 436 | register_rpcc_clocksource(cycle_freq); | ||
| 437 | |||
| 438 | state.last_time = cc1; | ||
| 439 | state.scaled_ticks_per_cycle | ||
| 440 | = ((unsigned long) HZ << FIX_SHIFT) / cycle_freq; | ||
| 441 | state.partial_tick = 0L; | ||
| 442 | 449 | ||
| 443 | /* Startup the timer source. */ | 450 | /* Startup the timer source. */ |
| 444 | alpha_mv.init_rtc(); | 451 | alpha_mv.init_rtc(); |
| 452 | init_rtc_clockevent(); | ||
| 445 | } | 453 | } |
| 446 | 454 | ||
| 447 | /* | 455 | /* Initialize the clock_event_device for secondary cpus. */ |
| 448 | * In order to set the CMOS clock precisely, set_rtc_mmss has to be | 456 | #ifdef CONFIG_SMP |
| 449 | * called 500 ms after the second nowtime has started, because when | 457 | void __init |
| 450 | * nowtime is written into the registers of the CMOS clock, it will | 458 | init_clockevent(void) |
| 451 | * jump to the next second precisely 500 ms later. Check the Motorola | ||
| 452 | * MC146818A or Dallas DS12887 data sheet for details. | ||
| 453 | * | ||
| 454 | * BUG: This routine does not handle hour overflow properly; it just | ||
| 455 | * sets the minutes. Usually you won't notice until after reboot! | ||
| 456 | */ | ||
| 457 | |||
| 458 | |||
| 459 | static int | ||
| 460 | set_rtc_mmss(unsigned long nowtime) | ||
| 461 | { | 459 | { |
| 462 | int retval = 0; | 460 | if (alpha_using_qemu) |
| 463 | int real_seconds, real_minutes, cmos_minutes; | 461 | init_qemu_clockevent(); |
| 464 | unsigned char save_control, save_freq_select; | 462 | else |
| 465 | 463 | init_rtc_clockevent(); | |
| 466 | /* irq are locally disabled here */ | ||
| 467 | spin_lock(&rtc_lock); | ||
| 468 | /* Tell the clock it's being set */ | ||
| 469 | save_control = CMOS_READ(RTC_CONTROL); | ||
| 470 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | ||
| 471 | |||
| 472 | /* Stop and reset prescaler */ | ||
| 473 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | ||
| 474 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | ||
| 475 | |||
| 476 | cmos_minutes = CMOS_READ(RTC_MINUTES); | ||
| 477 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
| 478 | cmos_minutes = bcd2bin(cmos_minutes); | ||
| 479 | |||
| 480 | /* | ||
| 481 | * since we're only adjusting minutes and seconds, | ||
| 482 | * don't interfere with hour overflow. This avoids | ||
| 483 | * messing with unknown time zones but requires your | ||
| 484 | * RTC not to be off by more than 15 minutes | ||
| 485 | */ | ||
| 486 | real_seconds = nowtime % 60; | ||
| 487 | real_minutes = nowtime / 60; | ||
| 488 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) { | ||
| 489 | /* correct for half hour time zone */ | ||
| 490 | real_minutes += 30; | ||
| 491 | } | ||
| 492 | real_minutes %= 60; | ||
| 493 | |||
| 494 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
| 495 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
| 496 | real_seconds = bin2bcd(real_seconds); | ||
| 497 | real_minutes = bin2bcd(real_minutes); | ||
| 498 | } | ||
| 499 | CMOS_WRITE(real_seconds,RTC_SECONDS); | ||
| 500 | CMOS_WRITE(real_minutes,RTC_MINUTES); | ||
| 501 | } else { | ||
| 502 | printk_once(KERN_NOTICE | ||
| 503 | "set_rtc_mmss: can't update from %d to %d\n", | ||
| 504 | cmos_minutes, real_minutes); | ||
| 505 | retval = -1; | ||
| 506 | } | ||
| 507 | |||
| 508 | /* The following flags have to be released exactly in this order, | ||
| 509 | * otherwise the DS12887 (popular MC146818A clone with integrated | ||
| 510 | * battery and quartz) will not reset the oscillator and will not | ||
| 511 | * update precisely 500 ms later. You won't find this mentioned in | ||
| 512 | * the Dallas Semiconductor data sheets, but who believes data | ||
| 513 | * sheets anyway ... -- Markus Kuhn | ||
| 514 | */ | ||
| 515 | CMOS_WRITE(save_control, RTC_CONTROL); | ||
| 516 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | ||
| 517 | spin_unlock(&rtc_lock); | ||
| 518 | |||
| 519 | return retval; | ||
| 520 | } | 464 | } |
| 465 | #endif | ||
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index bd0665cdc840..9c4c189eb22f 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c | |||
| @@ -241,6 +241,21 @@ do_entIF(unsigned long type, struct pt_regs *regs) | |||
| 241 | (const char *)(data[1] | (long)data[2] << 32), | 241 | (const char *)(data[1] | (long)data[2] << 32), |
| 242 | data[0]); | 242 | data[0]); |
| 243 | } | 243 | } |
| 244 | #ifdef CONFIG_ALPHA_WTINT | ||
| 245 | if (type == 4) { | ||
| 246 | /* If CALL_PAL WTINT is totally unsupported by the | ||
| 247 | PALcode, e.g. MILO, "emulate" it by overwriting | ||
| 248 | the insn. */ | ||
| 249 | unsigned int *pinsn | ||
| 250 | = (unsigned int *) regs->pc - 1; | ||
| 251 | if (*pinsn == PAL_wtint) { | ||
| 252 | *pinsn = 0x47e01400; /* mov 0,$0 */ | ||
| 253 | imb(); | ||
| 254 | regs->r0 = 0; | ||
| 255 | return; | ||
| 256 | } | ||
| 257 | } | ||
| 258 | #endif /* ALPHA_WTINT */ | ||
| 244 | die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"), | 259 | die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"), |
| 245 | regs, type, NULL); | 260 | regs, type, NULL); |
| 246 | } | 261 | } |
