2008-10-21 21:17:54

by Dimitri Sivanich

[permalink] [raw]
Subject: [PATCH 0/3] SGI RTC: add clocksource/clockevent driver and timer bios calls

The following patchset provides a driver and bios call framework for
synchronized RTC clocksource and clockevents for SGI systems.

With these patches, a module can be installed that registers the system-wide
synchronized RTC clocksource and timers as both a clocksource and clockevents
device running in high resolution mode.


[PATCH 1/3] SGI RTC: add clocksource driver
[PATCH 2/3] SGI RTC: add bios framework for RTC timer operations
[PATCH 3/3] SGI RTC: add RTC system interrupt

These patches should be installed on top of the following:
http://marc.info/?l=linux-kernel&m=122461934110503&w=2
http://marc.info/?l=linux-kernel&m=122461934110506&w=2
http://marc.info/?l=linux-kernel&m=122461934210509&w=2


2008-10-21 21:19:31

by Dimitri Sivanich

[permalink] [raw]
Subject: [PATCH 1/3] SGI RTC: add clocksource driver

This patch provides a driver for SGI RTC clocks and timers.

This provides a high resolution clock and timer source using the SGI
system-wide synchronized RTC clock/timer hardware.

Signed-off-by: Dimitri Sivanich <[email protected]>

Index: linux/drivers/clocksource/Makefile
===================================================================
--- linux.orig/drivers/clocksource/Makefile 2008-10-21 12:02:41.000000000 -0500
+++ linux/drivers/clocksource/Makefile 2008-10-21 12:02:44.000000000 -0500
@@ -2,3 +2,4 @@ obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_cl
obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o
obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o
+obj-$(CONFIG_SGI_RTC_TIMER) += rtc_uv.o
Index: linux/drivers/misc/Kconfig
===================================================================
--- linux.orig/drivers/misc/Kconfig 2008-10-21 12:02:41.000000000 -0500
+++ linux/drivers/misc/Kconfig 2008-10-21 12:02:44.000000000 -0500
@@ -488,4 +488,12 @@ config SGI_GRU_DEBUG
This option enables addition debugging code for the SGI GRU driver. If
you are unsure, say N.

