[PATCH 2/7] rtc-cmos: abstract locking primitives

From: Marc Zyngier
Date: Fri Apr 25 2014 - 05:36:12 EST


In order to be able to allow some architecture not to provide
the dreaded rtc_lock, define a couple of wrappers for taking/releasing
the lock.

Signed-off-by: Marc Zyngier <marc.zyngier@xxxxxxx>
---
drivers/rtc/rtc-cmos.c | 55 ++++++++++++++++++++++++++++-------------------
include/asm-generic/rtc.h | 27 +++++++++++++++++------
2 files changed, 53 insertions(+), 29 deletions(-)

diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index ae895e8..be2dd17 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -209,6 +209,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char rtc_control;
+ unsigned long flags;

if (!is_valid_irq(cmos->irq))
return -EIO;
@@ -220,7 +221,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
t->time.tm_mday = -1;
t->time.tm_mon = -1;

- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();
t->time.tm_sec = do_cmos_read(RTC_SECONDS_ALARM);
t->time.tm_min = do_cmos_read(RTC_MINUTES_ALARM);
t->time.tm_hour = do_cmos_read(RTC_HOURS_ALARM);
@@ -239,7 +240,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
}

rtc_control = do_cmos_read(RTC_CONTROL);
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
if (((unsigned)t->time.tm_sec) < 0x60)
@@ -327,6 +328,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char mon, mday, hrs, min, sec, rtc_control;
+ unsigned long flags;

if (!is_valid_irq(cmos->irq))
return -EIO;
@@ -347,7 +349,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
sec = (sec < 60) ? bin2bcd(sec) : 0xff;
}

- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();

/* next rtc irq must not be from previous alarm setting */
cmos_irq_disable(cmos, RTC_AIE);
@@ -372,7 +374,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
if (t->enabled)
cmos_irq_enable(cmos, RTC_AIE);

- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

return 0;
}
@@ -433,14 +435,14 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
if (alarm_disable_quirk)
return 0;

- spin_lock_irqsave(&rtc_lock, flags);
+ flags = rtc_cmos_lock();

if (enabled)
cmos_irq_enable(cmos, RTC_AIE);
else
cmos_irq_disable(cmos, RTC_AIE);

- spin_unlock_irqrestore(&rtc_lock, flags);
+ rtc_cmos_unlock(flags);
return 0;
}

@@ -450,11 +452,12 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char rtc_control, valid;
+ unsigned long flags;

- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();
rtc_control = do_cmos_read(RTC_CONTROL);
valid = do_cmos_read(RTC_VALID);
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

/* NOTE: at least ICH6 reports battery status using a different
* (non-RTC) bit; and SQWE is ignored on many current systems.
@@ -507,6 +510,7 @@ cmos_nvram_read(struct file *filp, struct kobject *kobj,
char *buf, loff_t off, size_t count)
{
int retval;
+ unsigned long flags;

if (unlikely(off >= attr->size))
return 0;
@@ -516,7 +520,7 @@ cmos_nvram_read(struct file *filp, struct kobject *kobj,
count = attr->size - off;

off += NVRAM_OFFSET;
- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();
for (retval = 0; count; count--, off++, retval++) {
if (off < 128)
*buf++ = do_cmos_read(off);
@@ -525,7 +529,7 @@ cmos_nvram_read(struct file *filp, struct kobject *kobj,
else
break;
}
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

return retval;
}
@@ -537,6 +541,7 @@ cmos_nvram_write(struct file *filp, struct kobject *kobj,
{
struct cmos_rtc *cmos;
int retval;
+ unsigned long flags;

cmos = dev_get_drvdata(container_of(kobj, struct device, kobj));
if (unlikely(off >= attr->size))
@@ -552,7 +557,7 @@ cmos_nvram_write(struct file *filp, struct kobject *kobj,
* NVRAM to update, updating checksums is also part of its job.
*/
off += NVRAM_OFFSET;
- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();
for (retval = 0; count; count--, off++, retval++) {
/* don't trash RTC registers */
if (off == cmos->day_alrm
@@ -566,7 +571,7 @@ cmos_nvram_write(struct file *filp, struct kobject *kobj,
else
break;
}
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

return retval;
}
@@ -590,8 +595,9 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
{
u8 irqstat;
u8 rtc_control;
+ unsigned long flags;

- spin_lock(&rtc_lock);
+ flags = rtc_cmos_lock();

/* When the HPET interrupt handler calls us, the interrupt
* status is passed as arg1 instead of the irq number. But
@@ -624,7 +630,7 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
hpet_mask_rtc_irq_bit(RTC_AIE);
do_cmos_read(RTC_INTR_FLAGS);
}
- spin_unlock(&rtc_lock);
+ rtc_cmos_unlock(flags);

if (is_intr(irqstat)) {
rtc_update_irq(p, 1, irqstat);
@@ -647,6 +653,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
int retval = 0;
unsigned char rtc_control;
unsigned address_space;
+ unsigned long flags;

/* there can be only one ... */
if (cmos_rtc.dev)
@@ -724,7 +731,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)

rename_region(ports, dev_name(&cmos_rtc.rtc->dev));

- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();

/* force periodic irq to CMOS reset default of 1024Hz;
*
@@ -741,7 +748,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)

rtc_control = do_cmos_read(RTC_CONTROL);

- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

/* FIXME:
* <asm-generic/rtc.h> doesn't know 12-hour mode either.
@@ -808,9 +815,11 @@ cleanup0:

static void cmos_do_shutdown(void)
{
- spin_lock_irq(&rtc_lock);
+ unsigned long flags;
+
+ flags = rtc_cmos_lock();
cmos_irq_disable(&cmos_rtc, RTC_IRQMASK);
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);
}

static void __exit cmos_do_remove(struct device *dev)
@@ -843,9 +852,10 @@ static int cmos_suspend(struct device *dev)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char tmp;
+ unsigned long flags;

/* only the alarm might be a wakeup event source */
- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();
cmos->suspend_ctrl = tmp = do_cmos_read(RTC_CONTROL);
if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
unsigned char mask;
@@ -860,7 +870,7 @@ static int cmos_suspend(struct device *dev)

cmos_checkintr(cmos, tmp);
}
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

