public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] rtc-cmos: private locking and MMIO support
@ 2014-04-25  9:31 Marc Zyngier
  2014-04-25  9:31 ` [PATCH 1/7] rtc-cmos: abstract IO accessors Marc Zyngier
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Marc Zyngier @ 2014-04-25  9:31 UTC (permalink / raw)
  To: linux-kernel, rtc-linux
  Cc: Russell King, Will Deacon, Catalin Marinas, Alessandro Zummo

The original PC-style CMOS RTC driver is so weird and full of hacks
that it has reached the status of a major piece of art.

Despite noticeable efforts to carry on with the spirit of tainting
every architecture under the sun, this patch series tries to make the
rtc-cmos driver a slightly better citizen by allowing architecture
code *not* to provide an exported lock when it is not strictly
required, and to allow for MMIO accessors on architectures that don't
have IO ports.

Please have a bucket ready.

The actual goal of the exercise is to allow the use of the RTC
emulation provided by kvmtool in KVM/ARM guests. This series has also
been tested on x86.

Marc Zyngier (7):
  rtc-cmos: abstract IO accessors
  rtc-cmos: abstract locking primitives
  rtc-cmos: allow MMIO to be used when initialized from FDT
  rtc-cmos: allow strictly MMIO based configurations
  rtc-cmos: implement driver private locking
  ARM: rtc: update CMOS RTC to support MMIO and private lock
  arm64: rtc: plug the PC CMOS RTC using MMIO accessors

 arch/arm/kernel/time.c               |   7 --
 arch/arm64/include/asm/mc146818rtc.h |  10 ++
 drivers/rtc/Kconfig                  |  15 ++-
 drivers/rtc/rtc-cmos.c               | 217 +++++++++++++++++++++++++----------
 include/asm-generic/rtc.h            |  92 ++++++++++-----
 5 files changed, 240 insertions(+), 101 deletions(-)
 create mode 100644 arch/arm64/include/asm/mc146818rtc.h

-- 
1.8.3.4


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/7] rtc-cmos: abstract IO accessors
  2014-04-25  9:31 [PATCH 0/7] rtc-cmos: private locking and MMIO support Marc Zyngier
@ 2014-04-25  9:31 ` Marc Zyngier
  2014-04-25  9:31 ` [PATCH 2/7] rtc-cmos: abstract locking primitives Marc Zyngier
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Marc Zyngier @ 2014-04-25  9:31 UTC (permalink / raw)
  To: linux-kernel, rtc-linux
  Cc: Russell King, Will Deacon, Catalin Marinas, Alessandro Zummo

Currently, rtc-cmos mandates the use of an I/O port, defined in an
architecture dependant way. This prevents the easy integration of
a platform that doesn't have the simple notion of an IO port.

Add wrappers around the CMOS_READ/CMOS_WRITE accessors, in order
to isolate the driver code from the vintage macros.

No feature is added.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/rtc/rtc-cmos.c    | 72 +++++++++++++++++++++++++----------------------
 include/asm-generic/rtc.h | 57 +++++++++++++++++++++----------------
 2 files changed, 72 insertions(+), 57 deletions(-)

diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 0963c93..ae895e8 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -221,24 +221,24 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
 	t->time.tm_mon = -1;
 
 	spin_lock_irq(&rtc_lock);
-	t->time.tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
-	t->time.tm_min = CMOS_READ(RTC_MINUTES_ALARM);
-	t->time.tm_hour = CMOS_READ(RTC_HOURS_ALARM);
+	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);
 
 	if (cmos->day_alrm) {
 		/* ignore upper bits on readback per ACPI spec */
-		t->time.tm_mday = CMOS_READ(cmos->day_alrm) & 0x3f;
+		t->time.tm_mday = do_cmos_read(cmos->day_alrm) & 0x3f;
 		if (!t->time.tm_mday)
 			t->time.tm_mday = -1;
 
 		if (cmos->mon_alrm) {
-			t->time.tm_mon = CMOS_READ(cmos->mon_alrm);
+			t->time.tm_mon = do_cmos_read(cmos->mon_alrm);
 			if (!t->time.tm_mon)
 				t->time.tm_mon = -1;
 		}
 	}
 
-	rtc_control = CMOS_READ(RTC_CONTROL);
+	rtc_control = do_cmos_read(RTC_CONTROL);
 	spin_unlock_irq(&rtc_lock);
 
 	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
@@ -284,7 +284,7 @@ static void cmos_checkintr(struct cmos_rtc *cmos, unsigned char rtc_control)
 	/* NOTE after changing RTC_xIE bits we always read INTR_FLAGS;
 	 * allegedly some older rtcs need that to handle irqs properly
 	 */
-	rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
+	rtc_intr = do_cmos_read(RTC_INTR_FLAGS);
 
 	if (is_hpet_enabled())
 		return;
@@ -301,11 +301,11 @@ static void cmos_irq_enable(struct cmos_rtc *cmos, unsigned char mask)
 	/* flush any pending IRQ status, notably for update irqs,
 	 * before we enable new IRQs
 	 */
-	rtc_control = CMOS_READ(RTC_CONTROL);
+	rtc_control = do_cmos_read(RTC_CONTROL);
 	cmos_checkintr(cmos, rtc_control);
 
 	rtc_control |= mask;
-	CMOS_WRITE(rtc_control, RTC_CONTROL);
+	do_cmos_write(rtc_control, RTC_CONTROL);
 	hpet_set_rtc_irq_bit(mask);
 
 	cmos_checkintr(cmos, rtc_control);
@@ -315,9 +315,9 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
 {
 	unsigned char	rtc_control;
 
-	rtc_control = CMOS_READ(RTC_CONTROL);
+	rtc_control = do_cmos_read(RTC_CONTROL);
 	rtc_control &= ~mask;
-	CMOS_WRITE(rtc_control, RTC_CONTROL);
+	do_cmos_write(rtc_control, RTC_CONTROL);
 	hpet_mask_rtc_irq_bit(mask);
 
 	cmos_checkintr(cmos, rtc_control);
@@ -337,7 +337,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 	min = t->time.tm_min;
 	sec = t->time.tm_sec;
 
-	rtc_control = CMOS_READ(RTC_CONTROL);
+	rtc_control = do_cmos_read(RTC_CONTROL);
 	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
 		/* Writing 0xff means "don't care" or "match all".  */
 		mon = (mon <= 12) ? bin2bcd(mon) : 0xff;
@@ -353,15 +353,15 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 	cmos_irq_disable(cmos, RTC_AIE);
 
 	/* update alarm */
-	CMOS_WRITE(hrs, RTC_HOURS_ALARM);
-	CMOS_WRITE(min, RTC_MINUTES_ALARM);
-	CMOS_WRITE(sec, RTC_SECONDS_ALARM);
+	do_cmos_write(hrs, RTC_HOURS_ALARM);
+	do_cmos_write(min, RTC_MINUTES_ALARM);
+	do_cmos_write(sec, RTC_SECONDS_ALARM);
 
 	/* the system may support an "enhanced" alarm */
 	if (cmos->day_alrm) {
-		CMOS_WRITE(mday, cmos->day_alrm);
+		do_cmos_write(mday, cmos->day_alrm);
 		if (cmos->mon_alrm)
-			CMOS_WRITE(mon, cmos->mon_alrm);
+			do_cmos_write(mon, cmos->mon_alrm);
 	}
 
 	/* FIXME the HPET alarm glue currently ignores day_alrm
@@ -452,8 +452,8 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)
 	unsigned char	rtc_control, valid;
 
 	spin_lock_irq(&rtc_lock);
-	rtc_control = CMOS_READ(RTC_CONTROL);
-	valid = CMOS_READ(RTC_VALID);
+	rtc_control = do_cmos_read(RTC_CONTROL);
+	valid = do_cmos_read(RTC_VALID);
 	spin_unlock_irq(&rtc_lock);
 
 	/* NOTE:  at least ICH6 reports battery status using a different
@@ -519,7 +519,7 @@ cmos_nvram_read(struct file *filp, struct kobject *kobj,
 	spin_lock_irq(&rtc_lock);
 	for (retval = 0; count; count--, off++, retval++) {
 		if (off < 128)
-			*buf++ = CMOS_READ(off);
+			*buf++ = do_cmos_read(off);
 		else if (can_bank2)
 			*buf++ = cmos_read_bank2(off);
 		else
@@ -560,7 +560,7 @@ cmos_nvram_write(struct file *filp, struct kobject *kobj,
 				|| off == cmos->century)
 			buf++;
 		else if (off < 128)
-			CMOS_WRITE(*buf++, off);
+			do_cmos_write(*buf++, off);
 		else if (can_bank2)
 			cmos_write_bank2(*buf++, off);
 		else
@@ -600,8 +600,8 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
 	 * Note that HPET and RTC are almost certainly out of phase,
 	 * giving different IRQ status ...
 	 */
-	irqstat = CMOS_READ(RTC_INTR_FLAGS);
-	rtc_control = CMOS_READ(RTC_CONTROL);
+	irqstat = do_cmos_read(RTC_INTR_FLAGS);
+	rtc_control = do_cmos_read(RTC_CONTROL);
 	if (is_hpet_enabled())
 		irqstat = (unsigned long)irq & 0xF0;
 
@@ -620,9 +620,9 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
 	if (irqstat & RTC_AIE) {
 		cmos_rtc.suspend_ctrl &= ~RTC_AIE;
 		rtc_control &= ~RTC_AIE;
-		CMOS_WRITE(rtc_control, RTC_CONTROL);
+		do_cmos_write(rtc_control, RTC_CONTROL);
 		hpet_mask_rtc_irq_bit(RTC_AIE);
-		CMOS_READ(RTC_INTR_FLAGS);
+		do_cmos_read(RTC_INTR_FLAGS);
 	}
 	spin_unlock(&rtc_lock);
 
@@ -734,12 +734,12 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 	 */
 	cmos_rtc.rtc->irq_freq = 1024;
 	hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq);
-	CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
+	do_cmos_write(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
 
 	/* disable irqs */
 	cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE);
 
-	rtc_control = CMOS_READ(RTC_CONTROL);
+	rtc_control = do_cmos_read(RTC_CONTROL);
 
 	spin_unlock_irq(&rtc_lock);
 
@@ -846,7 +846,7 @@ static int cmos_suspend(struct device *dev)
 
 	/* only the alarm might be a wakeup event source */
 	spin_lock_irq(&rtc_lock);
-	cmos->suspend_ctrl = tmp = CMOS_READ(RTC_CONTROL);
+	cmos->suspend_ctrl = tmp = do_cmos_read(RTC_CONTROL);
 	if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
 		unsigned char	mask;
 
@@ -855,7 +855,7 @@ static int cmos_suspend(struct device *dev)
 		else
 			mask = RTC_IRQMASK;
 		tmp &= ~mask;
-		CMOS_WRITE(tmp, RTC_CONTROL);
+		do_cmos_write(tmp, RTC_CONTROL);
 		hpet_mask_rtc_irq_bit(mask);
 
 		cmos_checkintr(cmos, tmp);
@@ -912,10 +912,10 @@ static int cmos_resume(struct device *dev)
 			hpet_rtc_timer_init();
 
 		do {
-			CMOS_WRITE(tmp, RTC_CONTROL);
+			do_cmos_write(tmp, RTC_CONTROL);
 			hpet_set_rtc_irq_bit(tmp & RTC_IRQMASK);
 
-			mask = CMOS_READ(RTC_INTR_FLAGS);
+			mask = do_cmos_read(RTC_INTR_FLAGS);
 			mask &= (tmp & RTC_IRQMASK) | RTC_IRQF;
 			if (!is_hpet_enabled() || !is_intr(mask))
 				break;
@@ -1114,13 +1114,19 @@ static __init void cmos_of_init(struct platform_device *pdev)
 	if (!node)
 		return;
 
+	/*
+	 * Try to map an MMIO region first. If it fails, we'll
+	 * fallback on I/O access.
+	 */
+	rtc_cmos_set_base(of_iomap(node, 0));
+
 	val = of_get_property(node, "ctrl-reg", NULL);
 	if (val)
-		CMOS_WRITE(be32_to_cpup(val), RTC_CONTROL);
+		do_cmos_write(be32_to_cpup(val), RTC_CONTROL);
 
 	val = of_get_property(node, "freq-reg", NULL);
 	if (val)
-		CMOS_WRITE(be32_to_cpup(val), RTC_FREQ_SELECT);
+		do_cmos_write(be32_to_cpup(val), RTC_FREQ_SELECT);
 
 	get_rtc_time(&time);
 	ret = rtc_valid_tm(&time);
diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
index fa86f24..313438a 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -28,6 +28,15 @@
 #define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
 #define RTC_DST_EN 0x01	        /* auto switch DST - works f. USA only */
 
+static inline u8 do_cmos_read(u8 reg)
+{
+	return CMOS_READ(reg);
+}
+
+static inline void do_cmos_write(u8 val, u8 reg)
+{
+	CMOS_WRITE(val, reg);
+}
 /*
  * Returns true if a clock update is in progress
  */
@@ -37,7 +46,7 @@ static inline unsigned char rtc_is_updating(void)
 	unsigned long flags;
 
 	spin_lock_irqsave(&rtc_lock, flags);
-	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+	uip = (do_cmos_read(RTC_FREQ_SELECT) & RTC_UIP);
 	spin_unlock_irqrestore(&rtc_lock, flags);
 	return uip;
 }
@@ -70,16 +79,16 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time)
 	 * by the RTC when initially set to a non-zero value.
 	 */
 	spin_lock_irqsave(&rtc_lock, flags);
-	time->tm_sec = CMOS_READ(RTC_SECONDS);
-	time->tm_min = CMOS_READ(RTC_MINUTES);
-	time->tm_hour = CMOS_READ(RTC_HOURS);
-	time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
-	time->tm_mon = CMOS_READ(RTC_MONTH);
-	time->tm_year = CMOS_READ(RTC_YEAR);
+	time->tm_sec = do_cmos_read(RTC_SECONDS);
+	time->tm_min = do_cmos_read(RTC_MINUTES);
+	time->tm_hour = do_cmos_read(RTC_HOURS);
+	time->tm_mday = do_cmos_read(RTC_DAY_OF_MONTH);
+	time->tm_mon = do_cmos_read(RTC_MONTH);
+	time->tm_year = do_cmos_read(RTC_YEAR);
 #ifdef CONFIG_MACH_DECSTATION
-	real_year = CMOS_READ(RTC_DEC_YEAR);
+	real_year = do_cmos_read(RTC_DEC_YEAR);
 #endif
-	ctrl = CMOS_READ(RTC_CONTROL);
+	ctrl = do_cmos_read(RTC_CONTROL);
 	spin_unlock_irqrestore(&rtc_lock, flags);
 
 	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
@@ -161,7 +170,7 @@ static inline int __set_rtc_time(struct rtc_time *time)
 	if (yrs >= 100)
 		yrs -= 100;
 
-	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
+	if (!(do_cmos_read(RTC_CONTROL) & RTC_DM_BINARY)
 	    || RTC_ALWAYS_BCD) {
 		sec = bin2bcd(sec);
 		min = bin2bcd(min);
@@ -171,23 +180,23 @@ static inline int __set_rtc_time(struct rtc_time *time)
 		yrs = bin2bcd(yrs);
 	}
 
-	save_control = CMOS_READ(RTC_CONTROL);
-	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
-	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+	save_control = do_cmos_read(RTC_CONTROL);
+	do_cmos_write((save_control|RTC_SET), RTC_CONTROL);
+	save_freq_select = do_cmos_read(RTC_FREQ_SELECT);
+	do_cmos_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
 
 #ifdef CONFIG_MACH_DECSTATION
-	CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
+	do_cmos_write(real_yrs, RTC_DEC_YEAR);
 #endif
-	CMOS_WRITE(yrs, RTC_YEAR);
-	CMOS_WRITE(mon, RTC_MONTH);
-	CMOS_WRITE(day, RTC_DAY_OF_MONTH);
-	CMOS_WRITE(hrs, RTC_HOURS);
-	CMOS_WRITE(min, RTC_MINUTES);
-	CMOS_WRITE(sec, RTC_SECONDS);
-
-	CMOS_WRITE(save_control, RTC_CONTROL);
-	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+	do_cmos_write(yrs, RTC_YEAR);
+	do_cmos_write(mon, RTC_MONTH);
+	do_cmos_write(day, RTC_DAY_OF_MONTH);
+	do_cmos_write(hrs, RTC_HOURS);
+	do_cmos_write(min, RTC_MINUTES);
+	do_cmos_write(sec, RTC_SECONDS);
+
+	do_cmos_write(save_control, RTC_CONTROL);
+	do_cmos_write(save_freq_select, RTC_FREQ_SELECT);
 
 	spin_unlock_irqrestore(&rtc_lock, flags);
 
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/7] rtc-cmos: abstract locking primitives
  2014-04-25  9:31 [PATCH 0/7] rtc-cmos: private locking and MMIO support Marc Zyngier
  2014-04-25  9:31 ` [PATCH 1/7] rtc-cmos: abstract IO accessors Marc Zyngier
