base/arch/x86_64/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_SMP
00044     if (params.mp) {
00045         times.apic_time = apic_read(APIC_TMCCT);
00046     }
00047 #endif /* CONFIG_SMP */
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_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 /* CONFIG_SMP */
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, &params, 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 }

Generated on Tue Feb 2 17:46:04 2010 for RTAI API by  doxygen 1.4.7