Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 53c2df2f authored by Atsushi Nemoto's avatar Atsushi Nemoto Committed by Ralf Baechle
Browse files

Use rtc_lock to protect RTC operations


    
Many RTC routines were not protected against each other, so there are
potential races, for example, ntp-update against /dev/rtc.  This patch
fixes them using rtc_lock.
    
Signed-off-by: default avatarAtsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent e329331a
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -41,7 +41,9 @@ rtc_ds1386_get_time(void)
	u8 byte;
	u8 temp;
	unsigned int year, month, day, hour, minute, second;
	unsigned long flags;

	spin_lock_irqsave(&rtc_lock, flags);
	/* let us freeze external registers */
	byte = READ_RTC(0xB);
	byte &= 0x3f;
@@ -60,6 +62,7 @@ rtc_ds1386_get_time(void)
	/* enable time transfer */
	byte |= 0x80;
	WRITE_RTC(0xB, byte);
	spin_unlock_irqrestore(&rtc_lock, flags);

	/* calc hour */
	if (temp & 0x40) {
@@ -81,7 +84,9 @@ rtc_ds1386_set_time(unsigned long t)
	u8 byte;
	u8 temp;
	u8 year, month, day, hour, minute, second;
	unsigned long flags;

	spin_lock_irqsave(&rtc_lock, flags);
	/* let us freeze external registers */
	byte = READ_RTC(0xB);
	byte &= 0x3f;
@@ -133,6 +138,7 @@ rtc_ds1386_set_time(unsigned long t)
	if (second != READ_RTC(0x1)) {
		WRITE_RTC(0x1, second);
	}
	spin_unlock_irqrestore(&rtc_lock, flags);

	return 0;
}
+22 −2
Original line number Diff line number Diff line
@@ -37,10 +37,25 @@
#include <asm/dec/machtype.h>


/*
 * Returns true if a clock update is in progress
 */
static inline unsigned char dec_rtc_is_updating(void)
{
	unsigned char uip;
	unsigned long flags;

	spin_lock_irqsave(&rtc_lock, flags);
	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
	spin_unlock_irqrestore(&rtc_lock, flags);
	return uip;
}

