Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba7eda4c authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Thomas Gleixner
Browse files

x86_64: Add (not yet used) clock event functions

parent 02290683
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
@@ -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>
@@ -57,6 +58,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
@@ -866,6 +938,13 @@ static void __init calibrate_APIC_clock(void)
	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;
}

+6 −0
Original line number Diff line number Diff line
@@ -40,6 +40,10 @@ config CLOCKSOURCE_WATCHDOG
	bool
	default y

config GENERIC_CLOCKEVENTS_MIGR
	bool
	default y

config ZONE_DMA32
	bool
	default y
@@ -134,6 +138,8 @@ source "init/Kconfig"

menu "Processor type and features"

source "kernel/time/Kconfig"

choice
	prompt "Subarchitecture Type"
	default X86_PC