xref: /openbsd/sys/arch/hppa/dev/clock.c (revision a6445c1d)
1 /*	$OpenBSD: clock.c,v 1.29 2014/03/29 18:09:29 guenther 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 u_long	cpu_hzticks;
45 int	timeset;
46 
47 int	cpu_hardclock(void *);
48 u_int	itmr_get_timecount(struct timecounter *);
49 
50 struct timecounter itmr_timecounter = {
51 	itmr_get_timecount, NULL, 0xffffffff, 0, "itmr", 0, NULL
52 };
53 
54 void
55 cpu_initclocks(void)
56 {
57 	struct cpu_info *ci = curcpu();
58 	u_long __itmr;
59 
60 	cpu_hzticks = (PAGE0->mem_10msec * 100) / hz;
61 
62 	itmr_timecounter.tc_frequency = PAGE0->mem_10msec * 100;
63 	tc_init(&itmr_timecounter);
64 
65 	mfctl(CR_ITMR, __itmr);
66 	ci->ci_itmr = __itmr;
67 	__itmr += cpu_hzticks;
68 	mtctl(__itmr, CR_ITMR);
69 }
70 
71 int
72 cpu_hardclock(void *v)
73 {
74 	struct cpu_info *ci = curcpu();
75 	u_long __itmr, delta, eta;
76 	int wrap;
77 	register_t eiem;
78 
79 	/*
80 	 * Invoke hardclock as many times as there has been cpu_hzticks
81 	 * ticks since the last interrupt.
82 	 */
83 	for (;;) {
84 		mfctl(CR_ITMR, __itmr);
85 		delta = __itmr - ci->ci_itmr;
86 		if (delta >= cpu_hzticks) {
87 			hardclock(v);
88 			ci->ci_itmr += cpu_hzticks;
89 		} else
90 			break;
91 	}
92 
93 	/*
94 	 * Program the next clock interrupt, making sure it will
95 	 * indeed happen in the future. This is done with interrupts
96 	 * disabled to avoid a possible race.
97 	 */
98 	eta = ci->ci_itmr + cpu_hzticks;
99 	wrap = eta < ci->ci_itmr;	/* watch out for a wraparound */
100 	__asm volatile("mfctl	%%cr15, %0": "=r" (eiem));
101 	__asm volatile("mtctl	%r0, %cr15");
102 	mtctl(eta, CR_ITMR);
103 	mfctl(CR_ITMR, __itmr);
104 	/*
105 	 * If we were close enough to the next tick interrupt
106 	 * value, by the time we have programmed itmr, it might
107 	 * have passed the value, which would cause a complete
108 	 * cycle until the next interrupt occurs. On slow
109 	 * models, this would be a disaster (a complete cycle
110 	 * taking over two minutes on a 715/33).
111 	 *
112 	 * We expect that it will only be necessary to postpone
113 	 * the interrupt once. Thus, there are two cases:
114 	 * - We are expecting a wraparound: eta < cpu_itmr.
115 	 *   itmr is in tracks if either >= cpu_itmr or < eta.
116 	 * - We are not wrapping: eta > cpu_itmr.
117 	 *   itmr is in tracks if >= cpu_itmr and < eta (we need
118 	 *   to keep the >= cpu_itmr test because itmr might wrap
119 	 *   before eta does).
120 	 */
121 	if ((wrap && !(eta > __itmr || __itmr >= ci->ci_itmr)) ||
122 	    (!wrap && !(eta > __itmr && __itmr >= ci->ci_itmr))) {
123 		eta += cpu_hzticks;
124 		mtctl(eta, CR_ITMR);
125 	}
126 	__asm volatile("mtctl	%0, %%cr15":: "r" (eiem));
127 
128 	return (1);
129 }
130 
131 /*
132  * initialize the system time from the time of day clock
133  */
134 void
135 inittodr(time_t t)
136 {
137 	struct pdc_tod tod PDC_ALIGNMENT;
138 	int 	error, tbad = 0;
139 	struct timespec ts;
140 
141 	if (t < 12*SECYR) {
142 		printf ("WARNING: preposterous time in file system");
143 		t = 6*SECYR + 186*SECDAY + SECDAY/2;
144 		tbad = 1;
145 	}
146 
147 	if ((error = pdc_call((iodcio_t)pdc,
148 	    1, PDC_TOD, PDC_TOD_READ, &tod, 0, 0, 0, 0, 0)))
149 		printf("clock: failed to fetch (%d)\n", error);
150 
151 	ts.tv_sec = tod.sec;
152 	ts.tv_nsec = tod.usec * 1000;
153 	tc_setclock(&ts);
154 	timeset = 1;
155 
156 	if (!tbad) {
157 		u_long	dt;
158 
159 		dt = (tod.sec < t)?  t - tod.sec : tod.sec - t;
160 
161 		if (dt < 2 * SECDAY)
162 			return;
163 		printf("WARNING: clock %s %ld days",
164 		    tod.sec < t? "lost" : "gained", dt / SECDAY);
165 	}
166 
167 	printf (" -- CHECK AND RESET THE DATE!\n");
168 }
169 
170 /*
171  * reset the time of day clock to the value in time
172  */
173 void
174 resettodr()
175 {
176 	struct timeval tv;
177 	int error;
178 
179 	/*
180 	 * We might have been called by boot() due to a crash early
181 	 * on.  Don't reset the clock chip in this case.
182 	 */
183 	if (!timeset)
184 		return;
185 
186 	microtime(&tv);
187 
188 	if ((error = pdc_call((iodcio_t)pdc, 1, PDC_TOD, PDC_TOD_WRITE,
189 	    tv.tv_sec, tv.tv_usec)))
190 		printf("clock: failed to save (%d)\n", error);
191 }
192 
193 void
194 setstatclockrate(int newhz)
195 {
196 	/* nothing we can do */
197 }
198 
199 u_int
200 itmr_get_timecount(struct timecounter *tc)
201 {
202 	u_long __itmr;
203 
204 	mfctl(CR_ITMR, __itmr);
205 	return (__itmr);
206 }
207