xref: /openbsd-src/sys/arch/hppa/dev/clock.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: clock.c,v 1.23 2009/02/08 18:33:28 miod Exp $	*/
2 
3 /*
4  * Copyright (c) 1998-2003 Michael Shalayeff
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/timetc.h>
33 
34 #include <dev/clock_subr.h>
35 
36 #include <machine/pdc.h>
37 #include <machine/iomod.h>
38 #include <machine/psl.h>
39 #include <machine/intr.h>
40 #include <machine/reg.h>
41 #include <machine/cpufunc.h>
42 #include <machine/autoconf.h>
43 
44 #if defined(DDB)
45 #include <uvm/uvm_extern.h>
46 #include <machine/db_machdep.h>
47 #include <ddb/db_sym.h>
48 #include <ddb/db_extern.h>
49 #endif
50 
51 u_long	cpu_itmr, cpu_hzticks;
52 
53 int	cpu_hardclock(void *);
54 u_int	itmr_get_timecount(struct timecounter *);
55 
56 struct timecounter itmr_timecounter = {
57 	itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL
58 };
59 
60 void
61 cpu_initclocks()
62 {
63 	u_long __itmr;
64 
65 	itmr_timecounter.tc_frequency = PAGE0->mem_10msec * 100;
66 	tc_init(&itmr_timecounter);
67 
68 	mfctl(CR_ITMR, __itmr);
69 	cpu_itmr = __itmr;
70 	__itmr += cpu_hzticks;
71 	mtctl(__itmr, CR_ITMR);
72 }
73 
74 int
75 cpu_hardclock(void *v)
76 {
77 	u_long __itmr, delta, eta;
78 	int wrap;
79 	register_t eiem;
80 
81 	/*
82 	 * Invoke hardclock as many times as there has been cpu_hzticks
83 	 * ticks since the last interrupt.
84 	 */
85 	for (;;) {
86 		mfctl(CR_ITMR, __itmr);
87 		delta = __itmr - cpu_itmr;
88 		if (delta >= cpu_hzticks) {
89 			hardclock(v);
90 			cpu_itmr += cpu_hzticks;
91 		} else
92 			break;
93 	}
94 
95 	/*
96 	 * Program the next clock interrupt, making sure it will
97 	 * indeed happen in the future. This is done with interrupts
98 	 * disabled to avoid a possible race.
99 	 */
100 	eta = cpu_itmr + cpu_hzticks;
101 	wrap = eta < cpu_itmr;	/* watch out for a wraparound */
102 	__asm __volatile("mfctl	%%cr15, %0": "=r" (eiem));
103 	__asm __volatile("mtctl	%r0, %cr15");
104 	mtctl(eta, CR_ITMR);
105 	mfctl(CR_ITMR, __itmr);
106 	/*
107 	 * If we were close enough to the next tick interrupt
108 	 * value, by the time we have programmed itmr, it might
109 	 * have passed the value, which would cause a complete
110 	 * cycle until the next interrupt occurs. On slow
111 	 * models, this would be a disaster (a complete cycle
112 	 * taking over two minutes on a 715/33).
113 	 *
114 	 * We expect that it will only be necessary to postpone
115 	 * the interrupt once. Thus, there are two cases:
116 	 * - We are expecting a wraparound: eta < cpu_itmr.
117 	 *   itmr is in tracks if either >= cpu_itmr or < eta.
118 	 * - We are not wrapping: eta > cpu_itmr.
119 	 *   itmr is in tracks if >= cpu_itmr and < eta (we need
120 	 *   to keep the >= cpu_itmr test because itmr might wrap
121 	 *   before eta does).
122 	 */
123 	if ((wrap && !(eta > __itmr || __itmr >= cpu_itmr)) ||
124 	    (!wrap && !(eta > __itmr && __itmr >= cpu_itmr))) {
125 		eta += cpu_hzticks;
126 		mtctl(eta, CR_ITMR);
127 	}
128 	__asm __volatile("mtctl	%0, %%cr15":: "r" (eiem));
129 
130 	return (1);
131 }
132 
133 /*
134  * initialize the system time from the time of day clock
135  */
136 void
137 inittodr(t)
138 	time_t t;
139 {
140 	struct pdc_tod tod PDC_ALIGNMENT;
141 	int 	error, tbad = 0;
142 	struct timespec ts;
143 
144 	if (t < 12*SECYR) {
145 		printf ("WARNING: preposterous time in file system");
146 		t = 6*SECYR + 186*SECDAY + SECDAY/2;
147 		tbad = 1;
148 	}
149 
150 	if ((error = pdc_call((iodcio_t)pdc,
151 	    1, PDC_TOD, PDC_TOD_READ, &tod, 0, 0, 0, 0, 0)))
152 		printf("clock: failed to fetch (%d)\n", error);
153 
154 	ts.tv_sec = tod.sec;
155 	ts.tv_nsec = tod.usec * 1000;
156 	tc_setclock(&ts);
157 
158 	if (!tbad) {
159 		u_long	dt;
160 
161 		dt = (tod.sec < t)?  t - tod.sec : tod.sec - t;
162 
163 		if (dt < 2 * SECDAY)
164 			return;
165 		printf("WARNING: clock %s %ld days",
166 		    tod.sec < t? "lost" : "gained", dt / SECDAY);
167 	}
168 
169 	printf (" -- CHECK AND RESET THE DATE!\n");
170 }
171 
172 /*
173  * reset the time of day clock to the value in time
174  */
175 void
176 resettodr()
177 {
178 	struct timeval tv;
179 	int error;
180 
181 	microtime(&tv);
182 
183 	if ((error = pdc_call((iodcio_t)pdc, 1, PDC_TOD, PDC_TOD_WRITE,
184 	    tv.tv_sec, tv.tv_usec)))
185 		printf("clock: failed to save (%d)\n", error);
186 }
187 
188 void
189 setstatclockrate(newhz)
190 	int newhz;
191 {
192 	/* nothing we can do */
193 }
194 
195 u_int
196 itmr_get_timecount(struct timecounter *tc)
197 {
198 	u_long __itmr;
199 
200 	mfctl(CR_ITMR, __itmr);
201 	return (__itmr);
202 }
203