static unsigned long dec_rtc_get_time(void)
{
	unsigned int year, mon, day, hour, min, sec, real_year;
	int i;
	unsigned long flags;

	/* The Linux interpretation of the DS1287 clock register contents:
	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
@@ -49,11 +64,12 @@ static unsigned long dec_rtc_get_time(void)
	 */
	/* read RTC exactly on falling edge of update flag */
	for (i = 0; i < 1000000; i++)	/* may take up to 1 second... */
		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
		if (dec_rtc_is_updating())
			break;
	for (i = 0; i < 1000000; i++)	/* must try at least 2.228 ms */
		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
		if (!dec_rtc_is_updating())
			break;
	spin_lock_irqsave(&rtc_lock, flags);
	/* Isn't this overkill?  UIP above should guarantee consistency */
	do {
		sec = CMOS_READ(RTC_SECONDS);
@@ -77,6 +93,7 @@ static unsigned long dec_rtc_get_time(void)
	 * of unused BBU RAM locations.
	 */
	real_year = CMOS_READ(RTC_DEC_YEAR);
	spin_unlock_irqrestore(&rtc_lock, flags);
	year += real_year - 72 + 2000;

	return mktime(year, mon, day, hour, min, sec);
@@ -95,6 +112,8 @@ static int dec_rtc_set_mmss(unsigned long nowtime)
	int real_seconds, real_minutes, cmos_minutes;
	unsigned char save_control, save_freq_select;

	/* irq are locally disabled here */
	spin_lock(&rtc_lock);
	/* tell the clock it's being set */
	save_control = CMOS_READ(RTC_CONTROL);
	CMOS_WRITE((save_control | RTC_SET), RTC_CONTROL);
@@ -141,6 +160,7 @@ static int dec_rtc_set_mmss(unsigned long nowtime)
	 */
	CMOS_WRITE(save_control, RTC_CONTROL);
	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
	spin_unlock(&rtc_lock);

	return retval;
}
+6 −0
Original line number Diff line number Diff line
@@ -57,7 +57,9 @@ rtc_ds1742_get_time(void)
{
	unsigned int year, month, day, hour, minute, second;
	unsigned int century;
	unsigned long flags;

	spin_lock_irqsave(&rtc_lock, flags);
	CMOS_WRITE(RTC_READ, RTC_CONTROL);
	second = BCD2BIN(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK);
	minute = BCD2BIN(CMOS_READ(RTC_MINUTES));
@@ -67,6 +69,7 @@ rtc_ds1742_get_time(void)
	year = BCD2BIN(CMOS_READ(RTC_YEAR));
	century = BCD2BIN(CMOS_READ(RTC_CENTURY) & RTC_CENTURY_MASK);
	CMOS_WRITE(0, RTC_CONTROL);
	spin_unlock_irqrestore(&rtc_lock, flags);

	year += century * 100;

@@ -81,7 +84,9 @@ rtc_ds1742_set_time(unsigned long t)
	u8 year, month, day, hour, minute, second;
	u8 cmos_year, cmos_month, cmos_day, cmos_hour, cmos_minute, cmos_second;
	int cmos_century;
	unsigned long flags;

	spin_lock_irqsave(&rtc_lock, flags);
	CMOS_WRITE(RTC_READ, RTC_CONTROL);
	cmos_second = (u8)(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK);
	cmos_minute = (u8)CMOS_READ(RTC_MINUTES);
@@ -139,6 +144,7 @@ rtc_ds1742_set_time(unsigned long t)

	/* RTC_CENTURY and RTC_CONTROL share same address... */
	CMOS_WRITE(cmos_century, RTC_CONTROL);
	spin_unlock_irqrestore(&rtc_lock, flags);

	return 0;
}
+9 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <asm/lasat/lasat.h>
#include <linux/delay.h>
#include <asm/lasat/ds1603.h>
#include <asm/time.h>

#include "ds1603.h"

@@ -138,19 +139,27 @@ static void rtc_end_op(void)
unsigned long ds1603_read(void)
{
	unsigned long word;
	unsigned long flags;

	spin_lock_irqsave(&rtc_lock, flags);
	rtc_init_op();
	rtc_write_byte(READ_TIME_CMD);
	word = rtc_read_word();
	rtc_end_op();
	spin_unlock_irqrestore(&rtc_lock, flags);
	return word;
}

int ds1603_set(unsigned long time)
{
	unsigned long flags;

	spin_lock_irqsave(&rtc_lock, flags);
	rtc_init_op();
	rtc_write_byte(SET_TIME_CMD);
	rtc_write_word(time);
	rtc_end_op();
	spin_unlock_irqrestore(&rtc_lock, flags);

	return 0;
}
+6 −0
Original line number Diff line number Diff line
@@ -149,7 +149,9 @@ arch_initcall(per_cpu_mappings);
unsigned long m48t37y_get_time(void)
{
	unsigned int year, month, day, hour, min, sec;
	unsigned long flags;

	spin_lock_irqsave(&rtc_lock, flags);
	/* stop the update */
	rtc_base[0x7ff8] = 0x40;

@@ -166,6 +168,7 @@ unsigned long m48t37y_get_time(void)

	/* start the update */
	rtc_base[0x7ff8] = 0x00;
	spin_unlock_irqrestore(&rtc_lock, flags);

	return mktime(year, month, day, hour, min, sec);
}
@@ -173,11 +176,13 @@ unsigned long m48t37y_get_time(void)
int m48t37y_set_time(unsigned long sec)
{
	struct rtc_time tm;
	unsigned long flags;

	/* convert to a more useful format -- note months count from 0 */
	to_tm(sec, &tm);
	tm.tm_mon += 1;

	spin_lock_irqsave(&rtc_lock, flags);
	/* enable writing */
	rtc_base[0x7ff8] = 0x80;

@@ -201,6 +206,7 @@ int m48t37y_set_time(unsigned long sec)

	/* disable writing */
	rtc_base[0x7ff8] = 0x00;
	spin_unlock_irqrestore(&rtc_lock, flags);

	return 0;
}
Loading