feat: further kernel power and power optimizations
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* InputEvents.cpp
|
||||
* Shared input activity event source
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include "InputEvents.hpp"
|
||||
#include <atomic>
|
||||
#include <Sched/Scheduler.hpp>
|
||||
#include <Timekeeping/ApicTimer.hpp>
|
||||
|
||||
namespace Drivers::InputEvents {
|
||||
|
||||
static std::atomic<uint64_t> g_serial{1};
|
||||
static uint8_t g_waitObject;
|
||||
|
||||
struct WaitContext {
|
||||
uint64_t observedSerial;
|
||||
};
|
||||
|
||||
static bool SerialStillObserved(void* rawContext) {
|
||||
auto* context = static_cast<WaitContext*>(rawContext);
|
||||
return context != nullptr &&
|
||||
g_serial.load(std::memory_order_acquire) == context->observedSerial;
|
||||
}
|
||||
|
||||
uint64_t GetSerial() {
|
||||
return g_serial.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void NotifyActivity() {
|
||||
Timekeeping::NoteInteractiveActivity();
|
||||
g_serial.fetch_add(1, std::memory_order_release);
|
||||
Sched::WakeObjectWaiters(&g_waitObject);
|
||||
}
|
||||
|
||||
uint64_t WaitForChange(uint64_t observedSerial, uint64_t timeoutMs) {
|
||||
uint64_t current = GetSerial();
|
||||
if (current != observedSerial || timeoutMs == 0) {
|
||||
return current;
|
||||
}
|
||||
|
||||
WaitContext context{observedSerial};
|
||||
uint64_t start = Timekeeping::GetMilliseconds();
|
||||
|
||||
for (;;) {
|
||||
current = GetSerial();
|
||||
if (current != observedSerial) {
|
||||
return current;
|
||||
}
|
||||
|
||||
uint64_t waitMs = 0;
|
||||
if (timeoutMs == UINT64_MAX) {
|
||||
waitMs = 0;
|
||||
} else {
|
||||
uint64_t elapsed = Timekeeping::GetMilliseconds() - start;
|
||||
if (elapsed >= timeoutMs) {
|
||||
return current;
|
||||
}
|
||||
waitMs = timeoutMs - elapsed;
|
||||
if (waitMs == 0) {
|
||||
waitMs = 1;
|
||||
}
|
||||
}
|
||||
|
||||
Sched::BlockOnObjectIf(&g_waitObject, waitMs, SerialStillObserved, &context);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* InputEvents.hpp
|
||||
* Shared input activity event source
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace Drivers::InputEvents {
|
||||
|
||||
// Monotonic serial incremented after mouse or keyboard state changes.
|
||||
uint64_t GetSerial();
|
||||
|
||||
// Notify latency-sensitive input activity and wake input waiters.
|
||||
void NotifyActivity();
|
||||
|
||||
// Wait until the serial differs from observedSerial or timeoutMs elapses.
|
||||
// timeoutMs == 0 is a poll; timeoutMs == UINT64_MAX waits indefinitely.
|
||||
uint64_t WaitForChange(uint64_t observedSerial, uint64_t timeoutMs);
|
||||
|
||||
}
|
||||
@@ -124,6 +124,10 @@ namespace Drivers::Net::E1000E {
|
||||
return *(volatile uint32_t*)(g_mmioBase + reg);
|
||||
}
|
||||
|
||||
static void ConfigureInterruptModeration() {
|
||||
WriteReg(REG_ITR, ITR_INTERVAL_512US);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// SW/FW semaphore (prevents conflicts with Intel Management Engine)
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -586,6 +590,7 @@ namespace Drivers::Net::E1000E {
|
||||
|
||||
SetupRx();
|
||||
SetupTx();
|
||||
ConfigureInterruptModeration();
|
||||
|
||||
if (SetupMsi(bus, device, function)) {
|
||||
WriteReg(REG_IMS, ICR_RXT0 | ICR_TXDW | ICR_TXQE | ICR_LSC | ICR_RXDMT0);
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Drivers::Net::E1000E {
|
||||
constexpr uint32_t REG_CTRL_EXT = 0x0018; // Extended Device Control
|
||||
constexpr uint32_t REG_MDIC = 0x0020; // MDI Control (PHY access)
|
||||
constexpr uint32_t REG_ICR = 0x00C0; // Interrupt Cause Read
|
||||
constexpr uint32_t REG_ITR = 0x00C4; // Interrupt Throttling
|
||||
constexpr uint32_t REG_IMS = 0x00D0; // Interrupt Mask Set
|
||||
constexpr uint32_t REG_IMC = 0x00D8; // Interrupt Mask Clear
|
||||
constexpr uint32_t REG_RCTL = 0x0100; // Receive Control
|
||||
@@ -93,6 +94,7 @@ namespace Drivers::Net::E1000E {
|
||||
constexpr uint32_t ICR_RXDMT0 = (1 << 4); // RX Descriptor Minimum Threshold
|
||||
constexpr uint32_t ICR_RXO = (1 << 6); // Receiver Overrun
|
||||
constexpr uint32_t ICR_RXT0 = (1 << 7); // Receiver Timer Interrupt
|
||||
constexpr uint32_t ITR_INTERVAL_512US = 2048; // 2048 * 256 ns
|
||||
|
||||
// TX descriptor command bits
|
||||
constexpr uint8_t TXCMD_EOP = (1 << 0); // End Of Packet
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <Terminal/Terminal.hpp>
|
||||
#include <Hal/Apic/Interrupts.hpp>
|
||||
#include <Hal/Apic/IoApic.hpp>
|
||||
#include <Drivers/Input/InputEvents.hpp>
|
||||
|
||||
namespace Drivers::PS2::Keyboard {
|
||||
|
||||
@@ -86,14 +87,15 @@ namespace Drivers::PS2::Keyboard {
|
||||
return shift ^ caps;
|
||||
}
|
||||
|
||||
static void BufferPush(const KeyEvent& event) {
|
||||
static bool BufferPush(const KeyEvent& event) {
|
||||
uint32_t nextHead = (g_BufferHead + 1) & (KeyBufferSize - 1);
|
||||
if (nextHead == g_BufferTail) {
|
||||
// Buffer full, drop the event
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
g_KeyBuffer[g_BufferHead] = event;
|
||||
g_BufferHead = nextHead;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool BufferPop(KeyEvent& event) {
|
||||
@@ -105,6 +107,16 @@ namespace Drivers::PS2::Keyboard {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void PushAndNotify(const KeyEvent& event) {
|
||||
g_BufferLock.Acquire();
|
||||
bool pushed = BufferPush(event);
|
||||
g_BufferLock.Release();
|
||||
|
||||
if (pushed) {
|
||||
Drivers::InputEvents::NotifyActivity();
|
||||
}
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
Kt::KernelLogStream(Kt::INFO, "PS2/KB") << "Initializing keyboard driver";
|
||||
|
||||
@@ -169,9 +181,7 @@ namespace Drivers::PS2::Keyboard {
|
||||
.Alt = g_Modifiers.LeftAlt || g_Modifiers.RightAlt,
|
||||
.CapsLock = g_Modifiers.CapsLock
|
||||
};
|
||||
g_BufferLock.Acquire();
|
||||
BufferPush(event);
|
||||
g_BufferLock.Release();
|
||||
PushAndNotify(event);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -229,9 +239,7 @@ namespace Drivers::PS2::Keyboard {
|
||||
.Alt = g_Modifiers.LeftAlt || g_Modifiers.RightAlt,
|
||||
.CapsLock = g_Modifiers.CapsLock
|
||||
};
|
||||
g_BufferLock.Acquire();
|
||||
BufferPush(event);
|
||||
g_BufferLock.Release();
|
||||
PushAndNotify(event);
|
||||
return;
|
||||
}
|
||||
if (isModifier) return;
|
||||
@@ -256,9 +264,7 @@ namespace Drivers::PS2::Keyboard {
|
||||
.CapsLock = g_Modifiers.CapsLock
|
||||
};
|
||||
|
||||
g_BufferLock.Acquire();
|
||||
BufferPush(event);
|
||||
g_BufferLock.Release();
|
||||
PushAndNotify(event);
|
||||
}
|
||||
|
||||
bool IsKeyAvailable() {
|
||||
@@ -292,9 +298,7 @@ namespace Drivers::PS2::Keyboard {
|
||||
}
|
||||
|
||||
void InjectKeyEvent(const KeyEvent& event) {
|
||||
g_BufferLock.Acquire();
|
||||
BufferPush(event);
|
||||
g_BufferLock.Release();
|
||||
PushAndNotify(event);
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <Terminal/Terminal.hpp>
|
||||
#include <Hal/Apic/Interrupts.hpp>
|
||||
#include <Hal/Apic/IoApic.hpp>
|
||||
#include <Drivers/Input/InputEvents.hpp>
|
||||
|
||||
namespace Drivers::PS2::Mouse {
|
||||
|
||||
@@ -170,6 +171,7 @@ namespace Drivers::PS2::Mouse {
|
||||
if (g_State.Y > g_MaxY) g_State.Y = g_MaxY;
|
||||
|
||||
g_StateLock.Release();
|
||||
Drivers::InputEvents::NotifyActivity();
|
||||
}
|
||||
|
||||
MouseState GetMouseState() {
|
||||
@@ -236,6 +238,7 @@ namespace Drivers::PS2::Mouse {
|
||||
if (g_State.Y > g_MaxY) g_State.Y = g_MaxY;
|
||||
|
||||
g_StateLock.Release();
|
||||
Drivers::InputEvents::NotifyActivity();
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@@ -377,4 +377,17 @@ namespace Drivers::USB::HidKeyboard {
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t GetNextTickDeadline() {
|
||||
if (g_RepeatKey == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t firstRepeat = g_RepeatStartMs + TYPEMATIC_DELAY_MS;
|
||||
if (g_LastRepeatMs == 0 || g_LastRepeatMs < firstRepeat) {
|
||||
return firstRepeat;
|
||||
}
|
||||
|
||||
return g_LastRepeatMs + TYPEMATIC_PERIOD_MS;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,4 +18,8 @@ namespace Drivers::USB::HidKeyboard {
|
||||
// Timer tick for typematic repeat (call from periodic timer, e.g. 1ms)
|
||||
void Tick();
|
||||
|
||||
// Earliest millisecond deadline when typematic repeat needs service again.
|
||||
// Returns 0 when no repeat is pending.
|
||||
uint64_t GetNextTickDeadline();
|
||||
|
||||
};
|
||||
|
||||
@@ -959,7 +959,7 @@ namespace Drivers::USB::Xhci {
|
||||
|
||||
// Enable interrupter 0
|
||||
WriteRt(IR0_IMAN, IMAN_IE);
|
||||
WriteRt(IR0_IMOD, 0);
|
||||
WriteRt(IR0_IMOD, IMOD_INTERVAL_100US);
|
||||
|
||||
// Start controller
|
||||
WriteOp(OP_USBCMD, USBCMD_RS | USBCMD_INTE | USBCMD_HSEE);
|
||||
@@ -1269,7 +1269,7 @@ namespace Drivers::USB::Xhci {
|
||||
// Step 13: Enable interrupter 0
|
||||
// -----------------------------------------------------------------
|
||||
WriteRt(IR0_IMAN, IMAN_IE);
|
||||
WriteRt(IR0_IMOD, 0); // No moderation
|
||||
WriteRt(IR0_IMOD, IMOD_INTERVAL_100US);
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Step 14: Start controller
|
||||
|
||||
@@ -110,6 +110,7 @@ namespace Drivers::USB::Xhci {
|
||||
// IMAN bits
|
||||
constexpr uint32_t IMAN_IP = (1 << 0); // Interrupt Pending
|
||||
constexpr uint32_t IMAN_IE = (1 << 1); // Interrupt Enable
|
||||
constexpr uint32_t IMOD_INTERVAL_100US = 400; // 100 us in 250 ns units
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TRB (Transfer Request Block) - 16 bytes
|
||||
|
||||
Reference in New Issue
Block a user