@ 2014-04-25  9:31 ` Marc Zyngier
  2014-04-25  9:31 ` [PATCH 3/7] rtc-cmos: allow MMIO to be used when initialized from FDT Marc Zyngier
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Marc Zyngier @ 2014-04-25  9:31 UTC (permalink / raw)
  To: linux-kernel, rtc-linux
  Cc: Russell King, Will Deacon, Catalin Marinas, Alessandro Zummo

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@arm.com>
---
 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


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/7] rtc-cmos: allow MMIO to be used when initialized from FDT
  2014-04-25  9:31 [PATCH 0/7] rtc-cmos: private locking and MMIO support Marc Zyngier
  2014-04-25  9:31 ` [PATCH 1/7] rtc-cmos: abstract IO accessors Marc Zyngier
  2014-04-25  9:31 ` [PATCH 2/7] rtc-cmos: abstract locking primitives Marc Zyngier
@ 2014-04-25  9:31 ` Marc Zyngier
  2014-04-25  9:31 ` [PATCH 4/7] rtc-cmos: allow strictly MMIO based configurations Marc Zyngier
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Marc Zyngier @ 2014-04-25  9:31 UTC (permalink / raw)
  To: linux-kernel, rtc-linux
  Cc: Russell King, Will Deacon, Catalin Marinas, Alessandro Zummo

