OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [kernel/] [time.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/kernel/time.c
3
 *
4
 *  Copyright (C) 1991, 1992  Linus Torvalds
5
 *
6
 *  This file contains the interface functions for the various
7
 *  time related system calls: time, stime, gettimeofday, settimeofday,
8
 *                             adjtime
9
 */
10
/*
11
 * Modification history kernel/time.c
12
 *
13
 * 1993-09-02    Philip Gladstone
14
 *      Created file with time related functions from sched.c and adjtimex()
15
 * 1993-10-08    Torsten Duwe
16
 *      adjtime interface update and CMOS clock write code
17
 * 1995-08-13    Torsten Duwe
18
 *      kernel PLL updated to 1994-12-13 specs (rfc-1589)
19
 * 1996-10-22, 1997-09-13    Ulrich Windl
20
 *      support for external PPS signal, error checking in adjtimex()
21
 *      Updated NTP code according to technical memorandum Jan '96
22
 *      "A Kernel Model for Precision Timekeeping" by Dave Mills
23
 * 1998-03-05   Ulrich Windl
24
 *      Allow time_constant larger than MAXTC(6) for NTP v4
25
 *      (debated with and blessed by Dave Mills, despite of earlier work
26
 *      and words)
27
 */
28
 
29
#include <linux/errno.h>
30
#include <linux/sched.h>
31
#include <linux/kernel.h>
32
#include <linux/param.h>
33
#include <linux/string.h>
34
#include <linux/mm.h>
35
#include <linux/timex.h>
36
 
37
#include <asm/segment.h>
38
 
39
/*
40
 * The timezone where the local system is located.  Used as a default by some
41
 * programs who obtain this value by using gettimeofday.
42
 */
43
struct timezone sys_tz = { 0, 0};
44
 
45
#ifndef __alpha__
46
 
47
/*
48
 * sys_time() can be implemented in user-level using
49
 * sys_gettimeofday().  Is this for backwards compatibility?  If so,
50
 * why not move it into the appropriate arch directory (for those
51
 * architectures that need it).
52
 */
53
asmlinkage int sys_time(int * tloc)
54
{
55
        int i;
56
 
57
        i = CURRENT_TIME;
58
        if (tloc) {
59
                int error = verify_area(VERIFY_WRITE, tloc, sizeof(*tloc));
60
                if (error)
61
                        return error;
62
                put_user(i,tloc);
63
        }
64
        return i;
65
}
66
 
67
/*
68
 * sys_stime() can be implemented in user-level using
69
 * sys_settimeofday().  Is this for backwards compatibility?  If so,
70
 * why not move it into the appropriate arch directory (for those
71
 * architectures that need it).
72
 */
73
asmlinkage int sys_stime(int * tptr)
74
{
75
        int error, value;
76
 
77
        if (!suser())
78
                return -EPERM;
79
        error = verify_area(VERIFY_READ, tptr, sizeof(*tptr));
80
        if (error)
81
                return error;
82
        value = get_user(tptr);
83
        cli();
84
        xtime.tv_sec = value;
85
        xtime.tv_usec = 0;
86
        time_adjust = 0; /* stop active adjtime() */
87
        time_status |= STA_UNSYNC;
88
        time_state = TIME_ERROR;        /* p. 24, (a) */
89
        time_maxerror = NTP_PHASE_LIMIT;
90
        time_esterror = NTP_PHASE_LIMIT;
91
        sti();
92
        return 0;
93
}
94
 
95
#endif
96
 
97
asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
98
{
99
        int error;
100
 
101
        if (tv) {
102
                struct timeval ktv;
103
                error = verify_area(VERIFY_WRITE, tv, sizeof *tv);
104
                if (error)
105
                        return error;
106
                do_gettimeofday(&ktv);
107
                memcpy_tofs(tv, &ktv, sizeof(ktv));
108
        }
109
        if (tz) {
110
                error = verify_area(VERIFY_WRITE, tz, sizeof *tz);
111
                if (error)
112
                        return error;
113
                memcpy_tofs(tz, &sys_tz, sizeof(sys_tz));
114
        }
115
        return 0;
116
}
117
 
118
/*
119
 * Adjust the time obtained from the CMOS to be UTC time instead of
120
 * local time.
121
 *
122
 * This is ugly, but preferable to the alternatives.  Otherwise we
123
 * would either need to write a program to do it in /etc/rc (and risk
124
 * confusion if the program gets run more than once; it would also be
125
 * hard to make the program warp the clock precisely n hours)  or
126
 * compile in the timezone information into the kernel.  Bad, bad....
127
 *
128
 *                                              - TYT, 1992-01-01
129
 *
130
 * The best thing to do is to keep the CMOS clock in universal time (UTC)
131
 * as real UNIX machines always do it. This avoids all headaches about
132
 * daylight saving times and warping kernel clocks.
133
 */
134
inline static void warp_clock(void)
135
{
136
        cli();
137
        xtime.tv_sec += sys_tz.tz_minuteswest * 60;
138
        sti();
139
}
140
 
141
/*
142
 * In case for some reason the CMOS clock has not already been running
143
 * in UTC, but in some local time: The first time we set the timezone,
144
 * we will warp the clock so that it is ticking UTC time instead of
145
 * local time. Presumably, if someone is setting the timezone then we
146
 * are running in an environment where the programs understand about
147
 * timezones. This should be done at boot time in the /etc/rc script,
148
 * as soon as possible, so that the clock can be set right. Otherwise,
149
 * various programs will get confused when the clock gets warped.
150
 */
151
asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
152
{
153
        static int      firsttime = 1;
154
        struct timeval  new_tv;
155
        struct timezone new_tz;
156
 
157
        if (!suser())
158
                return -EPERM;
159
        if (tv) {
160
                int error = verify_area(VERIFY_READ, tv, sizeof(*tv));
161
                if (error)
162
                        return error;
163
                memcpy_fromfs(&new_tv, tv, sizeof(*tv));
164
        }
165
        if (tz) {
166
                int error = verify_area(VERIFY_READ, tz, sizeof(*tz));
167
                if (error)
168
                        return error;
169
                memcpy_fromfs(&new_tz, tz, sizeof(*tz));
170
        }
171
        if (tz) {
172
                sys_tz = new_tz;
173
                if (firsttime) {
174
                        firsttime = 0;
175
                        if (!tv)
176
                                warp_clock();
177
                }
178
        }
179
        if (tv)
180
                do_settimeofday(&new_tv);
181
        return 0;
182
}
183
 
184
long pps_offset = 0;             /* pps time offset (us) */
185
long pps_jitter = MAXTIME;      /* time dispersion (jitter) (us) */
186
 
187
long pps_freq = 0;               /* frequency offset (scaled ppm) */
188
long pps_stabil = MAXFREQ;      /* frequency dispersion (scaled ppm) */
189
 
190
long pps_valid = PPS_VALID;     /* pps signal watchdog counter */
191
 
192
int pps_shift = PPS_SHIFT;      /* interval duration (s) (shift) */
193
 
194
long pps_jitcnt = 0;             /* jitter limit exceeded */
195
long pps_calcnt = 0;             /* calibration intervals */
196
long pps_errcnt = 0;             /* calibration errors */
197
long pps_stbcnt = 0;             /* stability limit exceeded */
198
 
199
/* hook for a loadable hardpps kernel module */
200
void (*hardpps_ptr)(struct timeval *) = (void (*)(struct timeval *))0;
201
 
202
/* adjtimex mainly allows reading (and writing, if superuser) of
203
 * kernel time-keeping variables. used by xntpd.
204
 */
205
asmlinkage int sys_adjtimex(struct timex *txc_p)
206
{
207
        long ltemp, mtemp, save_adjust;
208
        int error = 0;
209
 
210
        /* Local copy of parameter */
211
        struct timex txc;
212
 
213
        error = verify_area(VERIFY_WRITE, txc_p, sizeof(struct timex));
214
        if (error)
215
                return error;   /* do not write results */
216
 
217
        /* Copy the user data space into the kernel copy
218
         * structure. But bear in mind that the structures
219
         * may change
220
         */
221
        memcpy_fromfs(&txc, txc_p, sizeof(struct timex));
222
 
223
        /* In order to modify anything, you gotta be super-user! */
224
        if (txc.modes && !suser())
225
                return -EPERM;
226
 
227
        /* Now we validate the data before disabling interrupts
228
         */
229
        if (txc.modes != ADJ_OFFSET_SINGLESHOT && (txc.modes & ADJ_OFFSET))
230
                /* adjustment Offset limited to +- .512 seconds */
231
                if (txc.offset <= - MAXPHASE || txc.offset >= MAXPHASE )
232
                        return -EINVAL;
233
 
234
        cli();
235
 
236
        /* Save for later - semantics of adjtime() is to return old value */
237
        save_adjust = time_adjust;
238
 
239
        /* If there are input parameters, then process them */
240
#if 0   /* STA_CLOCKERR is never set yet */
241
        time_status &= ~STA_CLOCKERR;           /* reset STA_CLOCKERR */
242
#endif
243
        if (txc.modes)
244
        {
245
            if (time_state == TIME_ERROR)
246
                time_state = TIME_OK;           /* reset error -- why? */
247
 
248
            if (txc.modes & ADJ_STATUS) /* only set allowed bits */
249
                time_status = (txc.status & ~STA_RONLY) |
250
                              (time_status & STA_RONLY);
251
 
252
            if (txc.modes & ADJ_FREQUENCY) {    /* p. 22 */
253
                if (txc.freq > MAXFREQ || txc.freq < -MAXFREQ) {
254
                    error = -EINVAL;
255
                    goto leave;
256
                }
257
                time_freq = txc.freq - pps_freq;
258
            }
259
 
260
            if (txc.modes & ADJ_MAXERROR) {
261
                if (txc.maxerror < 0 || txc.maxerror >= NTP_PHASE_LIMIT) {
262
                    error = -EINVAL;
263
                    goto leave;
264
                }
265
                time_maxerror = txc.maxerror;
266
            }
267
 
268
            if (txc.modes & ADJ_ESTERROR) {
269
                if (txc.esterror < 0 || txc.esterror >= NTP_PHASE_LIMIT) {
270
                    error = -EINVAL;
271
                    goto leave;
272
                }
273
                time_esterror = txc.esterror;
274
            }
275
 
276
            if (txc.modes & ADJ_TIMECONST) {    /* p. 24 */
277
                if (txc.constant < 0) {          /* NTP v4 uses values > 6 */
278
                    error = -EINVAL;
279
                    goto leave;
280
                }
281
                time_constant = txc.constant;
282
            }
283
 
284
            if (txc.modes & ADJ_OFFSET) {       /* values checked earlier */
285
                if (txc.modes == ADJ_OFFSET_SINGLESHOT) {
286
                    /* adjtime() is independent from ntp_adjtime() */
287
                    time_adjust = txc.offset;
288
                }
289
                else if ( time_status & (STA_PLL | STA_PPSTIME) ) {
290
                    ltemp = (time_status & (STA_PPSTIME | STA_PPSSIGNAL)) ==
291
                            (STA_PPSTIME | STA_PPSSIGNAL) ?
292
                            pps_offset : txc.offset;
293
 
294
                    /*
295
                     * Scale the phase adjustment and
296
                     * clamp to the operating range.
297
                     */
298
                    if (ltemp > MAXPHASE)
299
                        time_offset = MAXPHASE << SHIFT_UPDATE;
300
                    else if (ltemp < -MAXPHASE)
301
                        time_offset = -(MAXPHASE << SHIFT_UPDATE);
302
                    else
303
                        time_offset = ltemp << SHIFT_UPDATE;
304
 
305
                    /*
306
                     * Select whether the frequency is to be controlled
307
                     * and in which mode (PLL or FLL). Clamp to the operating
308
                     * range. Ugly multiply/divide should be replaced someday.
309
                     */
310
 
311
                    if (time_status & STA_FREQHOLD || time_reftime == 0)
312
                        time_reftime = xtime.tv_sec;
313
                    mtemp = xtime.tv_sec - time_reftime;
314
                    time_reftime = xtime.tv_sec;
315
                    if (time_status & STA_FLL) {
316
                        if (mtemp >= MINSEC) {
317
                            ltemp = (time_offset / mtemp) << (SHIFT_USEC -
318
                                                              SHIFT_UPDATE);
319
                            if (ltemp < 0)
320
                                time_freq -= -ltemp >> SHIFT_KH;
321
                            else
322
                                time_freq += ltemp >> SHIFT_KH;
323
                        } else /* calibration interval too short (p. 12) */
324
                                time_state = TIME_ERROR;
325
                    } else {    /* PLL mode */
326
                        if (mtemp < MAXSEC) {
327
                            ltemp *= mtemp;
328
                            if (ltemp < 0)
329
                                time_freq -= -ltemp >> (time_constant +
330
                                                        time_constant +
331
                                                        SHIFT_KF - SHIFT_USEC);
332
                            else
333
                                time_freq += ltemp >> (time_constant +
334
                                                       time_constant +
335
                                                       SHIFT_KF - SHIFT_USEC);
336
                        } else /* calibration interval too long (p. 12) */
337
                                time_state = TIME_ERROR;
338
                    }
339
                    if (time_freq > time_tolerance)
340
                        time_freq = time_tolerance;
341
                    else if (time_freq < -time_tolerance)
342
                        time_freq = -time_tolerance;
343
                } /* STA_PLL || STA_PPSTIME */
344
            } /* txc.modes & ADJ_OFFSET */
345
            if (txc.modes & ADJ_TICK) {
346
                /* if the quartz is off by more than 10% something is
347
                   VERY wrong ! */
348
                if (txc.tick < 900000/HZ || txc.tick > 1100000/HZ) {
349
                    error = -EINVAL;
350
                    goto leave;
351
                }
352
                tick = txc.tick;
353
            }
354
        } /* txc.modes */
355
leave:  if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
356
            || ((time_status & (STA_PPSFREQ|STA_PPSTIME)) != 0
357
                && (time_status & STA_PPSSIGNAL) == 0)
358
            /* p. 24, (b) */
359
            || ((time_status & (STA_PPSTIME|STA_PPSJITTER))
360
                == (STA_PPSTIME|STA_PPSJITTER))
361
            /* p. 24, (c) */
362
            || ((time_status & STA_PPSFREQ) != 0
363
                && (time_status & (STA_PPSWANDER|STA_PPSERROR)) != 0))
364
            /* p. 24, (d) */
365
                time_state = TIME_ERROR;
366
 
367
        if ((txc.modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
368
            txc.offset     = save_adjust;
369
        else {
370
            if (time_offset < 0)
371
                txc.offset = -(-time_offset >> SHIFT_UPDATE);
372
            else
373
                txc.offset = time_offset >> SHIFT_UPDATE;
374
        }
375
        txc.freq           = time_freq + pps_freq;
376
        txc.maxerror       = time_maxerror;
377
        txc.esterror       = time_esterror;
378
        txc.status         = time_status;
379
        txc.constant       = time_constant;
380
        txc.precision      = time_precision;
381
        txc.tolerance      = time_tolerance;
382
        do_gettimeofday(&txc.time);
383
        txc.tick           = tick;
384
        txc.ppsfreq        = pps_freq;
385
        txc.jitter         = pps_jitter >> PPS_AVG;
386
        txc.shift          = pps_shift;
387
        txc.stabil         = pps_stabil;
388
        txc.jitcnt         = pps_jitcnt;
389
        txc.calcnt         = pps_calcnt;
390
        txc.errcnt         = pps_errcnt;
391
        txc.stbcnt         = pps_stbcnt;
392
 
393
        sti();
394
 
395
        memcpy_tofs(txc_p, &txc, sizeof(struct timex));
396
        return(error < 0 ? error : time_state);
397
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.