diff -urN 2.2.15pre13/arch/alpha/kernel/alpha_ksyms.c rtc/arch/alpha/kernel/alpha_ksyms.c --- 2.2.15pre13/arch/alpha/kernel/alpha_ksyms.c Fri Jan 7 18:19:06 2000 +++ rtc/arch/alpha/kernel/alpha_ksyms.c Tue Mar 7 03:18:43 2000 @@ -37,6 +37,7 @@ extern struct hwrpb_struct *hwrpb; extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); +extern spinlock_t rtc_lock; /* these are C runtime functions with special calling conventions: */ extern void __divl (void); @@ -184,6 +185,8 @@ EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); #endif /* __SMP__ */ + +EXPORT_SYMBOL(rtc_lock); /* * The following are special because they're not called diff -urN 2.2.15pre13/arch/alpha/kernel/time.c rtc/arch/alpha/kernel/time.c --- 2.2.15pre13/arch/alpha/kernel/time.c Sun Jan 2 18:26:32 2000 +++ rtc/arch/alpha/kernel/time.c Tue Mar 7 03:18:27 2000 @@ -47,6 +47,7 @@ static int set_rtc_mmss(unsigned long); +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; /* * Shift amount by which scaled_ticks_per_cycle is scaled. Shifting @@ -443,6 +444,8 @@ 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); @@ -492,6 +495,7 @@ */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); return retval; } diff -urN 2.2.15pre13/arch/i386/kernel/i386_ksyms.c rtc/arch/i386/kernel/i386_ksyms.c --- 2.2.15pre13/arch/i386/kernel/i386_ksyms.c Mon Jan 17 16:44:33 2000 +++ rtc/arch/i386/kernel/i386_ksyms.c Tue Mar 7 03:19:01 2000 @@ -20,6 +20,7 @@ extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); +extern spinlock_t rtc_lock; #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE) extern struct drive_info_struct drive_info; @@ -119,3 +120,5 @@ #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); #endif + +EXPORT_SYMBOL(rtc_lock); diff -urN 2.2.15pre13/arch/i386/kernel/time.c rtc/arch/i386/kernel/time.c --- 2.2.15pre13/arch/i386/kernel/time.c Sat Mar 4 18:02:00 2000 +++ rtc/arch/i386/kernel/time.c Tue Mar 7 03:18:27 2000 @@ -78,6 +78,8 @@ extern rwlock_t xtime_lock; +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; + static inline unsigned long do_fast_gettimeoffset(void) { register unsigned long eax asm("ax"); @@ -301,6 +303,8 @@ int real_seconds, real_minutes, cmos_minutes; unsigned char save_control, save_freq_select; + /* gets recalled with irq locally disabled */ + spin_lock(&rtc_lock); save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); @@ -346,6 +350,7 @@ */ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); return retval; } diff -urN 2.2.15pre13/drivers/char/rtc.c rtc/drivers/char/rtc.c --- 2.2.15pre13/drivers/char/rtc.c Sun Jan 2 18:26:37 2000 +++ rtc/drivers/char/rtc.c Tue Mar 7 03:18:27 2000 @@ -113,10 +113,15 @@ unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +extern spinlock_t rtc_lock; + /* * A very tiny interrupt handler. It runs with SA_INTERRUPT set, - * so that there is no possibility of conflicting with the - * set_rtc_mmss() call that happens during some timer interrupts. + * but there is possibility of conflicting with the set_rtc_mmss() + * call (the rtc irq and the timer irq can easily run at the same + * time in two different CPUs). So we need to serializes + * accesses to the chip with the rtc_lock spinlock that each + * architecture should implement in the timer code. * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) */ @@ -131,7 +136,10 @@ rtc_irq_data += 0x100; rtc_irq_data &= ~0xff; + /* runs with irq locally disabled (see SA_INTERRUPT flag). */ + spin_lock(&rtc_lock); rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); + spin_unlock(&rtc_lock); wake_up_interruptible(&rtc_wait); if (rtc_status & RTC_TIMER_ON) @@ -276,8 +284,7 @@ if (sec >= 60) sec = 0xff; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -288,7 +295,7 @@ CMOS_WRITE(hrs, RTC_HOURS_ALARM); CMOS_WRITE(min, RTC_MINUTES_ALARM); CMOS_WRITE(sec, RTC_SECONDS_ALARM); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } @@ -336,12 +343,11 @@ if ((yrs -= epoch) > 255) /* They are unsigned */ return -EINVAL; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { if (yrs > 169) { - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return -EINVAL; } if (yrs >= 100) @@ -370,7 +376,7 @@ CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ @@ -405,12 +411,11 @@ rtc_freq = arg; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0; val |= (16 - tmp); CMOS_WRITE(val, RTC_FREQ_SELECT); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } #ifdef __alpha__ @@ -465,15 +470,14 @@ unsigned char tmp; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); tmp = CMOS_READ(RTC_CONTROL); tmp &= ~RTC_PIE; tmp &= ~RTC_AIE; tmp &= ~RTC_UIE; CMOS_WRITE(tmp, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); if (rtc_status & RTC_TIMER_ON) { rtc_status &= ~RTC_TIMER_ON; @@ -546,11 +550,10 @@ while (jiffies - uip_watchdog < 2*HZ/100) barrier(); - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); year = CMOS_READ(RTC_YEAR); ctrl = CMOS_READ(RTC_CONTROL); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) BCD_TO_BIN(year); /* This should never happen... */ @@ -568,11 +571,10 @@ init_timer(&rtc_irq_timer); rtc_irq_timer.function = rtc_dropped_irq; rtc_wait = NULL; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); /* Initialize periodic freq. to CMOS reset default, which is 1024Hz */ CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); rtc_freq = 1024; return 0; } @@ -596,12 +598,11 @@ printk(KERN_INFO "rtc: lost some interrupts at %ldHz.\n", rtc_freq); mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); rtc_irq_data += ((rtc_freq/HZ)<<8); rtc_irq_data &= ~0xff; rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); } /* @@ -615,11 +616,10 @@ unsigned char batt, ctrl; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); batt = CMOS_READ(RTC_VALID) & RTC_VRT; ctrl = CMOS_READ(RTC_CONTROL); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); p = buf; @@ -690,10 +690,9 @@ unsigned long flags; unsigned char uip; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); return uip; } @@ -723,8 +722,7 @@ * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated * by the RTC when initially set to a non-zero value. */ - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); @@ -732,7 +730,7 @@ rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); rtc_tm->tm_year = CMOS_READ(RTC_YEAR); ctrl = CMOS_READ(RTC_CONTROL); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -763,13 +761,12 @@ * Only the values that we read from the RTC are set. That * means only tm_hour, tm_min, and tm_sec. */ - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM); alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM); alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM); ctrl = CMOS_READ(RTC_CONTROL); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -794,13 +791,12 @@ unsigned char val; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); val = CMOS_READ(RTC_CONTROL); val &= ~bit; CMOS_WRITE(val, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); rtc_irq_data = 0; } @@ -809,12 +805,11 @@ unsigned char val; unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&rtc_lock, flags); val = CMOS_READ(RTC_CONTROL); val |= bit; CMOS_WRITE(val, RTC_CONTROL); CMOS_READ(RTC_INTR_FLAGS); rtc_irq_data = 0; - restore_flags(flags); + spin_unlock_irqrestore(&rtc_lock, flags); }