Currently, rtc-cmos mandates the use of an I/O port. If the
resource obtained from the device tree is instead a memory mapped
range, the probing will fail.

Let the cmos_of_init function try to ioremap the range obtained
from FDT. Should this fail, fallback to the normal I/O port.

Tested on KVM/ARM with kvmtools as the backend for RTC emulation.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/rtc/Kconfig       |  3 +++
 drivers/rtc/rtc-cmos.c    | 67 ++++++++++++++++++++++++++++++++++++++++++-----
 include/asm-generic/rtc.h |  5 ++++
 3 files changed, 68 insertions(+), 7 deletions(-)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 2e565f8..7e88866 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -677,6 +677,9 @@ config RTC_DRV_CMOS
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-cmos.
 
+config RTC_DRV_CMOS_MMIO
+	bool
+
 config RTC_DRV_ALPHA
 	bool "Alpha PC-style CMOS"
 	depends on ALPHA
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index be2dd17..d535e72 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -37,6 +37,7 @@
 #include <linux/log2.h>
 #include <linux/pm.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/dmi.h>
 
@@ -66,6 +67,41 @@ struct cmos_rtc {
 
 static const char driver_name[] = "rtc_cmos";
 
+#ifdef CONFIG_RTC_DRV_CMOS_MMIO
+static void __iomem *rtc_cmos_base;
+
+static u8 do_cmos_read(u8 reg)
+{
+	u8 val;
+
+	if (rtc_cmos_base) {
+		writeb(reg, rtc_cmos_base);
+		val = readb(rtc_cmos_base + 1);
+	} else {
+		val = CMOS_READ(reg);
+	}
+
+	return val;
+}
+
+static void do_cmos_write(u8 val, u8 reg)
+{
+	if (rtc_cmos_base) {
+		writeb(reg, rtc_cmos_base);
+		writeb(val, rtc_cmos_base + 1);
+	} else {
+		CMOS_WRITE(val, reg);
+	}
+}
+
+static inline void rtc_cmos_set_base(void __iomem *base)
+{
+	rtc_cmos_base = base;
+}
+#else
+static void rtc_cmos_set_base(void __iomem *base) {}
+#endif
+
 /* 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.
@@ -663,13 +699,23 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 		return -ENODEV;
 
 	/* Claim I/O ports ASAP, minimizing conflict with legacy driver.
-	 *
-	 * REVISIT non-x86 systems may instead use memory space resources
-	 * (needing ioremap etc), not i/o space resources like this ...
+	 * MMIO gets requested the same way, not that it matters much.
 	 */
-	ports = request_region(ports->start,
-			resource_size(ports),
-			driver_name);
+	switch(resource_type(ports)) {
+	case IORESOURCE_IO:
+		ports = request_region(ports->start,
+				       resource_size(ports),
+				       driver_name);
+		break;
+	case IORESOURCE_MEM:
+		ports = request_mem_region(ports->start,
+					   resource_size(ports),
+					   driver_name);
+		break;
+	default:		/* Martian I/O??? */
+		ports = NULL;
+	}
+
 	if (!ports) {
 		dev_dbg(dev, "i/o registers already in use\n");
 		return -EBUSY;
@@ -1160,10 +1206,17 @@ static inline void cmos_of_init(struct platform_device *pdev) {}
 
 static int __init cmos_platform_probe(struct platform_device *pdev)
 {
+	struct resource *ports;
+
 	cmos_of_init(pdev);
+
+	ports = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!ports)
+		ports = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
 	cmos_wake_setup(&pdev->dev);
 	return cmos_do_probe(&pdev->dev,
-			platform_get_resource(pdev, IORESOURCE_IO, 0),
+			ports,
 			platform_get_irq(pdev, 0));
 }
 
diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
index 1ad3e78..236693b 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -28,6 +28,10 @@
 #define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
 #define RTC_DST_EN 0x01	        /* auto switch DST - works f. USA only */
 
+#ifdef CONFIG_RTC_DRV_CMOS_MMIO
+static u8 do_cmos_read(u8 reg);
+static void do_cmos_write(u8 val, u8 reg);
+#else
 static inline u8 do_cmos_read(u8 reg)
 {
 	return CMOS_READ(reg);
@@ -37,6 +41,7 @@ static inline void do_cmos_write(u8 val, u8 reg)
 {
 	CMOS_WRITE(val, reg);
 }
+#endif
 
 static inline unsigned long rtc_cmos_lock(void)
 {
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/7] rtc-cmos: allow strictly MMIO based configurations
  2014-04-25  9:31 [PATCH 0/7] rtc-cmos: private locking and MMIO support Marc Zyngier
                   ` (2 preceding siblings ...)
  2014-04-25  9:31 ` [PATCH 3/7] rtc-cmos: allow MMIO to be used when initialized from FDT Marc Zyngier
@ 2014-04-25  9:31 ` Marc Zyngier
  2014-04-25  9:31 ` [PATCH 5/7] rtc-cmos: implement driver private locking Marc Zyngier
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Marc Zyngier @ 2014-04-25  9:31 UTC (permalink / raw)
  To: linux-kernel, rtc-linux
  Cc: Russell King, Will Deacon, Catalin Marinas, Alessandro Zummo

For those new fancy architectures lacking any kind of I/O ports,
and unwilling to emulate them, introduce the new config symbol
RTC_DRV_CMOS_MMIO_STRICT, which provides default (and explosive)
legacy I/O port accessors.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/rtc/Kconfig    | 4 ++++
 drivers/rtc/rtc-cmos.c | 5 +++++
 2 files changed, 9 insertions(+)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 7e88866..10974f7 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -680,6 +680,10 @@ config RTC_DRV_CMOS
 config RTC_DRV_CMOS_MMIO
 	bool
 
+config RTC_DRV_CMOS_MMIO_STRICT
+	select RTC_DRV_CMOS_MMIO
+	bool
+
 config RTC_DRV_ALPHA
 	bool "Alpha PC-style CMOS"
 	depends on ALPHA
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index d535e72..e2d1338 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -70,6 +70,11 @@ static const char driver_name[] = "rtc_cmos";
 #ifdef CONFIG_RTC_DRV_CMOS_MMIO
 static void __iomem *rtc_cmos_base;
 
+#ifdef CONFIG_RTC_DRV_CMOS_MMIO_STRICT
+#define CMOS_READ(reg)		({BUG(); 0;})
+#define CMOS_WRITE(val,reg)	BUG();
+#endif
+
 static u8 do_cmos_read(u8 reg)
 {
 	u8 val;
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/7] rtc-cmos: implement driver private locking
  2014-04-25  9:31 [PATCH 0/7] rtc-cmos: private locking and MMIO support Marc Zyngier
                   ` (3 preceding siblings ...)
  2014-04-25  9:31 ` [PATCH 4/7] rtc-cmos: allow strictly MMIO based configurations Marc Zyngier
@ 2014-04-25  9:31 ` Marc Zyngier
  2014-04-25  9:31 ` [PATCH 6/7] ARM: rtc: update CMOS RTC to support MMIO and private lock Marc Zyngier
  2014-04-25  9:31 ` [PATCH 7/7] arm64: rtc: plug the PC CMOS RTC using MMIO accessors Marc Zyngier
  6 siblings, 0 replies; 10+ messages in thread
From: Marc Zyngier @ 2014-04-25  9:31 UTC (permalink / raw)
  To: linux-kernel, rtc-linux
  Cc: Russell King, Will Deacon, Catalin Marinas, Alessandro Zummo

A number of architecture happen to share a lock between the rtc-cmos
driver and the core architectural code for good reasons (or at least,
reasons that matter to the architecture).

Other architectures don't do that, but still have to define a lock
that is only used by the RTC driver. How annoying!

Implement a set of driver private locking primitives, and expose
a config option allowing the architecture to select it if it doesn't
require to share the lock with the RTC driver.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 drivers/rtc/Kconfig       |  3 +++
 drivers/rtc/rtc-cmos.c    | 16 ++++++++++++++++
 include/asm-generic/rtc.h |  5 +++++
 3 files changed, 24 insertions(+)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 10974f7..12bc27d 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -684,6 +684,9 @@ config RTC_DRV_CMOS_MMIO_STRICT
 	select RTC_DRV_CMOS_MMIO
 	bool
 
+config RTC_DRV_CMOS_PRIV_LOCK
+	bool
+
 config RTC_DRV_ALPHA
 	bool "Alpha PC-style CMOS"
 	depends on ALPHA
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index e2d1338..eb5d05c 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -107,6 +107,22 @@ static inline void rtc_cmos_set_base(void __iomem *base)
 static void rtc_cmos_set_base(void __iomem *base) {}
 #endif
 
+#ifdef CONFIG_RTC_DRV_CMOS_PRIV_LOCK
+static DEFINE_SPINLOCK(rtc_private_lock);
+
+static unsigned long rtc_cmos_lock(void)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&rtc_private_lock, flags);
+	return flags;
+}
+
+static void rtc_cmos_unlock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&rtc_private_lock, flags);
+}
+#endif
+
 /* 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.
diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
index 236693b..1d21408 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -43,6 +43,10 @@ static inline void do_cmos_write(u8 val, u8 reg)
 }
 #endif
 
+#ifdef CONFIG_RTC_DRV_CMOS_PRIV_LOCK
+static unsigned long rtc_cmos_lock(void);
+static void rtc_cmos_unlock(unsigned long flags);
+#else
 static inline unsigned long rtc_cmos_lock(void)
 {
 	unsigned long flags;
@@ -54,6 +58,7 @@ static inline void rtc_cmos_unlock(unsigned long flags)
 {
 	spin_unlock_irqrestore(&rtc_lock, flags);
 }
+#endif
 
 /*
  * Returns true if a clock update is in progress
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/7] ARM: rtc: update CMOS RTC to support MMIO and private lock
  2014-04-25  9:31 [PATCH 0/7] rtc-cmos: private locking and MMIO support Marc Zyngier
                   ` (4 preceding siblings ...)
  2014-04-25  9:31 ` [PATCH 5/7] rtc-cmos: implement driver private locking Marc Zyngier
@ 2014-04-25  9:31 ` Marc Zyngier
  2014-04-25 10:27   ` Russell King - ARM Linux
  2014-04-25  9:31 ` [PATCH 7/7] arm64: rtc: plug the PC CMOS RTC using MMIO accessors Marc Zyngier
  6 siblings, 1 reply; 10+ messages in thread
From: Marc Zyngier @ 2014-04-25  9:31 UTC (permalink / raw)
  To: linux-kernel, rtc-linux
  Cc: Russell King, Will Deacon, Catalin Marinas, Alessandro Zummo

So far, the CMOS RTC (PC-style mc146818) has always been used
through an ISA I/O port of some sort, with each platform configuring
the address in a static way.

Some platforms (KVM with kvmtools, for example) offer a MMIO version
of the CMOS RTC, which requires a different access method.

This patch select the RTC_DRV_CMOS_MMIO configuration in order to
support MMIO accesses as well as the older IO port method.

While we're at it, switch to RTC_DRV_CMOS_PRIV_LOCK and remove the
ancient rtc_lock.

Tested on Cortex-A7 with KVM and kvmtools.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kernel/time.c | 7 -------
 drivers/rtc/Kconfig    | 2 ++
 2 files changed, 2 insertions(+), 7 deletions(-)

diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 829a96d..38c8718 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -32,13 +32,6 @@
 #include <asm/stacktrace.h>
 #include <asm/thread_info.h>
 
-#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || \
-    defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE)
-/* this needs a better home */
-DEFINE_SPINLOCK(rtc_lock);
-EXPORT_SYMBOL(rtc_lock);
-#endif	/* pc-style 'CMOS' RTC support */
-
 /* change this if you have some constant time drift */
 #define USECS_PER_JIFFY	(1000000/HZ)
 
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 12bc27d..b2a512e 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -662,6 +662,8 @@ config RTC_DRV_CMOS
 	tristate "PC-style 'CMOS'"
 	depends on X86 || ARM || M32R || PPC || MIPS || SPARC64
 	default y if X86
+	select RTC_DRV_CMOS_MMIO if ARM
+	select RTC_DRV_CMOS_PRIV_LOCK if ARM
 	help
 	  Say "yes" here to get direct support for the real time clock
 	  found in every PC or ACPI-based system, and some other boards.
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/7] arm64: rtc: plug the PC CMOS RTC using MMIO accessors
  2014-04-25  9:31 [PATCH 0/7] rtc-cmos: private locking and MMIO support Marc Zyngier
                   ` (5 preceding siblings ...)
  2014-04-25  9:31 ` [PATCH 6/7] ARM: rtc: update CMOS RTC to support MMIO and private lock Marc Zyngier
