#ifdef RTC_IRQ
 static void rtc_dropped_irq(unsigned long data);
 
-static void set_rtc_irq_bit(unsigned char bit);
-static void mask_rtc_irq_bit(unsigned char bit);
+static void set_rtc_irq_bit_locked(unsigned char bit);
+static void mask_rtc_irq_bit_locked(unsigned char bit);
+
+static inline void set_rtc_irq_bit(unsigned char bit)
+{
+       spin_lock_irq(&rtc_lock);
+       set_rtc_irq_bit_locked(bit);
+       spin_unlock_irq(&rtc_lock);
+}
+
+static void mask_rtc_irq_bit(unsigned char bit)
+{
+       spin_lock_irq(&rtc_lock);
+       mask_rtc_irq_bit_locked(bit);
+       spin_unlock_irq(&rtc_lock);
+}
 #endif
 
 static int rtc_proc_open(struct inode *inode, struct file *file);
        }
        case RTC_PIE_OFF:       /* Mask periodic int. enab. bit */
        {
-               mask_rtc_irq_bit(RTC_PIE);
+               unsigned long flags; /* can be called from isr via rtc_control() */
+               spin_lock_irqsave (&rtc_lock, flags);
+               mask_rtc_irq_bit_locked(RTC_PIE);
                if (rtc_status & RTC_TIMER_ON) {
-                       spin_lock_irq (&rtc_lock);
                        rtc_status &= ~RTC_TIMER_ON;
                        del_timer(&rtc_irq_timer);
-                       spin_unlock_irq (&rtc_lock);
                }
+               spin_unlock_irqrestore (&rtc_lock, flags);
                return 0;
        }
        case RTC_PIE_ON:        /* Allow periodic ints          */
        {
-
+               unsigned long flags; /* can be called from isr via rtc_control() */
                /*
                 * We don't really want Joe User enabling more
                 * than 64Hz of interrupts on a multi-user machine.
                        (!capable(CAP_SYS_RESOURCE)))
                        return -EACCES;
 
+               spin_lock_irqsave (&rtc_lock, flags);
                if (!(rtc_status & RTC_TIMER_ON)) {
-                       spin_lock_irq (&rtc_lock);
                        rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
                        add_timer(&rtc_irq_timer);
                        rtc_status |= RTC_TIMER_ON;
-                       spin_unlock_irq (&rtc_lock);
                }
-               set_rtc_irq_bit(RTC_PIE);
+               set_rtc_irq_bit_locked(RTC_PIE);
+               spin_unlock_irqrestore (&rtc_lock, flags);
                return 0;
        }
        case RTC_UIE_OFF:       /* Mask ints from RTC updates.  */
        {
                int tmp = 0;
                unsigned char val;
+               unsigned long flags; /* can be called from isr via rtc_control() */
 
                /* 
                 * The max we can do is 8192Hz.
                if (arg != (1<<tmp))
                        return -EINVAL;
 
-               spin_lock_irq(&rtc_lock);
+               spin_lock_irqsave(&rtc_lock, flags);
                if (hpet_set_periodic_freq(arg)) {
-                       spin_unlock_irq(&rtc_lock);
+                       spin_unlock_irqrestore(&rtc_lock, flags);
                        return 0;
                }
                rtc_freq = arg;
                val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
                val |= (16 - tmp);
                CMOS_WRITE(val, RTC_FREQ_SELECT);
-               spin_unlock_irq(&rtc_lock);
+               spin_unlock_irqrestore(&rtc_lock, flags);
                return 0;
        }
 #endif
 #ifndef RTC_IRQ
        return -EIO;
 #else
-       spin_lock_irq(&rtc_task_lock);
+       unsigned long flags;
+       if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET)
+               return -EINVAL;
+       spin_lock_irqsave(&rtc_task_lock, flags);
        if (rtc_callback != task) {
-               spin_unlock_irq(&rtc_task_lock);
+               spin_unlock_irqrestore(&rtc_task_lock, flags);
                return -ENXIO;
        }
-       spin_unlock_irq(&rtc_task_lock);
+       spin_unlock_irqrestore(&rtc_task_lock, flags);
        return rtc_do_ioctl(cmd, arg, 1);
 #endif
 }
  * meddles with the interrupt enable/disable bits.
  */
 
-static void mask_rtc_irq_bit(unsigned char bit)
+static void mask_rtc_irq_bit_locked(unsigned char bit)
 {
        unsigned char val;
 
-       spin_lock_irq(&rtc_lock);
-       if (hpet_mask_rtc_irq_bit(bit)) {
-               spin_unlock_irq(&rtc_lock);
+       if (hpet_mask_rtc_irq_bit(bit))
                return;
-       }
        val = CMOS_READ(RTC_CONTROL);
        val &=  ~bit;
        CMOS_WRITE(val, RTC_CONTROL);
        CMOS_READ(RTC_INTR_FLAGS);
 
        rtc_irq_data = 0;
-       spin_unlock_irq(&rtc_lock);
 }
 
-static void set_rtc_irq_bit(unsigned char bit)
+static void set_rtc_irq_bit_locked(unsigned char bit)
 {
        unsigned char val;
 
-       spin_lock_irq(&rtc_lock);
-       if (hpet_set_rtc_irq_bit(bit)) {
-               spin_unlock_irq(&rtc_lock);
+       if (hpet_set_rtc_irq_bit(bit))
                return;
-       }
        val = CMOS_READ(RTC_CONTROL);
        val |= bit;
        CMOS_WRITE(val, RTC_CONTROL);
        CMOS_READ(RTC_INTR_FLAGS);
 
        rtc_irq_data = 0;
-       spin_unlock_irq(&rtc_lock);
 }
 #endif