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     int ret;
00132 
00133     ret = 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 KTHREADS:
00141         case KLATENCY: {
00142             rt_set_oneshot_mode();
00143             period = start_rt_timer(nano2count(args[1]));
00144             if (args[0] == KLATENCY) {
00145                 rt_task_init_cpuid(&rtask, spv, args[2], STACKSIZE, 0, 0, 0, hard_cpu_id());
00146             } else {
00147                 rt_kthread_init_cpuid(&rtask, spv, args[2], STACKSIZE, 0, 0, 0, hard_cpu_id()); 
00148             }
00149             expected = rt_get_time() + 100*period;
00150             rt_task_make_periodic(&rtask, expected, period);
00151             break;
00152         }
00153 
00154         case END_KLATENCY: {
00155             stop_rt_timer();
00156             rt_task_delete(&rtask);
00157             break;
00158         }
00159 
00160         case FREQ_CAL: {
00161             times.intrs = -1;
00162             reset_count = args[1]*HZ;
00163             count = 0;
00164             rt_assign_irq_to_cpu(TIMER_8254_IRQ, 1 << hard_cpu_id());
00165             rt_request_timer(just_ret, COUNT, 1);
00166             rt_request_global_irq(TIMER_8254_IRQ, calibrate);
00167             break;
00168         }
00169 
00170         case END_FREQ_CAL: {
00171                 rt_free_timer();
00172                 rt_reset_irq_to_sym_mode(TIMER_8254_IRQ);
00173                 rt_free_global_irq(TIMER_8254_IRQ);
00174             break;
00175         }
00176 
00177         case BUS_CHECK: {
00178             loops = maxj = 0;
00179             bus_period = imuldiv(args[1], CPU_FREQ, 1000000000);
00180             bus_threshold = imuldiv(args[2], CPU_FREQ, 1000000000);
00181             use_parport = args[3];
00182             rt_assign_irq_to_cpu(TIMER_8254_IRQ, 1 << hard_cpu_id());
00183             rt_request_timer((void *)rt_timer_tick_ext, imuldiv(args[1], FREQ_8254, 1000000000), 0);
00184             rt_set_global_irq_ext(TIMER_8254_IRQ, 1, 0);
00185             break;
00186         }
00187 
00188         case END_BUS_CHECK: {
00189                 rt_free_timer();
00190                 rt_reset_irq_to_sym_mode(TIMER_8254_IRQ);
00191             break;
00192         }
00193         case GET_PARAMS: {
00194             rtf_put(0, &params, sizeof(params));
00195             break;
00196         }
00197     } 
00198     return 0;
00199 }
00200 
00201 static int srq;
00202 
00203 int init_module(void)
00204 {
00205 #ifdef CONFIG_X86_LOCAL_APIC
00206     params.mp        = 1;
00207 #endif /* CONFIG_X86_LOCAL_APIC */
00208     params.freq_apic = RTAI_FREQ_APIC;
00209     params.cpu_freq  = RTAI_CPU_FREQ;
00210     rtf_create(0, FIFOBUFSIZE);
00211     if ((srq = rt_request_srq(CALSRQ, (void *)user_srq, user_srq)) < 0) {
00212                 printk("No sysrq available for the calibration.\n");
00213                 return srq;
00214     }
00215     return 0;
00216 }
00217 
00218 void cleanup_module(void)
00219 {
00220     rt_free_srq(srq);
00221     rtf_destroy(0);
00222     return;
00223 }

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