@ 2014-04-25  9:31 ` Marc Zyngier
  6 siblings, 0 replies; 10+ messages in thread
From: Marc Zyngier @ 2014-04-25  9:31 UTC (permalink / raw)
  To: linux-kernel, rtc-linux
  Cc: Russell King, Will Deacon, Catalin Marinas, Alessandro Zummo

Add the now minimal gunk to enable the PC-style CMOS RTC.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/mc146818rtc.h | 10 ++++++++++
 drivers/rtc/Kconfig                  |  5 +++--
 drivers/rtc/rtc-cmos.c               |  2 +-
 3 files changed, 14 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm64/include/asm/mc146818rtc.h

diff --git a/arch/arm64/include/asm/mc146818rtc.h b/arch/arm64/include/asm/mc146818rtc.h
new file mode 100644
index 0000000..79cc1f3
--- /dev/null
+++ b/arch/arm64/include/asm/mc146818rtc.h
@@ -0,0 +1,10 @@
+/*
+ * Machine dependent access functions for RTC registers.
+ * In the arm64 case, pretty much nothing.
+ */
+#ifndef __ARM64_MC146818RTC_H__
+#define __ARM64_MC146818RTC_H__
+
+#define RTC_ALWAYS_BCD	0
+
+#endif /* __ARM64_MC146818RTC_H__ */
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index b2a512e..5944c92 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -660,10 +660,11 @@ comment "Platform RTC drivers"
 
 config RTC_DRV_CMOS
 	tristate "PC-style 'CMOS'"
-	depends on X86 || ARM || M32R || PPC || MIPS || SPARC64
+	depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 || ARM64
 	default y if X86
 	select RTC_DRV_CMOS_MMIO if ARM
-	select RTC_DRV_CMOS_PRIV_LOCK if ARM
+	select RTC_DRV_CMOS_MMIO_STRICT if ARM64
+	select RTC_DRV_CMOS_PRIV_LOCK if (ARM || ARM64)
 	help
 	  Say "yes" here to get direct support for the real time clock
 	  found in every PC or ACPI-based system, and some other boards.
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index eb5d05c..d84e3a5 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -754,7 +754,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 	address_space = 64;
 #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) \
 			|| defined(__sparc__) || defined(__mips__) \
-			|| defined(__powerpc__)
+			|| defined(__powerpc__) || defined(CONFIG_ARM64)
 	address_space = 128;
 #else
 #warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
-- 
1.8.3.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 6/7] ARM: rtc: update CMOS RTC to support MMIO and private lock
  2014-04-25  9:31 ` [PATCH 6/7] ARM: rtc: update CMOS RTC to support MMIO and private lock Marc Zyngier
