Skip to content

Commit

Permalink
Use rtc_lock to protect RTC operations
Browse files Browse the repository at this point in the history
    
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: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
  • Loading branch information
Atsushi Nemoto authored and Ralf Baechle committed Nov 7, 2005
1 parent e329331 commit 53c2df2
Show file tree
Hide file tree
Showing 13 changed files with 111 additions and 4 deletions.
6 changes: 6 additions & 0 deletions arch/mips/ddb5xxx/common/rtc_ds1386.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
24 changes: 22 additions & 2 deletions arch/mips/dec/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down
6 changes: 6 additions & 0 deletions arch/mips/jmr3927/common/rtc_ds1742.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down
9 changes: 9 additions & 0 deletions arch/mips/lasat/ds1603.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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;
}
Expand Down
6 changes: 6 additions & 0 deletions arch/mips/momentum/jaguar_atx/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -166,18 +168,21 @@ 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);
}

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;

Expand All @@ -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;
}
Expand Down
6 changes: 6 additions & 0 deletions arch/mips/momentum/ocelot_3/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ void setup_wired_tlb_entries(void)
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;

Expand All @@ -152,18 +154,21 @@ 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);
}

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;

Expand All @@ -187,6 +192,7 @@ int m48t37y_set_time(unsigned long sec)

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

return 0;
}
Expand Down
6 changes: 6 additions & 0 deletions arch/mips/momentum/ocelot_c/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ unsigned long m48t37y_get_time(void)
unsigned char* rtc_base = (unsigned char*)0xfc800000;
#endif
unsigned int year, month, day, hour, min, sec;
unsigned long flags;

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

Expand All @@ -157,6 +159,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);
}
Expand All @@ -169,11 +172,13 @@ int m48t37y_set_time(unsigned long sec)
unsigned char* rtc_base = (unsigned char*)0xfc800000;
#endif
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;

Expand All @@ -197,6 +202,7 @@ int m48t37y_set_time(unsigned long sec)

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

return 0;
}
Expand Down
6 changes: 6 additions & 0 deletions arch/mips/pmc-sierra/yosemite/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ void __init bus_error_init(void)
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 to the time */
m48t37_base->control = 0x40;

Expand All @@ -88,18 +90,21 @@ unsigned long m48t37y_get_time(void)

/* Start the update to the time again */
m48t37_base->control = 0x00;
spin_unlock_irqrestore(&rtc_lock, flags);

return mktime(year, month, day, hour, min, sec);
}

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 */
m48t37_base->control = 0x80;

Expand All @@ -123,6 +128,7 @@ int m48t37y_set_time(unsigned long sec)

/* disable writing */
m48t37_base->control = 0x00;
spin_unlock_irqrestore(&rtc_lock, flags);

return 0;
}
Expand Down
6 changes: 6 additions & 0 deletions arch/mips/sgi-ip22/ip22-time.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ static unsigned long indy_rtc_get_time(void)
{
unsigned int yrs, mon, day, hrs, min, sec;
unsigned int save_control;
unsigned long flags;

spin_lock_irqsave(&rtc_lock, flags);
save_control = hpc3c0->rtcregs[RTC_CMD] & 0xff;
hpc3c0->rtcregs[RTC_CMD] = save_control | RTC_TE;

Expand All @@ -47,6 +49,7 @@ static unsigned long indy_rtc_get_time(void)
yrs = BCD2BIN(hpc3c0->rtcregs[RTC_YEAR] & 0xff);

hpc3c0->rtcregs[RTC_CMD] = save_control;
spin_unlock_irqrestore(&rtc_lock, flags);

if (yrs < 45)
yrs += 30;
Expand All @@ -60,6 +63,7 @@ static int indy_rtc_set_time(unsigned long tim)
{
struct rtc_time tm;
unsigned int save_control;
unsigned long flags;

to_tm(tim, &tm);

Expand All @@ -68,6 +72,7 @@ static int indy_rtc_set_time(unsigned long tim)
if (tm.tm_year >= 100)
tm.tm_year -= 100;

spin_lock_irqsave(&rtc_lock, flags);
save_control = hpc3c0->rtcregs[RTC_CMD] & 0xff;
hpc3c0->rtcregs[RTC_CMD] = save_control | RTC_TE;

Expand All @@ -80,6 +85,7 @@ static int indy_rtc_set_time(unsigned long tim)
hpc3c0->rtcregs[RTC_HUNDREDTH_SECOND] = 0;

hpc3c0->rtcregs[RTC_CMD] = save_control;
spin_unlock_irqrestore(&rtc_lock, flags);

return 0;
}
Expand Down
Loading

0 comments on commit 53c2df2

Please sign in to comment.