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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [kernel/] [time.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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