@ 2014-04-25 10:27   ` Russell King - ARM Linux
  2014-04-25 12:32     ` Marc Zyngier
  0 siblings, 1 reply; 10+ messages in thread
From: Russell King - ARM Linux @ 2014-04-25 10:27 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: linux-kernel, rtc-linux, Will Deacon, Catalin Marinas,
	Alessandro Zummo

On Fri, Apr 25, 2014 at 10:31:14AM +0100, Marc Zyngier wrote:
> So far, the CMOS RTC (PC-style mc146818) has always been used
> through an ISA I/O port of some sort, with each platform configuring
> the address in a static way.
> 
> Some platforms (KVM with kvmtools, for example) offer a MMIO version
> of the CMOS RTC, which requires a different access method.
> 
> This patch select the RTC_DRV_CMOS_MMIO configuration in order to
> support MMIO accesses as well as the older IO port method.
> 
> While we're at it, switch to RTC_DRV_CMOS_PRIV_LOCK and remove the
> ancient rtc_lock.

rtc_lock is there so that if you build the RTC driver and nvram driver
in, and load them, they will both want to access the RTC via its
indexed registers, and they need to share the lock to avoid trampling
on each others toes.

Yes, it should be handled in a more modern way, but I don't think you
can simply get rid of this in this manner.  We can have both these
drivers loaded on ARM platforms.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 6/7] ARM: rtc: update CMOS RTC to support MMIO and private lock
  2014-04-25 10:27   ` Russell King - ARM Linux
@ 2014-04-25 12:32     ` Marc Zyngier
  0 siblings, 0 replies; 10+ messages in thread
