headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / kernel / arch / x86 / timers / x86_apic.cpp
blob568cd65244fe669134a7c0db9e17d7f1f444e283
1 /*
2 * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved.
3 * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
4 * Distributed under the terms of the MIT License.
6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
7 * Distributed under the terms of the NewOS License.
8 */
10 #include <timer.h>
11 #include <arch/x86/timer.h>
13 #include <int.h>
14 #include <arch/x86/apic.h>
16 #include <arch/cpu.h>
18 #include "apic_timer.h"
21 /* Method Prototypes */
22 static int apic_timer_get_priority();
23 static status_t apic_timer_set_hardware_timer(bigtime_t relativeTimeout);
24 static status_t apic_timer_clear_hardware_timer();
25 static status_t apic_timer_init(struct kernel_args *args);
27 static uint32 sApicTicsPerSec = 0;
29 struct timer_info gAPICTimer = {
30 "APIC",
31 &apic_timer_get_priority,
32 &apic_timer_set_hardware_timer,
33 &apic_timer_clear_hardware_timer,
34 &apic_timer_init
38 static int
39 apic_timer_get_priority()
41 return 3;
45 static int32
46 apic_timer_interrupt(void *data)
48 return timer_interrupt();
52 #define MIN_TIMEOUT 1
54 static status_t
55 apic_timer_set_hardware_timer(bigtime_t relativeTimeout)
57 if (relativeTimeout < MIN_TIMEOUT)
58 relativeTimeout = MIN_TIMEOUT;
60 // calculation should be ok, since it's going to be 64-bit
61 uint32 ticks = ((relativeTimeout * sApicTicsPerSec) / 1000000);
63 cpu_status state = disable_interrupts();
65 uint32 config = apic_lvt_timer() | APIC_LVT_MASKED; // mask the timer
66 apic_set_lvt_timer(config);
68 apic_set_lvt_initial_timer_count(0); // zero out the timer
70 config = apic_lvt_timer() & ~APIC_LVT_MASKED; // unmask the timer
71 apic_set_lvt_timer(config);
73 //TRACE_TIMER(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, tics/sec %lu, tics %lu\n",
74 // config, relativeTimeout, sApicTicsPerSec, ticks));
76 apic_set_lvt_initial_timer_count(ticks); // start it up
78 restore_interrupts(state);
80 return B_OK;
84 static status_t
85 apic_timer_clear_hardware_timer()
87 cpu_status state = disable_interrupts();
89 uint32 config = apic_lvt_timer() | APIC_LVT_MASKED;
90 // mask the timer
91 apic_set_lvt_timer(config);
93 apic_set_lvt_initial_timer_count(0); // zero out the timer
95 restore_interrupts(state);
96 return B_OK;
100 static status_t
101 apic_timer_init(struct kernel_args *args)
103 if (!apic_available())
104 return B_ERROR;
106 sApicTicsPerSec = args->arch_args.apic_time_cv_factor;
108 reserve_io_interrupt_vectors(1, 0xfb - ARCH_INTERRUPT_BASE,
109 INTERRUPT_TYPE_LOCAL_IRQ);
110 install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE,
111 &apic_timer_interrupt, NULL, B_NO_LOCK_VECTOR);
113 return B_OK;
117 status_t
118 apic_timer_per_cpu_init(struct kernel_args *args, int32 cpu)
120 /* setup timer */
121 uint32 config = apic_lvt_timer() & APIC_LVT_TIMER_MASK;
122 config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked
123 apic_set_lvt_timer(config);
125 apic_set_lvt_initial_timer_count(0); // zero out the clock
127 config = apic_lvt_timer_divide_config() & 0xfffffff0;
128 config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1
129 apic_set_lvt_timer_divide_config(config);
130 return B_OK;