Kernel: Prefer 32 bit HPET timers on 32 bit target
This commit is contained in:
@@ -197,17 +197,36 @@ namespace Kernel
|
|||||||
return BAN::Error::from_errno(ENOTSUP);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set timer period to 1000 Hz
|
||||||
|
const uint64_t ticks_per_ms = m_ticks_per_s / 1000;
|
||||||
|
|
||||||
|
#if ARCH(x86_64)
|
||||||
|
const bool use_64bit_timer = !!(timer0.configuration & Tn_SIZE_CAP);
|
||||||
|
#else
|
||||||
|
// Spec recommends using 32 bit timers when the cpu can't do atomic 64 bit accesses
|
||||||
|
const bool use_64bit_timer = !!(timer0.configuration & Tn_SIZE_CAP) && (ticks_per_ms > 0xFFFFFFFF);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!use_64bit_timer && ticks_per_ms >= 0x100000000)
|
||||||
|
{
|
||||||
|
dprintln("HPET: cannot create 1 kHz timer");
|
||||||
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
// enable interrupts
|
// enable interrupts
|
||||||
timer0.configuration = timer0.configuration | Tn_INT_ENB_CNF;
|
timer0.configuration |= Tn_INT_ENB_CNF;
|
||||||
// edge triggered interrupts
|
// edge triggered interrupts
|
||||||
timer0.configuration = timer0.configuration & ~Tn_INT_TYPE_CNF;
|
timer0.configuration &= ~Tn_INT_TYPE_CNF;
|
||||||
// periodic timer
|
// periodic timer
|
||||||
timer0.configuration = timer0.configuration | Tn_TYPE_CNF;
|
timer0.configuration |= Tn_TYPE_CNF;
|
||||||
// disable 32 bit mode
|
// set 32 bit mode
|
||||||
timer0.configuration = timer0.configuration & ~Tn_32MODE_CNF;
|
if (use_64bit_timer)
|
||||||
|
timer0.configuration &= ~Tn_32MODE_CNF;
|
||||||
|
else
|
||||||
|
timer0.configuration |= Tn_32MODE_CNF;
|
||||||
// disable FSB interrupts
|
// disable FSB interrupts
|
||||||
if (timer0.configuration & Tn_FSB_INT_DEL_CAP)
|
if (timer0.configuration & Tn_FSB_INT_DEL_CAP)
|
||||||
timer0.configuration = timer0.configuration & ~Tn_FSB_EN_CNF;
|
timer0.configuration &= ~Tn_FSB_EN_CNF;
|
||||||
|
|
||||||
uint16_t irq;
|
uint16_t irq;
|
||||||
if (header->legacy_replacement_irq_routing_cable)
|
if (header->legacy_replacement_irq_routing_cable)
|
||||||
@@ -244,10 +263,7 @@ namespace Kernel
|
|||||||
timer0.configuration = (timer0.configuration & ~Tn_INT_ROUTE_CNF_MASK) | (gsi << Tn_INT_ROUTE_CNF_SHIFT);
|
timer0.configuration = (timer0.configuration & ~Tn_INT_ROUTE_CNF_MASK) | (gsi << Tn_INT_ROUTE_CNF_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set timer period to 1000 Hz
|
if (use_64bit_timer)
|
||||||
const uint64_t ticks_per_ms = m_ticks_per_s / 1000;
|
|
||||||
|
|
||||||
if (timer0.configuration & Tn_SIZE_CAP)
|
|
||||||
{
|
{
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
timer0.configuration = timer0.configuration | Tn_VAL_SET_CNF;
|
timer0.configuration = timer0.configuration | Tn_VAL_SET_CNF;
|
||||||
@@ -259,16 +275,11 @@ namespace Kernel
|
|||||||
timer0.comparator.high = ticks_per_ms >> 32;
|
timer0.comparator.high = ticks_per_ms >> 32;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (ticks_per_ms <= 0xFFFFFFFF)
|
else
|
||||||
{
|
{
|
||||||
timer0.configuration = timer0.configuration | Tn_VAL_SET_CNF;
|
timer0.configuration = timer0.configuration | Tn_VAL_SET_CNF;
|
||||||
timer0.comparator.low = ticks_per_ms;
|
timer0.comparator.low = ticks_per_ms;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
dprintln("HPET: cannot create 1 kHz timer");
|
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
set_irq(irq);
|
set_irq(irq);
|
||||||
InterruptController::get().enable_irq(irq);
|
InterruptController::get().enable_irq(irq);
|
||||||
|
|||||||
Reference in New Issue
Block a user