+config SGI_RTC_TIMER
+ tristate "SGI RTC driver"
+ depends on X86_64 || IA64_SGI_UV
+ default m
+ ---help---
+ This option enables RTC event handling and adds the systemwide RTC
+ as a high resolution clock source for SGI systems.
+
endif # MISC_DEVICES
Index: linux/drivers/clocksource/rtc_uv.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/drivers/clocksource/rtc_uv.c 2008-10-21 12:29:00.000000000 -0500
@@ -0,0 +1,213 @@
+/*
+ * SGI RTC clock/timer routines.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) Dimitri Sivanich
+ */
+#include <linux/module.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <asm/genapic.h>
+#include <asm/uv/bios.h>
+#include <asm/uv/uv_mmrs.h>
+#include <asm/uv/uv_hub.h>
+
+MODULE_LICENSE("GPL");
+
+#define RTC_NAME "sgi_rtc"
+
+static cycle_t uv_read_rtc(void);
+static int uv_rtc_next_event(unsigned long, struct clock_event_device *);
+static void uv_rtc_timer_setup(enum clock_event_mode,
+ struct clock_event_device *);
+static void uv_rtc_timer_broadcast(cpumask_t);
+
+
+static struct clocksource clocksource_uv = {
+ .name = RTC_NAME,
+ .rating = 400,
+ .read = uv_read_rtc,
+ .shift = 0,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static struct clock_event_device clock_event_device_uv = {
+ .name = RTC_NAME,
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 10,
+ .rating = 400,
+ .irq = -1,
+ .set_next_event = uv_rtc_next_event,
+ .set_mode = uv_rtc_timer_setup,
+ .event_handler = NULL,
+ .broadcast = uv_rtc_timer_broadcast
+};
+
+static DEFINE_PER_CPU(struct clock_event_device, cpu_ced);
+
+/* Send IPIs to another node */
+static void
+uv_rtc_send_IPI(int cpu, int vector)
+{
+ unsigned long val, apicid, lapicid;
+ int pnode;
+
+ apicid = per_cpu(x86_cpu_to_apicid, cpu);
+ lapicid = apicid & 0x3f;
+ pnode = uv_apicid_to_pnode(apicid);
+
+ val = (1UL << UVH_IPI_INT_SEND_SHFT) | (lapicid <<
+ UVH_IPI_INT_APIC_ID_SHFT) |
+ (vector << UVH_IPI_INT_VECTOR_SHFT);
+ uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
+}
+
+/*
+ * Read the RTC.
+ */
+static cycle_t
+uv_read_rtc(void)
+{
+ cycle_t ticks;
+ uv_bios_rtct(UV_RTC_READ, &ticks, 0, 0, 0, 0);
+ return ticks;
+}
+
+/*
+ * Program the next event, relative to now
+ */
+static int
+uv_rtc_next_event(unsigned long delta, struct clock_event_device *ced)
+{
+ int ced_cpu = first_cpu(ced->cpumask);
+
+ return uv_bios_rtct(UV_RTC_EVT_SET, &ced_cpu, &delta, 0, 0, 0);
+}
+
+/*
+ * Setup the RTC timer in oneshot mode
+ */
+static void
+uv_rtc_timer_setup(enum clock_event_mode mode, struct clock_event_device *evt)
+{
+ unsigned long flags;
+ int ced_cpu = first_cpu(evt->cpumask);
+
+ local_irq_save(flags);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ case CLOCK_EVT_MODE_ONESHOT:
+ uv_bios_rtct(UV_RTC_EVT_START, &ced_cpu, 0, 0, 0, 0);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ uv_bios_rtct(UV_RTC_EVT_STOP, &ced_cpu, 0, 0, 0, 0);
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ uv_bios_rtct(UV_RTC_EVT_RESUME, &ced_cpu, 0, 0, 0, 0);
+ break;
+ }
+
+ local_irq_restore(flags);
+}
+
+/*
+ * Local APIC timer broadcast function
+ */
+static void
+uv_rtc_timer_broadcast(cpumask_t mask)
+{
+ int cpu;
+ for_each_cpu_mask(cpu, mask)
+ uv_rtc_send_IPI(cpu, RTC_TIMER_VECTOR);
+}
+
+static void
+uv_rtc_interrupt(void)
+{
+ struct clock_event_device *ced = &__get_cpu_var(cpu_ced);
+ unsigned long flags;
+ int cpu = smp_processor_id();
+
+ local_irq_save(flags);
+ if (!ced || !ced->event_handler ||
+ uv_bios_rtct(UV_RTC_EVT_ACK, &cpu, 0, 0, 0, 0)) {
+ local_irq_restore(flags);
+ printk(KERN_WARNING
+ "Spurious uv_rtc timer interrupt on cpu %d\n",
+ smp_processor_id());
+ return;
+ }
+ local_irq_restore(flags);
+ ced->event_handler(ced);
+}
+
+static __init void
+uv_rtc_register_clockevents(void *data)
+{
+ struct clock_event_device *ced = &__get_cpu_var(cpu_ced);
+
+ memcpy(ced, &clock_event_device_uv, sizeof(clock_event_device_uv));
+ cpus_clear(ced->cpumask);
+ cpu_set(smp_processor_id(), ced->cpumask);
+ clockevents_register_device(ced);
+}
+
+static __init int
+uv_rtc_setup_clock(void)
+{
+ u64 vector = RTC_TIMER_VECTOR;
+ int rc;
+
+ if (!is_uv_system() || uv_rtc_reg_extension(uv_rtc_interrupt))
+ return -1;
+
+ /* Setup and register the clocksource */
+ if (uv_bios_rtct(UV_RTC_MASK, &clocksource_uv.mask, 0, 0, 0, 0) ==
+ BIOS_STATUS_UNIMPLEMENTED) {
+ uv_rtc_unreg_extension();
+ printk("BIOS RTC unimplemented\n");
+ return -1;
+ }
+
+ clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
+ clocksource_uv.shift);
+
+ rc = clocksource_register(&clocksource_uv);
+ if (rc) {
+ uv_rtc_unreg_extension();
+ return -1;
+ }
+
+ /* Setup and register clockevents */
+ uv_bios_rtct(UV_RTC_EVT_INIT, &vector, 0, 0, 0, 0);
+
+ clock_event_device_uv.mult = div_sc(sn_rtc_cycles_per_second,
+ NSEC_PER_SEC, clock_event_device_uv.shift);
+
+ clock_event_device_uv.min_delta_ns = NSEC_PER_SEC /
+ sn_rtc_cycles_per_second;
+ clock_event_device_uv.max_delta_ns = clocksource_uv.mask *
+ (NSEC_PER_SEC / sn_rtc_cycles_per_second);
+
+ smp_call_function(uv_rtc_register_clockevents, NULL, 0);
+ uv_rtc_register_clockevents(NULL);
+
+ return 0;
+}
+module_init(uv_rtc_setup_clock);
Index: linux/kernel/time/clockevents.c
===================================================================
--- linux.orig/kernel/time/clockevents.c 2008-10-21 12:02:41.000000000 -0500
+++ linux/kernel/time/clockevents.c 2008-10-21 12:02:44.000000000 -0500
@@ -183,6 +183,7 @@ void clockevents_register_device(struct

spin_unlock(&clockevents_lock);
}
+EXPORT_SYMBOL_GPL(clockevents_register_device);

