]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/ia64/ia64/clock.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / ia64 / ia64 / clock.c
1 /*-
2  * Copyright (c) 2005, 2009-2011 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/efi.h>
34 #include <sys/interrupt.h>
35 #include <sys/priority.h>
36 #include <sys/proc.h>
37 #include <sys/queue.h>
38 #include <sys/sysctl.h>
39 #include <sys/systm.h>
40 #include <sys/timeet.h>
41 #include <sys/timetc.h>
42 #include <sys/pcpu.h>
43
44 #include <machine/cpu.h>
45 #include <machine/intr.h>
46 #include <machine/intrcnt.h>
47 #include <machine/md_var.h>
48 #include <machine/smp.h>
49
50 #define CLOCK_ET_OFF            0
51 #define CLOCK_ET_PERIODIC       1
52 #define CLOCK_ET_ONESHOT        2
53
54 static struct eventtimer ia64_clock_et;
55 static u_int ia64_clock_xiv;
56
57 #ifndef SMP
58 static timecounter_get_t ia64_get_timecount;
59
60 static struct timecounter ia64_timecounter = {
61         ia64_get_timecount,     /* get_timecount */
62         0,                      /* no poll_pps */
63         ~0u,                    /* counter_mask */
64         0,                      /* frequency */
65         "ITC"                   /* name */
66 };
67
68 static u_int
69 ia64_get_timecount(struct timecounter* tc)
70 {
71         return ia64_get_itc();
72 }
73 #endif
74
75 static u_int
76 ia64_ih_clock(struct thread *td, u_int xiv, struct trapframe *tf)
77 {
78         struct eventtimer *et;
79         struct trapframe *stf;
80         uint64_t itc, load;
81         uint32_t mode;
82
83         PCPU_INC(md.stats.pcs_nclks);
84         intrcnt[INTRCNT_CLOCK]++;
85
86         itc = ia64_get_itc();
87         PCPU_SET(md.clock, itc);
88
89         mode = PCPU_GET(md.clock_mode);
90         if (mode == CLOCK_ET_PERIODIC) {
91                 load = PCPU_GET(md.clock_load);
92                 ia64_set_itm(itc + load);
93         } else
94                 ia64_set_itv((1 << 16) | xiv);
95
96         ia64_set_eoi(0);
97         ia64_srlz_d();
98
99         et = &ia64_clock_et;
100         if (et->et_active) {
101                 stf = td->td_intr_frame;
102                 td->td_intr_frame = tf;
103                 et->et_event_cb(et, et->et_arg);
104                 td->td_intr_frame = stf;
105         }
106         return (1);
107 }
108
109 /*
110  * Event timer start method.
111  */
112 static int
113 ia64_clock_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
114 {
115         u_long itc, load;
116         register_t is;
117
118         if (period != 0) {
119                 PCPU_SET(md.clock_mode, CLOCK_ET_PERIODIC);
120                 load = (et->et_frequency * period) >> 32;
121         } else {
122                 PCPU_SET(md.clock_mode, CLOCK_ET_ONESHOT);
123                 load = 0;
124         }
125
126         PCPU_SET(md.clock_load, load);
127
128         if (first != 0)
129                 load = (et->et_frequency * first) >> 32;
130
131         is = intr_disable();
132         itc = ia64_get_itc();
133         ia64_set_itm(itc + load);
134         ia64_set_itv(ia64_clock_xiv);
135         ia64_srlz_d();
136         intr_restore(is);
137         return (0);
138 }
139
140 /*
141  * Event timer stop method.
142  */
143 static int
144 ia64_clock_stop(struct eventtimer *et)
145 {
146
147         ia64_set_itv((1 << 16) | ia64_clock_xiv);
148         ia64_srlz_d();
149         PCPU_SET(md.clock_mode, CLOCK_ET_OFF);
150         PCPU_SET(md.clock_load, 0);
151         return (0);
152 }
153
154 /*
155  * We call cpu_initclocks() on the APs as well. It allows us to
156  * group common initialization in the same function.
157  */
158 void
159 cpu_initclocks()
160 {
161
162         ia64_clock_stop(NULL);
163         if (PCPU_GET(cpuid) == 0)
164                 cpu_initclocks_bsp();
165         else
166                 cpu_initclocks_ap();
167 }
168
169 static void
170 clock_configure(void *dummy)
171 {
172         struct eventtimer *et;
173         u_long itc_freq;
174
175         ia64_clock_xiv = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI,
176             ia64_ih_clock);
177         if (ia64_clock_xiv == 0)
178                 panic("No XIV for clock interrupts");
179
180         itc_freq = (u_long)ia64_itc_freq() * 1000000ul;
181
182         et = &ia64_clock_et;
183         et->et_name = "ITC";
184         et->et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU;
185         et->et_quality = 1000;
186         et->et_frequency = itc_freq;
187         et->et_min_period = SBT_1S / (10 * hz);
188         et->et_max_period = (0xfffffffeul << 32) / itc_freq;
189         et->et_start = ia64_clock_start;
190         et->et_stop = ia64_clock_stop;
191         et->et_priv = NULL;
192         et_register(et);
193
194 #ifndef SMP
195         ia64_timecounter.tc_frequency = itc_freq;
196         tc_init(&ia64_timecounter);
197 #endif
198 }
199 SYSINIT(clkcfg, SI_SUB_CONFIGURE, SI_ORDER_SECOND, clock_configure, NULL);