if (tmp & RTC_AIE) {
cmos->enabled_wake = 1;
@@ -892,6 +902,7 @@ static int cmos_resume(struct device *dev)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char tmp;
+ unsigned long flags;

if (cmos->enabled_wake) {
if (cmos->wake_off)
@@ -901,7 +912,7 @@ static int cmos_resume(struct device *dev)
cmos->enabled_wake = 0;
}

- spin_lock_irq(&rtc_lock);
+ flags = rtc_cmos_lock();
tmp = cmos->suspend_ctrl;
cmos->suspend_ctrl = 0;
/* re-enable any irqs previously active */
@@ -928,7 +939,7 @@ static int cmos_resume(struct device *dev)
hpet_mask_rtc_irq_bit(RTC_AIE);
} while (mask & RTC_AIE);
}
- spin_unlock_irq(&rtc_lock);
+ rtc_cmos_unlock(flags);

dev_dbg(dev, "resume, ctrl %02x\n", tmp);

diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
index 313438a..1ad3e78 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -37,6 +37,19 @@ static inline void do_cmos_write(u8 val, u8 reg)
{
CMOS_WRITE(val, reg);
}
+
+static inline unsigned long rtc_cmos_lock(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&rtc_lock, flags);
+ return flags;
+}
+
+static inline void rtc_cmos_unlock(unsigned long flags)
+{
+ spin_unlock_irqrestore(&rtc_lock, flags);
+}
+
/*
* Returns true if a clock update is in progress
*/
@@ -45,9 +58,9 @@ static inline unsigned char rtc_is_updating(void)
unsigned char uip;
unsigned long flags;

- spin_lock_irqsave(&rtc_lock, flags);
+ flags = rtc_cmos_lock();
uip = (do_cmos_read(RTC_FREQ_SELECT) & RTC_UIP);
- spin_unlock_irqrestore(&rtc_lock, flags);
+ rtc_cmos_unlock(flags);
return uip;
}

@@ -78,7 +91,7 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time)
* 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.
*/
- spin_lock_irqsave(&rtc_lock, flags);
+ flags = rtc_cmos_lock();
time->tm_sec = do_cmos_read(RTC_SECONDS);
time->tm_min = do_cmos_read(RTC_MINUTES);
time->tm_hour = do_cmos_read(RTC_HOURS);
@@ -89,7 +102,7 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time)
real_year = do_cmos_read(RTC_DEC_YEAR);
#endif
ctrl = do_cmos_read(RTC_CONTROL);
- spin_unlock_irqrestore(&rtc_lock, flags);
+ rtc_cmos_unlock(flags);

if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
@@ -142,7 +155,7 @@ static inline int __set_rtc_time(struct rtc_time *time)
if (yrs > 255) /* They are unsigned */
return -EINVAL;

- spin_lock_irqsave(&rtc_lock, flags);
+ flags = rtc_cmos_lock();
#ifdef CONFIG_MACH_DECSTATION
real_yrs = yrs;
leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
@@ -163,7 +176,7 @@ static inline int __set_rtc_time(struct rtc_time *time)
* whether the chip is in binary mode or not.
*/
if (yrs > 169) {
- spin_unlock_irqrestore(&rtc_lock, flags);
+ rtc_cmos_unlock(flags);
return -EINVAL;
}

@@ -198,7 +211,7 @@ static inline int __set_rtc_time(struct rtc_time *time)
do_cmos_write(save_control, RTC_CONTROL);
do_cmos_write(save_freq_select, RTC_FREQ_SELECT);

- spin_unlock_irqrestore(&rtc_lock, flags);
+ rtc_cmos_unlock(flags);

return 0;
}
--
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/