summaryrefslogtreecommitdiffstats
path: root/UefiCpuPkg/Library/CpuCommonFeaturesLib/ClockModulation.c
blob: 94d596605bf72c9c8df72f389b8c28edf822b06a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/** @file
  Clock Modulation feature.

  Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "CpuCommonFeatures.h"

typedef struct  {
  CPUID_THERMAL_POWER_MANAGEMENT_EAX  ThermalPowerManagementEax;
  MSR_IA32_CLOCK_MODULATION_REGISTER  ClockModulation;
} CLOCK_MODULATION_CONFIG_DATA;

/**
  Prepares for the data used by CPU feature detection and initialization.

  @param[in]  NumberOfProcessors  The number of CPUs in the platform.

  @return  Pointer to a buffer of CPU related configuration data.

  @note This service could be called by BSP only.
**/
VOID *
EFIAPI
ClockModulationGetConfigData (
  IN UINTN  NumberOfProcessors
  )
{
  UINT32    *ConfigData;

  ConfigData = AllocateZeroPool (sizeof (CLOCK_MODULATION_CONFIG_DATA) * NumberOfProcessors);
  ASSERT (ConfigData != NULL);
  return ConfigData;
}

/**
  Detects if Clock Modulation feature supported on current processor.

  @param[in]  ProcessorNumber  The index of the CPU executing this function.
  @param[in]  CpuInfo          A pointer to the REGISTER_CPU_FEATURE_INFORMATION
                               structure for the CPU executing this function.
  @param[in]  ConfigData       A pointer to the configuration buffer returned
                               by CPU_FEATURE_GET_CONFIG_DATA.  NULL if
                               CPU_FEATURE_GET_CONFIG_DATA was not provided in
                               RegisterCpuFeature().

  @retval TRUE     Clock Modulation feature is supported.
  @retval FALSE    Clock Modulation feature is not supported.

  @note This service could be called by BSP/APs.
**/
BOOLEAN
EFIAPI
ClockModulationSupport (
  IN UINTN                             ProcessorNumber,
  IN REGISTER_CPU_FEATURE_INFORMATION  *CpuInfo,
  IN VOID                              *ConfigData  OPTIONAL
  )
{
  CLOCK_MODULATION_CONFIG_DATA         *CmConfigData;

  if (CpuInfo->CpuIdVersionInfoEdx.Bits.ACPI == 1) {
    CmConfigData = (CLOCK_MODULATION_CONFIG_DATA *) ConfigData;
    ASSERT (CmConfigData != NULL);
    AsmCpuid (
      CPUID_THERMAL_POWER_MANAGEMENT,
      &CmConfigData[ProcessorNumber].ThermalPowerManagementEax.Uint32,
      NULL,
      NULL,
      NULL
      );
    CmConfigData[ProcessorNumber].ClockModulation.Uint64 = AsmReadMsr64 (MSR_IA32_CLOCK_MODULATION);
    return TRUE;
  }
  return FALSE;
}

/**
  Initializes Clock Modulation feature to specific state.

  @param[in]  ProcessorNumber  The index of the CPU executing this function.
  @param[in]  CpuInfo          A pointer to the REGISTER_CPU_FEATURE_INFORMATION
                               structure for the CPU executing this function.
  @param[in]  ConfigData       A pointer to the configuration buffer returned
                               by CPU_FEATURE_GET_CONFIG_DATA.  NULL if
                               CPU_FEATURE_GET_CONFIG_DATA was not provided in
                               RegisterCpuFeature().
  @param[in]  State            If TRUE, then the Clock Modulation feature must be enabled.
                               If FALSE, then the Clock Modulation feature must be disabled.

  @retval RETURN_SUCCESS       Clock Modulation feature is initialized.

  @note This service could be called by BSP only.
**/
RETURN_STATUS
EFIAPI
ClockModulationInitialize (
  IN UINTN                             ProcessorNumber,
  IN REGISTER_CPU_FEATURE_INFORMATION  *CpuInfo,
  IN VOID                              *ConfigData   OPTIONAL,
  IN BOOLEAN                           State
  )
{
  CLOCK_MODULATION_CONFIG_DATA         *CmConfigData;
  MSR_IA32_CLOCK_MODULATION_REGISTER   *ClockModulation;

  CmConfigData = (CLOCK_MODULATION_CONFIG_DATA *) ConfigData;
  ASSERT (CmConfigData != NULL);
  ClockModulation = &CmConfigData[ProcessorNumber].ClockModulation;

  if (State) {
    ClockModulation->Bits.OnDemandClockModulationEnable = 1;
    ClockModulation->Bits.OnDemandClockModulationDutyCycle = PcdGet8 (PcdCpuClockModulationDutyCycle) >> 1;
    if (CmConfigData[ProcessorNumber].ThermalPowerManagementEax.Bits.ECMD == 1) {
      ClockModulation->Bits.ExtendedOnDemandClockModulationDutyCycle = PcdGet8 (PcdCpuClockModulationDutyCycle) & BIT0;
    }
  } else {
    ClockModulation->Bits.OnDemandClockModulationEnable = 0;
  }

  CPU_REGISTER_TABLE_WRITE64 (
    ProcessorNumber,
    Msr,
    MSR_IA32_CLOCK_MODULATION,
    ClockModulation->Uint64
    );

  return RETURN_SUCCESS;
}