From: Marc Zyngier @ 2014-04-25 12:32 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-kernel@vger.kernel.org, rtc-linux@googlegroups.com,
	Will Deacon, Catalin Marinas, Alessandro Zummo

Hi Russell,

On 25/04/14 11:27, Russell King - ARM Linux wrote:
> On Fri, Apr 25, 2014 at 10:31:14AM +0100, Marc Zyngier wrote:
>> So far, the CMOS RTC (PC-style mc146818) has always been used
>> through an ISA I/O port of some sort, with each platform configuring
>> the address in a static way.
>>
>> Some platforms (KVM with kvmtools, for example) offer a MMIO version
>> of the CMOS RTC, which requires a different access method.
>>
>> This patch select the RTC_DRV_CMOS_MMIO configuration in order to
>> support MMIO accesses as well as the older IO port method.
>>
>> While we're at it, switch to RTC_DRV_CMOS_PRIV_LOCK and remove the
>> ancient rtc_lock.
> 
> rtc_lock is there so that if you build the RTC driver and nvram driver
> in, and load them, they will both want to access the RTC via its
> indexed registers, and they need to share the lock to avoid trampling
> on each others toes.

Ah, I completely missed that one. Note to self: never look at that kind
of code just after lunch...

> Yes, it should be handled in a more modern way, but I don't think you
> can simply get rid of this in this manner.  We can have both these
> drivers loaded on ARM platforms.

