FreeBSD/Linux Kernel Cross Reference
sys/sqt/clock.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992,1991 Carnegie Mellon University
4 * Copyright (c) 1991 Sequent Computer Systems
5 * All Rights Reserved.
6 *
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation is hereby granted, provided that both the copyright
9 * notice and this permission notice appear in all copies of the
10 * software, derivative works or modified versions, and any portions
11 * thereof, and that both notices appear in supporting documentation.
12 *
13 * CARNEGIE MELLON AND SEQUENT COMPUTER SYSTEMS ALLOW FREE USE OF
14 * THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND
15 * SEQUENT COMPUTER SYSTEMS DISCLAIM ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 *
18 * Carnegie Mellon requests users of this software to return to
19 *
20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
24 *
25 * any improvements or extensions that they make and grant Carnegie Mellon
26 * the rights to redistribute these changes.
27 */
28
29 /*
30 * HISTORY
31 * $Log: clock.c,v $
32 * Revision 2.4 93/11/17 18:45:58 dbg
33 * Added clock device code for new real-time clocks. Clock rate is
34 * (currently) fixed.
35 * [93/04/16 dbg]
36 *
37 * Revision 2.3 91/07/31 18:00:21 dbg
38 * Changed copyright.
39 * [91/07/31 dbg]
40 *
41 * Revision 2.2 91/05/08 12:55:04 dbg
42 * Adapted from Sequent Symmetry sources.
43 * [91/04/26 14:50:24 dbg]
44 *
45 */
46
47 #ifndef lint
48 static char rcsid[] = "$Header: clock.c,v 2.4 93/11/17 18:45:58 dbg Exp $";
49 #endif
50
51 /*
52 * Machine-dependent clock routines.
53 *
54 * Included are the time-of-day clock initialization and
55 * the per processor real-time clock initialization.
56 */
57
58 /*
59 * Revision 1.2 89/07/20 18:05:38 kak
60 * moved balance includes
61 *
62 * Revision 1.1 89/07/05 13:15:27 kak
63 * Initial revision
64 *
65 */
66
67 #include <mach/boolean.h>
68 #include <mach/time_spec.h>
69
70 #include <kern/clock.h>
71 #include <kern/kern_io.h>
72 #include <device/device_types.h>
73 #include <device/clock_dev.h>
74 #include <device/clock_status.h>
75 #include <machine/machspl.h>
76
77 #include <sqt/cfg.h>
78 #include <sqt/clock.h>
79 #include <sqt/slic.h>
80
81 #include <sqt/ioconf.h>
82 #include <sqt/vm_defs.h>
83 #include <sqt/hwparam.h>
84 #include <sqt/intctl.h>
85
86 #include <sqtsec/sec.h>
87
88 extern u_char cons_scsi; /* console scsi slic address */
89
90 /* For time-of-day handling */
91 struct sec_cib *todcib;
92 struct sec_gmode todgm; /* getmodes command */
93 struct sec_smode todsm; /* setmodes command */
94
95 #define CLOCKSQT_DEFAULT_RESOLUTION (NANOSEC_PER_SEC/HZ) /* 100 hz */
96
97 mach_clock_data_t clocksqt0;
98
99 void clocksqt_setresolution(mach_clock_t); /* forward */
100 void clocksqt_enable_interrupts(mach_clock_t);
101 void clocksqt_write(mach_clock_t, time_spec_t);
102 time_spec_t clocksqt_read(void);
103
104 struct clock_ops clocksqt_ops = {
105 clocksqt_setresolution,
106 clocksqt_write,
107 clocksqt_enable_interrupts
108 };
109
110 void clocksqt_init(void)
111 {
112 mach_clock_t clock = &clocksqt0;
113 time_spec_t cur_time;
114
115 clock_init(clock, &clocksqt_ops);
116
117 clock->resolution = CLOCKSQT_DEFAULT_RESOLUTION; /* @100 hz */
118 clocksqt_setresolution(clock);
119
120 sys_clock = &clocksqt0;
121
122 /*
123 * Read the current time from the TOD clock
124 */
125 cur_time = clocksqt_read();
126
127 clocksqt0.check_seconds = cur_time.seconds;
128 clocksqt0.time.nanoseconds = cur_time.nanoseconds;
129 clocksqt0.time.seconds = cur_time.seconds;
130 }
131
132 /*
133 * startrtclock()
134 * Start the real-time clock.
135 *
136 * Startrtclock restarts the real-time clock, which provides
137 * hardclock interrupts to kern_clock.c. On Sequent HW, this
138 * is one-time only per processor (eg, no restart, clock reprimes
139 * itself).
140 *
141 * Called by localinit() during selfinit().
142 * This turns on the processor-local SLIC timer.
143 *
144 * For testing/performance measurement convenience, enable_local_clock
145 * allows the per-processor clock to be left OFF. Need to patch the
146 * kernel binary or system memory to effect this.
147 */
148 static boolean_t enable_local_clock = TRUE; /* default ON */
149
150 void clocksqt_setresolution(
151 mach_clock_t clock)
152 {
153 register struct cpuslic *sl = va_slic;
154 spl_t s;
155
156 if (!enable_local_clock)
157 return;
158
159 /*
160 * Stop updates while we fix it
161 */
162 s = splhi();
163
164 sl->sl_trv = ((sys_clock_rate * 1000000) / (SL_TIMERDIV * HZ)) - 1;
165 /* clear prescaler, load reload value */
166 sl->sl_tcont = 0;
167 sl->sl_tctl = SL_TIMERINT | LCLKBIN; /* timer on in given bin */
168
169 splx(s);
170 }
171
172 /*
173 * Enable interrupts from MC clock chip
174 */
175 void clocksqt_enable_interrupts(
176 mach_clock_t clock)
177 {
178 clocksqt_setresolution(clock);
179 }
180
181 io_return_t clk_open(
182 int dev)
183 {
184 if (dev != 0)
185 return D_NO_SUCH_DEVICE;
186
187 return clock_open(&clocksqt0);
188 }
189
190 io_return_t clk_close(
191 int dev)
192 {
193 return D_SUCCESS;
194 }
195
196
197 io_return_t clk_getstat(
198 int dev,
199 int flavor,
200 dev_status_t stat,
201 natural_t *count)
202 {
203 return clock_getstat(&clocksqt0, flavor, stat, count);
204 }
205
206 io_return_t clk_setstat(
207 int dev,
208 int flavor,
209 dev_status_t stat,
210 natural_t count)
211 {
212 /*
213 * Can`t change resolution (would have to
214 * change it on all CPUs)
215 */
216 return clock_setstat(&clocksqt0, flavor, stat, count);
217 }
218
219 vm_offset_t clk_mmap(
220 dev_t dev,
221 vm_offset_t off,
222 vm_prot_t prot)
223 {
224 return clock_map_page(&clocksqt0, off, prot);
225 }
226
227 io_return_t clk_info(
228 int dev,
229 int flavor,
230 mach_clock_t *info)
231 {
232 if (flavor == D_INFO_CLOCK) {
233 *info = &clocksqt0;
234 return D_SUCCESS;
235 }
236 else {
237 return D_INVALID_OPERATION;
238 }
239 }
240
241 /*
242 * Routines to manipulate the SCED based time-of-day register.
243 * TOD clock interrupt handling done by todclock in kern_clock.c
244 *
245 *
246 * Inittodr initializes the time-of-day hardware which provides
247 * date functions. This starts the time-of-day clock.
248 *
249 */
250 time_spec_t clocksqt_read(void)
251 {
252 time_spec_t todr = { 0, 0 };
253 register struct sec_gmode *todgmptr = &todgm;
254 register int i;
255 spl_t s_ipl;
256
257 if (todcib == 0) {
258 printf("todcib null - inittodr returning!\n");
259 return todr;
260 }
261
262 /*
263 * Find console SCED and check if the TOD clock has
264 * failed powerup diagnostics.
265 */
266 for (i = 0; i < NSEC; i++) {
267 /* is SEC there? */
268 if ((SECvec & (1 << i)) == 0)
269 continue;
270
271 if (SEC_desc[i].sec_is_cons)
272 break;
273 }
274 if (SEC_desc[i].sec_diag_flags & CFG_S_TOD) {
275 /*
276 * Clear todr if TOD failed powerup diagnostics.
277 */
278 printf("WARNING: TOD failed powerup diagnostics\n");
279 } else {
280 /*
281 * get the current time-of-day from the SCED tod clock.
282 */
283 todgmptr->gm_status = 0;
284 todcib->cib_inst = SINST_GETMODE;
285 todcib->cib_status = KVTOPHYS(&todgm, int *);
286 s_ipl = splhi();
287 mIntr(cons_scsi, TODCLKBIN, SDEV_TOD);
288 splx(s_ipl);
289
290 while ((todgmptr->gm_status & SINST_INSDONE) == 0)
291 continue;
292
293 if (todgmptr->gm_status != SINST_INSDONE)
294 panic("Cannot get TOD value");
295
296 todr.seconds = todgmptr->gm_un.gm_tod.tod_newtime;
297 }
298
299 if (todr.seconds < 13*SECYR) {
300 printf("WARNING: TOD value bad -- ");
301 printf("Setting TOD to default time\n");
302 todr.seconds = 13*SECYR + 19*SECDAY + (2*SECDAY)/3;
303 }
304
305 /*
306 * Return the time.
307 */
308
309 return todr;
310 }
311
312 /*
313 * Set TOD clock from clock.
314 */
315 void clocksqt_write(
316 mach_clock_t clock,
317 time_spec_t new_time)
318 {
319 register struct sec_smode *todsmptr = &todsm;
320 spl_t s_ipl;
321
322 /*
323 * Update hardware, to nearest second
324 */
325 todsmptr->sm_status = 0;
326 todsmptr->sm_un.sm_tod.tod_freq = TODFREQ;
327 todcib->cib_inst = SINST_SETMODE;
328 todcib->cib_status = KVTOPHYS(&todsm, int *);
329
330 s_ipl = splhi();
331 todsmptr->sm_un.sm_tod.tod_newtime = new_time.seconds;
332
333 /*
334 * Bin 3 is sufficient, helps avoid SLIC-bus lockup.
335 */
336 mIntr(cons_scsi, 3, SDEV_TOD);
337 splx(s_ipl);
338
339 while ((todsmptr->sm_status & SINST_INSDONE) == 0)
340 continue;
341
342 if (todsmptr->sm_status != SINST_INSDONE)
343 panic("Cannot set TOD value");
344 }
Cache object: 745b3ed761bdb0be334a0bf10d8dabd3
|