/*
* Noop handler when we shut down an event device
Index: linux/kernel/time/clocksource.c
===================================================================
--- linux.orig/kernel/time/clocksource.c 2008-10-21 12:02:41.000000000 -0500
+++ linux/kernel/time/clocksource.c 2008-10-21 12:02:44.000000000 -0500
@@ -369,6 +369,7 @@ void clocksource_unregister(struct clock
next_clocksource = select_clocksource();
spin_unlock_irqrestore(&clocksource_lock, flags);
}
+EXPORT_SYMBOL(clocksource_unregister);

#ifdef CONFIG_SYSFS
/**

2008-10-21 21:20:42

by Dimitri Sivanich

[permalink] [raw]
Subject: [PATCH 2/3] SGI RTC: add bios framework for RTC timer operations

This patch provides a bios call framework for implementing SGI RTC timer
functions.

Signed-off-by: Dimitri Sivanich <[email protected]>

Index: linux/arch/x86/kernel/bios_uv.c
===================================================================
--- linux.orig/arch/x86/kernel/bios_uv.c 2008-10-21 12:09:46.000000000 -0500
+++ linux/arch/x86/kernel/bios_uv.c 2008-10-21 12:10:46.000000000 -0500
@@ -160,6 +160,66 @@ s64 uv_bios_freq_base(u64 clock_type, u6
}
EXPORT_SYMBOL_GPL(uv_bios_freq_base);

+int uv_bios_rtct(enum uv_bios_rtct_cmd which, void *a1, void *a2, void *a3,
+ void *a4, void *a5)
+{
+ int rc = 0;
+
+ switch (which) {
+ case UV_RTC_MASK:
+ rc = uv_bios_call(UV_BIOS_RTC_MASK, (u64)a1, 0, 0, 0, 0);
+ break;
+ case UV_RTC_READ:
+ rc = uv_bios_call(UV_BIOS_RTC_READ, (u64)a1, 0, 0, 0, 0);
+ break;
+ case UV_RTC_EVT_INIT:
+ rc = uv_bios_call(UV_BIOS_RTC_EVT_INIT, (u64)a1, (u64)a2,
+ (u64)a3, (u64)a4, (u64)a5);
+ break;
+ case UV_RTC_EVT_SET:
+ {
+ u64 apicid = per_cpu(x86_cpu_to_apicid, *(int *)a1);
+ rc = uv_bios_call(UV_BIOS_RTC_EVT_SET, apicid, (u64)a2, 0, 0,
+ 0);
+ }
+ break;
+ case UV_RTC_EVT_UNSET:
+ {
+ u64 apicid = per_cpu(x86_cpu_to_apicid, *(int *)a1);
+ rc = uv_bios_call(UV_BIOS_RTC_EVT_UNSET, apicid, 0, 0, 0, 0);
+ }
+ break;
+ case UV_RTC_EVT_ACK:
+ {
+ u64 apicid = per_cpu(x86_cpu_to_apicid, *(int *)a1);
+ rc = uv_bios_call(UV_BIOS_RTC_EVT_ACK, apicid, 0, 0, 0, 0);
+ }
+ break;
+ case UV_RTC_EVT_START:
+ {
+ u64 apicid = per_cpu(x86_cpu_to_apicid, *(int *)a1);
+ rc = uv_bios_call(UV_BIOS_RTC_EVT_START, apicid, 0, 0, 0, 0);
+ }
+ break;
+ case UV_RTC_EVT_STOP:
+ {
+ u64 apicid = per_cpu(x86_cpu_to_apicid, *(int *)a1);
+ rc = uv_bios_call(UV_BIOS_RTC_EVT_STOP, apicid, 0, 0, 0, 0);
+ }
+ break;
+ case UV_RTC_EVT_RESUME:
+ {
+ u64 apicid = per_cpu(x86_cpu_to_apicid, *(int *)a1);
+ rc = uv_bios_call(UV_BIOS_RTC_EVT_RESUME, apicid, 0, 0, 0, 0);
+ }
+ break;
+ default:
+ rc = -1;
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(uv_bios_rtct);

#ifdef CONFIG_EFI
void uv_bios_init(void)
Index: linux/include/asm-x86/uv/bios.h
===================================================================
--- linux.orig/include/asm-x86/uv/bios.h 2008-10-21 12:09:46.000000000 -0500
+++ linux/include/asm-x86/uv/bios.h 2008-10-21 12:10:46.000000000 -0500
@@ -36,7 +36,16 @@ enum uv_bios_cmd {
UV_BIOS_WATCHLIST_ALLOC,
UV_BIOS_WATCHLIST_FREE,
UV_BIOS_MEMPROTECT,
- UV_BIOS_GET_PARTITION_ADDR
+ UV_BIOS_GET_PARTITION_ADDR,
+ UV_BIOS_RTC_MASK,
+ UV_BIOS_RTC_READ,
+ UV_BIOS_RTC_EVT_INIT,
+ UV_BIOS_RTC_EVT_SET,
+ UV_BIOS_RTC_EVT_UNSET,
+ UV_BIOS_RTC_EVT_ACK,
+ UV_BIOS_RTC_EVT_START,
+ UV_BIOS_RTC_EVT_STOP,
+ UV_BIOS_RTC_EVT_RESUME
};

/*
@@ -66,6 +75,22 @@ enum {
BIOS_FREQ_BASE_REALTIME_CLOCK = 2
};

+/*
+ * Values for the BIOS rtct calls. It is passed as the first argument
+ * in the uv_bios_rtct call.
+ */
+enum uv_bios_rtct_cmd {
+ UV_RTC_MASK,
+ UV_RTC_READ,
+ UV_RTC_EVT_INIT,
+ UV_RTC_EVT_SET,
+ UV_RTC_EVT_UNSET,
+ UV_RTC_EVT_ACK,
+ UV_RTC_EVT_START,
+ UV_RTC_EVT_STOP,
+ UV_RTC_EVT_RESUME
+};
+
union partition_info_u {
u64 val;
struct {
@@ -106,6 +131,9 @@ extern int uv_bios_mq_watchlist_free(int
extern s64 uv_bios_change_memprotect(u64, u64, enum uv_memprotect);
extern s64 uv_bios_reserved_page_pa(u64, u64 *, u64 *, u64 *);

+extern int uv_bios_rtct(enum uv_bios_rtct_cmd, void *, void *, void *,
+ void *, void *);
+
extern void uv_bios_init(void);

extern unsigned long sn_rtc_cycles_per_second;

2008-10-21 21:22:09

by Dimitri Sivanich

[permalink] [raw]
Subject: [PATCH 3/3] SGI RTC: add RTC system interrupt

This patch allocates a system interrupt vector for architecture specific
use in implementing RTC timer interrupts.

Signed-off-by: Dimitri Sivanich <[email protected]>

Index: linux/arch/x86/kernel/entry_64.S
===================================================================
--- linux.orig/arch/x86/kernel/entry_64.S 2008-10-21 12:06:52.000000000 -0500
+++ linux/arch/x86/kernel/entry_64.S 2008-10-21 12:10:47.000000000 -0500
@@ -858,6 +858,10 @@ ENTRY(apic_timer_interrupt)
apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
END(apic_timer_interrupt)

+ENTRY(uv_rtc_timer_intr)
+ apicinterrupt RTC_TIMER_VECTOR,uv_rtc_timer_interrupt
+END(uv_rtc_timer_intr)
+
ENTRY(uv_bau_message_intr1)
apicinterrupt 220,uv_bau_message_interrupt
END(uv_bau_message_intr1)
Index: linux/arch/x86/kernel/irqinit_64.c
===================================================================
--- linux.orig/arch/x86/kernel/irqinit_64.c 2008-10-21 12:06:52.000000000 -0500
+++ linux/arch/x86/kernel/irqinit_64.c 2008-10-21 12:10:47.000000000 -0500
@@ -205,6 +205,9 @@ static void __init apic_intr_init(void)
/* self generated IPI for local APIC timer */
alloc_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);

+ /* IPI for RTC timers */
+ alloc_intr_gate(RTC_TIMER_VECTOR, uv_rtc_timer_intr);
+
/* IPI vectors for APIC spurious and error interrupts */
alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
Index: linux/include/asm-x86/irq_vectors.h
===================================================================
--- linux.orig/include/asm-x86/irq_vectors.h 2008-10-21 12:06:52.000000000 -0500
+++ linux/include/asm-x86/irq_vectors.h 2008-10-21 12:10:47.000000000 -0500
@@ -90,6 +90,7 @@
* sources per level' errata.
*/
#define LOCAL_TIMER_VECTOR 0xef
+#define RTC_TIMER_VECTOR 0xee

/*
* First APIC vector available to drivers: (vectors 0x30-0xee) we
Index: linux/arch/x86/kernel/genx2apic_uv_x.c
===================================================================
--- linux.orig/arch/x86/kernel/genx2apic_uv_x.c 2008-10-21 12:06:52.000000000 -0500
+++ linux/arch/x86/kernel/genx2apic_uv_x.c 2008-10-21 12:10:47.000000000 -0500
@@ -22,6 +22,7 @@
#include <asm/ipi.h>
#include <asm/genapic.h>
#include <asm/pgtable.h>
+#include <asm/idle.h>
#include <asm/uv/uv_mmrs.h>
#include <asm/uv/uv_hub.h>
#include <asm/uv/bios.h>
@@ -356,6 +357,46 @@ static __init void uv_rtc_init(void)
sn_rtc_cycles_per_second = ticks_per_sec;
}

+/* Function pointer for RTC interrupt handling */
+static void (*uv_rtc_interrupt_extension)(void);
+
+int
+uv_rtc_reg_extension(void (*fn)(void))
+{
+ if (uv_rtc_interrupt_extension)
+ return 1;
+
+ uv_rtc_interrupt_extension = fn;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(uv_rtc_reg_extension);
+
+void
+uv_rtc_unreg_extension(void)
+{
+ if (uv_rtc_interrupt_extension)
+ uv_rtc_interrupt_extension = NULL;
+}
+EXPORT_SYMBOL_GPL(uv_rtc_unreg_extension);
+
+void uv_rtc_timer_interrupt(struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+
+ ack_APIC_irq();
+
+ exit_idle();
+
+ irq_enter();
+
+ if (uv_rtc_interrupt_extension)
+ uv_rtc_interrupt_extension();
+
+ irq_exit();
+
+ set_irq_regs(old_regs);
+}
+
/*
* Called on each cpu to initialize the per_cpu UV data area.
* ZZZ hotplug not supported yet
Index: linux/include/asm-x86/genapic_64.h
===================================================================
--- linux.orig/include/asm-x86/genapic_64.h 2008-10-21 12:06:52.000000000 -0500
+++ linux/include/asm-x86/genapic_64.h 2008-10-21 12:10:47.000000000 -0500
@@ -49,6 +49,8 @@ extern int is_uv_system(void);

extern struct genapic apic_x2apic_uv_x;
DECLARE_PER_CPU(int, x2apic_extra_bits);
+extern int uv_rtc_reg_extension(void (*fn)(void));
+extern void uv_rtc_unreg_extension(void);
extern void uv_cpu_init(void);
extern void uv_system_init(void);
extern int uv_wakeup_secondary(int phys_apicid, unsigned int start_rip);
Index: linux/include/asm-x86/hw_irq.h
===================================================================
--- linux.orig/include/asm-x86/hw_irq.h 2008-10-21 12:06:52.000000000 -0500
+++ linux/include/asm-x86/hw_irq.h 2008-10-21 12:10:47.000000000 -0500
@@ -29,6 +29,7 @@

/* Interrupt handlers registered during init_IRQ */
extern void apic_timer_interrupt(void);
+extern void uv_rtc_timer_intr(void);
extern void error_interrupt(void);
extern void spurious_interrupt(void);
extern void thermal_interrupt(void);

2008-10-22 06:36:45

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 0/3] SGI RTC: add clocksource/clockevent driver and timer bios calls


* Dimitri Sivanich <[email protected]> wrote:

> The following patchset provides a driver and bios call framework for
> synchronized RTC clocksource and clockevents for SGI systems.
>
> With these patches, a module can be installed that registers the system-wide
> synchronized RTC clocksource and timers as both a clocksource and clockevents
> device running in high resolution mode.
>
>
> [PATCH 1/3] SGI RTC: add clocksource driver
> [PATCH 2/3] SGI RTC: add bios framework for RTC timer operations
> [PATCH 3/3] SGI RTC: add RTC system interrupt

hm, i dont really like the direction of this.

Why isnt there a native Linux driver offered for this? This isnt about
memory discovery or device discovery, where BIOS interaction might be
acceptable (and might be unavoidable). This is about hardware interfaces
and drivers, and the last thing we want there is BIOSes.

Ingo

2008-10-22 16:07:46

by Dimitri Sivanich

[permalink] [raw]
Subject: Re: [PATCH 0/3] SGI RTC: add clocksource/clockevent driver and timer bios calls

On Wed, Oct 22, 2008 at 08:36:13AM +0200, Ingo Molnar wrote:
>
> * Dimitri Sivanich <[email protected]> wrote:
>
> > The following patchset provides a driver and bios call framework for
> > synchronized RTC clocksource and clockevents for SGI systems.
> >
> > With these patches, a module can be installed that registers the system-wide
> > synchronized RTC clocksource and timers as both a clocksource and clockevents
> > device running in high resolution mode.
> >
> >
> > [PATCH 1/3] SGI RTC: add clocksource driver
> > [PATCH 2/3] SGI RTC: add bios framework for RTC timer operations
> > [PATCH 3/3] SGI RTC: add RTC system interrupt
>
> hm, i dont really like the direction of this.
>
> Why isnt there a native Linux driver offered for this? This isnt about
> memory discovery or device discovery, where BIOS interaction might be
> acceptable (and might be unavoidable). This is about hardware interfaces
> and drivers, and the last thing we want there is BIOSes.

Ingo,

I'm perfectly willing to do this with a native Linux driver. My reason for doing it the above way was that as the hardware interfaces change, we wouldn't have to be pulling all of those hardware interface changes into the community kernel.

I'll try to get a new patchset submitted for the native driver tomorrow.