Agreed. I suppose that would have to be handled by some kind of module
dependency, but it is starting to look even uglier than I initially thought.

Back to the drawing board...

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2014-04-25 12:33 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-04-25  9:31 [PATCH 0/7] rtc-cmos: private locking and MMIO support Marc Zyngier
2014-04-25  9:31 ` [PATCH 1/7] rtc-cmos: abstract IO accessors Marc Zyngier
2014-04-25  9:31 ` [PATCH 2/7] rtc-cmos: abstract locking primitives Marc Zyngier
2014-04-25  9:31 ` [PATCH 3/7] rtc-cmos: allow MMIO to be used when initialized from FDT Marc Zyngier
2014-04-25  9:31 ` [PATCH 4/7] rtc-cmos: allow strictly MMIO based configurations Marc Zyngier
2014-04-25  9:31 ` [PATCH 5/7] rtc-cmos: implement driver private locking Marc Zyngier
2014-04-25  9:31 ` [PATCH 6/7] ARM: rtc: update CMOS RTC to support MMIO and private lock Marc Zyngier
2014-04-25 10:27   ` Russell King - ARM Linux
2014-04-25 12:32     ` Marc Zyngier
2014-04-25  9:31 ` [PATCH 7/7] arm64: rtc: plug the PC CMOS RTC using MMIO accessors Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox