]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/ia64/ia64/clock.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.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/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, struct bintime *first,
109     struct bintime *period)
110 {
111         u_long itc, load;
112         register_t is;
113
114         if (period != NULL) {
115                 PCPU_SET(md.clock_mode, CLOCK_ET_PERIODIC);
116                 load = (et->et_frequency * (period->frac >> 32)) >> 32;
117                 if (period->sec > 0)
118                         load += et->et_frequency * period->sec;
119         } else {
120                 PCPU_SET(md.clock_mode, CLOCK_ET_ONESHOT);
121                 load = 0;
122         }
123
124         PCPU_SET(md.clock_load, load);
125
126         if (first != NULL) {
127                 load = (et->et_frequency * (first->frac >> 32)) >> 32;
128                 if (first->sec > 0)
129                         load += et->et_frequency * first->sec;
130         }
131
132         is = intr_disable();
133         itc = ia64_get_itc();
134         ia64_set_itm(itc + load);
135         ia64_set_itv(ia64_clock_xiv);
136         ia64_srlz_d();
137         intr_restore(is);
138         return (0);
139 }
140
141 /*
142  * Event timer stop method.
143  */
144 static int
145 ia64_clock_stop(struct eventtimer *et)
146 {
147
148         ia64_set_itv((1 << 16) | ia64_clock_xiv);
149         ia64_srlz_d();
150         PCPU_SET(md.clock_mode, CLOCK_ET_OFF);
151         PCPU_SET(md.clock_load, 0);
152         return (0);
153 }
154
155 /*
156  * We call cpu_initclocks() on the APs as well. It allows us to
157  * group common initialization in the same function.
158  */
159 void
160 cpu_initclocks()
161 {
162
163         ia64_clock_stop(NULL);
164         if (PCPU_GET(cpuid) == 0)
165                 cpu_initclocks_bsp();
166         else
167                 cpu_initclocks_ap();
168 }
169
170 static void
171 clock_configure(void *dummy)
172 {
173         struct eventtimer *et;
174         u_long itc_freq;
175
176         ia64_clock_xiv = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI,
177             ia64_ih_clock);
178         if (ia64_clock_xiv == 0)
179                 panic("No XIV for clock interrupts");
180
181         itc_freq = (u_long)ia64_itc_freq() * 1000000ul;
182
183         et = &ia64_clock_et;
184         et->et_name = "ITC";
185         et->et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU;
186         et->et_quality = 1000;
187         et->et_frequency = itc_freq;
188         et->et_min_period.sec = 0;
189         et->et_min_period.frac = (0x8000000000000000ul / (u_long)(10*hz)) << 1;
190         et->et_max_period.sec = 0xffffffff;
191         et->et_max_period.frac = ((0xfffffffeul << 32) / itc_freq) << 32;
192         et->et_start = ia64_clock_start;
193         et->et_stop = ia64_clock_stop;
194         et->et_priv = NULL;
195         et_register(et);
196
197 #ifndef SMP
198         ia64_timecounter.tc_frequency = itc_freq;
199         tc_init(&ia64_timecounter);
200 #endif
201 }
202 SYSINIT(clkcfg, SI_SUB_CONFIGURE, SI_ORDER_SECOND, clock_configure, NULL);