Patch by Dustin Howett which 'modularizes' timers. The best timer is
automatically selected at boot time. Pit and Apic timers are implemented for now. Thanks Dustin! git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26265 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
34ff70da4f
commit
6e29a04d36
@ -2,10 +2,12 @@
|
||||
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
#ifndef _NEWOS_KERNEL_ARCH_I386_TIMER
|
||||
#define _NEWOS_KERNEL_ARCH_I386_TIMER
|
||||
#ifndef _KERNEL_ARCH_X86_TIMER
|
||||
#define _KERNEL_ARCH_X86_TIMER
|
||||
|
||||
int apic_timer_interrupt(void);
|
||||
#define ISA_TIMER_MODULE_NAME "timers/x86/isa/v1"
|
||||
#define APIC_TIMER_MODULE_NAME "timers/x86/apic/v1"
|
||||
#define HPET_TIMER_MODULE_NAME "timers/x86/hpet/v1"
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -18,6 +18,18 @@ struct kernel_args;
|
||||
#define B_TIMER_ACQUIRE_THREAD_LOCK 0x8000
|
||||
#define B_TIMER_FLAGS B_TIMER_ACQUIRE_THREAD_LOCK
|
||||
|
||||
/* Timer info structure */
|
||||
struct timer_info {
|
||||
char *name;
|
||||
int (*get_priority)(void);
|
||||
status_t (*set_hardware_timer)(bigtime_t timeout);
|
||||
status_t (*clear_hardware_timer)(void);
|
||||
status_t (*init)(struct kernel_args *args);
|
||||
};
|
||||
|
||||
typedef struct timer_info timer_info;
|
||||
|
||||
|
||||
/* kernel functions */
|
||||
status_t timer_init(struct kernel_args *);
|
||||
int32 timer_interrupt(void);
|
||||
|
@ -4,18 +4,20 @@ SubDirHdrs [ FDirName $(TARGET_COMMON_DEBUG_OBJECT_DIR) system kernel ] ;
|
||||
# for syscall_numbers.h
|
||||
SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers ps2 ;
|
||||
SubDirHdrs $(SUBDIR) $(DOTDOT) generic ;
|
||||
SubDirHdrs $(SUBDIR) timers ;
|
||||
|
||||
UsePrivateKernelHeaders ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) generic ] ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) timers ] ;
|
||||
|
||||
KernelMergeObject kernel_arch_x86.o :
|
||||
arch_commpage.cpp
|
||||
arch_cpu.c
|
||||
arch_debug.cpp
|
||||
arch_debug_console.c
|
||||
arch_elf.c
|
||||
arch_hpet.c
|
||||
arch_int.c
|
||||
arch_platform.c
|
||||
# arch_selector.c
|
||||
@ -35,6 +37,10 @@ KernelMergeObject kernel_arch_x86.o :
|
||||
cpuid.S
|
||||
syscall.S
|
||||
vm86.cpp
|
||||
|
||||
x86_pit.c
|
||||
x86_apic.c
|
||||
x86_hpet.c
|
||||
|
||||
generic_vm_physical_page_mapper.cpp
|
||||
:
|
||||
|
@ -1,6 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <arch/x86/arch_hpet.h>
|
@ -17,6 +17,8 @@
|
||||
#include <arch/vm.h>
|
||||
#include <arch/smp.h>
|
||||
|
||||
#include <timer.h>
|
||||
|
||||
#include <arch/x86/smp_priv.h>
|
||||
#include <arch/x86/smp_apic.h>
|
||||
#include <arch/x86/timer.h>
|
||||
@ -39,23 +41,13 @@
|
||||
# define TRACE_TIMER(x) ;
|
||||
#endif
|
||||
|
||||
extern timer_info gAPICTimer;
|
||||
|
||||
static void *apic = NULL;
|
||||
static uint32 cpu_apic_id[B_MAX_CPU_COUNT] = {0, 0};
|
||||
static uint32 cpu_os_id[B_MAX_CPU_COUNT] = {0, 0};
|
||||
static uint32 cpu_apic_version[B_MAX_CPU_COUNT] = {0, 0};
|
||||
static void *ioapic = NULL;
|
||||
static uint32 apic_timer_tics_per_sec = 0;
|
||||
|
||||
|
||||
static int32
|
||||
i386_timer_interrupt(void *data)
|
||||
{
|
||||
arch_smp_ack_interrupt();
|
||||
|
||||
return apic_timer_interrupt();
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
i386_ici_interrupt(void *data)
|
||||
@ -147,16 +139,7 @@ setup_apic(kernel_args *args, int32 cpu)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* setup timer */
|
||||
config = apic_read(APIC_LVT_TIMER) & APIC_LVT_TIMER_MASK;
|
||||
config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked
|
||||
apic_write(APIC_LVT_TIMER, config);
|
||||
|
||||
apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the clock
|
||||
|
||||
config = apic_read(APIC_TIMER_DIVIDE_CONFIG) & 0xfffffff0;
|
||||
config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1
|
||||
apic_write(APIC_TIMER_DIVIDE_CONFIG, config);
|
||||
apic_smp_init_timer(args, cpu);
|
||||
|
||||
/* setup error vector to 0xfe */
|
||||
config = (apic_read(APIC_LVT_ERROR) & 0xffffff00) | 0xfe;
|
||||
@ -185,7 +168,6 @@ arch_smp_init(kernel_args *args)
|
||||
memcpy(cpu_apic_id, args->arch_args.cpu_apic_id, sizeof(args->arch_args.cpu_apic_id));
|
||||
memcpy(cpu_os_id, args->arch_args.cpu_os_id, sizeof(args->arch_args.cpu_os_id));
|
||||
memcpy(cpu_apic_version, args->arch_args.cpu_apic_version, sizeof(args->arch_args.cpu_apic_version));
|
||||
apic_timer_tics_per_sec = args->arch_args.apic_time_cv_factor;
|
||||
|
||||
// setup regions that represent the apic & ioapic
|
||||
map_physical_memory("local apic", (void *)args->arch_args.apic_phys, B_PAGE_SIZE,
|
||||
@ -197,7 +179,6 @@ arch_smp_init(kernel_args *args)
|
||||
arch_smp_per_cpu_init(args, 0);
|
||||
|
||||
// I/O interrupts start at ARCH_INTERRUPT_BASE, so all interrupts are shifted
|
||||
install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, &i386_timer_interrupt, NULL, B_NO_LOCK_VECTOR);
|
||||
install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, &i386_ici_interrupt, NULL, B_NO_LOCK_VECTOR);
|
||||
install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, &i386_smp_error_interrupt, NULL, B_NO_LOCK_VECTOR);
|
||||
install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, &i386_spurious_interrupt, NULL, B_NO_LOCK_VECTOR);
|
||||
@ -268,63 +249,3 @@ arch_smp_ack_interrupt(void)
|
||||
{
|
||||
apic_write(APIC_EOI, 0);
|
||||
}
|
||||
|
||||
#define MIN_TIMEOUT 1000
|
||||
|
||||
status_t
|
||||
arch_smp_set_apic_timer(bigtime_t relativeTimeout)
|
||||
{
|
||||
cpu_status state;
|
||||
uint32 config;
|
||||
uint32 ticks;
|
||||
|
||||
if (apic == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
if (relativeTimeout < MIN_TIMEOUT)
|
||||
relativeTimeout = MIN_TIMEOUT;
|
||||
|
||||
// calculation should be ok, since it's going to be 64-bit
|
||||
ticks = ((relativeTimeout * apic_timer_tics_per_sec) / 1000000);
|
||||
|
||||
state = disable_interrupts();
|
||||
|
||||
config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer
|
||||
apic_write(APIC_LVT_TIMER, config);
|
||||
|
||||
apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer
|
||||
|
||||
config = apic_read(APIC_LVT_TIMER) & ~APIC_LVT_MASKED; // unmask the timer
|
||||
apic_write(APIC_LVT_TIMER, config);
|
||||
|
||||
TRACE_TIMER(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, tics/sec %lu, tics %lu\n",
|
||||
config, relativeTimeout, apic_timer_tics_per_sec, ticks));
|
||||
|
||||
apic_write(APIC_INITIAL_TIMER_COUNT, ticks); // start it up
|
||||
|
||||
restore_interrupts(state);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_smp_clear_apic_timer(void)
|
||||
{
|
||||
cpu_status state;
|
||||
uint32 config;
|
||||
|
||||
if (apic == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
state = disable_interrupts();
|
||||
|
||||
config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer
|
||||
apic_write(APIC_LVT_TIMER, config);
|
||||
|
||||
apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer
|
||||
|
||||
restore_interrupts(state);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
@ -32,60 +32,24 @@
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
extern timer_info gPITTimer;
|
||||
extern timer_info gAPICTimer;
|
||||
extern timer_info gHPETTimer;
|
||||
|
||||
#define PIT_CLOCK_RATE 1193180
|
||||
#define PIT_MAX_TIMER_INTERVAL (0xffff * 1000000ll / PIT_CLOCK_RATE)
|
||||
|
||||
|
||||
static void
|
||||
set_isa_hardware_timer(bigtime_t relative_timeout)
|
||||
{
|
||||
uint16 next_event_clocks;
|
||||
|
||||
if (relative_timeout <= 0)
|
||||
next_event_clocks = 2;
|
||||
else if (relative_timeout < PIT_MAX_TIMER_INTERVAL)
|
||||
next_event_clocks = relative_timeout * PIT_CLOCK_RATE / 1000000;
|
||||
else
|
||||
next_event_clocks = 0xffff;
|
||||
|
||||
out8(0x30, 0x43);
|
||||
out8(next_event_clocks & 0xff, 0x40);
|
||||
out8((next_event_clocks >> 8) & 0xff, 0x40);
|
||||
|
||||
arch_int_enable_io_interrupt(0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
clear_isa_hardware_timer(void)
|
||||
{
|
||||
// mask out the timer
|
||||
arch_int_disable_io_interrupt(0);
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
isa_timer_interrupt(void *data)
|
||||
{
|
||||
return timer_interrupt();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
apic_timer_interrupt(void)
|
||||
{
|
||||
return timer_interrupt();
|
||||
}
|
||||
static timer_info *sTimers[] = {
|
||||
&gPITTimer,
|
||||
&gAPICTimer,
|
||||
&gHPETTimer,
|
||||
NULL
|
||||
};
|
||||
|
||||
static timer_info *sTimer = NULL;
|
||||
|
||||
void
|
||||
arch_timer_set_hardware_timer(bigtime_t timeout)
|
||||
{
|
||||
TRACE(("arch_timer_set_hardware_timer: timeout %lld\n", timeout));
|
||||
// try the apic timer first
|
||||
if (arch_smp_set_apic_timer(timeout) != B_OK)
|
||||
set_isa_hardware_timer(timeout);
|
||||
sTimer->set_hardware_timer(timeout);
|
||||
}
|
||||
|
||||
|
||||
@ -93,20 +57,41 @@ void
|
||||
arch_timer_clear_hardware_timer(void)
|
||||
{
|
||||
TRACE(("arch_timer_clear_hardware_timer\n"));
|
||||
if (arch_smp_clear_apic_timer() != B_OK)
|
||||
clear_isa_hardware_timer();
|
||||
sTimer->clear_hardware_timer();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
arch_init_timer(kernel_args *args)
|
||||
{
|
||||
//dprintf("arch_init_timer: entry\n");
|
||||
int i = 0;
|
||||
int bestPriority = -1;
|
||||
timer_info *timer = NULL;
|
||||
cpu_status state = disable_interrupts();
|
||||
|
||||
install_io_interrupt_handler(0, &isa_timer_interrupt, NULL, 0);
|
||||
clear_isa_hardware_timer();
|
||||
for (i = 0; (timer = sTimers[i]) != NULL; i++) {
|
||||
int priority;
|
||||
if (timer->init(args) != B_OK) {
|
||||
TRACE(("arch_init_timer: %s failed init. Skipping.\n", timer->name));
|
||||
continue;
|
||||
}
|
||||
|
||||
// apic timer interrupt set up by smp code
|
||||
priority = timer->get_priority();
|
||||
|
||||
if (priority > bestPriority) {
|
||||
bestPriority = priority;
|
||||
sTimer = timer;
|
||||
TRACE(("arch_init_timer: %s is now best timer module with prio %d.\n", timer->name, bestPriority));
|
||||
}
|
||||
}
|
||||
|
||||
if (sTimer != NULL) {
|
||||
dprintf("arch_init_timer: using %s timer.\n", sTimer->name);
|
||||
} else {
|
||||
panic("No system timers were found usable.\n");
|
||||
}
|
||||
|
||||
restore_interrupts(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
17
src/system/kernel/arch/x86/timers/apic.h
Normal file
17
src/system/kernel/arch/x86/timers/apic.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_ARCH_x86_TIMERS_APIC_H
|
||||
#define _KERNEL_ARCH_x86_TIMERS_APIC_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
/* Method Prototypes */
|
||||
static int apic_get_prio(void);
|
||||
static status_t apic_set_hardware_timer(bigtime_t relativeTimeout);
|
||||
static status_t apic_clear_hardware_timer(void);
|
||||
static status_t apic_init(struct kernel_args *args);
|
||||
status_t apic_smp_init_timer(struct kernel_args *args, int32 cpu);
|
||||
|
||||
#endif /* _KERNEL_ARCH_x86_TIMERS_APIC_H */
|
63
src/system/kernel/arch/x86/timers/hpet.h
Normal file
63
src/system/kernel/arch/x86/timers/hpet.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_ARCH_x86_TIMERS_HPET_H
|
||||
#define _KERNEL_ARCH_x86_TIMERS_HPET_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
/* All masks are 64 bits wide to represent bit locations;
|
||||
the HPET registers are 64 bits wide. */
|
||||
|
||||
/* Global Capability Register Masks */
|
||||
#define HPET_CAP_MASK_ID 0x00000000000000FF
|
||||
#define HPET_CAP_MASK_NUMTIMERS 0x0000000000001F00
|
||||
#define HPET_CAP_MASK_WIDTH 0x0000000000002000
|
||||
#define HPET_CAP_MASK_LEGACY 0x0000000000008000
|
||||
#define HPET_CAP_MASK_VENDOR_ID 0x00000000FFFF0000
|
||||
#define HPET_CAP_MASK_PERIOD 0xFFFFFFFF00000000
|
||||
|
||||
/* Convenience macros for Capability masks */
|
||||
#define HPET_GET_ID(regs) ((regs)->caps & HPET_CAP_MASK_ID)
|
||||
#define HPET_GET_NUM_TIMERS(regs) (((regs)->caps & HPET_CAP_MASK_NUMTIMERS) >> 8)
|
||||
#define HPET_IS_64BIT_CAPABLE(regs) (((regs)->caps & HPET_CAP_MASK_WIDTH) >> 13)
|
||||
#define HPET_IS_LEGACY_CAPABLE(regs) (((regs)->caps & HPET_CAP_MASK_LEGACY) >> 15)
|
||||
#define HPET_GET_VENDOR_ID(regs) (((regs)->caps & HPET_CAP_MASK_VENDOR_ID) >> 16)
|
||||
#define HPET_GET_PERIOD(regs) (((regs)->caps & HPET_CAP_MASK_PERIOD) >> 32)
|
||||
|
||||
/* Global Configuration Masks */
|
||||
#define HPET_CONF_MASK_ENABLED 0x0000000000000001
|
||||
#define HPET_CONF_MASK_LEGACY 0x0000000000000002
|
||||
|
||||
/* Convenience macros for Config masks */
|
||||
#define HPET_IS_ENABLED(regs) ((regs)->config & HPET_CONF_MASK_ENABLED)
|
||||
#define HPET_IS_LEGACY(regs) (((regs)->config & HPET_CONF_MASK_LEGACY) >> 1)
|
||||
|
||||
struct hpet_timer {
|
||||
uint64 config; /* Timer configuration and capabilities */
|
||||
uint64 comparator; /* Comparator value */
|
||||
uint64 introute; /* FSB Interrupt Routing */
|
||||
uint64 reserved;
|
||||
};
|
||||
|
||||
|
||||
struct hpet_regs {
|
||||
uint64 caps; /* HPET Capabilities and ID */
|
||||
uint64 reserved1;
|
||||
uint64 config; /* General Configuration */
|
||||
uint64 reserved2;
|
||||
uint64 intstatus; /* General Interrupt Status */
|
||||
uint8 reserved3[200];
|
||||
uint64 mainvalue; /* Main Counter Value */
|
||||
uint64 reserved4;
|
||||
struct hpet_timer timers[1]; /* Timers */
|
||||
};
|
||||
|
||||
/* Method prototypes */
|
||||
static int hpet_get_prio(void);
|
||||
static status_t hpet_set_hardware_timer(bigtime_t relativeTimeout);
|
||||
static status_t hpet_clear_hardware_timer(void);
|
||||
static status_t hpet_init(struct kernel_args *args);
|
||||
|
||||
#endif /* _KERNEL_ARCH_x86_TIMERS_HPET_H */
|
16
src/system/kernel/arch/x86/timers/pit.h
Normal file
16
src/system/kernel/arch/x86/timers/pit.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _KERNEL_ARCH_x86_TIMERS_PIT_H
|
||||
#define _KERNEL_ARCH_x86_TIMERS_PIT_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
/* Method Prototypes */
|
||||
static int pit_get_prio(void);
|
||||
static status_t pit_set_hardware_timer(bigtime_t relativeTimeout);
|
||||
static status_t pit_clear_hardware_timer(void);
|
||||
static status_t pit_init(struct kernel_args *args);
|
||||
|
||||
#endif /* _KERNEL_ARCH_x86_TIMERS_PIT_H */
|
170
src/system/kernel/arch/x86/timers/x86_apic.c
Normal file
170
src/system/kernel/arch/x86/timers/x86_apic.c
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
|
||||
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
#include <timer.h>
|
||||
#include <arch/x86/timer.h>
|
||||
|
||||
#include <int.h>
|
||||
#include <arch/x86/smp_apic.h>
|
||||
|
||||
#include <arch/cpu.h>
|
||||
#include <arch/smp.h>
|
||||
|
||||
#include "apic.h"
|
||||
|
||||
static void *sApicPtr = NULL;
|
||||
static uint32 sApicTicsPerSec = 0;
|
||||
|
||||
struct timer_info gAPICTimer = {
|
||||
"APIC",
|
||||
&apic_get_prio,
|
||||
&apic_set_hardware_timer,
|
||||
&apic_clear_hardware_timer,
|
||||
&apic_init
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
apic_get_prio(void)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
static uint32
|
||||
_apic_read(uint32 offset)
|
||||
{
|
||||
return *(volatile uint32 *)((char *)sApicPtr + offset);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_apic_write(uint32 offset, uint32 data)
|
||||
{
|
||||
*(volatile uint32 *)((char *)sApicPtr + offset) = data;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_apic_acknowledge_interrupt(void)
|
||||
{
|
||||
_apic_write(APIC_EOI, 0);
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
apic_timer_interrupt(void *data)
|
||||
{
|
||||
_apic_acknowledge_interrupt();
|
||||
return timer_interrupt();
|
||||
}
|
||||
|
||||
|
||||
#define MIN_TIMEOUT 1000
|
||||
|
||||
static status_t
|
||||
apic_set_hardware_timer(bigtime_t relativeTimeout)
|
||||
{
|
||||
cpu_status state;
|
||||
uint32 config;
|
||||
uint32 ticks;
|
||||
|
||||
if (sApicPtr == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
if (relativeTimeout < MIN_TIMEOUT)
|
||||
relativeTimeout = MIN_TIMEOUT;
|
||||
|
||||
// calculation should be ok, since it's going to be 64-bit
|
||||
ticks = ((relativeTimeout * sApicTicsPerSec) / 1000000);
|
||||
|
||||
state = disable_interrupts();
|
||||
|
||||
config = _apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer
|
||||
_apic_write(APIC_LVT_TIMER, config);
|
||||
|
||||
_apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer
|
||||
|
||||
config = _apic_read(APIC_LVT_TIMER) & ~APIC_LVT_MASKED; // unmask the timer
|
||||
_apic_write(APIC_LVT_TIMER, config);
|
||||
|
||||
//TRACE_TIMER(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, tics/sec %lu, tics %lu\n",
|
||||
// config, relativeTimeout, sApicTicsPerSec, ticks));
|
||||
|
||||
_apic_write(APIC_INITIAL_TIMER_COUNT, ticks); // start it up
|
||||
|
||||
restore_interrupts(state);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
apic_clear_hardware_timer(void)
|
||||
{
|
||||
cpu_status state;
|
||||
uint32 config;
|
||||
|
||||
if (sApicPtr == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
state = disable_interrupts();
|
||||
|
||||
config = _apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer
|
||||
_apic_write(APIC_LVT_TIMER, config);
|
||||
|
||||
_apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer
|
||||
|
||||
restore_interrupts(state);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
apic_init(struct kernel_args *args)
|
||||
{
|
||||
/* If we're in this method, arch_smp called the special init function.
|
||||
Therefore, if we got here with sApicPtr NULL, there is no APIC! */
|
||||
if (sApicPtr == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
apic_smp_init_timer(struct kernel_args *args, int32 cpu)
|
||||
{
|
||||
uint32 config;
|
||||
|
||||
if (args->arch_args.apic == NULL) {
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
/* This is in place of apic_preinit; if we're not already initialized,
|
||||
register the interrupt handler and set the pointers */
|
||||
if (sApicPtr == NULL) {
|
||||
sApicPtr = (void *)args->arch_args.apic;
|
||||
sApicTicsPerSec = args->arch_args.apic_time_cv_factor;
|
||||
install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, &apic_timer_interrupt, NULL, B_NO_LOCK_VECTOR);
|
||||
}
|
||||
|
||||
/* setup timer */
|
||||
config = _apic_read(APIC_LVT_TIMER) & APIC_LVT_TIMER_MASK;
|
||||
config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked
|
||||
_apic_write(APIC_LVT_TIMER, config);
|
||||
|
||||
_apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the clock
|
||||
|
||||
config = _apic_read(APIC_TIMER_DIVIDE_CONFIG) & 0xfffffff0;
|
||||
config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1
|
||||
_apic_write(APIC_TIMER_DIVIDE_CONFIG, config);
|
||||
|
||||
return B_OK;
|
||||
}
|
89
src/system/kernel/arch/x86/timers/x86_hpet.c
Normal file
89
src/system/kernel/arch/x86/timers/x86_hpet.c
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
/*
|
||||
* Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <timer.h>
|
||||
#include <arch/x86/timer.h>
|
||||
|
||||
#include "hpet.h"
|
||||
|
||||
static int32 sHPETAddr;
|
||||
static struct hpet_regs *sHPETRegs;
|
||||
|
||||
struct timer_info gHPETTimer = {
|
||||
"HPET",
|
||||
&hpet_get_prio,
|
||||
&hpet_set_hardware_timer,
|
||||
&hpet_clear_hardware_timer,
|
||||
&hpet_init
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
hpet_get_prio(void)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: Implement something similar to smp_acpi_probe from boot/.../smp.cpp-
|
||||
we need to get the hpet base address without talking to the acpi module,
|
||||
because there's no guarantee that it's actually present at this early point. */
|
||||
|
||||
static int
|
||||
hpet_set_enabled(struct hpet_regs *regs, bool enabled)
|
||||
{
|
||||
if (enabled)
|
||||
regs->config |= HPET_CONF_MASK_ENABLED;
|
||||
else
|
||||
regs->config &= ~HPET_CONF_MASK_ENABLED;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
hpet_set_legacy(struct hpet_regs *regs, bool enabled)
|
||||
{
|
||||
if (!HPET_IS_LEGACY_CAPABLE(regs))
|
||||
return B_NOT_SUPPORTED;
|
||||
|
||||
if (enabled)
|
||||
regs->config |= HPET_CONF_MASK_LEGACY;
|
||||
else
|
||||
regs->config &= ~HPET_CONF_MASK_LEGACY;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
hpet_timer_interrupt(void *data)
|
||||
{
|
||||
return timer_interrupt();
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
hpet_set_hardware_timer(bigtime_t relative_timeout)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
hpet_clear_hardware_timer(void)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
hpet_init(struct kernel_args *args)
|
||||
{
|
||||
/* hpet_acpi_probe() through a similar "scan spots" table to that of smp.cpp.
|
||||
Seems to be the most elegant solution right now. */
|
||||
|
||||
/* There is no hpet support proper, so error out on init */
|
||||
return B_ERROR;
|
||||
}
|
88
src/system/kernel/arch/x86/timers/x86_pit.c
Normal file
88
src/system/kernel/arch/x86/timers/x86_pit.c
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
|
||||
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
#include <timer.h>
|
||||
#include <arch/x86/timer.h>
|
||||
|
||||
#include <arch/int.h>
|
||||
#include <arch/cpu.h>
|
||||
|
||||
#include "pit.h"
|
||||
|
||||
#define PIT_CLOCK_RATE 1193180
|
||||
#define PIT_MAX_TIMER_INTERVAL (0xffff * 1000000ll / PIT_CLOCK_RATE)
|
||||
|
||||
static bool sPITTimerInitialized = false;
|
||||
|
||||
struct timer_info gPITTimer = {
|
||||
"PIT",
|
||||
&pit_get_prio,
|
||||
&pit_set_hardware_timer,
|
||||
&pit_clear_hardware_timer,
|
||||
&pit_init
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
pit_get_prio(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
pit_timer_interrupt(void *data)
|
||||
{
|
||||
return timer_interrupt();
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
pit_set_hardware_timer(bigtime_t relativeTimeout)
|
||||
{
|
||||
uint16 nextEventClocks;
|
||||
|
||||
if (relativeTimeout <= 0)
|
||||
nextEventClocks = 2;
|
||||
else if (relativeTimeout < PIT_MAX_TIMER_INTERVAL)
|
||||
nextEventClocks = relativeTimeout * PIT_CLOCK_RATE / 1000000;
|
||||
else
|
||||
nextEventClocks = 0xffff;
|
||||
|
||||
out8(0x30, 0x43);
|
||||
out8(nextEventClocks & 0xff, 0x40);
|
||||
out8((nextEventClocks >> 8) & 0xff, 0x40);
|
||||
|
||||
arch_int_enable_io_interrupt(0);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
pit_clear_hardware_timer(void)
|
||||
{
|
||||
arch_int_disable_io_interrupt(0);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
pit_init(struct kernel_args *args)
|
||||
{
|
||||
if (sPITTimerInitialized) {
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
install_io_interrupt_handler(0, &pit_timer_interrupt, NULL, 0);
|
||||
pit_clear_hardware_timer();
|
||||
|
||||
sPITTimerInitialized = true;
|
||||
|
||||
return B_OK;
|
||||
}
|
Loading…
Reference in New Issue
Block a user