1
0
forked from 0ad/0ad

workaround hardware/BIOS craziness

fixes #1047

This was SVN commit r10754.
This commit is contained in:
janwas 2011-12-17 20:41:32 +00:00
parent 5ec89d68eb
commit 36ef0a376d

View File

@ -60,19 +60,7 @@ public:
{
RETURN_STATUS_IF_ERR(MapRegisters(m_hpetRegisters));
// retrieve capabilities and ID
{
const u64 caps_and_id = Read64(CAPS_AND_ID);
const u8 revision = (u8)bits(caps_and_id, 0, 7);
ENSURE(revision != 0); // "the value must NOT be 00h"
m_counterBits = (caps_and_id & Bit<u64>(13))? 64 : 32;
const u16 vendorID = (u16)bits(caps_and_id, 16, 31);
const u32 period_fs = (u32)bits(caps_and_id, 32, 63);
ENSURE(period_fs != 0); // "a value of 0 in this field is not permitted"
ENSURE(period_fs <= 0x05F5E100); // 100 ns (min freq is 10 MHz)
m_frequency = 1e15 / period_fs;
debug_printf(L"HPET: rev=%X vendor=%X bits=%d period=%08X freq=%g\n", revision, vendorID, m_counterBits, period_fs, m_frequency);
}
RETURN_STATUS_IF_ERR(VerifyCapabilities(m_frequency, m_counterBits));
// start the counter (if not already running)
Write64(CONFIG, Read64(CONFIG)|1);
@ -199,6 +187,40 @@ private:
_mm_storel_epi64((__m128i*)address, value128);
}
Status VerifyCapabilities(double& frequency, u32& counterBits) const
{
// AMD document 43366 indicates the clock generator that drives the
// HPET is "spread-capable". Wikipedia's frequency hopping article
// explains that this reduces electromagnetic interference.
// The AMD document recommends BIOS writers add SMM hooks for
// reporting the resulting slightly different frequency.
// This apparently requires calibration triggered when the HPET is
// accessed, during which the config register is -1. We'll wait
// about 1 ms (MMIO is expected to take at least 1 us) and
// then ensure the HPET timer period is within reasonable bounds.
u64 caps_and_id = Read64(CAPS_AND_ID);
for(size_t reps = 0; reps < 1000; reps++)
{
if(caps_and_id != ~u64(0)) // register seems valid
break;
caps_and_id = Read64(CAPS_AND_ID);
}
const u8 revision = (u8)bits(caps_and_id, 0, 7);
ENSURE(revision != 0); // "the value must NOT be 00h"
counterBits = (caps_and_id & Bit<u64>(13))? 64 : 32;
const u16 vendorID = (u16)bits(caps_and_id, 16, 31);
const u32 period_fs = (u32)bits(caps_and_id, 32, 63);
ENSURE(period_fs != 0); // "a value of 0 in this field is not permitted"
frequency = 1e15 / period_fs;
debug_printf(L"HPET: rev=%X vendor=%X bits=%d period=%08X freq=%g\n", revision, vendorID, counterBits, period_fs, frequency);
if(period_fs > 0x05F5E100) // 100 ns (spec guarantees >= 10 MHz)
return ERR::CORRUPTED; // avoid using HPET (e.g. if calibration was still in progress)
return INFO::OK;
}
volatile void* m_hpetRegisters;
double m_frequency;
u32 m_counterBits;