mirror of
https://github.com/apache/nuttx.git
synced 2026-05-23 23:28:29 +08:00
arch/intel64: Added clkdev driver for TSC-deadline.
This commit added clkdev driver for TSC-deadline. Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
This commit is contained in:
committed by
Xiang Xiao
parent
6308167c45
commit
c8c9dbd127
@@ -83,11 +83,11 @@ endif()
|
||||
|
||||
if(CONFIG_ARCH_INTEL64_HAVE_TSC)
|
||||
if(CONFIG_SCHED_TICKLESS)
|
||||
list(APPEND SRCS intel64_tsc_tickless.c)
|
||||
list(APPEND SRCS intel64_tsc_oneshot.c)
|
||||
else()
|
||||
list(APPEND SRCS intel64_tsc_timerisr.c)
|
||||
list(APPEND SRCS intel64_tsc_ndelay.c)
|
||||
endif()
|
||||
list(APPEND SRCS intel64_tsc_ndelay.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_INTEL64_HPET)
|
||||
|
||||
@@ -67,6 +67,10 @@ choice
|
||||
config ARCH_INTEL64_TSC_DEADLINE
|
||||
bool "TSC DEADLINE timer support"
|
||||
select ARCH_INTEL64_HAVE_TSC
|
||||
select ONESHOT
|
||||
select ONESHOT_COUNT
|
||||
select ONESHOT_FAST_DIVISION
|
||||
select ALARM_ARCH
|
||||
---help---
|
||||
Select to enable the use of TSC DEADLINE timer of x86_64
|
||||
|
||||
@@ -78,7 +82,7 @@ config ARCH_INTEL64_TSC
|
||||
|
||||
config ARCH_INTEL64_HPET_ALARM
|
||||
bool "HPET timer alarm support"
|
||||
depends on ALARM_ARCH
|
||||
select ALARM_ARCH
|
||||
---help---
|
||||
With this option you can enable ALARM_ARCH features that works on top of
|
||||
the HPET timer instance. This is an alternative method to TSC timer to
|
||||
@@ -172,7 +176,7 @@ config INTEL64_HPET_MIN_DELAY
|
||||
endif # INTEL64_HPET
|
||||
|
||||
config INTEL64_ONESHOT
|
||||
bool "Oneshot timer support"
|
||||
bool "Oneshot HPET timer support"
|
||||
select INTEL64_HPET
|
||||
default n
|
||||
---help---
|
||||
|
||||
@@ -74,12 +74,12 @@ endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_INTEL64_HAVE_TSC),y)
|
||||
ifeq ($(CONFIG_SCHED_TICKLESS),y)
|
||||
CHIP_CSRCS += intel64_tsc_tickless.c
|
||||
CHIP_CSRCS += intel64_tsc_oneshot.c
|
||||
else
|
||||
CHIP_CSRCS += intel64_tsc_timerisr.c
|
||||
endif
|
||||
CHIP_CSRCS += intel64_tsc_ndelay.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_INTEL64_HPET),y)
|
||||
CHIP_CSRCS += intel64_hpet.c
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
/****************************************************************************
|
||||
* arch/x86_64/src/intel64/intel64_tsc_oneshot.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/spinlock.h>
|
||||
#include <nuttx/timers/oneshot.h>
|
||||
#include <nuttx/timers/arch_alarm.h>
|
||||
|
||||
#include "x86_64_internal.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define TMR_IRQ IRQ14
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static clkcnt_t intel64_tsc_max_delay(struct oneshot_lowerhalf_s *lower);
|
||||
static clkcnt_t intel64_tsc_current(struct oneshot_lowerhalf_s *lower);
|
||||
static void intel64_tsc_start_absolute(struct oneshot_lowerhalf_s *lower,
|
||||
clkcnt_t expected);
|
||||
static void intel64_tsc_start(struct oneshot_lowerhalf_s *lower,
|
||||
clkcnt_t delta);
|
||||
static void intel64_tsc_cancel(struct oneshot_lowerhalf_s *lower);
|
||||
|
||||
static const struct oneshot_operations_s g_intel64_tsc_ops =
|
||||
{
|
||||
.current = intel64_tsc_current,
|
||||
.start = intel64_tsc_start,
|
||||
.start_absolute = intel64_tsc_start_absolute,
|
||||
.cancel = intel64_tsc_cancel,
|
||||
.max_delay = intel64_tsc_max_delay
|
||||
};
|
||||
|
||||
static struct oneshot_lowerhalf_s g_intel64_tsc_lowerhalf =
|
||||
{
|
||||
.ops = &g_intel64_tsc_ops
|
||||
};
|
||||
|
||||
static uint64_t g_tsc_offset;
|
||||
|
||||
/****************************************************************************
|
||||
* Inline Functions
|
||||
****************************************************************************/
|
||||
|
||||
extern unsigned long g_x86_64_timer_freq;
|
||||
|
||||
#ifdef CONFIG_ARCH_INTEL64_HAVE_TSC_ADJUST
|
||||
static inline_function void intel64_tsc_set_offset(uint64_t offset)
|
||||
{
|
||||
uint64_t val = read_msr(MSR_IA32_TSC_ADJUST) + offset;
|
||||
write_msr(MSR_IA32_TSC_ADJUST, val);
|
||||
}
|
||||
|
||||
static inline_function uint64_t intel64_tsc_get_offset(void)
|
||||
{
|
||||
return 0ull;
|
||||
}
|
||||
#else
|
||||
static inline_function void intel64_tsc_set_offset(uint64_t offset)
|
||||
{
|
||||
g_tsc_offset = offset;
|
||||
}
|
||||
static inline_function uint64_t intel64_tsc_get_offset(void)
|
||||
{
|
||||
return g_tsc_offset;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline_function void intel64_mask_tmr(void)
|
||||
{
|
||||
/* Disable TSC Deadline interrupt */
|
||||
|
||||
#ifdef CONFIG_ARCH_INTEL64_TSC_DEADLINE
|
||||
write_msr(MSR_X2APIC_LVTT, TMR_IRQ | MSR_X2APIC_LVTT_TSC_DEADLINE |
|
||||
(1 << 16));
|
||||
#else
|
||||
write_msr(MSR_X2APIC_LVTT, TMR_IRQ | (1 << 16));
|
||||
#endif
|
||||
|
||||
/* Required when using TSC deadline mode. */
|
||||
|
||||
__asm__ volatile("mfence" : : : "memory");
|
||||
}
|
||||
|
||||
static inline_function void intel64_unmask_tmr(void)
|
||||
{
|
||||
/* Enable TSC Deadline interrupt */
|
||||
|
||||
#ifdef CONFIG_ARCH_INTEL64_TSC_DEADLINE
|
||||
write_msr(MSR_X2APIC_LVTT, TMR_IRQ | MSR_X2APIC_LVTT_TSC_DEADLINE);
|
||||
#else
|
||||
write_msr(MSR_X2APIC_LVTT, TMR_IRQ);
|
||||
#endif
|
||||
|
||||
/* Required when using TSC deadline mode. */
|
||||
|
||||
__asm__ volatile("mfence" : : : "memory");
|
||||
}
|
||||
|
||||
static inline_function void intel64_tsc_set_compare(uint64_t deadline)
|
||||
{
|
||||
write_msr(MSR_IA32_TSC_DEADLINE, deadline);
|
||||
}
|
||||
|
||||
static inline_function uint64_t intel64_tsc_count(void)
|
||||
{
|
||||
/* We do not need the memory barrier here. */
|
||||
|
||||
return rdtsc();
|
||||
}
|
||||
|
||||
static inline_function uint64_t intel64_tsc_freq(void)
|
||||
{
|
||||
#if CONFIG_ARCH_INTEL64_CORE_FREQ_KHZ == 0
|
||||
return g_x86_64_timer_freq;
|
||||
#else
|
||||
return CONFIG_ARCH_INTEL64_CORE_FREQ_KHZ * 1000ull;
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: intel64_tsc_compare_isr
|
||||
*
|
||||
* Description:
|
||||
* Common timer interrupt callback. When any oneshot timer interrupt
|
||||
* expires, this function will be called. It will forward the call to
|
||||
* the next level up.
|
||||
*
|
||||
* Input Parameters:
|
||||
* oneshot - The state associated with the expired timer
|
||||
*
|
||||
* Returned Value:
|
||||
* Always returns OK
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int intel64_tsc_compare_isr(int irq, void *regs, void *arg)
|
||||
{
|
||||
struct oneshot_lowerhalf_s *priv = &g_intel64_tsc_lowerhalf;
|
||||
|
||||
intel64_tsc_set_compare(UINT64_MAX);
|
||||
|
||||
/* Then perform the callback */
|
||||
|
||||
oneshot_process_callback(priv);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static clkcnt_t intel64_tsc_max_delay(struct oneshot_lowerhalf_s *lower)
|
||||
{
|
||||
return UINT64_MAX;
|
||||
}
|
||||
|
||||
static clkcnt_t intel64_tsc_current(struct oneshot_lowerhalf_s *lower)
|
||||
{
|
||||
/* We do not need memory barrier here. */
|
||||
|
||||
return intel64_tsc_count() + intel64_tsc_get_offset();
|
||||
}
|
||||
|
||||
static void intel64_tsc_start_absolute(struct oneshot_lowerhalf_s *lower,
|
||||
clkcnt_t expected)
|
||||
{
|
||||
intel64_tsc_set_compare(expected - intel64_tsc_get_offset());
|
||||
}
|
||||
|
||||
static void intel64_tsc_start(struct oneshot_lowerhalf_s *lower,
|
||||
clkcnt_t delta)
|
||||
{
|
||||
/* TSC Deadline is triggered when the counter is less than or equal
|
||||
* to the compare value, so it cannot set an overflow value.
|
||||
*/
|
||||
|
||||
clkcnt_t now = intel64_tsc_count() + intel64_tsc_get_offset();
|
||||
clkcnt_t expected = now + delta >= now ? now + delta : UINT64_MAX;
|
||||
intel64_tsc_set_compare(expected);
|
||||
}
|
||||
|
||||
static void intel64_tsc_cancel(struct oneshot_lowerhalf_s *lower)
|
||||
{
|
||||
intel64_tsc_set_compare(UINT64_MAX);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: oneshot_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the oneshot timer and return a oneshot lower half driver
|
||||
* instance.
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, a non-NULL instance of the oneshot lower-half driver is
|
||||
* returned. NULL is return on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct oneshot_lowerhalf_s *intel64_tsc_initialize(void)
|
||||
{
|
||||
struct oneshot_lowerhalf_s *priv = &g_intel64_tsc_lowerhalf;
|
||||
uint64_t freq;
|
||||
|
||||
tmrinfo("oneshot_initialize\n");
|
||||
|
||||
/* Attach handler */
|
||||
|
||||
freq = intel64_tsc_freq();
|
||||
|
||||
DEBUGASSERT(freq <= UINT32_MAX);
|
||||
|
||||
oneshot_count_init(priv, (uint32_t)freq);
|
||||
|
||||
tmrinfo("oneshot_initialize ok %p \n", priv);
|
||||
|
||||
return priv;
|
||||
}
|
||||
|
||||
void up_timer_initialize(void)
|
||||
{
|
||||
uint64_t tsc = intel64_tsc_count();
|
||||
|
||||
g_tsc_offset = 0ull - tsc;
|
||||
intel64_tsc_set_offset(g_tsc_offset);
|
||||
|
||||
up_alarm_set_lowerhalf(intel64_tsc_initialize());
|
||||
irq_attach(TMR_IRQ, (xcpt_t)intel64_tsc_compare_isr, NULL);
|
||||
|
||||
intel64_tsc_set_compare(UINT64_MAX);
|
||||
intel64_unmask_tmr();
|
||||
}
|
||||
|
||||
void intel64_timer_secondary_init(void)
|
||||
{
|
||||
intel64_tsc_set_offset(g_tsc_offset);
|
||||
|
||||
intel64_tsc_set_compare(UINT64_MAX);
|
||||
intel64_unmask_tmr();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user