[patch-mm 26/33] x86_64: apic add clock event functions

From: Thomas Gleixner
Date: Sun Jul 15 2007 - 12:16:57 EST


Add the clock event functions to apic.c. Still unused, but setup of
the factors integrated into the calibration code.

Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Signed-off-by: Chris Wright <chrisw@xxxxxxxxxxxx>
Signed-off-by: Ingo Molnar <mingo@xxxxxxx>

---
arch/x86_64/Kconfig | 6 +++
arch/x86_64/kernel/apic.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 85 insertions(+)

Index: linux-2.6.22-rc6-mm/arch/x86_64/Kconfig
===================================================================
--- linux-2.6.22-rc6-mm.orig/arch/x86_64/Kconfig 2007-07-15 17:30:43.000000000 +0200
+++ linux-2.6.22-rc6-mm/arch/x86_64/Kconfig 2007-07-15 17:48:54.000000000 +0200
@@ -28,6 +28,10 @@ config GENERIC_TIME
bool
default y

+config GENERIC_CLOCKEVENTS_MIGR
+ bool
+ default y
+
config GENERIC_TIME_VSYSCALL
bool
default y
@@ -138,6 +142,8 @@ source "init/Kconfig"

menu "Processor type and features"

+source "kernel/time/Kconfig"
+
choice
prompt "Subarchitecture Type"
default X86_PC
Index: linux-2.6.22-rc6-mm/arch/x86_64/kernel/apic.c
===================================================================
--- linux-2.6.22-rc6-mm.orig/arch/x86_64/kernel/apic.c 2007-07-15 17:42:19.000000000 +0200
+++ linux-2.6.22-rc6-mm/arch/x86_64/kernel/apic.c 2007-07-15 17:48:54.000000000 +0200
@@ -25,6 +25,7 @@
#include <linux/sysdev.h>
#include <linux/module.h>
#include <linux/ioport.h>
+#include <linux/clockchips.h>

#include <asm/atomic.h>
#include <asm/smp.h>
@@ -58,6 +59,77 @@ static struct resource lapic_resource =

static unsigned int calibration_result;

+static int lapic_next_event(unsigned long delta,
+ struct clock_event_device *evt);
+static void lapic_timer_setup(enum clock_event_mode mode,
+ struct clock_event_device *evt);
+
+static void lapic_timer_broadcast(cpumask_t mask);
+
+static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen);
+
+static struct clock_event_device lapic_clockevent = {
+ .name = "lapic",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
+ | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
+ .shift = 32,
+ .set_mode = lapic_timer_setup,
+ .set_next_event = lapic_next_event,
+ .broadcast = lapic_timer_broadcast,
+ .rating = 100,
+ .irq = -1,
+};
+static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
+
+static int lapic_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ apic_write(APIC_TMICT, delta);
+ return 0;
+}
+
+static void lapic_timer_setup(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ unsigned long flags;
+ unsigned int v;
+
+ /* Lapic used as dummy for broadcast ? */
+ if (evt->features & CLOCK_EVT_FEAT_DUMMY)
+ return;
+
+ local_irq_save(flags);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ case CLOCK_EVT_MODE_ONESHOT:
+ __setup_APIC_LVTT(calibration_result,
+ mode != CLOCK_EVT_MODE_PERIODIC, 1);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ v = apic_read(APIC_LVTT);
+ v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+ apic_write(APIC_LVTT, v);
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ /* Nothing to do here */
+ break;
+ }
+
+ local_irq_restore(flags);
+}
+
+/*
+ * Local APIC timer broadcast function
+ */
+static void lapic_timer_broadcast(cpumask_t mask)
+{
+#ifdef CONFIG_SMP
+ send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
+#endif
+}
+
/*
* cpu_mask that denotes the CPUs that needs timer interrupt coming in as
* IPIs in place of local APIC timers
@@ -867,6 +939,13 @@ static void __init calibrate_APIC_clock(
printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
result / 1000 / 1000, result / 1000 % 1000);

+ /* Calculate the scaled math multiplication factor */
+ lapic_clockevent.mult = div_sc(result, NSEC_PER_SEC, 32);
+ lapic_clockevent.max_delta_ns =
+ clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
+ lapic_clockevent.min_delta_ns =
+ clockevent_delta2ns(0xF, &lapic_clockevent);
+
calibration_result = result / HZ;
}


--

-
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/