Revision 8caa0065 hw/hpet.c
b/hw/hpet.c | ||
---|---|---|
39 | 39 |
#define DPRINTF(...) |
40 | 40 |
#endif |
41 | 41 |
|
42 |
#define HPET_MSI_SUPPORT 0 |
|
43 |
|
|
42 | 44 |
struct HPETState; |
43 | 45 |
typedef struct HPETTimer { /* timers */ |
44 | 46 |
uint8_t tn; /*timer number*/ |
... | ... | |
47 | 49 |
/* Memory-mapped, software visible timer registers */ |
48 | 50 |
uint64_t config; /* configuration/cap */ |
49 | 51 |
uint64_t cmp; /* comparator */ |
50 |
uint64_t fsb; /* FSB route, not supported now */
|
|
52 |
uint64_t fsb; /* FSB route */ |
|
51 | 53 |
/* Hidden register state */ |
52 | 54 |
uint64_t period; /* Last value written to comparator */ |
53 | 55 |
uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit |
... | ... | |
59 | 61 |
SysBusDevice busdev; |
60 | 62 |
uint64_t hpet_offset; |
61 | 63 |
qemu_irq irqs[HPET_NUM_IRQ_ROUTES]; |
64 |
uint32_t flags; |
|
62 | 65 |
uint8_t rtc_irq_level; |
63 | 66 |
uint8_t num_timers; |
64 | 67 |
HPETTimer timer[HPET_MAX_TIMERS]; |
... | ... | |
80 | 83 |
return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT; |
81 | 84 |
} |
82 | 85 |
|
86 |
static uint32_t timer_fsb_route(HPETTimer *t) |
|
87 |
{ |
|
88 |
return t->config & HPET_TN_FSB_ENABLE; |
|
89 |
} |
|
90 |
|
|
83 | 91 |
static uint32_t hpet_enabled(HPETState *s) |
84 | 92 |
{ |
85 | 93 |
return s->config & HPET_CFG_ENABLE; |
... | ... | |
179 | 187 |
mask = 1 << timer->tn; |
180 | 188 |
if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) { |
181 | 189 |
s->isr &= ~mask; |
182 |
qemu_irq_lower(s->irqs[route]); |
|
190 |
if (!timer_fsb_route(timer)) { |
|
191 |
qemu_irq_lower(s->irqs[route]); |
|
192 |
} |
|
193 |
} else if (timer_fsb_route(timer)) { |
|
194 |
stl_phys(timer->fsb >> 32, timer->fsb & 0xffffffff); |
|
183 | 195 |
} else if (timer->config & HPET_TN_TYPE_LEVEL) { |
184 | 196 |
s->isr |= mask; |
185 | 197 |
qemu_irq_raise(s->irqs[route]); |
... | ... | |
216 | 228 |
/* Push number of timers into capability returned via HPET_ID */ |
217 | 229 |
s->capability &= ~HPET_ID_NUM_TIM_MASK; |
218 | 230 |
s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT; |
231 |
|
|
232 |
/* Derive HPET_MSI_SUPPORT from the capability of the first timer. */ |
|
233 |
s->flags &= ~(1 << HPET_MSI_SUPPORT); |
|
234 |
if (s->timer[0].config & HPET_TN_FSB_CAP) { |
|
235 |
s->flags |= 1 << HPET_MSI_SUPPORT; |
|
236 |
} |
|
219 | 237 |
return 0; |
220 | 238 |
} |
221 | 239 |
|
... | ... | |
361 | 379 |
case HPET_TN_CMP + 4: |
362 | 380 |
return timer->cmp >> 32; |
363 | 381 |
case HPET_TN_ROUTE: |
382 |
return timer->fsb; |
|
383 |
case HPET_TN_ROUTE + 4: |
|
364 | 384 |
return timer->fsb >> 32; |
365 | 385 |
default: |
366 | 386 |
DPRINTF("qemu: invalid hpet_ram_readl\n"); |
... | ... | |
444 | 464 |
switch ((addr - 0x100) % 0x20) { |
445 | 465 |
case HPET_TN_CFG: |
446 | 466 |
DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n"); |
467 |
if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) { |
|
468 |
update_irq(timer, 0); |
|
469 |
} |
|
447 | 470 |
val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK); |
448 | 471 |
timer->config = (timer->config & 0xffffffff00000000ULL) | val; |
449 | 472 |
if (new_val & HPET_TN_32BIT) { |
... | ... | |
501 | 524 |
hpet_set_timer(timer); |
502 | 525 |
} |
503 | 526 |
break; |
527 |
case HPET_TN_ROUTE: |
|
528 |
timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val; |
|
529 |
break; |
|
504 | 530 |
case HPET_TN_ROUTE + 4: |
505 |
DPRINTF("qemu: hpet_ram_writel HPET_TN_ROUTE + 4\n");
|
|
531 |
timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff);
|
|
506 | 532 |
break; |
507 | 533 |
default: |
508 | 534 |
DPRINTF("qemu: invalid hpet_ram_writel\n"); |
... | ... | |
610 | 636 |
|
611 | 637 |
hpet_del_timer(timer); |
612 | 638 |
timer->cmp = ~0ULL; |
613 |
timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP; |
|
639 |
timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP; |
|
640 |
if (s->flags & (1 << HPET_MSI_SUPPORT)) { |
|
641 |
timer->config |= HPET_TN_FSB_CAP; |
|
642 |
} |
|
614 | 643 |
/* advertise availability of ioapic inti2 */ |
615 | 644 |
timer->config |= 0x00000004ULL << 32; |
616 | 645 |
timer->period = 0ULL; |
... | ... | |
686 | 715 |
.init = hpet_init, |
687 | 716 |
.qdev.props = (Property[]) { |
688 | 717 |
DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS), |
718 |
DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false), |
|
689 | 719 |
DEFINE_PROP_END_OF_LIST(), |
690 | 720 |
}, |
691 | 721 |
}; |
Also available in: Unified diff