summaryrefslogtreecommitdiff
path: root/ReferenceCode/Haswell/PowerManagement/Smm/PowerMgmtS3.c
blob: 6a262311a9c037c4e56f073e35e6f19efc0ca3f1 (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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/** @file
  This is the SMM driver for saving and restoring the powermanagement related MSRs

@copyright
  Copyright (c) 2011 - 2013 Intel Corporation. All rights reserved
  This software and associated documentation (if any) is furnished
  under a license and may only be used or copied in accordance
  with the terms of the license. Except as permitted by such
  license, no part of this software or documentation may be
  reproduced, stored in a retrieval system, or transmitted in any
  form or by any means without the express written consent of
  Intel Corporation.

  This file contains an 'Intel Peripheral Driver' and uniquely
  identified as "Intel Reference Module" and is
  licensed for Intel CPUs and chipsets under the terms of your
  license agreement with Intel or your vendor.  This file may
  be modified by the user, subject to additional terms of the
  license agreement

**/
#include "PowerMgmtS3.h"
#include "PowerMgmtDefinitions.h"
#include "CpuAccess.h"
#include "CpuPlatformLib.h"

#include EFI_PROTOCOL_DEPENDENCY (CpuPlatformPolicy)
#include EFI_PROTOCOL_DEPENDENCY (SmmSwDispatch)
#include EFI_PROTOCOL_DEPENDENCY (SmmBase)

///
/// SMM system table pointer
///
EFI_SMM_SYSTEM_TABLE             *mSmst;
DXE_CPU_PLATFORM_POLICY_PROTOCOL *mCpuPlatformPolicy;
///
/// MSR table for S3 resume
///
STATIC EFI_MSR_VALUES mMsrValues[] = {
  { MSR_IA32_PERF_CTRL,                 0, B_IA32_PERF_CTRLP_STATE_TARGET, TRUE },
  { MSR_PMG_IO_CAPTURE_BASE,            0, 0xFFFFFFFFFFFFFFFF, TRUE },
  { MSR_PMG_CST_CONFIG,                 0, 0xFFFFFFFFFFFFFFFF, TRUE },
  { MSR_MISC_PWR_MGMT,                  0, 0xFFFFFFFFFFFFFFFF, TRUE },
  { MSR_IA32_MISC_ENABLE,               0, B_CPUID_POWER_MANAGEMENT_EAX_TURBO | B_MSR_IA32_MISC_DISABLE_TURBO | B_MSR_IA32_MISC_ENABLE_MONITOR | B_MSR_IA32_MISC_ENABLE_TME | B_MSR_IA32_MISC_ENABLE_EIST, TRUE },
  { MSR_POWER_CTL,                      0, 0xFFFFFFFFFFFFFFFF, TRUE },
  { MSR_PACKAGE_POWER_LIMIT,            0, 0xFFFFFFFFFFFFFFFF, TRUE },
  { MSR_PLATFORM_POWER_LIMIT,           0, 0xFFFFFFFFFFFFFFFF, FALSE },
  { MSR_C_STATE_LATENCY_CONTROL_0,      0, 0xFFFFFFFFFFFFFFFF, TRUE },
  { MSR_C_STATE_LATENCY_CONTROL_1,      0, 0xFFFFFFFFFFFFFFFF, TRUE },
  { MSR_C_STATE_LATENCY_CONTROL_2,      0, 0xFFFFFFFFFFFFFFFF, TRUE },
  { MSR_C_STATE_LATENCY_CONTROL_3,      0, 0xFFFFFFFFFFFFFFFF, FALSE },
  { MSR_C_STATE_LATENCY_CONTROL_4,      0, 0xFFFFFFFFFFFFFFFF, FALSE },
  { MSR_C_STATE_LATENCY_CONTROL_5,      0, 0xFFFFFFFFFFFFFFFF, FALSE },
  { MSR_FLEX_RATIO,                     0, 0xFFFFFFFFFFFFFFFF, TRUE },
  { MSR_IA32_ENERGY_PERFORMANCE_BIAS,   0, 0xFFFFFFFFFFFFFFFF, TRUE },
  { MSR_CONFIG_TDP_CONTROL,             0, 0xFFFFFFFFFFFFFFFF, FALSE },
  { MSR_RFI_TUNNING,                    0, 0xFFFFFFFFFFFFFFFF, FALSE },
  { MSR_TURBO_ACTIVATION_RATIO,         0, 0xFFFFFFFFFFFFFFFF, FALSE },
  { MSR_DDR_RAPL_LIMIT,                 0, 0xFFFFFFFFFFFFFFFF, FALSE },
  { MSR_TURBO_RATIO_LIMIT,              0, 0xFFFFFFFFFFFFFFFF, TRUE }
};

/**
  Save processor MSR runtime settings for S3.

  @retval EFI_SUCCESS   Processor MSR setting is saved.
**/
STATIC
EFI_STATUS
S3SaveMsr (
  VOID
  )
{
  UINT32             Index;
  EFI_CPUID_REGISTER Cpuid06 = { 0, 0, 0, 0 };
  UINT64             MsrValue;

  for (Index = 0; Index < sizeof (mMsrValues) / sizeof (EFI_MSR_VALUES); Index++) {
    DEBUG ((EFI_D_INFO, " MSR Number: %x\n", mMsrValues[Index].Index));
    if (mMsrValues[Index].Index == MSR_IA32_ENERGY_PERFORMANCE_BIAS) {
      ///
      /// MSR_IA32_ENERGY_PERFORMANCE_BIAS (1B0h) is accessible only if CPUID(6), ECX[3] = 1 to indicate feature availability.
      ///
      AsmCpuid (CPUID_FUNCTION_6, &Cpuid06.RegEax, &Cpuid06.RegEbx, &Cpuid06.RegEcx, &Cpuid06.RegEdx);
      if (!(Cpuid06.RegEcx & B_CPUID_POWER_MANAGEMENT_ECX_ENERGY_EFFICIENT_POLICY_SUPPORT)) {
        mMsrValues[Index].RestoreFlag = FALSE;
        continue;
      }
    }
    ///
    /// Check for HSW specific MSRs
    ///
    MsrValue = AsmReadMsr64 (MSR_PLATFORM_INFO);
    ///
    ///
    /// Check PLATFORM_INFO MSR[34:33] > 0 before accessing the MSR_CONFIG_TDP_CONTROL
    ///
    if ((mMsrValues[Index].Index == MSR_CONFIG_TDP_CONTROL) &&
        ((RShiftU64 (MsrValue, N_MSR_PLATFORM_INFO_CONFIG_TDP_NUM_LEVELS_OFFSET) & 0x03))
        ) {
      mMsrValues[Index].RestoreFlag = TRUE;
    }
    ///
    /// MSR_TURBO_ACTIVATION_RATIO, MSR_DDR_RAPL_LIMIT, MSR_RFI_TUNNING are supported only on HSW A0 or above.
    ///
    if (mMsrValues[Index].Index == MSR_TURBO_ACTIVATION_RATIO) {
      mMsrValues[Index].RestoreFlag = TRUE;
    }
    if (mMsrValues[Index].Index == MSR_DDR_RAPL_LIMIT) {
      mMsrValues[Index].RestoreFlag = TRUE;
    }
    ///
    /// Check PLATFORM_INFO MSR[25] == 1 before accessing the MSR_RFI_TUNNING
    ///
    if (mMsrValues[Index].Index == MSR_RFI_TUNNING) {
      if ((mCpuPlatformPolicy->PowerMgmtConfig->RfiFreqTunningOffset != AUTO) && (MsrValue & B_FIVR_RFI_TUNING_AVAIL)) {
        mMsrValues[Index].RestoreFlag = TRUE;
      }
    }

    if(GetCpuSku()== EnumCpuUlt) {
      if ((mMsrValues[Index].Index == MSR_C_STATE_LATENCY_CONTROL_3) ||
          (mMsrValues[Index].Index == MSR_C_STATE_LATENCY_CONTROL_4)||
          (mMsrValues[Index].Index == MSR_C_STATE_LATENCY_CONTROL_5)){
        mMsrValues[Index].RestoreFlag = TRUE;
      }
    }

    ///
    /// PL3 is supported on HSW ULT C0 & HSW  C0 and later 
    ///
    if (mMsrValues[Index].Index == MSR_PLATFORM_POWER_LIMIT) {
      if (((GetCpuFamily() == EnumCpuHsw) && (GetCpuStepping() >= EnumHswC0))
         || ((GetCpuFamily() == EnumCpuHswUlt) && (GetCpuStepping() >= EnumHswUltC0))) {
        mMsrValues[Index].RestoreFlag = TRUE;
      }
    }

    if (mMsrValues[Index].RestoreFlag == TRUE) {
      mMsrValues[Index].Value = AsmReadMsr64 (mMsrValues[Index].Index);
      DEBUG ((EFI_D_INFO, " MSR Number %x read Done \n", mMsrValues[Index].Index));
    }
  }

  return EFI_SUCCESS;
}

/**
  Restore processor MSR runtime settings for S3.

  @param[in] DispatchHandle  - The handle of this callback, obtained when registering
  @param[in] DispatchContex  - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT

  @retval EFI_SUCCESS   Processor MSR setting is restored.
**/
void
S3RestoreMsr (
  IN EFI_HANDLE                  DispatchHandle,
  IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContex
  )
{
  ///
  /// Restore MSR's on all logical processors.
  ///
  RunOnAllLogicalProcessors (ApSafeRestoreMsr, NULL);
}

/**
  Runs the specified procedure on all logical processors, passing in the
  parameter buffer to the procedure.

  @param[in] Procedure     The function to be run.
  @param[in] Buffer        Pointer to a parameter buffer.

  @retval EFI_SUCCESS
**/
STATIC
EFI_STATUS
RunOnAllLogicalProcessors (
  IN OUT EFI_AP_PROCEDURE Procedure,
  IN OUT VOID             *Buffer
  )
{
  UINTN      Index;
  EFI_STATUS Status;
  ///
  /// Run the procedure on all logical processors.
  ///
  (*Procedure)(Buffer);
  for (Index = 1; Index < mSmst->NumberOfCpus; Index++) {
    Status = EFI_NOT_READY;
    while (Status != EFI_SUCCESS) {
      Status = mSmst->SmmStartupThisAp (Procedure, Index, Buffer);
      if (Status != EFI_SUCCESS) {
        ///
        /// SmmStartupThisAp might return failure if AP is busy executing some other code. Let's wait for sometime and try again.
        ///
        PchPmTimerStall (PPM_WAIT_PERIOD);
      }
    }
  }

  return EFI_SUCCESS;
}

/**
  This function will restore MSR settings.

  This function must be MP safe.

  @param[in] Buffer        Unused

  @retval EFI_SUCCESS   MSR restored
**/
VOID
EFIAPI
ApSafeRestoreMsr (
  IN OUT VOID *Buffer
  )
{
  UINT32 Index;
  UINT64 MsrValue;

  for (Index = 0; Index < sizeof (mMsrValues) / sizeof (EFI_MSR_VALUES); Index++) {
    ///
    /// Check RestoreFlag and skip restoring the MSR if it is set to FALSE
    ///
    if (mMsrValues[Index].RestoreFlag == FALSE) {
      DEBUG ((EFI_D_INFO, "Skipping MSR : %x as RestoreFalg is set to FALSE \n", mMsrValues[Index].Index));
      continue;
    }
    ///
    /// Check for Lock bits before programming
    ///
    MsrValue = AsmReadMsr64 (mMsrValues[Index].Index);
    if ((mMsrValues[Index].Index == MSR_CONFIG_TDP_CONTROL) && (MsrValue & CONFIG_TDP_CONTROL_LOCK)) {
      continue;
    }

    if ((mMsrValues[Index].Index == MSR_TURBO_ACTIVATION_RATIO) && (MsrValue & MSR_TURBO_ACTIVATION_RATIO_LOCK)) {
      continue;
    }

    if ((mMsrValues[Index].Index == MSR_PACKAGE_POWER_LIMIT) && (MsrValue & B_POWER_LIMIT_LOCK)) {
      continue;
    }

    if ((mMsrValues[Index].Index == MSR_PLATFORM_POWER_LIMIT) && (MsrValue & B_POWER_LIMIT_LOCK)) {
      continue;
    }

    if ((mMsrValues[Index].Index == MSR_DDR_RAPL_LIMIT) && (MsrValue & B_POWER_LIMIT_LOCK)) {
      continue;
    }

    MsrValue = AsmReadMsr64 (mMsrValues[Index].Index);
    MsrValue &= ~mMsrValues[Index].BitMask;
    MsrValue |= (mMsrValues[Index].Value & mMsrValues[Index].BitMask);
    AsmWriteMsr64 (mMsrValues[Index].Index, MsrValue);
  }

  return;
}

/**
  Initialize the S3 power management Handler.

  @param[in] ImageHandle   - Pointer to the loaded image protocol for this driver
  @param[in] SystemTable   - Pointer to the EFI System Table

  @retval EFI_SUCCESS   The driver installes/initialized correctly.
**/
EFI_STATUS
PowerMgmtS3SmmEntryPoint (
  IN EFI_HANDLE       ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
{

  EFI_STATUS                   Status;
  EFI_SMM_SW_DISPATCH_CONTEXT  SwContext;
  EFI_SMM_SW_DISPATCH_PROTOCOL *SwDispatch;
  EFI_HANDLE                   SwHandle;
  EFI_SMM_BASE_PROTOCOL        *SmmBase;

  SwHandle = 0;
  DEBUG ((EFI_D_INFO, " PpmS3SmmEntryPoint Started : \n"));
  ///
  /// Determine if we are in boot service or SMM.
  ///
  Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, (VOID **) &SmmBase);
  ASSERT_EFI_ERROR (Status);

  ///
  /// Initialize global variables
  ///
  Status = SmmBase->GetSmstLocation (SmmBase, &mSmst);
  ASSERT_EFI_ERROR (Status);

  ///
  /// Locate platform configuration information
  ///
  Status = gBS->LocateProtocol (&gDxeCpuPlatformPolicyProtocolGuid, NULL, (VOID **) &mCpuPlatformPolicy);
  ASSERT_EFI_ERROR (Status);

  ///
  /// Locate the ICH SMM SW dispatch protocol
  ///
  Status = gBS->LocateProtocol (&gEfiSmmSwDispatchProtocolGuid, NULL, (VOID **) &SwDispatch);
  ASSERT_EFI_ERROR (Status);

  ///
  /// Register ACPI S3 MSR restore handler
  ///
  SwContext.SwSmiInputValue = mCpuPlatformPolicy->PowerMgmtConfig->S3RestoreMsrSwSmiNumber;

  Status = SwDispatch->Register (
                  SwDispatch,
                  (EFI_SMM_SW_DISPATCH) S3RestoreMsr,
                  &SwContext,
                  &SwHandle
                  );
  ASSERT_EFI_ERROR (Status);

  ///
  ///  Save MSRs for S3 Resume.
  ///
  DEBUG ((EFI_D_INFO, " Saving Processor MSR for S3 Resume \n"));

  S3SaveMsr ();

  return EFI_SUCCESS;
}