Fixes for hpet counter read, choose better PIT divisor
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use crate::acpi::hpet::Hpet;
|
||||
use super::pit;
|
||||
|
||||
const LEG_RT_CNF: u64 = 2;
|
||||
const ENABLE_CNF: u64 = 1;
|
||||
@@ -14,7 +15,7 @@ pub(crate) const MAIN_COUNTER_OFFSET: usize = 0xF0;
|
||||
// const NUM_TIMER_CAP_MASK: u64 = 0x0f00;
|
||||
const LEG_RT_CAP: u64 = 0x8000;
|
||||
const T0_CONFIG_CAPABILITY_OFFSET: usize = 0x100;
|
||||
const T0_COMPARATOR_OFFSET: usize = 0x108;
|
||||
pub(crate) const T0_COMPARATOR_OFFSET: usize = 0x108;
|
||||
|
||||
const PER_INT_CAP: u64 = 0x10;
|
||||
|
||||
@@ -35,10 +36,8 @@ pub unsafe fn init(hpet: &mut Hpet) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
let counter_clk_period_fs = capability >> 32;
|
||||
let desired_fs_period: u64 = 2_250_286 * 1_000_000;
|
||||
|
||||
let clk_periods_per_kernel_tick: u64 = desired_fs_period / counter_clk_period_fs;
|
||||
let period_fs = capability >> 32;
|
||||
let divisor = (pit::RATE as u64 * 1_000_000) / period_fs;
|
||||
|
||||
let t0_capabilities = hpet.base_address.read_u64(T0_CONFIG_CAPABILITY_OFFSET);
|
||||
if t0_capabilities & PER_INT_CAP == 0 {
|
||||
@@ -51,9 +50,9 @@ pub unsafe fn init(hpet: &mut Hpet) -> bool {
|
||||
let t0_config_word: u64 = TN_VAL_SET_CNF | TN_TYPE_CNF | TN_INT_ENB_CNF;
|
||||
hpet.base_address.write_u64(T0_CONFIG_CAPABILITY_OFFSET, t0_config_word);
|
||||
// set accumulator value
|
||||
hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, counter + clk_periods_per_kernel_tick);
|
||||
hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, counter + divisor);
|
||||
// set interval
|
||||
hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, clk_periods_per_kernel_tick);
|
||||
hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, divisor);
|
||||
|
||||
// Enable interrupts from the HPET
|
||||
{
|
||||
|
||||
@@ -10,7 +10,14 @@ const ACCESS_LATCH: u8 = 0b00 << 4;
|
||||
const ACCESS_LOHI: u8 = 0b11 << 4;
|
||||
const MODE_2: u8 = 0b010 << 1;
|
||||
|
||||
const CHAN0_DIVISOR: u16 = 2685;
|
||||
// 1 / (1.193182 MHz) = 838,095,110 femtoseconds ~= 838.095 ns
|
||||
pub const PERIOD_FS: u128 = 838_095_110;
|
||||
|
||||
// 461 / (1.193182 MHz) = 3863618.00071 ns ~= 386 us or 2.588 kHz
|
||||
pub const CHAN0_DIVISOR: u16 = 461;
|
||||
|
||||
// Calculated interrupt period in nanoseconds based on divisor and period
|
||||
pub const RATE: u128 = (CHAN0_DIVISOR as u128 * PERIOD_FS) / 1_000_000;
|
||||
|
||||
pub unsafe fn init() {
|
||||
COMMAND.write(SELECT_CHAN0 | ACCESS_LOHI | MODE_2);
|
||||
|
||||
@@ -4,15 +4,13 @@ use alloc::vec::Vec;
|
||||
|
||||
use crate::{interrupt, interrupt_stack};
|
||||
use crate::context::timeout;
|
||||
use crate::device::{local_apic, ioapic, pic};
|
||||
use crate::device::{local_apic, ioapic, pic, pit};
|
||||
use crate::device::serial::{COM1, COM2};
|
||||
use crate::ipi::{ipi, IpiKind, IpiTarget};
|
||||
use crate::scheme::debug::{debug_input, debug_notify};
|
||||
use crate::scheme::serio::serio_input;
|
||||
use crate::{context, time};
|
||||
|
||||
pub const PIT_RATE: u128 = 2_250_286;
|
||||
|
||||
//resets to 0 in context::switch()
|
||||
#[thread_local]
|
||||
pub static PIT_TICKS: AtomicUsize = AtomicUsize::new(0);
|
||||
@@ -140,7 +138,7 @@ interrupt_stack!(pit_stack, |_stack| {
|
||||
// Saves CPU time by not sending IRQ event irq_trigger(0);
|
||||
|
||||
{
|
||||
*time::OFFSET.lock() += PIT_RATE;
|
||||
*time::OFFSET.lock() += pit::RATE;
|
||||
}
|
||||
|
||||
eoi(0);
|
||||
@@ -268,7 +266,7 @@ interrupt!(lapic_error, || {
|
||||
|
||||
interrupt!(calib_pit, || {
|
||||
{
|
||||
*time::OFFSET.lock() += PIT_RATE;
|
||||
*time::OFFSET.lock() += pit::RATE;
|
||||
}
|
||||
|
||||
eoi(0);
|
||||
|
||||
@@ -3,14 +3,28 @@ use super::device::{hpet, pit};
|
||||
|
||||
pub fn counter() -> u128 {
|
||||
if let Some(ref hpet) = *ACPI_TABLE.hpet.read() {
|
||||
let capability = unsafe { hpet.base_address.read_u64(hpet::CAPABILITY_OFFSET) };
|
||||
let period_fs = (capability >> 32) as u128;
|
||||
//TODO: handle rollover?
|
||||
//TODO: improve performance
|
||||
|
||||
// Current count
|
||||
let counter = unsafe { hpet.base_address.read_u64(hpet::MAIN_COUNTER_OFFSET) };
|
||||
(counter as u128 * period_fs) / 1_000_000
|
||||
// Comparator holds next interrupt count
|
||||
let comparator = unsafe { hpet.base_address.read_u64(hpet::T0_COMPARATOR_OFFSET) };
|
||||
// Get period in femtoseconds
|
||||
let capability = unsafe { hpet.base_address.read_u64(hpet::CAPABILITY_OFFSET) };
|
||||
let period_fs = capability >> 32;
|
||||
// Calculate divisor
|
||||
let divisor = (pit::RATE as u64 * 1_000_000) / period_fs;
|
||||
// Calculate last interrupt
|
||||
let last_interrupt = comparator.saturating_sub(divisor);
|
||||
// Calculate ticks since last interrupt
|
||||
let elapsed = counter.saturating_sub(last_interrupt);
|
||||
// Calculate nanoseconds since last interrupt
|
||||
(elapsed as u128 * period_fs as u128) / 1_000_000
|
||||
} else {
|
||||
// 1.193182 MHz PIT is approximately 838.095 nanoseconds
|
||||
let period_ns = 838;
|
||||
let counter = unsafe { pit::read() };
|
||||
counter as u128 * period_ns
|
||||
// Read ticks since last interrupt
|
||||
let elapsed = unsafe { pit::read() };
|
||||
// Calculate nanoseconds since last interrupt
|
||||
(elapsed as u128 * pit::PERIOD_FS) / 1_000_000
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::acpi::hpet::Hpet;
|
||||
use super::pit;
|
||||
|
||||
const LEG_RT_CNF: u64 = 2;
|
||||
const ENABLE_CNF: u64 = 1;
|
||||
@@ -14,7 +15,7 @@ pub(crate) const MAIN_COUNTER_OFFSET: usize = 0xF0;
|
||||
// const NUM_TIMER_CAP_MASK: u64 = 0x0f00;
|
||||
const LEG_RT_CAP: u64 = 0x8000;
|
||||
const T0_CONFIG_CAPABILITY_OFFSET: usize = 0x100;
|
||||
const T0_COMPARATOR_OFFSET: usize = 0x108;
|
||||
pub(crate) const T0_COMPARATOR_OFFSET: usize = 0x108;
|
||||
|
||||
const PER_INT_CAP: u64 = 0x10;
|
||||
|
||||
@@ -35,10 +36,8 @@ pub unsafe fn init(hpet: &mut Hpet) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
let counter_clk_period_fs = capability >> 32;
|
||||
let desired_fs_period: u64 = 2_250_286 * 1_000_000;
|
||||
|
||||
let clk_periods_per_kernel_tick: u64 = desired_fs_period / counter_clk_period_fs;
|
||||
let period_fs = capability >> 32;
|
||||
let divisor = (pit::RATE as u64 * 1_000_000) / period_fs;
|
||||
|
||||
let t0_capabilities = hpet.base_address.read_u64(T0_CONFIG_CAPABILITY_OFFSET);
|
||||
if t0_capabilities & PER_INT_CAP == 0 {
|
||||
@@ -51,9 +50,9 @@ pub unsafe fn init(hpet: &mut Hpet) -> bool {
|
||||
let t0_config_word: u64 = TN_VAL_SET_CNF | TN_TYPE_CNF | TN_INT_ENB_CNF;
|
||||
hpet.base_address.write_u64(T0_CONFIG_CAPABILITY_OFFSET, t0_config_word);
|
||||
// set accumulator value
|
||||
hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, counter + clk_periods_per_kernel_tick);
|
||||
hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, counter + divisor);
|
||||
// set interval
|
||||
hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, clk_periods_per_kernel_tick);
|
||||
hpet.base_address.write_u64(T0_COMPARATOR_OFFSET, divisor);
|
||||
|
||||
// Enable interrupts from the HPET
|
||||
{
|
||||
|
||||
@@ -10,7 +10,14 @@ const ACCESS_LATCH: u8 = 0b00 << 4;
|
||||
const ACCESS_LOHI: u8 = 0b11 << 4;
|
||||
const MODE_2: u8 = 0b010 << 1;
|
||||
|
||||
const CHAN0_DIVISOR: u16 = 2685;
|
||||
// 1 / (1.193182 MHz) = 838,095,110 femtoseconds ~= 838.095 ns
|
||||
pub const PERIOD_FS: u128 = 838_095_110;
|
||||
|
||||
// 461 / (1.193182 MHz) = 3863618.00071 ns ~= 386 us or 2.588 kHz
|
||||
pub const CHAN0_DIVISOR: u16 = 461;
|
||||
|
||||
// Calculated interrupt period in nanoseconds based on divisor and period
|
||||
pub const RATE: u128 = (CHAN0_DIVISOR as u128 * PERIOD_FS) / 1_000_000;
|
||||
|
||||
pub unsafe fn init() {
|
||||
COMMAND.write(SELECT_CHAN0 | ACCESS_LOHI | MODE_2);
|
||||
|
||||
@@ -4,15 +4,13 @@ use alloc::vec::Vec;
|
||||
|
||||
use crate::{interrupt, interrupt_stack};
|
||||
use crate::context::timeout;
|
||||
use crate::device::{local_apic, ioapic, pic};
|
||||
use crate::device::{local_apic, ioapic, pic, pit};
|
||||
use crate::device::serial::{COM1, COM2};
|
||||
use crate::ipi::{ipi, IpiKind, IpiTarget};
|
||||
use crate::scheme::debug::{debug_input, debug_notify};
|
||||
use crate::scheme::serio::serio_input;
|
||||
use crate::{context, time};
|
||||
|
||||
pub const PIT_RATE: u128 = 2_250_286;
|
||||
|
||||
//resets to 0 in context::switch()
|
||||
#[thread_local]
|
||||
pub static PIT_TICKS: AtomicUsize = AtomicUsize::new(0);
|
||||
@@ -140,7 +138,7 @@ interrupt_stack!(pit_stack, |_stack| {
|
||||
// Saves CPU time by not sending IRQ event irq_trigger(0);
|
||||
|
||||
{
|
||||
*time::OFFSET.lock() += PIT_RATE;
|
||||
*time::OFFSET.lock() += pit::RATE;
|
||||
}
|
||||
|
||||
eoi(0);
|
||||
@@ -268,7 +266,7 @@ interrupt!(lapic_error, || {
|
||||
|
||||
interrupt!(calib_pit, || {
|
||||
{
|
||||
*time::OFFSET.lock() += PIT_RATE;
|
||||
*time::OFFSET.lock() += pit::RATE;
|
||||
}
|
||||
|
||||
eoi(0);
|
||||
|
||||
@@ -3,14 +3,28 @@ use super::device::{hpet, pit};
|
||||
|
||||
pub fn counter() -> u128 {
|
||||
if let Some(ref hpet) = *ACPI_TABLE.hpet.read() {
|
||||
let capability = unsafe { hpet.base_address.read_u64(hpet::CAPABILITY_OFFSET) };
|
||||
let period_fs = (capability >> 32) as u128;
|
||||
//TODO: handle rollover?
|
||||
//TODO: improve performance
|
||||
|
||||
// Current count
|
||||
let counter = unsafe { hpet.base_address.read_u64(hpet::MAIN_COUNTER_OFFSET) };
|
||||
(counter as u128 * period_fs) / 1_000_000
|
||||
// Comparator holds next interrupt count
|
||||
let comparator = unsafe { hpet.base_address.read_u64(hpet::T0_COMPARATOR_OFFSET) };
|
||||
// Get period in femtoseconds
|
||||
let capability = unsafe { hpet.base_address.read_u64(hpet::CAPABILITY_OFFSET) };
|
||||
let period_fs = capability >> 32;
|
||||
// Calculate divisor
|
||||
let divisor = (pit::RATE as u64 * 1_000_000) / period_fs;
|
||||
// Calculate last interrupt
|
||||
let last_interrupt = comparator.saturating_sub(divisor);
|
||||
// Calculate ticks since last interrupt
|
||||
let elapsed = counter.saturating_sub(last_interrupt);
|
||||
// Calculate nanoseconds since last interrupt
|
||||
(elapsed as u128 * period_fs as u128) / 1_000_000
|
||||
} else {
|
||||
// 1.193182 MHz PIT is approximately 838.095 nanoseconds
|
||||
let period_ns = 838;
|
||||
let counter = unsafe { pit::read() };
|
||||
counter as u128 * period_ns
|
||||
// Read ticks since last interrupt
|
||||
let elapsed = unsafe { pit::read() };
|
||||
// Calculate nanoseconds since last interrupt
|
||||
(elapsed as u128 * pit::PERIOD_FS) / 1_000_000
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ pub unsafe fn switch() -> bool {
|
||||
|
||||
// Set old context as not running and update CPU time
|
||||
from_context_guard.running = false;
|
||||
from_context_guard.cpu_time += switch_time - from_context_guard.switch_time;
|
||||
from_context_guard.cpu_time += switch_time.saturating_sub(from_context_guard.switch_time);
|
||||
|
||||
// Set new context as running and set switch time
|
||||
to_context.running = true;
|
||||
|
||||
Reference in New Issue
Block a user