Skip to content
Permalink
Browse files

drivers/timer/loapic_timer.c: migrate to new local APIC accessors

More clearly differentiate MVIC vs. APIC timer code, and use new APIC
accessors in include/drivers/loapic.h. Remove extraneous comments, and
other light cleanup work.

This driver is in need of a serious overhaul -- despite appearing to
have support for TICKLESS_KERNEL and DEVICE_POWER_MANAGEMENT, bitrot
has taken its toll and the driver will not build with these enabled.
These should be removed or made to work... but not in this patch.

Old x2APIC-related accessors in kernel_arch_func.h are eliminated.

Signed-off-by: Charles E. Youse <charles.youse@intel.com>
  • Loading branch information...
Charles E. Youse authored and nashif committed Jun 7, 2019
1 parent aaecce4 commit e9f6cb259482bc96453cfb3bb5ae70300f598bf0
Showing with 64 additions and 104 deletions.
  1. +0 −14 arch/x86/include/kernel_arch_func.h
  2. +14 −0 drivers/interrupt_controller/loapic_intr.c
  3. +50 −90 drivers/timer/loapic_timer.c
@@ -67,20 +67,6 @@ z_set_thread_return_value(struct k_thread *thread, unsigned int value)

extern void k_cpu_atomic_idle(unsigned int key);

#ifdef CONFIG_X2APIC
#define MSR_X2APIC_BASE 0x00000800

static inline u32_t read_x2apic(unsigned int reg)
{
return z_x86_msr_read(MSR_X2APIC_BASE + reg);
}

static inline void write_x2apic(unsigned int reg, u32_t val)
{
z_x86_msr_write(MSR_X2APIC_BASE + reg, val);
}
#endif

extern FUNC_NORETURN void z_x86_userspace_enter(k_thread_entry_t user_entry,
void *p1, void *p2, void *p3,
u32_t stack_end,
@@ -64,6 +64,20 @@ u32_t loapic_suspend_buf[LOPIC_SUSPEND_BITS_REQD / 32] = {0};
static u32_t loapic_device_power_state = DEVICE_PM_ACTIVE_STATE;
#endif

/*
* this should not be a function at all, really, it should be
* hand-coded in include/drivers/sysapic.h. but for now it remains
* a function, just moved here from drivers/timer/loapic_timer.c
* where it REALLY didn't belong.
*/

#ifdef CONFIG_X2APIC
void z_x2apic_eoi(void)
{
x86_write_x2apic(LOAPIC_EOI, 0);
}
#endif

/**
*
* @brief Initialize the Local APIC or xAPIC
@@ -8,15 +8,6 @@
* @file
* @brief Intel Local APIC timer driver
*
* This module implements a kernel device driver for the Intel local APIC
* timer device. It provides the standard "system clock driver" interfaces for
* use with P6 (PentiumPro, II, III) and P7 (Pentium4) family processors.
* The local APIC timer contains a 32-bit programmable down counter that
* generates an interrupt for use by the local processor when it reaches zero.
* The time base is derived from the processor's bus clock, divided by a value
* specified in the divide configuration register. After reset, the timer is
* initialized to zero.
*
* Typically, the local APIC timer operates in periodic mode. That is, after
* its down counter reaches zero and triggers a timer interrupt, it is reset
* to its initial value and the down counting continues.
@@ -91,32 +82,6 @@
#define LOAPIC_TIMER_PERIODIC 0x00020000 /* Timer Mode: Periodic */


/* Helpful macros and inlines for programming timer.
* We support both standard LOAPIC, and MVIC which has a similar
* interface
*/

#if defined(CONFIG_LOAPIC)
#define _REG_TIMER ((volatile u32_t *) \
(CONFIG_LOAPIC_BASE_ADDRESS + LOAPIC_TIMER))
#define _REG_TIMER_ICR ((volatile u32_t *) \
(CONFIG_LOAPIC_BASE_ADDRESS + LOAPIC_TIMER_ICR))
#define _REG_TIMER_CCR ((volatile u32_t *) \
(CONFIG_LOAPIC_BASE_ADDRESS + LOAPIC_TIMER_CCR))
#define _REG_TIMER_CFG ((volatile u32_t *) \
(CONFIG_LOAPIC_BASE_ADDRESS + LOAPIC_TIMER_CONFIG))
#define TIMER_IRQ CONFIG_LOAPIC_TIMER_IRQ
#define TIMER_IRQ_PRIORITY CONFIG_LOAPIC_TIMER_IRQ_PRIORITY
#elif defined(CONFIG_MVIC)

