|
@@ -149,8 +149,22 @@ static void get_rtc_alm_time (struct rtc_time *alm_tm);
|
|
#ifdef RTC_IRQ
|
|
#ifdef RTC_IRQ
|
|
static void rtc_dropped_irq(unsigned long data);
|
|
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
|
|
#endif
|
|
|
|
|
|
static int rtc_proc_open(struct inode *inode, struct file *file);
|
|
static int rtc_proc_open(struct inode *inode, struct file *file);
|
|
@@ -401,18 +415,19 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
}
|
|
}
|
|
case RTC_PIE_OFF: /* Mask periodic int. enab. bit */
|
|
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) {
|
|
if (rtc_status & RTC_TIMER_ON) {
|
|
- spin_lock_irq (&rtc_lock);
|
|
|
|
rtc_status &= ~RTC_TIMER_ON;
|
|
rtc_status &= ~RTC_TIMER_ON;
|
|
del_timer(&rtc_irq_timer);
|
|
del_timer(&rtc_irq_timer);
|
|
- spin_unlock_irq (&rtc_lock);
|
|
|
|
}
|
|
}
|
|
|
|
+ spin_unlock_irqrestore (&rtc_lock, flags);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
case RTC_PIE_ON: /* Allow periodic ints */
|
|
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
|
|
* We don't really want Joe User enabling more
|
|
* than 64Hz of interrupts on a multi-user machine.
|
|
* than 64Hz of interrupts on a multi-user machine.
|
|
@@ -421,14 +436,14 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
(!capable(CAP_SYS_RESOURCE)))
|
|
(!capable(CAP_SYS_RESOURCE)))
|
|
return -EACCES;
|
|
return -EACCES;
|
|
|
|
|
|
|
|
+ spin_lock_irqsave (&rtc_lock, flags);
|
|
if (!(rtc_status & RTC_TIMER_ON)) {
|
|
if (!(rtc_status & RTC_TIMER_ON)) {
|
|
- spin_lock_irq (&rtc_lock);
|
|
|
|
rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
|
|
rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
|
|
add_timer(&rtc_irq_timer);
|
|
add_timer(&rtc_irq_timer);
|
|
rtc_status |= RTC_TIMER_ON;
|
|
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;
|
|
return 0;
|
|
}
|
|
}
|
|
case RTC_UIE_OFF: /* Mask ints from RTC updates. */
|
|
case RTC_UIE_OFF: /* Mask ints from RTC updates. */
|
|
@@ -609,6 +624,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
{
|
|
{
|
|
int tmp = 0;
|
|
int tmp = 0;
|
|
unsigned char val;
|
|
unsigned char val;
|
|
|
|
+ unsigned long flags; /* can be called from isr via rtc_control() */
|
|
|
|
|
|
/*
|
|
/*
|
|
* The max we can do is 8192Hz.
|
|
* The max we can do is 8192Hz.
|
|
@@ -631,9 +647,9 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
if (arg != (1<<tmp))
|
|
if (arg != (1<<tmp))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- spin_lock_irq(&rtc_lock);
|
|
|
|
|
|
+ spin_lock_irqsave(&rtc_lock, flags);
|
|
if (hpet_set_periodic_freq(arg)) {
|
|
if (hpet_set_periodic_freq(arg)) {
|
|
- spin_unlock_irq(&rtc_lock);
|
|
|
|
|
|
+ spin_unlock_irqrestore(&rtc_lock, flags);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
rtc_freq = arg;
|
|
rtc_freq = arg;
|
|
@@ -641,7 +657,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
|
val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
|
|
val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
|
|
val |= (16 - tmp);
|
|
val |= (16 - tmp);
|
|
CMOS_WRITE(val, RTC_FREQ_SELECT);
|
|
CMOS_WRITE(val, RTC_FREQ_SELECT);
|
|
- spin_unlock_irq(&rtc_lock);
|
|
|
|
|
|
+ spin_unlock_irqrestore(&rtc_lock, flags);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
@@ -844,12 +860,15 @@ int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
|
|
#ifndef RTC_IRQ
|
|
#ifndef RTC_IRQ
|
|
return -EIO;
|
|
return -EIO;
|
|
#else
|
|
#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) {
|
|
if (rtc_callback != task) {
|
|
- spin_unlock_irq(&rtc_task_lock);
|
|
|
|
|
|
+ spin_unlock_irqrestore(&rtc_task_lock, flags);
|
|
return -ENXIO;
|
|
return -ENXIO;
|
|
}
|
|
}
|
|
- spin_unlock_irq(&rtc_task_lock);
|
|
|
|
|
|
+ spin_unlock_irqrestore(&rtc_task_lock, flags);
|
|
return rtc_do_ioctl(cmd, arg, 1);
|
|
return rtc_do_ioctl(cmd, arg, 1);
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
@@ -1306,40 +1325,32 @@ static void get_rtc_alm_time(struct rtc_time *alm_tm)
|
|
* meddles with the interrupt enable/disable bits.
|
|
* 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;
|
|
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;
|
|
return;
|
|
- }
|
|
|
|
val = CMOS_READ(RTC_CONTROL);
|
|
val = CMOS_READ(RTC_CONTROL);
|
|
val &= ~bit;
|
|
val &= ~bit;
|
|
CMOS_WRITE(val, RTC_CONTROL);
|
|
CMOS_WRITE(val, RTC_CONTROL);
|
|
CMOS_READ(RTC_INTR_FLAGS);
|
|
CMOS_READ(RTC_INTR_FLAGS);
|
|
|
|
|
|
rtc_irq_data = 0;
|
|
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;
|
|
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;
|
|
return;
|
|
- }
|
|
|
|
val = CMOS_READ(RTC_CONTROL);
|
|
val = CMOS_READ(RTC_CONTROL);
|
|
val |= bit;
|
|
val |= bit;
|
|
CMOS_WRITE(val, RTC_CONTROL);
|
|
CMOS_WRITE(val, RTC_CONTROL);
|
|
CMOS_READ(RTC_INTR_FLAGS);
|
|
CMOS_READ(RTC_INTR_FLAGS);
|
|
|
|
|
|
rtc_irq_data = 0;
|
|
rtc_irq_data = 0;
|
|
- spin_unlock_irq(&rtc_lock);
|
|
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|