123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- proc.c
- Abstract:
- This module implements support for processor devices in ACPI.
- Author:
- Evan Green 28-Sep-2015
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include "acpip.h"
- #include "proc.h"
- #include "namespce.h"
- #include "resdesc.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- AcpipCreateGlobalProcessorContext (
- VOID
- );
- VOID
- AcpipProcessorInitializeCStates (
- PACPI_OBJECT NamespaceObject,
- PACPI_PROCESSOR_CONTEXT Device
- );
- KSTATUS
- AcpipInitializeCStatesOnProcessor (
- PPM_IDLE_STATE_INTERFACE Interface,
- PPM_IDLE_PROCESSOR_STATE Processor
- );
- KSTATUS
- AcpipProcessorGetOsProcessorId (
- ULONG AcpiId,
- PULONG OsId
- );
- ULONG
- AcpipGetProcessorCount (
- VOID
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Set this boolean to print processor power enumeration information.
- //
- BOOL AcpiDebugProcessorPowerEnumeration = FALSE;
- //
- // Remember the number of processors and how many have successfully started.
- //
- ULONG AcpiProcessorCount;
- ULONG AcpiInitializedProcessorCount;
- PACPI_PROCESSOR_GLOBAL_CONTEXT AcpiProcessor;
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- AcpipProcessorStart (
- PACPI_DEVICE_CONTEXT Device
- )
- /*++
- Routine Description:
- This routine starts an ACPI processor object.
- Arguments:
- Device - Supplies a pointer to the ACPI information associated with
- the processor device.
- Return Value:
- Status code.
- --*/
- {
- ULONG AcpiId;
- ULONG BlockAddress;
- ULONG BlockSize;
- PACPI_OBJECT NamespaceObject;
- ULONG OsId;
- PACPI_PROCESSOR_CONTEXT Processor;
- ULONG ReadyCount;
- UINTN Size;
- KSTATUS Status;
- PACPI_OBJECT UidMethod;
- PACPI_OBJECT UidReturnValue;
- Processor = NULL;
- UidReturnValue = NULL;
- if (Device->Processor != NULL) {
- Status = STATUS_SUCCESS;
- goto ProcessorStartEnd;
- }
- if (AcpiProcessor == NULL) {
- Status = AcpipCreateGlobalProcessorContext();
- if (!KSUCCESS(Status)) {
- goto ProcessorStartEnd;
- }
- }
- //
- // Perform architecture specific initialization before evaluating processor
- // methods, such as calling _OSC.
- //
- Status = AcpipArchInitializeProcessorManagement(Device->NamespaceObject);
- if (!KSUCCESS(Status)) {
- goto ProcessorStartEnd;
- }
- //
- // Get the ACPI processor ID.
- //
- AcpiId = -1;
- BlockAddress = 0;
- BlockSize = 0;
- NamespaceObject = Device->NamespaceObject;
- if (NamespaceObject->Type == AcpiObjectProcessor) {
- AcpiId = NamespaceObject->U.Processor.ProcessorId;
- BlockAddress = NamespaceObject->U.Processor.ProcessorBlockAddress;
- BlockSize = NamespaceObject->U.Processor.ProcessorBlockLength;
- } else {
- ASSERT(NamespaceObject->Type == AcpiObjectDevice);
- //
- // Attempt to find and execute the _UID function.
- //
- UidMethod = AcpipFindNamedObject(NamespaceObject, ACPI_METHOD__UID);
- if (UidMethod == NULL) {
- Status = STATUS_DEVICE_NOT_CONNECTED;
- goto ProcessorStartEnd;
- }
- Status = AcpiExecuteMethod(UidMethod, NULL, 0, 0, &UidReturnValue);
- if (!KSUCCESS(Status)) {
- goto ProcessorStartEnd;
- }
- if (UidReturnValue == NULL) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto ProcessorStartEnd;
- }
- //
- // Convert to a device ID string if needed.
- //
- if (UidReturnValue->Type == AcpiObjectInteger) {
- AcpiId = UidReturnValue->U.Integer.Value;
- } else if (UidReturnValue->Type == AcpiObjectString) {
- //
- // Consider supporting processor strings if needed.
- //
- ASSERT(FALSE);
- Status = STATUS_NOT_SUPPORTED;
- goto ProcessorStartEnd;
- }
- }
- //
- // Match the ACPI processor ID with an entry in the MADT, and determine the
- // OS processor number from that.
- //
- Status = AcpipProcessorGetOsProcessorId(AcpiId, &OsId);
- if (!KSUCCESS(Status)) {
- goto ProcessorStartEnd;
- }
- ASSERT(OsId < AcpiProcessor->ProcessorCount);
- Processor = &(AcpiProcessor->Processors[OsId]);
- Processor->BlockAddress = BlockAddress;
- Processor->BlockSize = BlockSize;
- Processor->AcpiId = AcpiId;
- Processor->OsId = OsId;
- AcpipProcessorInitializeCStates(NamespaceObject, Processor);
- //
- // This processor device is initialized. If this was the last one, then
- // register processor power management facilities.
- //
- ReadyCount = RtlAtomicAdd32(&(AcpiProcessor->StartedProcessorCount), 1) + 1;
- ASSERT(ReadyCount <= AcpiProcessor->ProcessorCount);
- if (ReadyCount == AcpiProcessor->ProcessorCount) {
- //
- // Register C-State handlers. Failure is not fatal.
- //
- if (Processor->CStateCount != 0) {
- Size = sizeof(PM_IDLE_STATE_INTERFACE);
- KeGetSetSystemInformation(SystemInformationPm,
- PmInformationIdleStateHandlers,
- &(AcpiProcessor->CStateInterface),
- &Size,
- TRUE);
- }
- }
- Status = STATUS_SUCCESS;
- ProcessorStartEnd:
- if (UidReturnValue != NULL) {
- AcpipObjectReleaseReference(UidReturnValue);
- }
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- AcpipCreateGlobalProcessorContext (
- VOID
- )
- /*++
- Routine Description:
- This routine creates and initializes the global ACPI processor context.
- Arguments:
- None.
- Return Value:
- None. Failure to initialize C-States is not fatal.
- --*/
- {
- UINTN AllocationSize;
- PACPI_PROCESSOR_GLOBAL_CONTEXT Context;
- ULONG ProcessorCount;
- KSTATUS Status;
- ProcessorCount = AcpipGetProcessorCount();
- AllocationSize = sizeof(ACPI_PROCESSOR_GLOBAL_CONTEXT) +
- (sizeof(ACPI_PROCESSOR_CONTEXT) * ProcessorCount);
- Context = MmAllocateNonPagedPool(AllocationSize, ACPI_ALLOCATION_TAG);
- if (Context == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateGlobalProcessorContextEnd;
- }
- RtlZeroMemory(Context, AllocationSize);
- Context->ProcessorCount = ProcessorCount;
- Context->Processors = (PACPI_PROCESSOR_CONTEXT)(Context + 1);
- Context->CStateInterface.InitializeIdleStates =
- AcpipInitializeCStatesOnProcessor;
- Context->CStateInterface.EnterIdleState = AcpipEnterCState;
- Context->CStateInterface.Context = Context;
- Status = STATUS_SUCCESS;
- CreateGlobalProcessorContextEnd:
- if (!KSUCCESS(Status)) {
- if (Context != NULL) {
- MmFreeNonPagedPool(Context);
- }
- }
- //
- // If device enumeration is parallelized, this should be an atomic compare
- // exchange and then a subsequent free if the exchange is lost.
- //
- ASSERT(AcpiProcessor == NULL);
- AcpiProcessor = Context;
- return Status;
- }
- VOID
- AcpipProcessorInitializeCStates (
- PACPI_OBJECT NamespaceObject,
- PACPI_PROCESSOR_CONTEXT Device
- )
- /*++
- Routine Description:
- This routine attempts to find and initialize the OS logical processor
- number for the given processor device.
- Arguments:
- NamespaceObject - Supplies the processor namespace object.
- Device - Supplies a pointer to the ACPI information associated with
- the processor device. On success, the OS ID will be filled in.
- Return Value:
- None. Failure to initialize C-States is not fatal.
- --*/
- {
- PACPI_CSTATE AcpiCState;
- ULONG Count;
- PACPI_OBJECT CountObject;
- PACPI_OBJECT Cst;
- ULONG CStateIndex;
- PACPI_OBJECT CStateLatencyObject;
- PACPI_OBJECT CStatePowerObject;
- PACPI_OBJECT CStateRegister;
- ACPI_CSTATE_TYPE CStateType;
- PACPI_OBJECT CStateTypeObject;
- PACPI_OBJECT CstMethod;
- ULONG Latency;
- PPM_IDLE_STATE OsCState;
- ULONG Power;
- PACPI_OBJECT StatePackage;
- KSTATUS Status;
- Cst = NULL;
- if (AcpiDebugProcessorPowerEnumeration != FALSE) {
- RtlDebugPrint("Processor %d (ACPI %d) C-States\n",
- Device->OsId,
- Device->AcpiId);
- }
- //
- // Attempt to find and execute the _CST function.
- //
- CstMethod = AcpipFindNamedObject(NamespaceObject, ACPI_METHOD__CST);
- if (CstMethod == NULL) {
- Status = STATUS_NOT_SUPPORTED;
- goto ProcessorInitializeCStatesEnd;
- }
- Status = AcpiExecuteMethod(CstMethod, NULL, 0, 0, &Cst);
- if (!KSUCCESS(Status)) {
- goto ProcessorInitializeCStatesEnd;
- }
- if ((Cst == NULL) || (Cst->Type != AcpiObjectPackage) ||
- (Cst->U.Package.ElementCount < 2)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto ProcessorInitializeCStatesEnd;
- }
- CountObject = Cst->U.Package.Array[0];
- Count = CountObject->U.Integer.Value;
- if ((CountObject->Type != AcpiObjectInteger) ||
- (Count + 1 > Cst->U.Package.ElementCount)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto ProcessorInitializeCStatesEnd;
- }
- if (Count > ACPI_MAX_CSTATES) {
- RtlDebugPrint("%d C-States!\n", Count);
- Count = ACPI_MAX_CSTATES;
- }
- Device->HighestNonC3 = 0;
- //
- // Loop over all the enumerated C-states.
- //
- for (CStateIndex = 0; CStateIndex < Count; CStateIndex += 1) {
- StatePackage = Cst->U.Package.Array[1 + CStateIndex];
- if ((StatePackage->Type != AcpiObjectPackage) ||
- (StatePackage->U.Package.ElementCount < 4)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto ProcessorInitializeCStatesEnd;
- }
- CStateRegister = StatePackage->U.Package.Array[0];
- CStateTypeObject = StatePackage->U.Package.Array[1];
- CStateLatencyObject = StatePackage->U.Package.Array[2];
- CStatePowerObject = StatePackage->U.Package.Array[3];
- if ((CStateRegister->Type != AcpiObjectBuffer) ||
- (CStateTypeObject->Type != AcpiObjectInteger) ||
- (CStateTypeObject->Type != AcpiObjectInteger) ||
- (CStatePowerObject->Type != AcpiObjectInteger)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto ProcessorInitializeCStatesEnd;
- }
- CStateType = CStateTypeObject->U.Integer.Value;
- Latency = CStateLatencyObject->U.Integer.Value;
- Power = CStatePowerObject->U.Integer.Value;
- AcpiCState = &(Device->AcpiCStates[CStateIndex]);
- OsCState = &(Device->OsCStates[CStateIndex]);
- Status = AcpipParseGenericAddress(CStateRegister,
- &(AcpiCState->Register));
- if (!KSUCCESS(Status)) {
- goto ProcessorInitializeCStatesEnd;
- }
- //
- // Determine if this is Intel-specific fixed function hardware.
- //
- if ((AcpiCState->Register.AddressSpaceId ==
- AddressSpaceFixedHardware) &&
- (AcpiCState->Register.RegisterBitWidth ==
- ACPI_FIXED_HARDWARE_INTEL)) {
- switch (AcpiCState->Register.RegisterBitOffset) {
- case ACPI_FIXED_HARDWARE_INTEL_CST_HALT:
- AcpiCState->Flags |= ACPI_CSTATE_HALT;
- break;
- case ACPI_FIXED_HARDWARE_INTEL_CST_IO_HALT:
- AcpiCState->Flags |= ACPI_CSTATE_IO_HALT;
- break;
- case ACPI_FIXED_HARDWARE_INTEL_CST_MWAIT:
- AcpiCState->Flags |= ACPI_CSTATE_MWAIT;
- if ((AcpiCState->Register.AccessSize &
- ACPI_INTEL_MWAIT_BUS_MASTER_AVOIDANCE) != 0) {
- AcpiCState->Flags |= ACPI_CSTATE_BUS_MASTER_AVOIDANCE;
- }
- break;
- }
- }
- AcpiCState->Type = CStateType;
- AcpiCState->Latency = Latency;
- AcpiCState->Power = Power;
- if (AcpiDebugProcessorPowerEnumeration != FALSE) {
- RtlDebugPrint("C%d: Type %d Latency %d us, Power %d mw\n",
- CStateIndex + 1,
- CStateType,
- Latency,
- Power);
- }
- //
- // Remember the highest C-state that is not C3 in case there is a
- // fallback from a C3 transition that couldn't happen.
- //
- if ((CStateType < AcpiC3) && (CStateIndex > Device->HighestNonC3)) {
- Device->HighestNonC3 = CStateIndex;
- }
- //
- // Initialize the target residency to twice the latency, assuming it
- // takes that much time to get in and get out.
- //
- OsCState->Name[0] = 'C';
- OsCState->Name[1] = '0' + CStateIndex + 1;
- OsCState->Name[2] = '\0';
- OsCState->ExitLatency = KeConvertMicrosecondsToTimeTicks(Latency);
- OsCState->TargetResidency = OsCState->ExitLatency * 2;
- }
- Device->CStateCount = Count;
- Status = STATUS_SUCCESS;
- ProcessorInitializeCStatesEnd:
- if (!KSUCCESS(Status)) {
- if (AcpiDebugProcessorPowerEnumeration != FALSE) {
- RtlDebugPrint("ACPI: C-State init failed on P%d: %x\n",
- Device->AcpiId,
- Status);
- }
- }
- if (Cst != NULL) {
- AcpipObjectReleaseReference(Cst);
- }
- return;
- }
- KSTATUS
- AcpipInitializeCStatesOnProcessor (
- PPM_IDLE_STATE_INTERFACE Interface,
- PPM_IDLE_PROCESSOR_STATE Processor
- )
- /*++
- Routine Description:
- This routine is called on a particular processor to initialize processor
- C-State support.
- Arguments:
- Interface - Supplies a pointer to the interface.
- Processor - Supplies a pointer to the context for this processor.
- Return Value:
- Status code.
- --*/
- {
- PACPI_PROCESSOR_CONTEXT Context;
- Context = &(AcpiProcessor->Processors[Processor->ProcessorNumber]);
- Processor->Context = Context;
- Processor->States = Context->OsCStates;
- Processor->StateCount = Context->CStateCount;
- return STATUS_SUCCESS;
- }
- KSTATUS
- AcpipProcessorGetOsProcessorId (
- ULONG AcpiId,
- PULONG OsId
- )
- /*++
- Routine Description:
- This routine attempts to find and initialize the OS logical processor
- number for the given processor device.
- Arguments:
- AcpiId - Supplies the ACPI processor ID to look up.
- OsId - Supplies a pointer where the OS processor index will be returned on
- success.
- Return Value:
- Status code.
- --*/
- {
- BOOL Active;
- PMADT_GENERIC_ENTRY CurrentEntry;
- BOOL Found;
- PMADT_GIC Gic;
- PMADT_LOCAL_APIC LocalApic;
- PMADT MadtTable;
- ULONG PhysicalId;
- KSTATUS Status;
- MadtTable = AcpiFindTable(MADT_SIGNATURE, NULL);
- if (MadtTable == NULL) {
- return STATUS_NOT_FOUND;
- }
- //
- // Find an MADT entry that matches this processor ID.
- //
- Found = FALSE;
- PhysicalId = -1;
- CurrentEntry = (PMADT_GENERIC_ENTRY)(MadtTable + 1);
- while ((UINTN)CurrentEntry <
- ((UINTN)MadtTable + MadtTable->Header.Length)) {
- if ((CurrentEntry->Type == MadtEntryTypeLocalApic) &&
- (CurrentEntry->Length == sizeof(MADT_LOCAL_APIC))) {
- LocalApic = (PMADT_LOCAL_APIC)CurrentEntry;
- if ((LocalApic->Flags & MADT_LOCAL_APIC_FLAG_ENABLED) != 0) {
- if (LocalApic->AcpiProcessorId == AcpiId) {
- PhysicalId = LocalApic->ApicId;
- Found = TRUE;
- break;
- }
- }
- } else if ((CurrentEntry->Type == MadtEntryTypeGic) &&
- (CurrentEntry->Length == sizeof(MADT_GIC))) {
- Gic = (PMADT_GIC)CurrentEntry;
- if ((Gic->Flags & MADT_LOCAL_GIC_FLAG_ENABLED) != 0) {
- if (Gic->AcpiProcessorId == AcpiId) {
- PhysicalId = Gic->GicId;
- Found = TRUE;
- break;
- }
- }
- }
- CurrentEntry = (PMADT_GENERIC_ENTRY)((PUCHAR)CurrentEntry +
- CurrentEntry->Length);
- }
- if (Found == FALSE) {
- return STATUS_NOT_FOUND;
- }
- Status = HlGetProcessorIndexFromId(PhysicalId, OsId, &Active);
- if (!KSUCCESS(Status)) {
- return Status;
- }
- if (Active == FALSE) {
- return STATUS_NOT_STARTED;
- }
- return STATUS_SUCCESS;
- }
- ULONG
- AcpipGetProcessorCount (
- VOID
- )
- /*++
- Routine Description:
- This routine determines the number of processors in the system.
- Arguments:
- None.
- Return Value:
- Returns the maximum number of processors in the system.
- --*/
- {
- PMADT_GENERIC_ENTRY CurrentEntry;
- PMADT_GIC Gic;
- PMADT_LOCAL_APIC LocalApic;
- PMADT MadtTable;
- ULONG ProcessorCount;
- MadtTable = AcpiFindTable(MADT_SIGNATURE, NULL);
- if (MadtTable == NULL) {
- return 1;
- }
- ProcessorCount = 0;
- CurrentEntry = (PMADT_GENERIC_ENTRY)(MadtTable + 1);
- while ((UINTN)CurrentEntry <
- ((UINTN)MadtTable + MadtTable->Header.Length)) {
- if ((CurrentEntry->Type == MadtEntryTypeLocalApic) &&
- (CurrentEntry->Length == sizeof(MADT_LOCAL_APIC))) {
- LocalApic = (PMADT_LOCAL_APIC)CurrentEntry;
- if ((LocalApic->Flags & MADT_LOCAL_APIC_FLAG_ENABLED) != 0) {
- ProcessorCount += 1;
- }
- } else if ((CurrentEntry->Type == MadtEntryTypeGic) &&
- (CurrentEntry->Length == sizeof(MADT_GIC))) {
- Gic = (PMADT_GIC)CurrentEntry;
- if ((Gic->Flags & MADT_LOCAL_GIC_FLAG_ENABLED) != 0) {
- ProcessorCount += 1;
- }
- }
- CurrentEntry = (PMADT_GENERIC_ENTRY)((PUCHAR)CurrentEntry +
- CurrentEntry->Length);
- }
- return ProcessorCount;
- }
|