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. 5 * 6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 10#include <timer.h> 11#include <arch/x86/timer.h> 12 13#include <int.h> 14#include <arch/x86/apic.h> 15 16#include <arch/cpu.h> 17 18#include "apic_timer.h" 19 20 21//#define TRACE_APIC 22#ifdef TRACE_APIC 23# define TRACE(x...) dprintf("apic: " x) 24#else 25# define TRACE(x...) ; 26#endif 27 28 29/* Method Prototypes */ 30static int apic_timer_get_priority(); 31static status_t apic_timer_set_hardware_timer(bigtime_t relativeTimeout); 32static status_t apic_timer_clear_hardware_timer(); 33static status_t apic_timer_init(struct kernel_args *args); 34 35static uint32 sApicTicsPerSec = 0; 36 37struct timer_info gAPICTimer = { 38 "APIC", 39 &apic_timer_get_priority, 40 &apic_timer_set_hardware_timer, 41 &apic_timer_clear_hardware_timer, 42 &apic_timer_init 43}; 44 45 46static int 47apic_timer_get_priority() 48{ 49 return 3; 50} 51 52 53static int32 54apic_timer_interrupt(void *data) 55{ 56 return timer_interrupt(); 57} 58 59 60#define MIN_TIMEOUT 1 61 62static status_t 63apic_timer_set_hardware_timer(bigtime_t relativeTimeout) 64{ 65 if (relativeTimeout < MIN_TIMEOUT) 66 relativeTimeout = MIN_TIMEOUT; 67 68 // calculation should be ok, since it's going to be 64-bit 69 uint32 ticks = ((relativeTimeout * sApicTicsPerSec) / 1000000); 70 71 cpu_status state = disable_interrupts(); 72 73 uint32 config = apic_lvt_timer() | APIC_LVT_MASKED; // mask the timer 74 apic_set_lvt_timer(config); 75 76 apic_set_lvt_initial_timer_count(0); // zero out the timer 77 78 config = apic_lvt_timer() & ~APIC_LVT_MASKED; // unmask the timer 79 apic_set_lvt_timer(config); 80 81 TRACE("arch_smp_set_apic_timer: config 0x%" B_PRIx32 ", timeout %" B_PRIdBIGTIME 82 ", tics/sec %" B_PRIu32 ", tics %" B_PRId32 "\n", config, relativeTimeout, 83 sApicTicsPerSec, ticks); 84 85 apic_set_lvt_initial_timer_count(ticks); // start it up 86 87 restore_interrupts(state); 88 89 return B_OK; 90} 91 92 93static status_t 94apic_timer_clear_hardware_timer() 95{ 96 cpu_status state = disable_interrupts(); 97 98 uint32 config = apic_lvt_timer() | APIC_LVT_MASKED; 99 // mask the timer 100 apic_set_lvt_timer(config); 101 102 apic_set_lvt_initial_timer_count(0); // zero out the timer 103 104 restore_interrupts(state); 105 return B_OK; 106} 107 108 109static status_t 110apic_timer_init(struct kernel_args *args) 111{ 112 if (!apic_available()) 113 return B_ERROR; 114 115 sApicTicsPerSec = args->arch_args.apic_time_cv_factor; 116 117 reserve_io_interrupt_vectors(1, 0xfb - ARCH_INTERRUPT_BASE, 118 INTERRUPT_TYPE_LOCAL_IRQ); 119 install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, 120 &apic_timer_interrupt, NULL, B_NO_LOCK_VECTOR); 121 122 return B_OK; 123} 124 125 126status_t 127apic_timer_per_cpu_init(struct kernel_args *args, int32 cpu) 128{ 129 /* setup timer */ 130 uint32 config = apic_lvt_timer() & APIC_LVT_TIMER_MASK; 131 config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked 132 apic_set_lvt_timer(config); 133 134 apic_set_lvt_initial_timer_count(0); // zero out the clock 135 136 config = apic_lvt_timer_divide_config() & 0xfffffff0; 137 config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1 138 apic_set_lvt_timer_divide_config(config); 139 return B_OK; 140} 141