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 --- |