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 */ 30 static int apic_timer_get_priority(); 31 static status_t apic_timer_set_hardware_timer(bigtime_t relativeTimeout); 32 static status_t apic_timer_clear_hardware_timer(); 33 static status_t apic_timer_init(struct kernel_args *args); 34 35 static uint32 sApicTicsPerSec = 0; 36 37 struct 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 46 static int 47 apic_timer_get_priority() 48 { 49 return 3; 50 } 51 52 53 static int32 54 apic_timer_interrupt(void *data) 55 { 56 return timer_interrupt(); 57 } 58 59 60 #define MIN_TIMEOUT 1 61 62 static status_t 63 apic_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 93 static status_t 94 apic_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 109 static status_t 110 apic_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 126 status_t 127 apic_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