]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/ia64/ia64/clock.c
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.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/interrupt.h>
34 #include <sys/priority.h>
35 #include <sys/proc.h>
36 #include <sys/queue.h>
37 #include <sys/sysctl.h>
38 #include <sys/systm.h>
39 #include <sys/timeet.h>
40 #include <sys/timetc.h>
41 #include <sys/pcpu.h>
42
43 #include <machine/cpu.h>
44 #include <machine/efi.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         uint64_t itc, load;
80         uint32_t mode;
81
82         PCPU_INC(md.stats.pcs_nclks);
83         intrcnt[INTRCNT_CLOCK]++;
84
85         itc = ia64_get_itc();
86         PCPU_SET(md.clock, itc);
87
88         mode = PCPU_GET(md.clock_mode);
89         if (mode == CLOCK_ET_PERIODIC) {
90                 load = PCPU_GET(md.clock_load);
91                 ia64_set_itm(itc + load);
92         } else
93                 ia64_set_itv((1 << 16) | xiv);
94
95         ia64_set_eoi(0);
96         ia64_srlz_d();
97
98         et = &ia64_clock_et;
99         if (et->et_active)
100                 et->et_event_cb(et, et->et_arg);
101         return (1);
102 }
103
104 /*
105  * Event timer start method.
106  */
107 static int
108 ia64_clock_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
109 {
110         u_long itc, load;
111         register_t is;
112
113         if (period != 0) {
114                 PCPU_SET(md.clock_mode, CLOCK_ET_PERIODIC);
115                 load = (et->et_frequency * period) >> 32;
116         } else {
117                 PCPU_SET(md.clock_mode, CLOCK_ET_ONESHOT);
118                 load = 0;
119         }
120
121         PCPU_SET(md.clock_load, load);
122
123         if (first != 0)
124                 load = (et->et_frequency * first) >> 32;
125
126         is = intr_disable();
127         itc = ia64_get_itc();
128         ia64_set_itm(itc + load);
129         ia64_set_itv(ia64_clock_xiv);
130         ia64_srlz_d();
131         intr_restore(is);
132         return (0);
133 }
134
135 /*
136  * Event timer stop method.
137  */
138 static int
139 ia64_clock_stop(struct eventtimer *et)
140 {
141
142         ia64_set_itv((1 << 16) | ia64_clock_xiv);
143         ia64_srlz_d();
144         PCPU_SET(md.clock_mode, CLOCK_ET_OFF);
145         PCPU_SET(md.clock_load, 0);
146         return (0);
147 }
148
149 /*
150  * We call cpu_initclocks() on the APs as well. It allows us to
151  * group common initialization in the same function.
152  */
153 void
154 cpu_initclocks()
155 {
156
157         ia64_clock_stop(NULL);
158         if (PCPU_GET(cpuid) == 0)
159                 cpu_initclocks_bsp();
160         else
161                 cpu_initclocks_ap();
162 }
163
164 static void
165 clock_configure(void *dummy)
166 {
167         struct eventtimer *et;
168         u_long itc_freq;
169
170         ia64_clock_xiv = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI,
171             ia64_ih_clock);
172         if (ia64_clock_xiv == 0)
173                 panic("No XIV for clock interrupts");
174
175         itc_freq = (u_long)ia64_itc_freq() * 1000000ul;
176
177         et = &ia64_clock_et;
178         et->et_name = "ITC";
179         et->et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU;
180         et->et_quality = 1000;
181         et->et_frequency = itc_freq;
182         et->et_min_period = SBT_1S / (10 * hz);
183         et->et_max_period = (0xfffffffeul << 32) / itc_freq;
184         et->et_start = ia64_clock_start;
185         et->et_stop = ia64_clock_stop;
186         et->et_priv = NULL;
187         et_register(et);
188
189 #ifndef SMP
190         ia64_timecounter.tc_frequency = itc_freq;
191         tc_init(&ia64_timecounter);
192 #endif
193 }
194 SYSINIT(clkcfg, SI_SUB_CONFIGURE, SI_ORDER_SECOND, clock_configure, NULL);