diff options
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/arm/mach-bcm/Kconfig | 1 | ||||
| -rw-r--r-- | arch/arm/mach-bcm/board_bcm.c | 7 | ||||
| -rw-r--r-- | arch/s390/include/asm/cpu_mf.h | 1 | ||||
| -rw-r--r-- | arch/um/drivers/chan.h | 2 | ||||
| -rw-r--r-- | arch/um/drivers/chan_kern.c | 4 | ||||
| -rw-r--r-- | arch/um/drivers/chan_user.c | 12 | ||||
| -rw-r--r-- | arch/um/drivers/chan_user.h | 6 | ||||
| -rw-r--r-- | arch/um/drivers/line.c | 42 | ||||
| -rw-r--r-- | arch/um/drivers/net_kern.c | 2 | ||||
| -rw-r--r-- | arch/um/drivers/ssl.c | 1 | ||||
| -rw-r--r-- | arch/um/drivers/stdio_console.c | 1 | ||||
| -rw-r--r-- | arch/um/os-Linux/signal.c | 2 | ||||
| -rw-r--r-- | arch/um/os-Linux/start_up.c | 2 | ||||
| -rw-r--r-- | arch/x86/Kconfig | 1 | ||||
| -rw-r--r-- | arch/x86/include/asm/cpufeature.h | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/intel.c | 12 | ||||
| -rw-r--r-- | arch/x86/kernel/rtc.c | 69 | ||||
| -rw-r--r-- | arch/x86/kernel/tsc.c | 6 | ||||
| -rw-r--r-- | arch/x86/platform/efi/efi.c | 24 | ||||
| -rw-r--r-- | arch/x86/platform/mrst/vrtc.c | 42 | 
20 files changed, 117 insertions, 121 deletions
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index bf02471d7e7..f11289519c3 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -6,6 +6,7 @@ config ARCH_BCM  	select ARM_ERRATA_764369 if SMP  	select ARM_GIC  	select CPU_V7 +	select CLKSRC_OF  	select GENERIC_CLOCKEVENTS  	select GENERIC_TIME  	select GPIO_BCM diff --git a/arch/arm/mach-bcm/board_bcm.c b/arch/arm/mach-bcm/board_bcm.c index f0f9abafad2..25959354047 100644 --- a/arch/arm/mach-bcm/board_bcm.c +++ b/arch/arm/mach-bcm/board_bcm.c @@ -16,14 +16,11 @@  #include <linux/device.h>  #include <linux/platform_device.h>  #include <linux/irqchip.h> +#include <linux/clocksource.h>  #include <asm/mach/arch.h>  #include <asm/mach/time.h> -static void timer_init(void) -{ -} -  static void __init board_init(void)  { @@ -35,7 +32,7 @@ static const char * const bcm11351_dt_compat[] = { "bcm,bcm11351", NULL, };  DT_MACHINE_START(BCM11351_DT, "Broadcom Application Processor")  	.init_irq = irqchip_init, -	.init_time = timer_init, +	.init_time = clocksource_of_init,  	.init_machine = board_init,  	.dt_compat = bcm11351_dt_compat,  MACHINE_END diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index f1eddd150dd..c879fad404c 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -12,6 +12,7 @@  #ifndef _ASM_S390_CPU_MF_H  #define _ASM_S390_CPU_MF_H +#include <linux/errno.h>  #include <asm/facility.h>  #define CPU_MF_INT_SF_IAE	(1 << 31)	/* invalid entry address */ diff --git a/arch/um/drivers/chan.h b/arch/um/drivers/chan.h index 78f1b899996..c512b0306dd 100644 --- a/arch/um/drivers/chan.h +++ b/arch/um/drivers/chan.h @@ -37,7 +37,7 @@ extern int console_write_chan(struct chan *chan, const char *buf,  extern int console_open_chan(struct line *line, struct console *co);  extern void deactivate_chan(struct chan *chan, int irq);  extern void reactivate_chan(struct chan *chan, int irq); -extern void chan_enable_winch(struct chan *chan, struct tty_struct *tty); +extern void chan_enable_winch(struct chan *chan, struct tty_port *port);  extern int enable_chan(struct line *line);  extern void close_chan(struct line *line);  extern int chan_window_size(struct line *line,  diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 15c553c239a..80b47cb71e0 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -122,10 +122,10 @@ static int open_chan(struct list_head *chans)  	return err;  } -void chan_enable_winch(struct chan *chan, struct tty_struct *tty) +void chan_enable_winch(struct chan *chan, struct tty_port *port)  {  	if (chan && chan->primary && chan->ops->winch) -		register_winch(chan->fd, tty); +		register_winch(chan->fd, port);  }  static void line_timer_cb(struct work_struct *work) diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 9be670ad23b..3fd7c3efdb1 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -216,7 +216,7 @@ static int winch_thread(void *arg)  	}  } -static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out, +static int winch_tramp(int fd, struct tty_port *port, int *fd_out,  		       unsigned long *stack_out)  {  	struct winch_data data; @@ -271,7 +271,7 @@ static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out,  	return err;  } -void register_winch(int fd, struct tty_struct *tty) +void register_winch(int fd, struct tty_port *port)  {  	unsigned long stack;  	int pid, thread, count, thread_fd = -1; @@ -281,17 +281,17 @@ void register_winch(int fd, struct tty_struct *tty)  		return;  	pid = tcgetpgrp(fd); -	if (is_skas_winch(pid, fd, tty)) { -		register_winch_irq(-1, fd, -1, tty, 0); +	if (is_skas_winch(pid, fd, port)) { +		register_winch_irq(-1, fd, -1, port, 0);  		return;  	}  	if (pid == -1) { -		thread = winch_tramp(fd, tty, &thread_fd, &stack); +		thread = winch_tramp(fd, port, &thread_fd, &stack);  		if (thread < 0)  			return; -		register_winch_irq(thread_fd, fd, thread, tty, stack); +		register_winch_irq(thread_fd, fd, thread, port, stack);  		count = write(thread_fd, &c, sizeof(c));  		if (count != sizeof(c)) diff --git a/arch/um/drivers/chan_user.h b/arch/um/drivers/chan_user.h index dc693298eb8..03f1b565c5f 100644 --- a/arch/um/drivers/chan_user.h +++ b/arch/um/drivers/chan_user.h @@ -38,10 +38,10 @@ extern int generic_window_size(int fd, void *unused, unsigned short *rows_out,  			       unsigned short *cols_out);  extern void generic_free(void *data); -struct tty_struct; -extern void register_winch(int fd,  struct tty_struct *tty); +struct tty_port; +extern void register_winch(int fd,  struct tty_port *port);  extern void register_winch_irq(int fd, int tty_fd, int pid, -			       struct tty_struct *tty, unsigned long stack); +			       struct tty_port *port, unsigned long stack);  #define __channel_help(fn, prefix) \  __uml_help(fn, prefix "[0-9]*=<channel description>\n" \ diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index f1b38571f94..be541cf69fd 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -305,7 +305,7 @@ static int line_activate(struct tty_port *port, struct tty_struct *tty)  		return ret;  	if (!line->sigio) { -		chan_enable_winch(line->chan_out, tty); +		chan_enable_winch(line->chan_out, port);  		line->sigio = 1;  	} @@ -315,8 +315,22 @@ static int line_activate(struct tty_port *port, struct tty_struct *tty)  	return 0;  } +static void unregister_winch(struct tty_struct *tty); + +static void line_destruct(struct tty_port *port) +{ +	struct tty_struct *tty = tty_port_tty_get(port); +	struct line *line = tty->driver_data; + +	if (line->sigio) { +		unregister_winch(tty); +		line->sigio = 0; +	} +} +  static const struct tty_port_operations line_port_ops = {  	.activate = line_activate, +	.destruct = line_destruct,  };  int line_open(struct tty_struct *tty, struct file *filp) @@ -340,18 +354,6 @@ int line_install(struct tty_driver *driver, struct tty_struct *tty,  	return 0;  } -static void unregister_winch(struct tty_struct *tty); - -void line_cleanup(struct tty_struct *tty) -{ -	struct line *line = tty->driver_data; - -	if (line->sigio) { -		unregister_winch(tty); -		line->sigio = 0; -	} -} -  void line_close(struct tty_struct *tty, struct file * filp)  {  	struct line *line = tty->driver_data; @@ -601,7 +603,7 @@ struct winch {  	int fd;  	int tty_fd;  	int pid; -	struct tty_struct *tty; +	struct tty_port *port;  	unsigned long stack;  	struct work_struct work;  }; @@ -655,7 +657,7 @@ static irqreturn_t winch_interrupt(int irq, void *data)  			goto out;  		}  	} -	tty = winch->tty; +	tty = tty_port_tty_get(winch->port);  	if (tty != NULL) {  		line = tty->driver_data;  		if (line != NULL) { @@ -663,6 +665,7 @@ static irqreturn_t winch_interrupt(int irq, void *data)  					 &tty->winsize.ws_col);  			kill_pgrp(tty->pgrp, SIGWINCH, 1);  		} +		tty_kref_put(tty);  	}   out:  	if (winch->fd != -1) @@ -670,7 +673,7 @@ static irqreturn_t winch_interrupt(int irq, void *data)  	return IRQ_HANDLED;  } -void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty, +void register_winch_irq(int fd, int tty_fd, int pid, struct tty_port *port,  			unsigned long stack)  {  	struct winch *winch; @@ -685,7 +688,7 @@ void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty,  				   .fd  	= fd,  				   .tty_fd 	= tty_fd,  				   .pid  	= pid, -				   .tty 	= tty, +				   .port 	= port,  				   .stack	= stack });  	if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, @@ -714,15 +717,18 @@ static void unregister_winch(struct tty_struct *tty)  {  	struct list_head *ele, *next;  	struct winch *winch; +	struct tty_struct *wtty;  	spin_lock(&winch_handler_lock);  	list_for_each_safe(ele, next, &winch_handlers) {  		winch = list_entry(ele, struct winch, list); -		if (winch->tty == tty) { +		wtty = tty_port_tty_get(winch->port); +		if (wtty == tty) {  			free_winch(winch);  			break;  		} +		tty_kref_put(wtty);  	}  	spin_unlock(&winch_handler_lock);  } diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index d8926c30362..39f186252e0 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -218,6 +218,7 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)  	spin_lock_irqsave(&lp->lock, flags);  	len = (*lp->write)(lp->fd, skb, lp); +	skb_tx_timestamp(skb);  	if (len == skb->len) {  		dev->stats.tx_packets++; @@ -281,6 +282,7 @@ static void uml_net_get_drvinfo(struct net_device *dev,  static const struct ethtool_ops uml_net_ethtool_ops = {  	.get_drvinfo	= uml_net_get_drvinfo,  	.get_link	= ethtool_op_get_link, +	.get_ts_info	= ethtool_op_get_ts_info,  };  static void uml_net_user_timer_expire(unsigned long _conn) diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index 16fdd0a0f9d..b8d14fa5205 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -105,7 +105,6 @@ static const struct tty_operations ssl_ops = {  	.throttle 		= line_throttle,  	.unthrottle 		= line_unthrottle,  	.install		= ssl_install, -	.cleanup		= line_cleanup,  	.hangup			= line_hangup,  }; diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 827777af3f6..7b361f36ca9 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -110,7 +110,6 @@ static const struct tty_operations console_ops = {  	.set_termios 		= line_set_termios,  	.throttle 		= line_throttle,  	.unthrottle 		= line_unthrottle, -	.cleanup		= line_cleanup,  	.hangup			= line_hangup,  }; diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index b1469fe9329..9d9f1b4bf82 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -15,7 +15,7 @@  #include <sysdep/mcontext.h>  #include "internal.h" -void (*sig_info[NSIG])(int, siginfo_t *, struct uml_pt_regs *) = { +void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {  	[SIGTRAP]	= relay_signal,  	[SIGFPE]	= relay_signal,  	[SIGILL]	= relay_signal, diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index da4b9e9999f..337518c5042 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -15,6 +15,8 @@  #include <sys/mman.h>  #include <sys/stat.h>  #include <sys/wait.h> +#include <sys/time.h> +#include <sys/resource.h>  #include <asm/unistd.h>  #include <init.h>  #include <os.h> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index a4f24f5b121..26bd7926153 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -120,6 +120,7 @@ config X86  	select OLD_SIGSUSPEND3 if X86_32 || IA32_EMULATION  	select OLD_SIGACTION if X86_32  	select COMPAT_OLD_SIGACTION if IA32_EMULATION +	select RTC_LIB  config INSTRUCTION_DECODER  	def_bool y diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h index 93fe929d1ce..a8466f203e6 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -100,6 +100,7 @@  #define X86_FEATURE_AMD_DCM     (3*32+27) /* multi-node processor */  #define X86_FEATURE_APERFMPERF	(3*32+28) /* APERFMPERF */  #define X86_FEATURE_EAGER_FPU	(3*32+29) /* "eagerfpu" Non lazy FPU restore */ +#define X86_FEATURE_NONSTOP_TSC_S3 (3*32+30) /* TSC doesn't stop in S3 state */  /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */  #define X86_FEATURE_XMM3	(4*32+ 0) /* "pni" SSE-3 */ diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 1905ce98bee..e7ae0d89e7e 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -96,6 +96,18 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)  			sched_clock_stable = 1;  	} +	/* Penwell and Cloverview have the TSC which doesn't sleep on S3 */ +	if (c->x86 == 6) { +		switch (c->x86_model) { +		case 0x27:	/* Penwell */ +		case 0x35:	/* Cloverview */ +			set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC_S3); +			break; +		default: +			break; +		} +	} +  	/*  	 * There is a known erratum on Pentium III and Core Solo  	 * and Core Duo CPUs. diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index 2e8f3d3b564..198eb201ed3 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c @@ -13,6 +13,7 @@  #include <asm/x86_init.h>  #include <asm/time.h>  #include <asm/mrst.h> +#include <asm/rtc.h>  #ifdef CONFIG_X86_32  /* @@ -36,70 +37,24 @@ EXPORT_SYMBOL(rtc_lock);   * 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'll only notice that after reboot!   */  int mach_set_rtc_mmss(unsigned long nowtime)  { -	int real_seconds, real_minutes, cmos_minutes; -	unsigned char save_control, save_freq_select; -	unsigned long flags; +	struct rtc_time tm;  	int retval = 0; -	spin_lock_irqsave(&rtc_lock, flags); - -	 /* 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; -	/* correct for half hour time zone */ -	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) -		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); +	rtc_time_to_tm(nowtime, &tm); +	if (!rtc_valid_tm(&tm)) { +		retval = set_rtc_time(&tm); +		if (retval) +			printk(KERN_ERR "%s: RTC write failed with error %d\n", +			       __FUNCTION__, retval);  	} else { -		printk_once(KERN_NOTICE -		       "set_rtc_mmss: can't update from %d to %d\n", -		       cmos_minutes, real_minutes); -		retval = -1; +		printk(KERN_ERR +		       "%s: Invalid RTC value: write of %lx to RTC failed\n", +			__FUNCTION__, nowtime); +		retval = -EINVAL;  	} - -	/* 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_irqrestore(&rtc_lock, flags); -  	return retval;  } diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 4b9ea101fe3..098b3cfda72 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -768,7 +768,8 @@ static cycle_t read_tsc(struct clocksource *cs)  static void resume_tsc(struct clocksource *cs)  { -	clocksource_tsc.cycle_last = 0; +	if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC_S3)) +		clocksource_tsc.cycle_last = 0;  }  static struct clocksource clocksource_tsc = { @@ -939,6 +940,9 @@ static int __init init_tsc_clocksource(void)  		clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;  	} +	if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC_S3)) +		clocksource_tsc.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP; +  	/*  	 * Trust the results of the earlier calibration on systems  	 * exporting a reliable TSC. diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 5f2ecaf3f9d..28d9efacc9b 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -48,6 +48,7 @@  #include <asm/cacheflush.h>  #include <asm/tlbflush.h>  #include <asm/x86_init.h> +#include <asm/rtc.h>  #define EFI_DEBUG	1 @@ -258,10 +259,10 @@ static efi_status_t __init phys_efi_get_time(efi_time_t *tm,  int efi_set_rtc_mmss(unsigned long nowtime)  { -	int real_seconds, real_minutes;  	efi_status_t 	status;  	efi_time_t 	eft;  	efi_time_cap_t 	cap; +	struct rtc_time	tm;  	status = efi.get_time(&eft, &cap);  	if (status != EFI_SUCCESS) { @@ -269,13 +270,20 @@ int efi_set_rtc_mmss(unsigned long nowtime)  		return -1;  	} -	real_seconds = nowtime % 60; -	real_minutes = nowtime / 60; -	if (((abs(real_minutes - eft.minute) + 15)/30) & 1) -		real_minutes += 30; -	real_minutes %= 60; -	eft.minute = real_minutes; -	eft.second = real_seconds; +	rtc_time_to_tm(nowtime, &tm); +	if (!rtc_valid_tm(&tm)) { +		eft.year = tm.tm_year + 1900; +		eft.month = tm.tm_mon + 1; +		eft.day = tm.tm_mday; +		eft.minute = tm.tm_min; +		eft.second = tm.tm_sec; +		eft.nanosecond = 0; +	} else { +		printk(KERN_ERR +		       "%s: Invalid EFI RTC value: write of %lx to EFI RTC failed\n", +		       __FUNCTION__, nowtime); +		return -1; +	}  	status = efi.set_time(&eft);  	if (status != EFI_SUCCESS) { diff --git a/arch/x86/platform/mrst/vrtc.c b/arch/x86/platform/mrst/vrtc.c index 225bd0f0f67..d62b0a3b5c1 100644 --- a/arch/x86/platform/mrst/vrtc.c +++ b/arch/x86/platform/mrst/vrtc.c @@ -85,27 +85,35 @@ unsigned long vrtc_get_time(void)  	return mktime(year, mon, mday, hour, min, sec);  } -/* Only care about the minutes and seconds */  int vrtc_set_mmss(unsigned long nowtime)  { -	int real_sec, real_min;  	unsigned long flags; -	int vrtc_min; +	struct rtc_time tm; +	int year; +	int retval = 0; -	spin_lock_irqsave(&rtc_lock, flags); -	vrtc_min = vrtc_cmos_read(RTC_MINUTES); - -	real_sec = nowtime % 60; -	real_min = nowtime / 60; -	if (((abs(real_min - vrtc_min) + 15)/30) & 1) -		real_min += 30; -	real_min %= 60; - -	vrtc_cmos_write(real_sec, RTC_SECONDS); -	vrtc_cmos_write(real_min, RTC_MINUTES); -	spin_unlock_irqrestore(&rtc_lock, flags); - -	return 0; +	rtc_time_to_tm(nowtime, &tm); +	if (!rtc_valid_tm(&tm) && tm.tm_year >= 72) { +		/* +		 * tm.year is the number of years since 1900, and the +		 * vrtc need the years since 1972. +		 */ +		year = tm.tm_year - 72; +		spin_lock_irqsave(&rtc_lock, flags); +		vrtc_cmos_write(year, RTC_YEAR); +		vrtc_cmos_write(tm.tm_mon, RTC_MONTH); +		vrtc_cmos_write(tm.tm_mday, RTC_DAY_OF_MONTH); +		vrtc_cmos_write(tm.tm_hour, RTC_HOURS); +		vrtc_cmos_write(tm.tm_min, RTC_MINUTES); +		vrtc_cmos_write(tm.tm_sec, RTC_SECONDS); +		spin_unlock_irqrestore(&rtc_lock, flags); +	} else { +		printk(KERN_ERR +		       "%s: Invalid vRTC value: write of %lx to vRTC failed\n", +			__FUNCTION__, nowtime); +		retval = -EINVAL; +	} +	return retval;  }  void __init mrst_rtc_init(void)  |