Commit bcd9b89c authored by David Brownell's avatar David Brownell Committed by Linus Torvalds

[PATCH] rtc-cmos lockdep fix, irq updates

Lockdep reported cmos_suspend() and cmos_resume() calling rtc_update_irq()
with IRQs enabled; not allowed.

Also fix problems seen on some hardware, whereby false alarm IRQs could be
reported (primarily to userspace); and update two comments to match changes
in ACPI.  Those make up most of this patch, by volume.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a2b091db
...@@ -59,6 +59,19 @@ struct cmos_rtc { ...@@ -59,6 +59,19 @@ struct cmos_rtc {
static const char driver_name[] = "rtc_cmos"; static const char driver_name[] = "rtc_cmos";
/* The RTC_INTR register may have e.g. RTC_PF set even if RTC_PIE is clear;
* always mask it against the irq enable bits in RTC_CONTROL. Bit values
* are the same: PF==PIE, AF=AIE, UF=UIE; so RTC_IRQMASK works with both.
*/
#define RTC_IRQMASK (RTC_PF | RTC_AF | RTC_UF)
static inline int is_intr(u8 rtc_intr)
{
if (!(rtc_intr & RTC_IRQF))
return 0;
return rtc_intr & RTC_IRQMASK;
}
/*----------------------------------------------------------------*/ /*----------------------------------------------------------------*/
static int cmos_read_time(struct device *dev, struct rtc_time *t) static int cmos_read_time(struct device *dev, struct rtc_time *t)
...@@ -188,7 +201,8 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) ...@@ -188,7 +201,8 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
rtc_control &= ~RTC_AIE; rtc_control &= ~RTC_AIE;
CMOS_WRITE(rtc_control, RTC_CONTROL); CMOS_WRITE(rtc_control, RTC_CONTROL);
rtc_intr = CMOS_READ(RTC_INTR_FLAGS); rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
if (rtc_intr) rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
if (is_intr(rtc_intr))
rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr); rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
/* update alarm */ /* update alarm */
...@@ -207,7 +221,8 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) ...@@ -207,7 +221,8 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
rtc_control |= RTC_AIE; rtc_control |= RTC_AIE;
CMOS_WRITE(rtc_control, RTC_CONTROL); CMOS_WRITE(rtc_control, RTC_CONTROL);
rtc_intr = CMOS_READ(RTC_INTR_FLAGS); rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
if (rtc_intr) rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
if (is_intr(rtc_intr))
rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr); rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
} }
...@@ -287,7 +302,8 @@ cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) ...@@ -287,7 +302,8 @@ cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
} }
CMOS_WRITE(rtc_control, RTC_CONTROL); CMOS_WRITE(rtc_control, RTC_CONTROL);
rtc_intr = CMOS_READ(RTC_INTR_FLAGS); rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
if (rtc_intr) rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
if (is_intr(rtc_intr))
rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr); rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
spin_unlock_irqrestore(&rtc_lock, flags); spin_unlock_irqrestore(&rtc_lock, flags);
return 0; return 0;
...@@ -353,12 +369,10 @@ static irqreturn_t cmos_interrupt(int irq, void *p) ...@@ -353,12 +369,10 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
spin_lock(&rtc_lock); spin_lock(&rtc_lock);
irqstat = CMOS_READ(RTC_INTR_FLAGS); irqstat = CMOS_READ(RTC_INTR_FLAGS);
irqstat &= (CMOS_READ(RTC_CONTROL) & RTC_IRQMASK) | RTC_IRQF;
spin_unlock(&rtc_lock); spin_unlock(&rtc_lock);
if (irqstat) { if (is_intr(irqstat)) {
/* NOTE: irqstat may have e.g. RTC_PF set
* even when RTC_PIE is clear...
*/
rtc_update_irq(p, 1, irqstat); rtc_update_irq(p, 1, irqstat);
return IRQ_HANDLED; return IRQ_HANDLED;
} else } else
...@@ -525,25 +539,26 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg) ...@@ -525,25 +539,26 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg)
{ {
struct cmos_rtc *cmos = dev_get_drvdata(dev); struct cmos_rtc *cmos = dev_get_drvdata(dev);
int do_wake = device_may_wakeup(dev); int do_wake = device_may_wakeup(dev);
unsigned char tmp, irqstat; unsigned char tmp;
/* only the alarm might be a wakeup event source */ /* only the alarm might be a wakeup event source */
spin_lock_irq(&rtc_lock); spin_lock_irq(&rtc_lock);
cmos->suspend_ctrl = tmp = CMOS_READ(RTC_CONTROL); cmos->suspend_ctrl = tmp = CMOS_READ(RTC_CONTROL);
if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
unsigned char irqstat;
if (do_wake) if (do_wake)
tmp &= ~(RTC_PIE|RTC_UIE); tmp &= ~(RTC_PIE|RTC_UIE);
else else
tmp &= ~(RTC_PIE|RTC_AIE|RTC_UIE); tmp &= ~(RTC_PIE|RTC_AIE|RTC_UIE);
CMOS_WRITE(tmp, RTC_CONTROL); CMOS_WRITE(tmp, RTC_CONTROL);
irqstat = CMOS_READ(RTC_INTR_FLAGS); irqstat = CMOS_READ(RTC_INTR_FLAGS);
} else irqstat &= (tmp & RTC_IRQMASK) | RTC_IRQF;
irqstat = 0; if (is_intr(irqstat))
rtc_update_irq(&cmos->rtc->class_dev, 1, irqstat);
}
spin_unlock_irq(&rtc_lock); spin_unlock_irq(&rtc_lock);
if (irqstat)
rtc_update_irq(&cmos->rtc->class_dev, 1, irqstat);
/* ACPI HOOK: enable ACPI_EVENT_RTC when (tmp & RTC_AIE) /* ACPI HOOK: enable ACPI_EVENT_RTC when (tmp & RTC_AIE)
* ... it'd be best if we could do that under rtc_lock. * ... it'd be best if we could do that under rtc_lock.
*/ */
...@@ -573,9 +588,10 @@ static int cmos_resume(struct device *dev) ...@@ -573,9 +588,10 @@ static int cmos_resume(struct device *dev)
spin_lock_irq(&rtc_lock); spin_lock_irq(&rtc_lock);
CMOS_WRITE(tmp, RTC_CONTROL); CMOS_WRITE(tmp, RTC_CONTROL);
tmp = CMOS_READ(RTC_INTR_FLAGS); tmp = CMOS_READ(RTC_INTR_FLAGS);
spin_unlock_irq(&rtc_lock); tmp &= (cmos->suspend_ctrl & RTC_IRQMASK) | RTC_IRQF;
if (tmp) if (is_intr(tmp))
rtc_update_irq(&cmos->rtc->class_dev, 1, tmp); rtc_update_irq(&cmos->rtc->class_dev, 1, tmp);
spin_unlock_irq(&rtc_lock);
} }
pr_debug("%s: resume, ctrl %02x\n", pr_debug("%s: resume, ctrl %02x\n",
...@@ -594,7 +610,7 @@ static int cmos_resume(struct device *dev) ...@@ -594,7 +610,7 @@ static int cmos_resume(struct device *dev)
/*----------------------------------------------------------------*/ /*----------------------------------------------------------------*/
/* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems, /* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems,
* the device node may alternatively be created as a PNP device. * the device node will always be created as a PNPACPI device.
*/ */
#ifdef CONFIG_PNPACPI #ifdef CONFIG_PNPACPI
...@@ -673,7 +689,7 @@ module_exit(cmos_exit); ...@@ -673,7 +689,7 @@ module_exit(cmos_exit);
/*----------------------------------------------------------------*/ /*----------------------------------------------------------------*/
/* Platform setup should have set up an RTC device, when PNPACPI is /* Platform setup should have set up an RTC device, when PNPACPI is
* unavailable ... this is the normal case, common even on PCs. * unavailable ... this could happen even on (older) PCs.
*/ */
static int __init cmos_platform_probe(struct platform_device *pdev) static int __init cmos_platform_probe(struct platform_device *pdev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment