clock.c revision 1.37
1/*	$OpenBSD: clock.c,v 1.37 2023/08/23 01:55:46 cheloha 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/clockintr.h>
33#include <sys/stdint.h>
34#include <sys/timetc.h>
35
36#include <dev/clock_subr.h>
37
38#include <machine/pdc.h>
39#include <machine/iomod.h>
40#include <machine/psl.h>
41#include <machine/intr.h>
42#include <machine/reg.h>
43#include <machine/cpufunc.h>
44#include <machine/autoconf.h>
45
46uint64_t itmr_nsec_cycle_ratio;
47uint64_t itmr_nsec_max;
48
49u_int	itmr_get_timecount(struct timecounter *);
50int	itmr_intr(void *);
51void	itmr_rearm(void *, uint64_t);
52void	itmr_trigger(void);
53void	itmr_trigger_masked(void);
54void	itmr_trigger_wrapper(void *);
55
56struct timecounter itmr_timecounter = {
57	.tc_get_timecount = itmr_get_timecount,
58	.tc_counter_mask = 0xffffffff,
59	.tc_frequency = 0,
60	.tc_name = "itmr",
61	.tc_quality = 0,
62	.tc_priv = NULL,
63	.tc_user = 0,
64};
65
66const struct intrclock itmr_intrclock = {
67	.ic_rearm = itmr_rearm,
68	.ic_trigger = itmr_trigger_wrapper
69};
70
71extern todr_chip_handle_t todr_handle;
72struct todr_chip_handle pdc_todr;
73
74int
75pdc_gettime(struct todr_chip_handle *handle, struct timeval *tv)
76{
77	struct pdc_tod tod PDC_ALIGNMENT;
78	int error;
79
80	if ((error = pdc_call((iodcio_t)pdc, 1, PDC_TOD, PDC_TOD_READ,
81	    &tod, 0, 0, 0, 0, 0))) {
82		printf("clock: failed to fetch (%d)\n", error);
83		return EIO;
84	}
85
86	tv->tv_sec = tod.sec;
87	tv->tv_usec = tod.usec;
88	return 0;
89}
90
91int
92pdc_settime(struct todr_chip_handle *handle, struct timeval *tv)
93{
94	int error;
95
96	if ((error = pdc_call((iodcio_t)pdc, 1, PDC_TOD, PDC_TOD_WRITE,
97	    tv->tv_sec, tv->tv_usec))) {
98		printf("clock: failed to save (%d)\n", error);
99		return EIO;
100	}
101
102	return 0;
103}
104
105void
106cpu_initclocks(void)
107{
108	uint64_t itmr_freq = PAGE0->mem_10msec * 100;
109
110	pdc_todr.todr_gettime = pdc_gettime;
111	pdc_todr.todr_settime = pdc_settime;
112	todr_handle = &pdc_todr;
113
114	itmr_timecounter.tc_frequency = itmr_freq;
115	tc_init(&itmr_timecounter);
116
117	stathz = hz;
118	profhz = stathz * 10;
119	clockintr_init(CL_RNDSTAT);
120
121	itmr_nsec_cycle_ratio = itmr_freq * (1ULL << 32) / 1000000000;
122	itmr_nsec_max = UINT64_MAX / itmr_nsec_cycle_ratio;
123}
124
125void
126cpu_startclock(void)
127{
128	clockintr_cpu_init(&itmr_intrclock);
129	clockintr_trigger();
130}
131
132int
133itmr_intr(void *v)
134{
135	clockintr_dispatch(v);
136	return (1);
137}
138
139void
140setstatclockrate(int newhz)
141{
142}
143
144u_int
145itmr_get_timecount(struct timecounter *tc)
146{
147	u_long __itmr;
148
149	mfctl(CR_ITMR, __itmr);
150	return (__itmr);
151}
152
153/*
154 * Program the next clock interrupt, making sure it will
155 * indeed happen in the future.  This is done with interrupts
156 * disabled to avoid a possible race.
157 */
158void
159itmr_rearm(void *unused, uint64_t nsecs)
160{
161	uint32_t cycles, t0, t1;
162	register_t eiem, eirr;
163
164	if (nsecs > itmr_nsec_max)
165		nsecs = itmr_nsec_max;
166	cycles = (nsecs * itmr_nsec_cycle_ratio) >> 32;
167
168	eiem = hppa_intr_disable();
169	mfctl(CR_ITMR, t0);
170	mtctl(t0 + cycles, CR_ITMR);
171	mfctl(CR_ITMR, t1);
172	mfctl(CR_EIRR, eirr);
173
174	/*
175	 * If at least "cycles" ITMR ticks have elapsed and the interrupt
176	 * isn't pending, we missed.  Fall back to itmr_trigger_masked().
177	 */
178	if (cycles <= t1 - t0) {
179		if (!ISSET(eirr, 1U << 31))
180			itmr_trigger_masked();
181	}
182	hppa_intr_enable(eiem);
183}
184
185void
186itmr_trigger(void)
187{
188	register_t eiem;
189
190	eiem = hppa_intr_disable();
191	itmr_trigger_masked();
192	hppa_intr_enable(eiem);
193}
194
195/* Trigger our own ITMR interrupt by setting EIR{0}. */
196void
197itmr_trigger_masked(void)
198{
199	struct iomod *cpu = (struct iomod *)curcpu()->ci_hpa;
200
201	cpu->io_eir = 0;
202	__asm volatile ("sync" ::: "memory");
203}
204
205void
206itmr_trigger_wrapper(void *unused)
207{
208	itmr_trigger();
209}
210