base/arch/i386/calibration/calibrate-module.c

Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 2003 Paolo Mantegazza <mantegazza@aero.polimi.it>, 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License as 00006 * published by the Free Software Foundation; either version 2 of the 00007 * License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 */ 00018 00019 #include <linux/sched.h> 00020 #include <linux/module.h> 00021 #include <linux/irq.h> 00022 #include <asm/uaccess.h> 00023 #include <asm/io.h> 00024 #include <rtai_sched.h> 00025 #include <rtai_fifos.h> 00026 #include "calibrate.h" 00027 00028 MODULE_LICENSE("GPL"); 00029 00030 #define COUNT 0xFFFFFFFFU 00031 00032 static struct params_t params = { 0, SETUP_TIME_8254, LATENCY_8254, 0, LATENCY_APIC, SETUP_TIME_APIC, CALIBRATED_APIC_FREQ, 0, CALIBRATED_CPU_FREQ, CLOCK_TICK_RATE, LATCH }; 00033 00034 static int reset_count, count; 00035 static struct times_t times; 00036 00037 static void calibrate(void) 00038 { 00039 static RTIME cpu_tbase; 00040 static unsigned long apic_tbase; 00041 00042 times.cpu_time = rd_CPU_ts(); 00043 #ifdef CONFIG_X86_LOCAL_APIC 00044 if (params.mp) { 00045 times.apic_time = apic_read(APIC_TMCCT); 00046 } 00047 #endif /* CONFIG_X86_LOCAL_APIC */ 00048 if (times.intrs < 0) { 00049 cpu_tbase = times.cpu_time; 00050 apic_tbase = times.apic_time; 00051 } 00052 times.intrs++; 00053 if (++count == reset_count) { 00054 count = 0; 00055 times.cpu_time -= cpu_tbase; 00056 times.apic_time = apic_tbase - times.apic_time; 00057 rtf_put(0, &times, sizeof(times)); 00058 } 00059 rt_pend_linux_irq(TIMER_8254_IRQ); 00060 #ifdef CONFIG_X86_LOCAL_APIC 00061 if (params.mp) { 00062 unsigned temp = (apic_read(APIC_ICR) & (~0xCDFFF)) | (APIC_DM_FIXED | APIC_DEST_ALLINC | LOCAL_TIMER_VECTOR); 00063 apic_write(APIC_ICR, temp); 00064 } 00065 #endif /* CONFIG_X86_LOCAL_APIC */ 00066 } 00067 00068 static void just_ret(void) 00069 { 00070 return; 00071 } 00072 00073 static RT_TASK rtask; 00074 static int period; 00075 static RTIME expected; 00076 00077 static void spv(long loops) 00078 { 00079 int skip, average = 0; 00080 for (skip = 0; skip < loops; skip++) { 00081 expected += period; 00082 rt_task_wait_period(); 00083 average += (int)count2nano(rt_get_time() - expected); 00084 } 00085 rtf_put(0, &average, sizeof(average)); 00086 rt_task_suspend(0); 00087 } 00088 00089 static RTIME t0; 00090 static int bus_period, bus_threshold, use_parport, loops, maxj, bit; 00091 00092 static int rt_timer_tick_ext(int irq, unsigned long data) 00093 { 00094 RTIME t; 00095 int jit; 00096 00097 if (loops++ < INILOOPS) { 00098 t0 = rdtsc(); 00099 } else { 00100 t = rdtsc(); 00101 if (use_parport) { 00102 outb(bit = 1 - bit, PARPORT); 00103 } 00104 if ((jit = abs((int)(t - t0) - bus_period)) > maxj) { 00105 maxj = jit; 00106 if (maxj > bus_threshold) { 00107 int msg; 00108 msg = imuldiv(maxj, 1000000000, CPU_FREQ); 00109 rtf_put(0, &msg, sizeof(msg)); 00110 } 00111 } 00112 t0 = t; 00113 } 00114 rt_times.tick_time = rt_times.intr_time; 00115 rt_times.intr_time = rt_times.tick_time + rt_times.periodic_tick; 00116 rt_set_timer_delay(0); 00117 if (rt_times.tick_time >= rt_times.linux_time) { 00118 rt_times.linux_time += rt_times.linux_tick; 00119 hard_sti(); 00120 rt_pend_linux_irq(TIMER_8254_IRQ); 00121 return 0; 00122 } 00123 hard_sti(); 00124 return 1; 00125 } 00126 00127 static long long user_srq(unsigned long whatever) 00128 { 00129 extern int calibrate_8254(void); 00130 unsigned long args[MAXARGS]; 00131 00132 copy_from_user(args, (unsigned long *)whatever, MAXARGS*sizeof(unsigned long)); 00133 switch (args[0]) { 00134 case CAL_8254: { 00135 return calibrate_8254(); 00136 break; 00137 } 00138 00139 case KLATENCY: { 00140 rt_set_oneshot_mode(); 00141 period = start_rt_timer(nano2count(args[1])); 00142 rt_task_init_cpuid(&rtask, spv, args[2], STACKSIZE, 0, 0, 0, hard_cpu_id()); 00143 expected = rt_get_time() + 100*period; 00144 rt_task_make_periodic(&rtask, expected, period); 00145 break; 00146 } 00147 00148 case END_KLATENCY: { 00149 stop_rt_timer(); 00150 rt_task_delete(&rtask); 00151 break; 00152 } 00153 00154 case FREQ_CAL: { 00155 times.intrs = -1; 00156 reset_count = args[1]*HZ; 00157 count = 0; 00158 rt_assign_irq_to_cpu(TIMER_8254_IRQ, 1 << hard_cpu_id()); 00159 rt_request_timer(just_ret, COUNT, 1); 00160 rt_request_global_irq(TIMER_8254_IRQ, calibrate); 00161 break; 00162 } 00163 00164 case END_FREQ_CAL: { 00165 rt_free_timer(); 00166 rt_reset_irq_to_sym_mode(TIMER_8254_IRQ); 00167 rt_free_global_irq(TIMER_8254_IRQ); 00168 break; 00169 } 00170 00171 case BUS_CHECK: { 00172 loops = maxj = 0; 00173 bus_period = imuldiv(args[1], CPU_FREQ, 1000000000); 00174 bus_threshold = imuldiv(args[2], CPU_FREQ, 1000000000); 00175 use_parport = args[3]; 00176 rt_assign_irq_to_cpu(TIMER_8254_IRQ, 1 << hard_cpu_id()); 00177 rt_request_timer((void *)rt_timer_tick_ext, imuldiv(args[1], FREQ_8254, 1000000000), 0); 00178 rt_set_global_irq_ext(TIMER_8254_IRQ, 1, 0); 00179 break; 00180 } 00181 00182 case END_BUS_CHECK: { 00183 rt_free_timer(); 00184 rt_reset_irq_to_sym_mode(TIMER_8254_IRQ); 00185 break; 00186 } 00187 case GET_PARAMS: { 00188 rtf_put(0, &params, sizeof(params)); 00189 break; 00190 } 00191 } 00192 return 0; 00193 } 00194 00195 static int srq; 00196 00197 int init_module(void) 00198 { 00199 #ifdef CONFIG_X86_LOCAL_APIC 00200 params.mp = 1; 00201 #endif /* CONFIG_X86_LOCAL_APIC */ 00202 params.freq_apic = RTAI_FREQ_APIC; 00203 params.cpu_freq = RTAI_CPU_FREQ; 00204 rtf_create(0, FIFOBUFSIZE); 00205 if ((srq = rt_request_srq(CALSRQ, (void *)user_srq, user_srq)) < 0) { 00206 printk("No sysrq available for the calibration.\n"); 00207 return srq; 00208 } 00209 return 0; 00210 } 00211 00212 void cleanup_module(void) 00213 { 00214 rt_free_srq(srq); 00215 rtf_destroy(0); 00216 return; 00217 }

Generated on Thu Nov 20 11:49:47 2008 for RTAI API by doxygen 1.3.8