/*++ Copyright(c) 1998 Microsoft Corporation Module Name: shared.c Abstract: routines shared outside of library Author: Todd Carpenter Environment: kernel mode Revision History: 03-28-01 : created, toddcar --*/ #include "processor.h" NTSTATUS ValidatePssLatencyValues ( IN PFDO_DATA DeviceExtension ) /*++ Routine Description: Arguments: Return Value: --*/ { NTSTATUS status = STATUS_SUCCESS; ULONG savedState = INVALID_PERF_STATE; ULONG targetState; ULONG x; ULONG latency; LARGE_INTEGER start; LARGE_INTEGER end; LARGE_INTEGER freq; DebugEnter(); DebugAssert(DeviceExtension); // // Save current state, go to highest perfstate available // if (DeviceExtension->CurrentPerfState != INVALID_PERF_STATE) { savedState = DeviceExtension->CurrentPerfState; } if (DeviceExtension->CurrentPerfState) { Acpi2PerfStateTransition(DeviceExtension, DeviceExtension->PpcResult); } // // Get Perf Counter Frequency // KeQueryPerformanceCounter(&freq); // // Walk though all available states, calulate transition latency // for (x = 0; x < DeviceExtension->PssPackage->NumPStates; x++) { targetState = DeviceExtension->PssPackage->NumPStates - x - 1; latency = 0; // // We should already be at PerfState == PpcResult, // and we can't go to a higher state // if (targetState < DeviceExtension->PpcResult) { continue; } start = KeQueryPerformanceCounter(NULL); status = Acpi2PerfStateTransition(DeviceExtension, targetState); end = KeQueryPerformanceCounter(NULL); // // Calculate transition latency. // if (NT_SUCCESS(status)) { latency = (ULONG)((end.QuadPart - start.QuadPart) * 1000000 / freq.QuadPart); } // // Record new latency value in unused BmLatency field // DeviceExtension->PssPackage->State[targetState].Latency = latency; } // // Restore saved Perf State // if (savedState != DeviceExtension->CurrentPerfState && savedState != INVALID_PERF_STATE) { Acpi2PerfStateTransition(DeviceExtension, savedState); } return status; } ULONG ReadGenAddr( IN PGEN_ADDR GenAddr ) { ULONG bitWidth; ULONG mask = 0; ULONG result = 0; DebugAssert(GenAddr); DebugAssert(GenAddr->BitWidth); DebugAssert(GenAddr->BitWidth <= 32); // // Figure out how wide our target register is. // bitWidth = GenAddr->BitWidth + GenAddr->BitOffset; if (bitWidth <= 8) { bitWidth = 8; } else if (bitWidth <= 16) { bitWidth = 16; } else { bitWidth = 32; } switch (GenAddr->AddressSpaceID) { case AcpiGenericSpaceIO: DebugAssert(!(GenAddr->Address.LowPart & 0Xffff0000)); DebugAssert(GenAddr->Address.HighPart == 0); switch (bitWidth) { case 8: result = READ_PORT_UCHAR((PUCHAR)(UINT_PTR)GenAddr->Address.LowPart); break; case 16: result = READ_PORT_USHORT((PUSHORT)(UINT_PTR)GenAddr->Address.LowPart); break; case 32: result = READ_PORT_ULONG((PULONG)(UINT_PTR)GenAddr->Address.LowPart); break; default: return 0; } break; case AcpiGenericSpaceMemory: // // This code path depends on the fact that the addresses // in these structures have already been converted to // virtual addresses. // switch (bitWidth) { case 8: result = READ_REGISTER_UCHAR((PUCHAR)GenAddr->Address.QuadPart); break; case 16: result = READ_REGISTER_USHORT((PUSHORT)GenAddr->Address.QuadPart); break; case 32: result = READ_REGISTER_ULONG((PULONG)GenAddr->Address.QuadPart); break; default: return 0; } break; default: return 0; } // // If the register is not actually byte-aligned, correct for that. // if (result && (bitWidth != GenAddr->BitWidth)) { result >>= GenAddr->BitOffset; result &= ((0x1ul << GenAddr->BitWidth) - 1); } return result; } VOID WriteGenAddr( IN PGEN_ADDR GenAddr, IN ULONG Value ) { ULONG bitWidth; ULONG data = 0; ULONG mask = 0; DebugAssert(GenAddr); DebugAssert(GenAddr->BitWidth); DebugAssert(GenAddr->BitWidth <= 32); // // Figure out how wide our target register is. // bitWidth = GenAddr->BitWidth + GenAddr->BitOffset; if (bitWidth <= 8) { bitWidth = 8; } else if (bitWidth <= 16) { bitWidth = 16; } else { bitWidth = 32; } switch (GenAddr->AddressSpaceID) { case AcpiGenericSpaceIO: DebugAssert(!(GenAddr->Address.LowPart & 0Xffff0000)); DebugAssert(GenAddr->Address.HighPart == 0); switch(bitWidth) { case 8: DebugAssert(!(Value & 0xffffff00)); if ((GenAddr->BitOffset != 0) || (GenAddr->BitWidth != bitWidth)) { data = READ_PORT_UCHAR((PUCHAR)(UINT_PTR)GenAddr->Address.LowPart); mask = (UCHAR)~0 >> (8 - GenAddr->BitWidth); mask = (UCHAR)~(mask << GenAddr->BitOffset); data &= mask; data |= (UCHAR)Value << GenAddr->BitOffset; } else { data = Value; } WRITE_PORT_UCHAR((PUCHAR)(UINT_PTR)GenAddr->Address.LowPart, (UCHAR)data); break; case 16: DebugAssert(!(Value & 0xffff0000)); if ((GenAddr->BitOffset != 0) || (GenAddr->BitWidth != bitWidth)) { data = READ_PORT_USHORT((PUSHORT)(UINT_PTR)GenAddr->Address.LowPart); mask = (USHORT)~0 >> (16 - GenAddr->BitWidth); mask = (USHORT)~(mask << GenAddr->BitOffset); data &= mask; data |= (USHORT)Value << GenAddr->BitOffset; } else { data = Value; } WRITE_PORT_USHORT((PUSHORT)(UINT_PTR)GenAddr->Address.LowPart, (USHORT)data); break; case 32: if ((GenAddr->BitOffset != 0) || (GenAddr->BitWidth != bitWidth)) { data = READ_PORT_ULONG((PULONG)(UINT_PTR)GenAddr->Address.LowPart); mask = (ULONG)~0 >> (32 - GenAddr->BitWidth); mask = ~(mask << GenAddr->BitOffset); data &= mask; data |= Value << GenAddr->BitOffset; } else { data = Value; } WRITE_PORT_ULONG((PULONG)(UINT_PTR)GenAddr->Address.LowPart, data); break; default: return; } break; case AcpiGenericSpaceMemory: // // This code path depends on the fact that the addresses in these structures // have already been converted to virtual addresses. // switch (bitWidth) { case 8: DebugAssert(!(Value & 0xffffff00)); if ((GenAddr->BitOffset != 0) || (GenAddr->BitWidth != bitWidth)) { data = READ_REGISTER_UCHAR((PUCHAR)GenAddr->Address.QuadPart); mask = (UCHAR)~0 >> (8 - GenAddr->BitWidth); mask = (UCHAR)~(mask << GenAddr->BitOffset); data &= mask; data |= (UCHAR)Value << GenAddr->BitOffset; } else { data = Value; } WRITE_REGISTER_UCHAR((PUCHAR)GenAddr->Address.QuadPart, (UCHAR)data); break; case 16: DebugAssert(!(Value & 0xffff0000)); if ((GenAddr->BitOffset != 0) || (GenAddr->BitWidth != bitWidth)) { data = READ_REGISTER_USHORT((PUSHORT)GenAddr->Address.QuadPart); mask = (USHORT)~0 >> (16 - GenAddr->BitWidth); mask = (USHORT)~(mask << GenAddr->BitOffset); data &= mask; data |= (USHORT)Value << GenAddr->BitOffset; } else { data = Value; } WRITE_REGISTER_USHORT((PUSHORT)GenAddr->Address.QuadPart, (USHORT)data); break; case 32: if ((GenAddr->BitOffset != 0) || (GenAddr->BitWidth != bitWidth)) { data = READ_REGISTER_ULONG((PULONG)GenAddr->Address.QuadPart); mask = (ULONG)~0 >> (32 - GenAddr->BitWidth); mask = ~(mask << GenAddr->BitOffset); data &= mask; data |= Value << GenAddr->BitOffset; } else { data = Value; } WRITE_REGISTER_ULONG((PULONG)GenAddr->Address.QuadPart, data); break; default: return; } break; default: return; } } // // Misc Debug Routines // #if DBG VOID DumpPSS( IN PACPI_PSS_PACKAGE PStates ) { ULONG x; PACPI_PSS_DESCRIPTOR pState; DebugAssert(PStates); DebugPrint((TRACE, "\n")); DebugPrint((TRACE, "_PSS:\n")); for (x = 0; x < PStates->NumPStates; x++) { pState = &PStates->State[x]; DebugPrint((TRACE, "State: #%u\n", x)); DebugPrint((TRACE, " Core Frequency %u mhz\n",pState->CoreFrequency)); DebugPrint((TRACE, " Power %u mW\n", pState->Power)); DebugPrint((TRACE, " Transition Latency %u us\n", pState->Latency)); DebugPrint((TRACE, " Bus Master Latency %u us\n", pState->BmLatency)); DebugPrint((TRACE, " Control value 0x%x\n", pState->Control)); DebugPrint((TRACE, " Status value 0x%x\n", pState->Status)); DebugPrint((TRACE, "\n")); } } #endif