]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/ia64/ia64/clock.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / ia64 / ia64 / clock.c
1 /*-
2  * Copyright (c) 2005 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
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.
14  *
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.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/bus.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>
39 #include <sys/pcpu.h>
40
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>
47
48 SYSCTL_NODE(_debug, OID_AUTO, clock, CTLFLAG_RW, 0, "clock statistics");
49
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");
53
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");
57
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");
61
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");
65
66 static u_int ia64_clock_xiv;
67 static uint64_t ia64_clock_reload;
68
69 #ifndef SMP
70 static timecounter_get_t ia64_get_timecount;
71
72 static struct timecounter ia64_timecounter = {
73         ia64_get_timecount,     /* get_timecount */
74         0,                      /* no poll_pps */
75         ~0u,                    /* counter_mask */
76         0,                      /* frequency */
77         "ITC"                   /* name */
78 };
79
80 static u_int
81 ia64_get_timecount(struct timecounter* tc)
82 {
83         return ia64_get_itc();
84 }
85 #endif
86
87 static u_int
88 ia64_ih_clock(struct thread *td, u_int xiv, struct trapframe *tf)
89 {
90         uint64_t adj, clk, itc;
91         int64_t delta;
92         int count;
93
94         PCPU_INC(md.stats.pcs_nclks);
95
96         if (PCPU_GET(cpuid) == 0) {
97                 /*
98                  * Clock processing on the BSP.
99                  */
100                 intrcnt[INTRCNT_CLOCK]++;
101
102                 itc = ia64_get_itc();
103
104                 adj = PCPU_GET(md.clockadj);
105                 clk = PCPU_GET(md.clock);
106
107                 delta = itc - clk;
108                 count = 0;
109                 while (delta >= ia64_clock_reload) {
110 #ifdef SMP
111                         ipi_all_but_self(ia64_clock_xiv);
112 #endif
113                         hardclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
114                         if (profprocs != 0)
115                                 profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
116                         statclock(TRAPF_USERMODE(tf));
117                         delta -= ia64_clock_reload;
118                         clk += ia64_clock_reload;
119                         if (adj != 0)
120                                 adjust_ticks++;
121                         count++;
122                 }
123                 ia64_set_itm(ia64_get_itc() + ia64_clock_reload - adj);
124                 ia64_srlz_d();
125                 if (count > 0) {
126                         adjust_lost += count - 1;
127                         if (delta > (ia64_clock_reload >> 3)) {
128                                 if (adj == 0)
129                                         adjust_edges++;
130                                 adj = ia64_clock_reload >> 4;
131                         } else
132                                 adj = 0;
133                 } else {
134                         adj = 0;
135                         adjust_excess++;
136                 }
137                 PCPU_SET(md.clock, clk);
138                 PCPU_SET(md.clockadj, adj);
139         } else {
140                 /*
141                  * Clock processing on the BSP.
142                  */
143                 hardclock_cpu(TRAPF_USERMODE(tf));
144                 if (profprocs != 0)
145                         profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
146                 statclock(TRAPF_USERMODE(tf));
147         }
148
149         return (0);
150 }
151
152 /*
153  * Start the real-time and statistics clocks. We use ar.itc and cr.itm
154  * to implement a 1000hz clock.
155  */
156 void
157 cpu_initclocks()
158 {
159         u_long itc_freq;
160
161         ia64_clock_xiv = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI,
162             ia64_ih_clock);
163         if (ia64_clock_xiv == 0)
164                 panic("No XIV for clock interrupts");
165
166         itc_freq = (u_long)ia64_itc_freq() * 1000000ul;
167
168         stathz = hz;
169         ia64_clock_reload = (itc_freq + hz/2) / hz;
170
171 #ifndef SMP
172         ia64_timecounter.tc_frequency = itc_freq;
173         tc_init(&ia64_timecounter);
174 #endif
175
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);
180         ia64_srlz_d();
181 }
182
183 void
184 cpu_startprofclock(void)
185 {
186
187         /* nothing to do */
188 }
189
190 void
191 cpu_stopprofclock(void)
192 {
193
194         /* nothing to do */
195 }