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 #include <arch/smp.h> 18 19 #include "apic_timer.h" 20 21 22 /* Method Prototypes */ 23 static int apic_timer_get_priority(); 24 static status_t apic_timer_set_hardware_timer(bigtime_t relativeTimeout); 25 static status_t apic_timer_clear_hardware_timer(); 26 static status_t apic_timer_init(struct kernel_args *args); 27 28 static uint32 sApicTicsPerSec = 0; 29 30 struct timer_info gAPICTimer = { 31 "APIC", 32 &apic_timer_get_priority, 33 &apic_timer_set_hardware_timer, 34 &apic_timer_clear_hardware_timer, 35 &apic_timer_init 36 }; 37 38 39 static int 40 apic_timer_get_priority() 41 { 42 return 3; 43 } 44 45 46 static int32 47 apic_timer_interrupt(void *data) 48 { 49 return timer_interrupt(); 50 } 51 52 53 #define MIN_TIMEOUT 1 54 55 static status_t 56 apic_timer_set_hardware_timer(bigtime_t relativeTimeout) 57 { 58 if (relativeTimeout < MIN_TIMEOUT) 59 relativeTimeout = MIN_TIMEOUT; 60 61 // calculation should be ok, since it's going to be 64-bit 62 uint32 ticks = ((relativeTimeout * sApicTicsPerSec) / 1000000); 63 64 cpu_status state = disable_interrupts(); 65 66 uint32 config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer 67 apic_write(APIC_LVT_TIMER, config); 68 69 apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer 70 71 config = apic_read(APIC_LVT_TIMER) & ~APIC_LVT_MASKED; // unmask the timer 72 apic_write(APIC_LVT_TIMER, config); 73 74 //TRACE_TIMER(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, tics/sec %lu, tics %lu\n", 75 // config, relativeTimeout, sApicTicsPerSec, ticks)); 76 77 apic_write(APIC_INITIAL_TIMER_COUNT, ticks); // start it up 78 79 restore_interrupts(state); 80 81 return B_OK; 82 } 83 84 85 static status_t 86 apic_timer_clear_hardware_timer() 87 { 88 cpu_status state = disable_interrupts(); 89 90 uint32 config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; 91 // mask the timer 92 apic_write(APIC_LVT_TIMER, config); 93 94 apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer 95 96 restore_interrupts(state); 97 return B_OK; 98 } 99 100 101 static status_t 102 apic_timer_init(struct kernel_args *args) 103 { 104 if (!apic_available()) 105 return B_ERROR; 106 107 sApicTicsPerSec = args->arch_args.apic_time_cv_factor; 108 109 reserve_io_interrupt_vectors(1, 0xfb - ARCH_INTERRUPT_BASE); 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_read(APIC_LVT_TIMER) & APIC_LVT_TIMER_MASK; 122 config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked 123 apic_write(APIC_LVT_TIMER, config); 124 125 apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the clock 126 127 config = apic_read(APIC_TIMER_DIVIDE_CONFIG) & 0xfffffff0; 128 config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1 129 apic_write(APIC_TIMER_DIVIDE_CONFIG, config); 130 return B_OK; 131 } 132