#define _REG_TIMER ((volatile u32_t *)MVIC_LVTTIMER)
#define _REG_TIMER_ICR ((volatile u32_t *)MVIC_ICR)
#define _REG_TIMER_CCR ((volatile u32_t *)MVIC_CCR)
/* MVIC has no TIMER_CFG register */
#define TIMER_IRQ CONFIG_MVIC_TIMER_IRQ
#define TIMER_IRQ_PRIORITY -1
#endif

#if defined(CONFIG_TICKLESS_IDLE)
#define TIMER_MODE_ONE_SHOT 0
#define TIMER_MODE_PERIODIC 1
@@ -150,13 +115,6 @@ static u32_t reg_timer_cfg_save;
#endif
#endif

#ifdef CONFIG_X2APIC
void z_x2apic_eoi(void)
{
write_x2apic(LOAPIC_EOI >> 4, 0);
}
#endif

/**
*
* @brief Set the timer for periodic mode
@@ -167,11 +125,12 @@ void z_x2apic_eoi(void)
*/
static inline void periodic_mode_set(void)
{
#ifndef CONFIG_X2APIC
*_REG_TIMER |= LOAPIC_TIMER_PERIODIC;
#ifdef CONFIG_MVIC
sys_write32(sys_read32(MVIC_LVTTIMER) | LOAPIC_TIMER_PERIODIC,
MVIC_LVTTIMER);
#else
write_x2apic(LOAPIC_TIMER >> 4,
read_x2apic(LOAPIC_TIMER >> 4) | LOAPIC_TIMER_PERIODIC);
x86_write_loapic(LOAPIC_TIMER,
x86_read_loapic(LOAPIC_TIMER) | LOAPIC_TIMER_PERIODIC);
#endif
}

@@ -188,10 +147,10 @@ static inline void periodic_mode_set(void)
*/
static inline void initial_count_register_set(u32_t count)
{
#ifndef CONFIG_X2APIC
*_REG_TIMER_ICR = count;
#ifdef CONFIG_MVIC
sys_write32(count, MVIC_ICR);
#else
write_x2apic(LOAPIC_TIMER_ICR >> 4, count);
x86_write_loapic(LOAPIC_TIMER_ICR, count);
#endif
}

@@ -206,32 +165,15 @@ static inline void initial_count_register_set(u32_t count)
*/
static inline void one_shot_mode_set(void)
{
*_REG_TIMER &= ~LOAPIC_TIMER_PERIODIC;
}
#endif /* CONFIG_TICKLESS_IDLE */

/**
*
* @brief Set the rate at which the timer is decremented
*
* This routine sets rate at which the timer is decremented to match the
* external bus frequency.
* This is not supported with MVIC, only real LOAPIC.
*
* @return N/A
*/
#ifndef CONFIG_MVIC
static inline void divide_configuration_register_set(void)
{
#ifndef CONFIG_X2APIC
*_REG_TIMER_CFG = (*_REG_TIMER_CFG & ~0xf) | LOAPIC_TIMER_DIVBY_1;
#ifdef CONFIG_MVIC
sys_write32(sys_read32(MVIC_LVTTIMER) & ~LOAPIC_TIMER_PERIODIC,
MVIC_LVTTIMER);
#else
write_x2apic(LOAPIC_TIMER_CONFIG >> 4,
(read_x2apic(LOAPIC_TIMER_CONFIG >> 4) & ~0xf)
| LOAPIC_TIMER_DIVBY_1);
x86_write_loapic(LOAPIC_TIMER,
x86_read_loapic(LOAPIC_TIMER) & ~LOAPIC_TIMER_PERIODIC);
#endif
}
#endif
#endif /* CONFIG_TICKLESS_IDLE */

