00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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_SMP
00044 if (params.mp) {
00045 times.apic_time = apic_read(APIC_TMCCT);
00046 }
00047 #endif
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, ×, sizeof(times));
00058 }
00059 rt_pend_linux_irq(TIMER_8254_IRQ);
00060 #ifdef CONFIG_SMP
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
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 int rv;
00131 unsigned long args[MAXARGS];
00132
00133 rv = copy_from_user(args, (unsigned long *)whatever, MAXARGS*sizeof(unsigned long));
00134 switch (args[0]) {
00135 case CAL_8254: {
00136 return calibrate_8254();
00137 break;
00138 }
00139
00140 case KLATENCY: {
00141 rt_set_oneshot_mode();
00142 period = start_rt_timer(nano2count(args[1]));
00143 rt_task_init_cpuid(&rtask, spv, args[2], STACKSIZE, 0, 0, 0, hard_cpu_id());
00144 expected = rt_get_time() + 100*period;
00145 rt_task_make_periodic(&rtask, expected, period);
00146 break;
00147 }
00148
00149 case END_KLATENCY: {
00150 stop_rt_timer();
00151 rt_task_delete(&rtask);
00152 break;
00153 }
00154
00155 case FREQ_CAL: {
00156 times.intrs = -1;
00157 reset_count = args[1]*100;
00158 count = 0;
00159 rt_assign_irq_to_cpu(TIMER_8254_IRQ, 1 << hard_cpu_id());
00160 rt_request_timer(just_ret, COUNT, 1);
00161 rt_request_global_irq(TIMER_8254_IRQ, calibrate);
00162 break;
00163 }
00164
00165 case END_FREQ_CAL: {
00166 rt_free_timer();
00167 rt_reset_irq_to_sym_mode(TIMER_8254_IRQ);
00168 rt_free_global_irq(TIMER_8254_IRQ);
00169 break;
00170 }
00171
00172 case BUS_CHECK: {
00173 loops = maxj = 0;
00174 bus_period = imuldiv(args[1], CPU_FREQ, 1000000000);
00175 bus_threshold = imuldiv(args[2], CPU_FREQ, 1000000000);
00176 use_parport = args[3];
00177 rt_assign_irq_to_cpu(TIMER_8254_IRQ, 1 << hard_cpu_id());
00178 rt_request_timer((void *)rt_timer_tick_ext, imuldiv(args[1], FREQ_8254, 1000000000), 0);
00179 rt_set_global_irq_ext(TIMER_8254_IRQ, 1, 0);
00180 break;
00181 }
00182
00183 case END_BUS_CHECK: {
00184 rt_free_timer();
00185 rt_reset_irq_to_sym_mode(TIMER_8254_IRQ);
00186 break;
00187 }
00188 case GET_PARAMS: {
00189 rtf_put(0, ¶ms, sizeof(params));
00190 break;
00191 }
00192 }
00193 return 0;
00194 }
00195
00196 static int srq;
00197
00198 int init_module(void)
00199 {
00200 params.mp = num_online_cpus() > 1;
00201 params.freq_apic = RTAI_FREQ_APIC;
00202 params.cpu_freq = RTAI_CPU_FREQ;
00203 rtf_create(0, FIFOBUFSIZE);
00204 if ((srq = rt_request_srq(CALSRQ, (void *)user_srq, user_srq)) < 0) {
00205 printk("No sysrq available for the calibration.\n");
00206 return srq;
00207 }
00208 return 0;
00209 }
00210
00211 void cleanup_module(void)
00212 {
00213 rt_free_srq(srq);
00214 rtf_destroy(0);
00215 return;
00216 }