93 lines
3.9 KiB
C++
93 lines
3.9 KiB
C++
/*
|
|
* AcpiPower.hpp
|
|
* ACPI device power management: _PSx methods, _PRx power resources,
|
|
* _DSM calls, and finding the namespace node behind a PCI function
|
|
* Copyright (c) 2026 Daniel Hammer
|
|
*/
|
|
|
|
#pragma once
|
|
#include <cstdint>
|
|
#include <ACPI/AML/AmlNamespace.hpp>
|
|
|
|
namespace Hal {
|
|
namespace AcpiPower {
|
|
|
|
// ============================================================================
|
|
|
|
// PCI <-> ACPI
|
|
|
|
// ============================================================================
|
|
// The Device node describing PCI function bus:dev.fn, or -1. When
|
|
// firmware declares more than one node at the same address (a generic
|
|
// placeholder plus a vendor SSDT's real one is common for GPUs), the
|
|
// one carrying power-management objects wins.
|
|
int32_t FindPciDevice(uint8_t bus, uint8_t dev, uint8_t fn);
|
|
|
|
// Forget the PCI address map built by FindPciDevice (bus numbers may
|
|
// change across a resume).
|
|
void InvalidatePciMap();
|
|
|
|
// True when `device` has a child object named `name` ("_PS3").
|
|
bool HasObject(int32_t device, const char* name);
|
|
|
|
// ============================================================================
|
|
|
|
// Power resources
|
|
|
|
// ============================================================================
|
|
static constexpr int MaxResources = 8;
|
|
|
|
// The power resources the device lists in _PR0.._PR3 (deduplicated).
|
|
int CollectResources(int32_t device, int32_t* out, int max);
|
|
|
|
// _STA of a power resource: 1 on, 0 off, -1 unknown.
|
|
int ResourceState(int32_t resource);
|
|
|
|
// ============================================================================
|
|
|
|
// Device power transitions
|
|
|
|
// ============================================================================
|
|
struct D3ColdReport {
|
|
bool RanPs3;
|
|
int ResourcesOff; // resources whose _OFF was run
|
|
int ResourcesShared; // left on: some other present device needs them
|
|
int ResourcesStillOn; // _OFF ran but _STA still says on
|
|
};
|
|
|
|
// Put an ACPI device into D3cold the way the spec orders it: _PS3,
|
|
// then every power resource it depends on off, last-listed first. A
|
|
// resource that a device outside `owners` also depends on is left
|
|
// on -- `owners` lists the nodes being powered down together (the
|
|
// functions of one card and the port above them), which may freely
|
|
// share, as may anything below them in the namespace. The PCI side
|
|
// (PMCSR to D3hot) is the caller's to do first.
|
|
void EnterD3Cold(int32_t device, const int32_t* owners, int ownerCount,
|
|
D3ColdReport& report);
|
|
|
|
// ============================================================================
|
|
|
|
// _DSM
|
|
|
|
// ============================================================================
|
|
// Evaluate _DSM(uuid, revision, function, arg3) on a device. False
|
|
// when the device has no _DSM or it failed.
|
|
bool EvaluateDsm(int32_t device, const uint8_t uuid[16], uint64_t revision,
|
|
uint64_t function, const AML::Object& arg3, AML::Object& result);
|
|
|
|
// The function bitmap _DSM function 0 reports for (uuid, revision),
|
|
// 0 when unsupported. Bit 0 set means "some functions exist".
|
|
uint64_t DsmFunctions(int32_t device, const uint8_t uuid[16], uint64_t revision,
|
|
const AML::Object& arg3);
|
|
|
|
// Helpers for building _DSM / method arguments.
|
|
AML::Object IntegerArg(uint64_t value);
|
|
AML::Object BufferArg(const uint8_t* bytes, uint32_t length);
|
|
AML::Object EmptyPackageArg();
|
|
|
|
// Integer value of a method result: an integer as is, a buffer read
|
|
// little-endian (up to 8 bytes).
|
|
uint64_t ResultInteger(const AML::Object& result);
|
|
};
|
|
};
|