2 * Copyright (c) 2005 Marcel Moolenaar
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/kernel.h>
33 #include <sys/interrupt.h>
34 #include <sys/priority.h>
35 #include <sys/queue.h>
36 #include <sys/sysctl.h>
37 #include <sys/systm.h>
38 #include <sys/timetc.h>
41 #include <machine/cpu.h>
42 #include <machine/efi.h>
43 #include <machine/intr.h>
44 #include <machine/intrcnt.h>
45 #include <machine/md_var.h>
46 #include <machine/smp.h>
48 SYSCTL_NODE(_debug, OID_AUTO, clock, CTLFLAG_RW, 0, "clock statistics");
50 static int adjust_edges = 0;
51 SYSCTL_INT(_debug_clock, OID_AUTO, adjust_edges, CTLFLAG_RD,
52 &adjust_edges, 0, "Number of times ITC got more than 12.5% behind");
54 static int adjust_excess = 0;
55 SYSCTL_INT(_debug_clock, OID_AUTO, adjust_excess, CTLFLAG_RD,
56 &adjust_excess, 0, "Total number of ignored ITC interrupts");
58 static int adjust_lost = 0;
59 SYSCTL_INT(_debug_clock, OID_AUTO, adjust_lost, CTLFLAG_RD,
60 &adjust_lost, 0, "Total number of lost ITC interrupts");
62 static int adjust_ticks = 0;
63 SYSCTL_INT(_debug_clock, OID_AUTO, adjust_ticks, CTLFLAG_RD,
64 &adjust_ticks, 0, "Total number of ITC interrupts with adjustment");
66 static u_int ia64_clock_xiv;
67 static uint64_t ia64_clock_reload;
70 static timecounter_get_t ia64_get_timecount;
72 static struct timecounter ia64_timecounter = {
73 ia64_get_timecount, /* get_timecount */
75 ~0u, /* counter_mask */
81 ia64_get_timecount(struct timecounter* tc)
83 return ia64_get_itc();
88 ia64_ih_clock(struct thread *td, u_int xiv, struct trapframe *tf)
90 uint64_t adj, clk, itc;
94 PCPU_INC(md.stats.pcs_nclks);
96 if (PCPU_GET(cpuid) == 0) {
98 * Clock processing on the BSP.
100 intrcnt[INTRCNT_CLOCK]++;
102 itc = ia64_get_itc();
104 adj = PCPU_GET(md.clockadj);
105 clk = PCPU_GET(md.clock);
109 while (delta >= ia64_clock_reload) {
111 ipi_all_but_self(ia64_clock_xiv);
113 hardclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
115 profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
116 statclock(TRAPF_USERMODE(tf));
117 delta -= ia64_clock_reload;
118 clk += ia64_clock_reload;
123 ia64_set_itm(ia64_get_itc() + ia64_clock_reload - adj);
126 adjust_lost += count - 1;
127 if (delta > (ia64_clock_reload >> 3)) {
130 adj = ia64_clock_reload >> 4;
137 PCPU_SET(md.clock, clk);
138 PCPU_SET(md.clockadj, adj);
141 * Clock processing on the BSP.
143 hardclock_cpu(TRAPF_USERMODE(tf));
145 profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
146 statclock(TRAPF_USERMODE(tf));
153 * Start the real-time and statistics clocks. We use ar.itc and cr.itm
154 * to implement a 1000hz clock.
161 ia64_clock_xiv = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI,
163 if (ia64_clock_xiv == 0)
164 panic("No XIV for clock interrupts");
166 itc_freq = (u_long)ia64_itc_freq() * 1000000ul;
169 ia64_clock_reload = (itc_freq + hz/2) / hz;
172 ia64_timecounter.tc_frequency = itc_freq;
173 tc_init(&ia64_timecounter);
176 PCPU_SET(md.clockadj, 0);
177 PCPU_SET(md.clock, ia64_get_itc());
178 ia64_set_itm(PCPU_GET(md.clock) + ia64_clock_reload);
179 ia64_set_itv(ia64_clock_xiv);
184 cpu_startprofclock(void)
191 cpu_stopprofclock(void)