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>
This commit is contained in:
parent
2f88d151cb
commit
5f7dc5d750
|
@ -21,6 +21,7 @@ struct pci_dev;
|
||||||
struct pci_ops;
|
struct pci_ops;
|
||||||
struct pci_controller;
|
struct pci_controller;
|
||||||
struct _alpha_agp_info;
|
struct _alpha_agp_info;
|
||||||
|
struct rtc_time;
|
||||||
|
|
||||||
struct alpha_machine_vector
|
struct alpha_machine_vector
|
||||||
{
|
{
|
||||||
|
@ -94,6 +95,9 @@ struct alpha_machine_vector
|
||||||
|
|
||||||
struct _alpha_agp_info *(*agp_info)(void);
|
struct _alpha_agp_info *(*agp_info)(void);
|
||||||
|
|
||||||
|
unsigned int (*rtc_get_time)(struct rtc_time *);
|
||||||
|
int (*rtc_set_time)(struct rtc_time *);
|
||||||
|
|
||||||
const char *vector_name;
|
const char *vector_name;
|
||||||
|
|
||||||
/* NUMA information */
|
/* NUMA information */
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
#ifndef _ALPHA_RTC_H
|
#ifndef _ALPHA_RTC_H
|
||||||
#define _ALPHA_RTC_H
|
#define _ALPHA_RTC_H
|
||||||
|
|
||||||
/*
|
#if defined(CONFIG_ALPHA_GENERIC)
|
||||||
* Alpha uses the default access methods for the RTC.
|
# define get_rtc_time alpha_mv.rtc_get_time
|
||||||
*/
|
# define set_rtc_time alpha_mv.rtc_set_time
|
||||||
|
#else
|
||||||
|
# if defined(CONFIG_ALPHA_MARVEL) && defined(CONFIG_SMP)
|
||||||
|
# define get_rtc_time marvel_get_rtc_time
|
||||||
|
# define set_rtc_time marvel_set_rtc_time
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <asm-generic/rtc.h>
|
#include <asm-generic/rtc.h>
|
||||||
|
|
||||||
|
|
|
@ -658,16 +658,8 @@ __marvel_rtc_io(u8 b, unsigned long addr, int write)
|
||||||
rtc_access.data = bcd2bin(b);
|
rtc_access.data = bcd2bin(b);
|
||||||
rtc_access.function = 0x48 + !write; /* GET/PUT_TOY */
|
rtc_access.function = 0x48 + !write; /* GET/PUT_TOY */
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
|
||||||
if (smp_processor_id() != boot_cpuid)
|
|
||||||
smp_call_function_single(boot_cpuid,
|
|
||||||
__marvel_access_rtc,
|
|
||||||
&rtc_access, 1);
|
|
||||||
else
|
|
||||||
__marvel_access_rtc(&rtc_access);
|
|
||||||
#else
|
|
||||||
__marvel_access_rtc(&rtc_access);
|
__marvel_access_rtc(&rtc_access);
|
||||||
#endif
|
|
||||||
ret = bin2bcd(rtc_access.data);
|
ret = bin2bcd(rtc_access.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,10 @@
|
||||||
#define CAT1(x,y) x##y
|
#define CAT1(x,y) x##y
|
||||||
#define CAT(x,y) CAT1(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 \
|
#define DO_EV4_MMU \
|
||||||
.max_asn = EV4_MAX_ASN, \
|
.max_asn = EV4_MAX_ASN, \
|
||||||
|
|
|
@ -145,6 +145,8 @@ extern void smp_percpu_timer_interrupt(struct pt_regs *);
|
||||||
extern irqreturn_t timer_interrupt(int irq, void *dev);
|
extern irqreturn_t timer_interrupt(int irq, void *dev);
|
||||||
extern void common_init_rtc(void);
|
extern void common_init_rtc(void);
|
||||||
extern unsigned long est_cycle_freq;
|
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 */
|
/* smc37c93x.c */
|
||||||
extern void SMC93x_Init(void);
|
extern void SMC93x_Init(void);
|
||||||
|
|
|
@ -261,6 +261,8 @@ struct alpha_machine_vector jensen_mv __initmv = {
|
||||||
.machine_check = jensen_machine_check,
|
.machine_check = jensen_machine_check,
|
||||||
.max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
|
.max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
|
||||||
.rtc_port = 0x170,
|
.rtc_port = 0x170,
|
||||||
|
.rtc_get_time = common_get_rtc_time,
|
||||||
|
.rtc_set_time = common_set_rtc_time,
|
||||||
|
|
||||||
.nr_irqs = 16,
|
.nr_irqs = 16,
|
||||||
.device_interrupt = jensen_device_interrupt,
|
.device_interrupt = jensen_device_interrupt,
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <asm/hwrpb.h>
|
#include <asm/hwrpb.h>
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
#include <asm/vga.h>
|
#include <asm/vga.h>
|
||||||
|
#include <asm/rtc.h>
|
||||||
|
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "err_impl.h"
|
#include "err_impl.h"
|
||||||
|
@ -426,6 +427,57 @@ marvel_init_rtc(void)
|
||||||
init_rtc_irq();
|
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
|
static void
|
||||||
marvel_smp_callin(void)
|
marvel_smp_callin(void)
|
||||||
{
|
{
|
||||||
|
@ -466,7 +518,9 @@ marvel_smp_callin(void)
|
||||||
struct alpha_machine_vector marvel_ev7_mv __initmv = {
|
struct alpha_machine_vector marvel_ev7_mv __initmv = {
|
||||||
.vector_name = "MARVEL/EV7",
|
.vector_name = "MARVEL/EV7",
|
||||||
DO_EV7_MMU,
|
DO_EV7_MMU,
|
||||||
DO_DEFAULT_RTC,
|
.rtc_port = 0x70,
|
||||||
|
.rtc_get_time = marvel_get_rtc_time,
|
||||||
|
.rtc_set_time = marvel_set_rtc_time,
|
||||||
DO_MARVEL_IO,
|
DO_MARVEL_IO,
|
||||||
.machine_check = marvel_machine_check,
|
.machine_check = marvel_machine_check,
|
||||||
.max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
|
.max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS,
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/hwrpb.h>
|
#include <asm/hwrpb.h>
|
||||||
#include <asm/8253pit.h>
|
#include <asm/8253pit.h>
|
||||||
|
#include <asm/rtc.h>
|
||||||
|
|
||||||
#include <linux/mc146818rtc.h>
|
#include <linux/mc146818rtc.h>
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
|
@ -180,6 +181,15 @@ common_init_rtc(void)
|
||||||
init_rtc_irq();
|
init_rtc_irq();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int common_get_rtc_time(struct rtc_time *time)
|
||||||
|
{
|
||||||
|
return __get_rtc_time(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
/* Validate a computed cycle counter result against the known bounds for
|
||||||
the given processor core. There's too much brokenness in the way of
|
the given processor core. There's too much brokenness in the way of
|
||||||
|
|
|
@ -42,7 +42,7 @@ static inline unsigned char rtc_is_updating(void)
|
||||||
return uip;
|
return uip;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned int get_rtc_time(struct rtc_time *time)
|
static inline unsigned int __get_rtc_time(struct rtc_time *time)
|
||||||
{
|
{
|
||||||
unsigned char ctrl;
|
unsigned char ctrl;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -108,8 +108,12 @@ static inline unsigned int get_rtc_time(struct rtc_time *time)
|
||||||
return RTC_24H;
|
return RTC_24H;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef get_rtc_time
|
||||||
|
#define get_rtc_time __get_rtc_time
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Set the current date and time in the real time clock. */
|
/* Set the current date and time in the real time clock. */
|
||||||
static inline int set_rtc_time(struct rtc_time *time)
|
static inline int __set_rtc_time(struct rtc_time *time)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned char mon, day, hrs, min, sec;
|
unsigned char mon, day, hrs, min, sec;
|
||||||
|
@ -190,11 +194,15 @@ static inline int set_rtc_time(struct rtc_time *time)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef set_rtc_time
|
||||||
|
#define set_rtc_time __set_rtc_time
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline unsigned int get_rtc_ss(void)
|
static inline unsigned int get_rtc_ss(void)
|
||||||
{
|
{
|
||||||
struct rtc_time h;
|
struct rtc_time h;
|
||||||
|
|
||||||
get_rtc_time(&h);
|
__get_rtc_time(&h);
|
||||||
return h.tm_sec;
|
return h.tm_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue