Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Ivan Kokshaysky and committed by
Linus Torvalds
5f7dc5d7 2f88d151

+98 -17
+4
arch/alpha/include/asm/machvec.h
··· 21 21 struct pci_ops; 22 22 struct pci_controller; 23 23 struct _alpha_agp_info; 24 + struct rtc_time; 24 25 25 26 struct alpha_machine_vector 26 27 { ··· 94 93 struct pci_ops *pci_ops; 95 94 96 95 struct _alpha_agp_info *(*agp_info)(void); 96 + 97 + unsigned int (*rtc_get_time)(struct rtc_time *); 98 + int (*rtc_set_time)(struct rtc_time *); 97 99 98 100 const char *vector_name; 99 101
+9 -3
arch/alpha/include/asm/rtc.h
··· 1 1 #ifndef _ALPHA_RTC_H 2 2 #define _ALPHA_RTC_H 3 3 4 - /* 5 - * Alpha uses the default access methods for the RTC. 6 - */ 4 + #if defined(CONFIG_ALPHA_GENERIC) 5 + # define get_rtc_time alpha_mv.rtc_get_time 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 14 #include <asm-generic/rtc.h> 9 15
+1 -9
arch/alpha/kernel/core_marvel.c
··· 658 658 rtc_access.data = bcd2bin(b); 659 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 661 __marvel_access_rtc(&rtc_access); 670 - #endif 662 + 671 663 ret = bin2bcd(rtc_access.data); 672 664 break; 673 665
+4 -1
arch/alpha/kernel/machvec_impl.h
··· 40 40 #define CAT1(x,y) x##y 41 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 48 #define DO_EV4_MMU \ 46 49 .max_asn = EV4_MAX_ASN, \
+2
arch/alpha/kernel/proto.h
··· 145 145 extern irqreturn_t timer_interrupt(int irq, void *dev); 146 146 extern void common_init_rtc(void); 147 147 extern unsigned long est_cycle_freq; 148 + extern unsigned int common_get_rtc_time(struct rtc_time *time); 149 + extern int common_set_rtc_time(struct rtc_time *time); 148 150 149 151 /* smc37c93x.c */ 150 152 extern void SMC93x_Init(void);
+2
arch/alpha/kernel/sys_jensen.c
··· 261 261 .machine_check = jensen_machine_check, 262 262 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, 263 263 .rtc_port = 0x170, 264 + .rtc_get_time = common_get_rtc_time, 265 + .rtc_set_time = common_set_rtc_time, 264 266 265 267 .nr_irqs = 16, 266 268 .device_interrupt = jensen_device_interrupt,
+55 -1
arch/alpha/kernel/sys_marvel.c
··· 23 23 #include <asm/hwrpb.h> 24 24 #include <asm/tlbflush.h> 25 25 #include <asm/vga.h> 26 + #include <asm/rtc.h> 26 27 27 28 #include "proto.h" 28 29 #include "err_impl.h" ··· 427 426 init_rtc_irq(); 428 427 } 429 428 429 + struct marvel_rtc_time { 430 + struct rtc_time *time; 431 + int retval; 432 + }; 433 + 434 + #ifdef CONFIG_SMP 435 + static void 436 + smp_get_rtc_time(void *data) 437 + { 438 + struct marvel_rtc_time *mrt = data; 439 + mrt->retval = __get_rtc_time(mrt->time); 440 + } 441 + 442 + static void 443 + smp_set_rtc_time(void *data) 444 + { 445 + struct marvel_rtc_time *mrt = data; 446 + mrt->retval = __set_rtc_time(mrt->time); 447 + } 448 + #endif 449 + 450 + static unsigned int 451 + marvel_get_rtc_time(struct rtc_time *time) 452 + { 453 + #ifdef CONFIG_SMP 454 + struct marvel_rtc_time mrt; 455 + 456 + if (smp_processor_id() != boot_cpuid) { 457 + mrt.time = time; 458 + smp_call_function_single(boot_cpuid, smp_get_rtc_time, &mrt, 1); 459 + return mrt.retval; 460 + } 461 + #endif 462 + return __get_rtc_time(time); 463 + } 464 + 465 + static int 466 + marvel_set_rtc_time(struct rtc_time *time) 467 + { 468 + #ifdef CONFIG_SMP 469 + struct marvel_rtc_time mrt; 470 + 471 + if (smp_processor_id() != boot_cpuid) { 472 + mrt.time = time; 473 + smp_call_function_single(boot_cpuid, smp_set_rtc_time, &mrt, 1); 474 + return mrt.retval; 475 + } 476 + #endif 477 + return __set_rtc_time(time); 478 + } 479 + 430 480 static void 431 481 marvel_smp_callin(void) 432 482 { ··· 518 466 struct alpha_machine_vector marvel_ev7_mv __initmv = { 519 467 .vector_name = "MARVEL/EV7", 520 468 DO_EV7_MMU, 521 - DO_DEFAULT_RTC, 469 + .rtc_port = 0x70, 470 + .rtc_get_time = marvel_get_rtc_time, 471 + .rtc_set_time = marvel_set_rtc_time, 522 472 DO_MARVEL_IO, 523 473 .machine_check = marvel_machine_check, 524 474 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
+10
arch/alpha/kernel/time.c
··· 46 46 #include <asm/io.h> 47 47 #include <asm/hwrpb.h> 48 48 #include <asm/8253pit.h> 49 + #include <asm/rtc.h> 49 50 50 51 #include <linux/mc146818rtc.h> 51 52 #include <linux/time.h> ··· 181 180 init_rtc_irq(); 182 181 } 183 182 183 + unsigned int common_get_rtc_time(struct rtc_time *time) 184 + { 185 + return __get_rtc_time(time); 186 + } 187 + 188 + int common_set_rtc_time(struct rtc_time *time) 189 + { 190 + return __set_rtc_time(time); 191 + } 184 192 185 193 /* Validate a computed cycle counter result against the known bounds for 186 194 the given processor core. There's too much brokenness in the way of
+11 -3
include/asm-generic/rtc.h
··· 42 42 return uip; 43 43 } 44 44 45 - static inline unsigned int get_rtc_time(struct rtc_time *time) 45 + static inline unsigned int __get_rtc_time(struct rtc_time *time) 46 46 { 47 47 unsigned char ctrl; 48 48 unsigned long flags; ··· 108 108 return RTC_24H; 109 109 } 110 110 111 + #ifndef get_rtc_time 112 + #define get_rtc_time __get_rtc_time 113 + #endif 114 + 111 115 /* Set the current date and time in the real time clock. */ 112 - static inline int set_rtc_time(struct rtc_time *time) 116 + static inline int __set_rtc_time(struct rtc_time *time) 113 117 { 114 118 unsigned long flags; 115 119 unsigned char mon, day, hrs, min, sec; ··· 194 190 return 0; 195 191 } 196 192 193 + #ifndef set_rtc_time 194 + #define set_rtc_time __set_rtc_time 195 + #endif 196 + 197 197 static inline unsigned int get_rtc_ss(void) 198 198 { 199 199 struct rtc_time h; 200 200 201 - get_rtc_time(&h); 201 + __get_rtc_time(&h); 202 202 return h.tm_sec; 203 203 } 204 204