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 /* 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); 26 27 static uint32 sApicTicsPerSec = 0; 28 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 35 }; 36 37 38 static int 39 apic_timer_get_priority() 40 { 41 return 3; 42 } 43 44 45 static int32 46 apic_timer_interrupt(void *data) 47 { 48 return timer_interrupt(); 49 } 50 51 52 #define MIN_TIMEOUT 1 53 54 static status_t 55 apic_timer_set_hardware_timer(bigtime_t relativeTimeout) 56 { 57 if (relativeTimeout < MIN_TIMEOUT) 58 relativeTimeout = MIN_TIMEOUT; 59 60 // calculation should be ok, since it's going to be 64-bit 61 uint32 ticks = ((relativeTimeout * sApicTicsPerSec) / 1000000); 62 63 cpu_status state = disable_interrupts(); 64 65 uint32 config = apic_lvt_timer() | APIC_LVT_MASKED; // mask the timer 66 apic_set_lvt_timer(config); 67 68 apic_set_lvt_initial_timer_count(0); // zero out the timer 69 70 config = apic_lvt_timer() & ~APIC_LVT_MASKED; // unmask the timer 71 apic_set_lvt_timer(config); 72 73 //TRACE_TIMER(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, tics/sec %lu, tics %lu\n", 74 // config, relativeTimeout, sApicTicsPerSec, ticks)); 75 76 apic_set_lvt_initial_timer_count(ticks); // start it up 77 78 restore_interrupts(state); 79 80 return B_OK; 81 } 82 83 84 static status_t 85 apic_timer_clear_hardware_timer() 86 { 87 cpu_status state = disable_interrupts(); 88 89 uint32 config = apic_lvt_timer() | APIC_LVT_MASKED; 90 // mask the timer 91 apic_set_lvt_timer(config); 92 93 apic_set_lvt_initial_timer_count(0); // zero out the timer 94 95 restore_interrupts(state); 96 return B_OK; 97 } 98 99 100 static status_t 101 apic_timer_init(struct kernel_args *args) 102 { 103 if (!apic_available()) 104 return B_ERROR; 105 106 sApicTicsPerSec = args->arch_args.apic_time_cv_factor; 107 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); 112 113 return B_OK; 114 } 115 116 117 status_t 118 apic_timer_per_cpu_init(struct kernel_args *args, int32 cpu) 119 { 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); 124 125 apic_set_lvt_initial_timer_count(0); // zero out the clock 126 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; 131 } 132