#if defined(CONFIG_TICKLESS_KERNEL) || defined(CONFIG_TICKLESS_IDLE)
/**
@@ -246,10 +188,10 @@ static inline void divide_configuration_register_set(void)
*/
static inline u32_t current_count_register_get(void)
{
#ifndef CONFIG_X2APIC
return *_REG_TIMER_CCR;
#ifdef CONFIG_MVIC
return sys_read32(MVIC_CCR);
#else
return read_x2apic(LOAPIC_TIMER_CCR >> 4);
return x86_read_loapic(LOAPIC_TIMER_CCR);
#endif
}
#endif
@@ -265,7 +207,11 @@ static inline u32_t current_count_register_get(void)
*/
static inline u32_t initial_count_register_get(void)
{
return *_REG_TIMER_ICR;
#ifdef CONFIG_MVIC
return sys_read32(MVIC_ICR);
#else
return x86_read_loapic(LOAPIC_TIMER_ICR);
#endif
}
#endif /* CONFIG_TICKLESS_IDLE */

@@ -658,8 +604,11 @@ int z_clock_driver_init(struct device *device)
tickless_idle_init();

#ifndef CONFIG_MVIC
divide_configuration_register_set();
x86_write_loapic(LOAPIC_TIMER_CONFIG,
(x86_read_loapic(LOAPIC_TIMER_CONFIG) & ~0xf)
| LOAPIC_TIMER_DIVBY_1);
#endif

#ifdef CONFIG_TICKLESS_KERNEL
one_shot_mode_set();
#else
@@ -669,12 +618,15 @@ int z_clock_driver_init(struct device *device)
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
loapic_timer_device_power_state = DEVICE_PM_ACTIVE_STATE;
#endif
IRQ_CONNECT(TIMER_IRQ, TIMER_IRQ_PRIORITY, timer_int_handler, 0, 0);

/* Everything has been configured. It is now safe to enable the
* interrupt
*/
irq_enable(TIMER_IRQ);
#ifdef CONFIG_MVIC
IRQ_CONNECT(CONFIG_MVIC_TIMER_IRQ, -1, timer_int_handler, 0, 0);
irq_enable(CONFIG_MVIC_TIMER_IRQ);
#else
IRQ_CONNECT(CONFIG_LOAPIC_TIMER_IRQ, CONFIG_LOAPIC_TIMER_IRQ_PRIORITY,
timer_int_handler, 0, 0);
irq_enable(CONFIG_LOAPIC_TIMER_IRQ);
#endif

return 0;
}
@@ -684,9 +636,11 @@ static int sys_clock_suspend(struct device *dev)
{
ARG_UNUSED(dev);

reg_timer_save = *_REG_TIMER;
#ifndef CONFIG_MVIC
reg_timer_cfg_save = *_REG_TIMER_CFG;
#ifdef CONFIG_MVIC
reg_timer_save = sys_read32(MVIC_LVTTIMER);
#else
reg_timer_save = x86_read_loapic(LOAPIC_TIMER);
reg_timer_cfg_save = x86_read_loapic(LOAPIC_TIMER_CONFIG);
#endif

loapic_timer_device_power_state = DEVICE_PM_SUSPEND_STATE;
@@ -698,9 +652,11 @@ static int sys_clock_resume(struct device *dev)
{
ARG_UNUSED(dev);

*_REG_TIMER = reg_timer_save;
#ifndef CONFIG_MVIC
*_REG_TIMER_CFG = reg_timer_cfg_save;
#ifdef CONFIG_MVIC
sys_write32(reg_timer_save, MVIC_LVTTIMER);
#else
x86_write_loapic(LOAPIC_TIMER, reg_timer_save);
x86_write_loapic(LOAPIC_TIMER_CONFIG, reg_timer_cfg_save);
#endif

/*
@@ -802,9 +758,13 @@ void sys_clock_disable(void)

key = irq_lock();

irq_disable(TIMER_IRQ);
initial_count_register_set(0);
#ifdef CONFIG_MVIC
irq_disable(MVIC_TIMER_IRQ);
#else
irq_disable(CONFIG_LOAPIC_TIMER_IRQ);
#endif

initial_count_register_set(0);
irq_unlock(key);
}

0 comments on commit e9f6cb2

Please sign in to comment.
You can’t perform that action at this time.