aboutsummaryrefslogtreecommitdiffstats
path: root/arch/alpha
diff options
context:
space:
mode:
authorIvan Kokshaysky <ink@jurassic.park.msu.ru>2009-01-15 16:51:19 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-15 19:39:40 -0500
commit5f7dc5d75076fd1c1fc6bc09f2467509d20db24a (patch)
treec105f8463607381acd7d02bdda75641b3f497e37 /arch/alpha
parent2f88d151cb8e73587983d7feccd70672ff6730fe (diff)
alpha: fix RTC on marvel
Unlike other alphas, marvel doesn't have real PC-style CMOS clock hardware - RTC accesses are emulated via PAL calls. Unfortunately, for unknown reason these calls work only on CPU #0. So current implementation for arbitrary CPU makes CMOS_READ/WRITE to be executed on CPU #0 via IPI. However, for obvious reason this doesn't work with standard get/set_rtc_time() functions, where a bunch of CMOS accesses is done with disabled interrupts. Solved by making the IPI calls for entire get/set_rtc_time() functions, not for individual CMOS accesses. Which is also a lot more effective performance-wise. The patch is largely based on the code from Jay Estabrook. My changes: - tweak asm-generic/rtc.h by adding a couple of #defines to avoid a massive code duplication in arch/alpha/include/asm/rtc.h; - sys_marvel.c: fix get/set_rtc_time() return values (Jay's FIXMEs). NOTE: this fixes *only* LIB_RTC drivers. Legacy (CONFIG_RTC) driver wont't work on marvel. Actually I think that we should just disable CONFIG_RTC on alpha (maybe in 2.6.30?), like most other arches - AFAIK, all modern distributions use LIB_RTC anyway. Signed-off-by: Ivan Kokshaysky <ink@jurassic.park.msu.ru> Cc: Richard Henderson <rth@twiddle.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/alpha')
-rw-r--r--arch/alpha/include/asm/machvec.h4
-rw-r--r--arch/alpha/include/asm/rtc.h12
-rw-r--r--arch/alpha/kernel/core_marvel.c10
-rw-r--r--arch/alpha/kernel/machvec_impl.h5
-rw-r--r--arch/alpha/kernel/proto.h2
-rw-r--r--arch/alpha/kernel/sys_jensen.c2
-rw-r--r--arch/alpha/kernel/sys_marvel.c56
-rw-r--r--arch/alpha/kernel/time.c10
8 files changed, 87 insertions, 14 deletions
diff --git a/arch/alpha/include/asm/machvec.h b/arch/alpha/include/asm/machvec.h
index a86c083cdf7f..fea4ea75b79d 100644
--- a/arch/alpha/include/asm/machvec.h
+++ b/arch/alpha/include/asm/machvec.h
@@ -21,6 +21,7 @@ struct pci_dev;
21struct pci_ops; 21struct pci_ops;
22struct pci_controller; 22struct pci_controller;
23struct _alpha_agp_info; 23struct _alpha_agp_info;
24struct rtc_time;
24 25
25struct alpha_machine_vector 26struct alpha_machine_vector
26{ 27{
@@ -94,6 +95,9 @@ struct alpha_machine_vector
94 95
95 struct _alpha_agp_info *(*agp_info)(void); 96 struct _alpha_agp_info *(*agp_info)(void);
96 97
98 unsigned int (*rtc_get_time)(struct rtc_time *);
99 int (*rtc_set_time)(struct rtc_time *);
100
97 const char *vector_name; 101 const char *vector_name;
98 102
99 /* NUMA information */ 103 /* NUMA information */
diff --git a/arch/alpha/include/asm/rtc.h b/arch/alpha/include/asm/rtc.h
index 4e854b1333eb..1f7fba671ae6 100644
--- a/arch/alpha/include/asm/rtc.h
+++ b/arch/alpha/include/asm/rtc.h
@@ -1,9 +1,15 @@
1#ifndef _ALPHA_RTC_H 1#ifndef _ALPHA_RTC_H
2#define _ALPHA_RTC_H 2#define _ALPHA_RTC_H
3 3
4/* 4#if defined(CONFIG_ALPHA_GENERIC)
5 * Alpha uses the default access methods for the RTC. 5# define get_rtc_time alpha_mv.rtc_get_time
6 */ 6# define set_rtc_time alpha_mv.rtc_set_time
7#else
8# if defined(CONFIG_ALPHA_MARVEL) && defined(CONFIG_SMP)
9# define get_rtc_time marvel_get_rtc_time
10# define set_rtc_time marvel_set_rtc_time
11# endif
12#endif
7 13
8#include <asm-generic/rtc.h> 14#include <asm-generic/rtc.h>
9 15
diff --git a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c
index 9cd8dca742a7..e302daecbe56 100644
--- a/arch/alpha/kernel/core_marvel.c
+++ b/arch/alpha/kernel/core_marvel.c
@@ -658,16 +658,8 @@ __marvel_rtc_io(u8 b, unsigned long addr, int write)
658 rtc_access.data = bcd2bin(b); 658 rtc_access.data = bcd2bin(b);
659 rtc_access.function = 0x48 + !write; /* GET/PUT_TOY */ 659 rtc_access.function = 0x48 + !write; /* GET/PUT_TOY */
660 660
661#ifdef CONFIG_SMP
662 if (smp_processor_id() != boot_cpuid)
663 smp_call_function_single(boot_cpuid,
664 __marvel_access_rtc,
665 &rtc_access, 1);
666 else
667 __marvel_access_rtc(&rtc_access);
668#else
669 __marvel_access_rtc(&rtc_access); 661 __marvel_access_rtc(&rtc_access);
670#endif 662
671 ret = bin2bcd(rtc_access.data); 663 ret = bin2bcd(rtc_access.data);
672 break; 664 break;
673 665
diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h
index 466c9dff8181..512685f78097 100644
--- a/arch/alpha/kernel/machvec_impl.h
+++ b/arch/alpha/kernel/machvec_impl.h
@@ -40,7 +40,10 @@
40#define CAT1(x,y) x##y 40#define CAT1(x,y) x##y
41#define CAT(x,y) CAT1(x,y) 41#define CAT(x,y) CAT1(x,y)
42 42
43#define DO_DEFAULT_RTC .rtc_port = 0x70 43#define DO_DEFAULT_RTC \
44 .rtc_port = 0x70, \
45 .rtc_get_time = common_get_rtc_time, \
46 .rtc_set_time = common_set_rtc_time
44 47
45#define DO_EV4_MMU \ 48#define DO_EV4_MMU \
46 .max_asn = EV4_MAX_ASN, \ 49 .max_asn = EV4_MAX_ASN, \
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index 708d5ca87782..fe14c6747cd6 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -145,6 +145,8 @@ extern void smp_percpu_timer_interrupt(struct pt_regs *);
145extern irqreturn_t timer_interrupt(int irq, void *dev); 145extern irqreturn_t timer_interrupt(int irq, void *dev);
146extern void common_init_rtc(void); 146extern void common_init_rtc(void);
147extern unsigned long est_cycle_freq; 147extern unsigned long est_cycle_freq;
148extern unsigned int common_get_rtc_time(struct rtc_time *time);
149extern int common_set_rtc_time(struct rtc_time *time);
148 150
149/* smc37c93x.c */ 151/* smc37c93x.c */
150extern void SMC93x_Init(void); 152extern void SMC93x_Init(void);
diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c
index 2c3de97de46c..e2516f9a8967 100644
--- a/arch/alpha/kernel/sys_jensen.c
+++ b/arch/alpha/kernel/sys_jensen.c
@@ -261,6 +261,8 @@ struct alpha_machine_vector jensen_mv __initmv = {
261 .machine_check = jensen_machine_check, 261 .machine_check = jensen_machine_check,
262 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, 262 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
263 .rtc_port = 0x170, 263 .rtc_port = 0x170,
264 .rtc_get_time = common_get_rtc_time,
265 .rtc_set_time = common_set_rtc_time,
264 266
265 .nr_irqs = 16, 267 .nr_irqs = 16,
266 .device_interrupt = jensen_device_interrupt, 268 .device_interrupt = jensen_device_interrupt,
diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c
index 828449cd2636..c5a1a2438c67 100644
--- a/arch/alpha/kernel/sys_marvel.c
+++ b/arch/alpha/kernel/sys_marvel.c
@@ -23,6 +23,7 @@
23#include <asm/hwrpb.h> 23#include <asm/hwrpb.h>
24#include <asm/tlbflush.h> 24#include <asm/tlbflush.h>
25#include <asm/vga.h> 25#include <asm/vga.h>
26#include <asm/rtc.h>
26 27
27#include "proto.h" 28#include "proto.h"
28#include "err_impl.h" 29#include "err_impl.h"
@@ -426,6 +427,57 @@ marvel_init_rtc(void)
426 init_rtc_irq(); 427 init_rtc_irq();
427} 428}
428 429
430struct marvel_rtc_time {
431 struct rtc_time *time;
432 int retval;
433};
434
435#ifdef CONFIG_SMP
436static void
437smp_get_rtc_time(void *data)
438{
439 struct marvel_rtc_time *mrt = data;
440 mrt->retval = __get_rtc_time(mrt->time);
441}
442
443static void
444smp_set_rtc_time(void *data)
445{
446 struct marvel_rtc_time *mrt = data;
447 mrt->retval = __set_rtc_time(mrt->time);
448}
449#endif
450
451static unsigned int
452marvel_get_rtc_time(struct rtc_time *time)
453{
454#ifdef CONFIG_SMP
455 struct marvel_rtc_time mrt;
456
457 if (smp_processor_id() != boot_cpuid) {
458 mrt.time = time;
459 smp_call_function_single(boot_cpuid, smp_get_rtc_time, &mrt, 1);
460 return mrt.retval;
461 }
462#endif
463 return __get_rtc_time(time);
464}
465
466static int
467marvel_set_rtc_time(struct rtc_time *time)
468{
469#ifdef CONFIG_SMP
470 struct marvel_rtc_time mrt;
471
472 if (smp_processor_id() != boot_cpuid) {
473 mrt.time = time;
474 smp_call_function_single(boot_cpuid, smp_set_rtc_time, &mrt, 1);
475 return mrt.retval;
476 }
477#endif
478 return __set_rtc_time(time);
479}
480
429static void 481static void
430marvel_smp_callin(void) 482marvel_smp_callin(void)
431{ 483{
@@ -466,7 +518,9 @@ marvel_smp_callin(void)
466struct alpha_machine_vector marvel_ev7_mv __initmv = { 518struct alpha_machine_vector marvel_ev7_mv __initmv = {
467 .vector_name = "MARVEL/EV7", 519 .vector_name = "MARVEL/EV7",
468 DO_EV7_MMU, 520 DO_EV7_MMU,
469 DO_DEFAULT_RTC, 521 .rtc_port = 0x70,
522 .rtc_get_time = marvel_get_rtc_time,
523 .rtc_set_time = marvel_set_rtc_time,
470 DO_MARVEL_IO, 524 DO_MARVEL_IO,
471 .machine_check = marvel_machine_check, 525 .machine_check = marvel_machine_check,
472 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, 526 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index e6a231435cba..b04e2cbf23a4 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -46,6 +46,7 @@
46#include <asm/io.h> 46#include <asm/io.h>
47#include <asm/hwrpb.h> 47#include <asm/hwrpb.h>
48#include <asm/8253pit.h> 48#include <asm/8253pit.h>
49#include <asm/rtc.h>
49 50
50#include <linux/mc146818rtc.h> 51#include <linux/mc146818rtc.h>
51#include <linux/time.h> 52#include <linux/time.h>
@@ -180,6 +181,15 @@ common_init_rtc(void)
180 init_rtc_irq(); 181 init_rtc_irq();
181} 182}
182 183
184unsigned int common_get_rtc_time(struct rtc_time *time)
185{
186 return __get_rtc_time(time);
187}
188
189int common_set_rtc_time(struct rtc_time *time)
190{
191 return __set_rtc_time(time);
192}
183 193
184/* Validate a computed cycle counter result against the known bounds for 194/* Validate a computed cycle counter result against the known bounds for
185 the given processor core. There's too much brokenness in the way of 195 the given processor core. There's too much brokenness in the way of