1 /** @file
2
3 Processor power management initialization code.
4
5 Copyright (c) 2013-2016 Intel Corporation.
6
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15
16 **/
17
18 #include "SmmPowerManagement.h"
19
20 //
21 // Global variables
22 //
23 extern EFI_ACPI_SDT_PROTOCOL *mAcpiSdt;
24 extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTable;
25
26 extern EFI_GUID gPowerManagementAcpiTableStorageGuid;
27
28 /**
29 This function is the entry of processor power management initialization code.
30 It initializes the processor's power management features based on the user
31 configurations and hardware capabilities.
32 **/
33 VOID
PpmInit(VOID)34 PpmInit (
35 VOID
36 )
37 {
38 //
39 // Processor Power Management Flags
40 //
41 mGlobalNvsAreaPtr->Cfgd = PcdGet32(PcdPpmFlags);
42
43 //
44 // Patch and publish power management related acpi tables
45 //
46 PpmPatchAndPublishAcpiTables();
47 }
48
49 /**
50 This function is to patch and publish power management related acpi tables.
51 **/
52 VOID
PpmPatchAndPublishAcpiTables(VOID)53 PpmPatchAndPublishAcpiTables (
54 VOID
55 )
56 {
57 //
58 // Patch FADT table to enable C2,C3
59 //
60 PpmPatchFadtTable();
61
62 //
63 // Load all the power management acpi tables and patch IST table
64 //
65 PpmLoadAndPatchPMTables();
66 }
67
68 /**
69 This function is to patch PLvl2Lat and PLvl3Lat to enable C2, C3 support in OS.
70 **/
71 VOID
PpmPatchFadtTable(VOID)72 PpmPatchFadtTable (
73 VOID
74 )
75 {
76 EFI_STATUS Status;
77 EFI_ACPI_DESCRIPTION_HEADER *Table;
78 EFI_ACPI_SDT_HEADER *CurrentTable;
79 EFI_ACPI_TABLE_VERSION Version;
80 UINTN Index;
81 UINTN Handle;
82
83 //
84 // Scan all the acpi tables to find FADT 2.0
85 //
86 Index = 0;
87 do {
88 Status = mAcpiSdt->GetAcpiTable (
89 Index,
90 &CurrentTable,
91 &Version,
92 &Handle
93 );
94 if (Status == EFI_NOT_FOUND) {
95 break;
96 }
97 ASSERT_EFI_ERROR (Status);
98 Index++;
99 } while (CurrentTable->Signature != EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE || CurrentTable->Revision != 0x03);
100
101 ASSERT (CurrentTable->Signature == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
102
103 Table = NULL;
104 Status = gBS->AllocatePool (EfiBootServicesData, CurrentTable->Length, (VOID **) &Table);
105 ASSERT (Table != NULL);
106 CopyMem (Table, CurrentTable, CurrentTable->Length);
107
108 //
109 // Update the ACPI table and recalculate checksum
110 //
111 Status = mAcpiTable->UninstallAcpiTable (mAcpiTable, Handle);
112 if (EFI_ERROR (Status)) {
113 //
114 // Should not get an error here ever, but abort if we do.
115 //
116 return ;
117 }
118
119 //
120 // Update the check sum
121 // It needs to be zeroed before the checksum calculation
122 //
123 ((EFI_ACPI_SDT_HEADER *)Table)->Checksum = 0;
124 ((EFI_ACPI_SDT_HEADER *)Table)->Checksum =
125 CalculateCheckSum8 ((VOID *)Table, Table->Length);
126
127 //
128 // Add the table
129 //
130 Status = mAcpiTable->InstallAcpiTable (
131 mAcpiTable,
132 Table,
133 Table->Length,
134 &Handle
135 );
136 ASSERT_EFI_ERROR (Status);
137 gBS->FreePool (Table);
138 }
139
140 VOID
SsdtTableUpdate(IN OUT EFI_ACPI_DESCRIPTION_HEADER * TableHeader)141 SsdtTableUpdate (
142 IN OUT EFI_ACPI_DESCRIPTION_HEADER *TableHeader
143 )
144 /*++
145
146 Routine Description:
147
148 Update the SSDT table
149
150 Arguments:
151
152 Table - The SSDT table to be patched
153
154 Returns:
155
156 None
157
158 --*/
159 {
160 UINT8 *CurrPtr;
161 UINT8 *SsdtPointer;
162 UINT32 *Signature;
163
164 //
165 // Loop through the ASL looking for values that we must fix up.
166 //
167 CurrPtr = (UINT8 *) TableHeader;
168 for (SsdtPointer = CurrPtr;
169 SsdtPointer <= (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length);
170 SsdtPointer++
171 )
172 {
173 Signature = (UINT32 *) SsdtPointer;
174 if ((*Signature) == SIGNATURE_32 ('P', 'M', 'B', 'A')) {
175 switch (*(Signature+1)) {
176 case (SIGNATURE_32 ('L', 'V', 'L', '0')):
177 Signature[0] = PcdGet16(PcdPmbaIoBaseAddress);
178 Signature[1] = 0;
179 break;
180 case (SIGNATURE_32 ('L', 'V', 'L', '2')):
181 Signature[0] = PcdGet16(PcdPmbaIoLVL2);
182 Signature[1] = 0;
183 break;
184 }
185 }
186 }
187 }
188
189 EFI_STATUS
LocateSupportProtocol(IN EFI_GUID * Protocol,OUT VOID ** Instance,IN UINT32 Type)190 LocateSupportProtocol (
191 IN EFI_GUID *Protocol,
192 OUT VOID **Instance,
193 IN UINT32 Type
194 )
195 /*++
196
197 Routine Description:
198
199 Locate the first instance of a protocol. If the protocol requested is an
200 FV protocol, then it will return the first FV that contains the ACPI table
201 storage file.
202
203 Arguments:
204
205 Protocol The protocol to find.
206 Instance Return pointer to the first instance of the protocol
207
208 Returns:
209
210 EFI_SUCCESS The function completed successfully.
211 EFI_NOT_FOUND The protocol could not be located.
212 EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol.
213
214 --*/
215 {
216 EFI_STATUS Status;
217 EFI_HANDLE *HandleBuffer;
218 UINTN NumberOfHandles;
219 EFI_FV_FILETYPE FileType;
220 UINT32 FvStatus;
221 EFI_FV_FILE_ATTRIBUTES Attributes;
222 UINTN Size;
223 UINTN i;
224
225 FvStatus = 0;
226
227 //
228 // Locate protocol.
229 //
230 Status = gBS->LocateHandleBuffer (
231 ByProtocol,
232 Protocol,
233 NULL,
234 &NumberOfHandles,
235 &HandleBuffer
236 );
237 if (EFI_ERROR (Status)) {
238
239 //
240 // Defined errors at this time are not found and out of resources.
241 //
242 return Status;
243 }
244
245
246
247 //
248 // Looking for FV with ACPI storage file
249 //
250
251 for (i = 0; i < NumberOfHandles; i++) {
252 //
253 // Get the protocol on this handle
254 // This should not fail because of LocateHandleBuffer
255 //
256 Status = gBS->HandleProtocol (
257 HandleBuffer[i],
258 Protocol,
259 Instance
260 );
261 ASSERT_EFI_ERROR (Status);
262
263 if (!Type) {
264 //
265 // Not looking for the FV protocol, so find the first instance of the
266 // protocol. There should not be any errors because our handle buffer
267 // should always contain at least one or LocateHandleBuffer would have
268 // returned not found.
269 //
270 break;
271 }
272
273 //
274 // See if it has the ACPI storage file
275 //
276
277 Status = ((EFI_FIRMWARE_VOLUME2_PROTOCOL*) (*Instance))->ReadFile (*Instance,
278 &gPowerManagementAcpiTableStorageGuid,
279 NULL,
280 &Size,
281 &FileType,
282 &Attributes,
283 &FvStatus
284 );
285
286 //
287 // If we found it, then we are done
288 //
289 if (Status == EFI_SUCCESS) {
290 break;
291 }
292 }
293
294 //
295 // Our exit status is determined by the success of the previous operations
296 // If the protocol was found, Instance already points to it.
297 //
298
299 //
300 // Free any allocated buffers
301 //
302 gBS->FreePool (HandleBuffer);
303
304 return Status;
305 }
306
307 /**
308 This function is to load all the power management acpi tables and patch IST table.
309 **/
310 VOID
PpmLoadAndPatchPMTables(VOID)311 PpmLoadAndPatchPMTables (
312 VOID
313 )
314 {
315 EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
316 EFI_STATUS Status;
317 INTN Instance;
318 EFI_ACPI_COMMON_HEADER *CurrentTable;
319 UINTN TableHandle;
320 UINT32 FvStatus;
321 UINTN Size;
322
323 Status = LocateSupportProtocol (&gEfiFirmwareVolume2ProtocolGuid, (VOID**)&FwVol, 1);
324 if (EFI_ERROR (Status)) {
325 return;
326 }
327
328 //
329 // Read tables from the storage file.
330 //
331 Instance = 0;
332 CurrentTable = NULL;
333
334 while (Status == EFI_SUCCESS) {
335
336 Status = FwVol->ReadSection (
337 FwVol,
338 &gPowerManagementAcpiTableStorageGuid,
339 EFI_SECTION_RAW,
340 Instance,
341 (VOID**)&CurrentTable,
342 &Size,
343 &FvStatus
344 );
345
346 if (!EFI_ERROR(Status)) {
347 SsdtTableUpdate ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable);
348
349 //
350 // Update the check sum
351 // It needs to be zeroed before the checksum calculation
352 //
353 ((EFI_ACPI_SDT_HEADER *)CurrentTable)->Checksum = 0;
354 ((EFI_ACPI_SDT_HEADER *)CurrentTable)->Checksum = (UINT8)
355 CalculateCheckSum8 ((VOID *)CurrentTable, CurrentTable->Length);
356
357 //
358 // Add the table
359 //
360 TableHandle = 0;
361 Status = mAcpiTable->InstallAcpiTable (
362 mAcpiTable,
363 CurrentTable,
364 CurrentTable->Length,
365 &TableHandle
366 );
367
368 ASSERT_EFI_ERROR (Status);
369
370 //
371 // Increment the instance
372 //
373 Instance++;
374 CurrentTable = NULL;
375 }
376 }
377
378 }
379