Deleted Added
full compact
vhpet.c (263035) vhpet.c (276428)
1/*-
2 * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
3 * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 10 unchanged lines hidden (view full) ---

19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
1/*-
2 * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
3 * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 10 unchanged lines hidden (view full) ---

19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: head/sys/amd64/vmm/io/vhpet.c 263035 2014-03-11 16:56:00Z tychon $
27 * $FreeBSD: head/sys/amd64/vmm/io/vhpet.c 276428 2014-12-30 22:19:34Z neel $
28 */
29
30#include <sys/cdefs.h>
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/amd64/vmm/io/vhpet.c 263035 2014-03-11 16:56:00Z tychon $");
31__FBSDID("$FreeBSD: head/sys/amd64/vmm/io/vhpet.c 276428 2014-12-30 22:19:34Z neel $");
32
33#include <sys/param.h>
34#include <sys/lock.h>
35#include <sys/mutex.h>
36#include <sys/kernel.h>
37#include <sys/malloc.h>
38#include <sys/systm.h>
39#include <sys/cpuset.h>

--- 59 unchanged lines hidden (view full) ---

99 sbintime_t now);
100
101static uint64_t
102vhpet_capabilities(void)
103{
104 uint64_t cap = 0;
105
106 cap |= 0x8086 << 16; /* vendor id */
32
33#include <sys/param.h>
34#include <sys/lock.h>
35#include <sys/mutex.h>
36#include <sys/kernel.h>
37#include <sys/malloc.h>
38#include <sys/systm.h>
39#include <sys/cpuset.h>

--- 59 unchanged lines hidden (view full) ---

99 sbintime_t now);
100
101static uint64_t
102vhpet_capabilities(void)
103{
104 uint64_t cap = 0;
105
106 cap |= 0x8086 << 16; /* vendor id */
107 cap |= HPET_CAP_LEG_RT; /* legacy routing capable */
108 cap |= (VHPET_NUM_TIMERS - 1) << 8; /* number of timers */
109 cap |= 1; /* revision */
110 cap &= ~HPET_CAP_COUNT_SIZE; /* 32-bit timer */
111
112 cap &= 0xffffffff;
113 cap |= (FS_PER_S / HPET_FREQ) << 32; /* tick period in fs */
114
115 return (cap);

--- 6 unchanged lines hidden (view full) ---

122 return ((vhpet->config & HPET_CNF_ENABLE) ? true : false);
123}
124
125static __inline bool
126vhpet_timer_msi_enabled(struct vhpet *vhpet, int n)
127{
128 const uint64_t msi_enable = HPET_TCAP_FSB_INT_DEL | HPET_TCNF_FSB_EN;
129
107 cap |= (VHPET_NUM_TIMERS - 1) << 8; /* number of timers */
108 cap |= 1; /* revision */
109 cap &= ~HPET_CAP_COUNT_SIZE; /* 32-bit timer */
110
111 cap &= 0xffffffff;
112 cap |= (FS_PER_S / HPET_FREQ) << 32; /* tick period in fs */
113
114 return (cap);

--- 6 unchanged lines hidden (view full) ---

121 return ((vhpet->config & HPET_CNF_ENABLE) ? true : false);
122}
123
124static __inline bool
125vhpet_timer_msi_enabled(struct vhpet *vhpet, int n)
126{
127 const uint64_t msi_enable = HPET_TCAP_FSB_INT_DEL | HPET_TCNF_FSB_EN;
128
130 /*
131 * LegacyReplacement Route configuration takes precedence over MSI
132 * for timers 0 and 1.
133 */
134 if (n == 0 || n == 1) {
135 if (vhpet->config & HPET_CNF_LEG_RT)
136 return (false);
137 }
138
139 if ((vhpet->timer[n].cap_config & msi_enable) == msi_enable)
140 return (true);
141 else
142 return (false);
143}
144
145static __inline int
146vhpet_timer_ioapic_pin(struct vhpet *vhpet, int n)
147{
148 /*
149 * If the timer is configured to use MSI then treat it as if the
150 * timer is not connected to the ioapic.
151 */
152 if (vhpet_timer_msi_enabled(vhpet, n))
153 return (0);
154
129 if ((vhpet->timer[n].cap_config & msi_enable) == msi_enable)
130 return (true);
131 else
132 return (false);
133}
134
135static __inline int
136vhpet_timer_ioapic_pin(struct vhpet *vhpet, int n)
137{
138 /*
139 * If the timer is configured to use MSI then treat it as if the
140 * timer is not connected to the ioapic.
141 */
142 if (vhpet_timer_msi_enabled(vhpet, n))
143 return (0);
144
155 if (vhpet->config & HPET_CNF_LEG_RT) {
156 /*
157 * In "legacy routing" timers 0 and 1 are connected to
158 * ioapic pins 2 and 8 respectively.
159 */
160 switch (n) {
161 case 0:
162 return (2);
163 case 1:
164 return (8);
165 }
166 }
167
168 return ((vhpet->timer[n].cap_config & HPET_TCNF_INT_ROUTE) >> 9);
169}
170
145 return ((vhpet->timer[n].cap_config & HPET_TCNF_INT_ROUTE) >> 9);
146}
147
171static __inline int
172vhpet_timer_atpic_pin(struct vhpet *vhpet, int n)
173{
174 if (vhpet->config & HPET_CNF_LEG_RT) {
175 /*
176 * In "legacy routing" timers 0 and 1 are connected to
177 * 8259 master pin 0 and slave pin 0 respectively.
178 */
179 switch (n) {
180 case 0:
181 return (0);
182 case 1:
183 return (8);
184 }
185 }
186
187 return (-1);
188}
189
190static uint32_t
191vhpet_counter(struct vhpet *vhpet, sbintime_t *nowptr)
192{
193 uint32_t val;
194 sbintime_t now, delta;
195
196 val = vhpet->countbase;
197 if (vhpet_counter_enabled(vhpet)) {

--- 13 unchanged lines hidden (view full) ---

211 KASSERT(nowptr == NULL, ("vhpet_counter: nowptr must be NULL"));
212 }
213 return (val);
214}
215
216static void
217vhpet_timer_clear_isr(struct vhpet *vhpet, int n)
218{
148static uint32_t
149vhpet_counter(struct vhpet *vhpet, sbintime_t *nowptr)
150{
151 uint32_t val;
152 sbintime_t now, delta;
153
154 val = vhpet->countbase;
155 if (vhpet_counter_enabled(vhpet)) {

--- 13 unchanged lines hidden (view full) ---

169 KASSERT(nowptr == NULL, ("vhpet_counter: nowptr must be NULL"));
170 }
171 return (val);
172}
173
174static void
175vhpet_timer_clear_isr(struct vhpet *vhpet, int n)
176{
219 int pin, legacy_pin;
177 int pin;
220
221 if (vhpet->isr & (1 << n)) {
222 pin = vhpet_timer_ioapic_pin(vhpet, n);
223 KASSERT(pin != 0, ("vhpet timer %d irq incorrectly routed", n));
224 vioapic_deassert_irq(vhpet->vm, pin);
178
179 if (vhpet->isr & (1 << n)) {
180 pin = vhpet_timer_ioapic_pin(vhpet, n);
181 KASSERT(pin != 0, ("vhpet timer %d irq incorrectly routed", n));
182 vioapic_deassert_irq(vhpet->vm, pin);
225
226 legacy_pin = vhpet_timer_atpic_pin(vhpet, n);
227 if (legacy_pin != -1)
228 vatpic_deassert_irq(vhpet->vm, legacy_pin);
229
230 vhpet->isr &= ~(1 << n);
231 }
232}
233
234static __inline bool
235vhpet_periodic_timer(struct vhpet *vhpet, int n)
236{
237

--- 9 unchanged lines hidden (view full) ---

247
248static __inline bool
249vhpet_timer_edge_trig(struct vhpet *vhpet, int n)
250{
251
252 KASSERT(!vhpet_timer_msi_enabled(vhpet, n), ("vhpet_timer_edge_trig: "
253 "timer %d is using MSI", n));
254
183 vhpet->isr &= ~(1 << n);
184 }
185}
186
187static __inline bool
188vhpet_periodic_timer(struct vhpet *vhpet, int n)
189{
190

--- 9 unchanged lines hidden (view full) ---

200
201static __inline bool
202vhpet_timer_edge_trig(struct vhpet *vhpet, int n)
203{
204
205 KASSERT(!vhpet_timer_msi_enabled(vhpet, n), ("vhpet_timer_edge_trig: "
206 "timer %d is using MSI", n));
207
255 /* The legacy replacement interrupts are always edge triggered */
256 if (vhpet->config & HPET_CNF_LEG_RT) {
257 if (n == 0 || n == 1)
258 return (true);
259 }
260
261 if ((vhpet->timer[n].cap_config & HPET_TCNF_INT_TYPE) == 0)
262 return (true);
263 else
264 return (false);
265}
266
267static void
268vhpet_timer_interrupt(struct vhpet *vhpet, int n)
269{
208 if ((vhpet->timer[n].cap_config & HPET_TCNF_INT_TYPE) == 0)
209 return (true);
210 else
211 return (false);
212}
213
214static void
215vhpet_timer_interrupt(struct vhpet *vhpet, int n)
216{
270 int pin, legacy_pin;
217 int pin;
271
272 /* If interrupts are not enabled for this timer then just return. */
273 if (!vhpet_timer_interrupt_enabled(vhpet, n))
274 return;
275
276 /*
277 * If a level triggered interrupt is already asserted then just return.
278 */

--- 9 unchanged lines hidden (view full) ---

288 }
289
290 pin = vhpet_timer_ioapic_pin(vhpet, n);
291 if (pin == 0) {
292 VM_CTR1(vhpet->vm, "hpet t%d intr is not routed to ioapic", n);
293 return;
294 }
295
218
219 /* If interrupts are not enabled for this timer then just return. */
220 if (!vhpet_timer_interrupt_enabled(vhpet, n))
221 return;
222
223 /*
224 * If a level triggered interrupt is already asserted then just return.
225 */

--- 9 unchanged lines hidden (view full) ---

235 }
236
237 pin = vhpet_timer_ioapic_pin(vhpet, n);
238 if (pin == 0) {
239 VM_CTR1(vhpet->vm, "hpet t%d intr is not routed to ioapic", n);
240 return;
241 }
242
296 legacy_pin = vhpet_timer_atpic_pin(vhpet, n);
297
298 if (vhpet_timer_edge_trig(vhpet, n)) {
299 vioapic_pulse_irq(vhpet->vm, pin);
243 if (vhpet_timer_edge_trig(vhpet, n)) {
244 vioapic_pulse_irq(vhpet->vm, pin);
300 if (legacy_pin != -1)
301 vatpic_pulse_irq(vhpet->vm, legacy_pin);
302 } else {
303 vhpet->isr |= 1 << n;
304 vioapic_assert_irq(vhpet->vm, pin);
245 } else {
246 vhpet->isr |= 1 << n;
247 vioapic_assert_irq(vhpet->vm, pin);
305 if (legacy_pin != -1)
306 vatpic_assert_irq(vhpet->vm, legacy_pin);
307 }
308}
309
310static void
311vhpet_adjust_compval(struct vhpet *vhpet, int n, uint32_t counter)
312{
313 uint32_t compval, comprate, compnext;
314

--- 259 unchanged lines hidden (view full) ---

574 * the 'config' register. If the HPET is going to be disabled
575 * then we need to update 'countbase' with the value right
576 * before it is disabled.
577 */
578 nowptr = vhpet_counter_enabled(vhpet) ? &now : NULL;
579 counter = vhpet_counter(vhpet, nowptr);
580 oldval = vhpet->config;
581 update_register(&vhpet->config, data, mask);
248 }
249}
250
251static void
252vhpet_adjust_compval(struct vhpet *vhpet, int n, uint32_t counter)
253{
254 uint32_t compval, comprate, compnext;
255

--- 259 unchanged lines hidden (view full) ---

515 * the 'config' register. If the HPET is going to be disabled
516 * then we need to update 'countbase' with the value right
517 * before it is disabled.
518 */
519 nowptr = vhpet_counter_enabled(vhpet) ? &now : NULL;
520 counter = vhpet_counter(vhpet, nowptr);
521 oldval = vhpet->config;
522 update_register(&vhpet->config, data, mask);
523
524 /*
525 * LegacyReplacement Routing is not supported so clear the
526 * bit explicitly.
527 */
528 vhpet->config &= ~HPET_CNF_LEG_RT;
529
582 if ((oldval ^ vhpet->config) & HPET_CNF_ENABLE) {
583 if (vhpet_counter_enabled(vhpet)) {
584 vhpet_start_counting(vhpet);
585 VM_CTR0(vhpet->vm, "hpet enabled");
586 } else {
587 vhpet_stop_counting(vhpet, counter, now);
588 VM_CTR0(vhpet->vm, "hpet disabled");
589 }

--- 223 unchanged lines hidden ---
530 if ((oldval ^ vhpet->config) & HPET_CNF_ENABLE) {
531 if (vhpet_counter_enabled(vhpet)) {
532 vhpet_start_counting(vhpet);
533 VM_CTR0(vhpet->vm, "hpet enabled");
534 } else {
535 vhpet_stop_counting(vhpet, counter, now);
536 VM_CTR0(vhpet->vm, "hpet disabled");
537 }

--- 223 unchanged lines hidden ---