1 /** @file
2 
3 Processor power management initialization code.
4 
5 Copyright (c) 2013-2015 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   EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE  *FadtPointer;
83 
84   //
85   // Scan all the acpi tables to find FADT 2.0
86   //
87   Index = 0;
88   do {
89     Status = mAcpiSdt->GetAcpiTable (
90                        Index,
91                        &CurrentTable,
92                        &Version,
93                        &Handle
94                        );
95     if (Status == EFI_NOT_FOUND) {
96       break;
97     }
98     ASSERT_EFI_ERROR (Status);
99     Index++;
100   } while (CurrentTable->Signature != EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE || CurrentTable->Revision != 0x03);
101 
102   ASSERT (CurrentTable->Signature == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
103 
104   Table  = NULL;
105   Status = gBS->AllocatePool (EfiBootServicesData, CurrentTable->Length, (VOID **) &Table);
106   ASSERT (Table != NULL);
107   CopyMem (Table, CurrentTable, CurrentTable->Length);
108 
109   FadtPointer = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE*) Table;
110 
111     //
112   // Update the ACPI table and recalculate checksum
113   //
114   Status = mAcpiTable->UninstallAcpiTable (mAcpiTable, Handle);
115   if (EFI_ERROR (Status)) {
116      //
117      // Should not get an error here ever, but abort if we do.
118      //
119      return ;
120   }
121 
122   //
123   // Update the check sum
124   // It needs to be zeroed before the checksum calculation
125   //
126   ((EFI_ACPI_SDT_HEADER *)Table)->Checksum = 0;
127   ((EFI_ACPI_SDT_HEADER *)Table)->Checksum =
128     CalculateCheckSum8 ((VOID *)Table, Table->Length);
129 
130   //
131   // Add the table
132   //
133   Status = mAcpiTable->InstallAcpiTable (
134                             mAcpiTable,
135                             Table,
136                             Table->Length,
137                             &Handle
138                             );
139   ASSERT_EFI_ERROR (Status);
140   gBS->FreePool (Table);
141 }
142 
143 VOID
SsdtTableUpdate(IN OUT EFI_ACPI_DESCRIPTION_HEADER * TableHeader)144 SsdtTableUpdate (
145   IN OUT   EFI_ACPI_DESCRIPTION_HEADER  *TableHeader
146   )
147 /*++
148 
149   Routine Description:
150 
151     Update the SSDT table
152 
153   Arguments:
154 
155     Table   - The SSDT table to be patched
156 
157   Returns:
158 
159     None
160 
161 --*/
162 {
163   UINT8      *CurrPtr;
164   UINT8      *SsdtPointer;
165   UINT32     *Signature;
166 
167   //
168   // Loop through the ASL looking for values that we must fix up.
169   //
170   CurrPtr = (UINT8 *) TableHeader;
171   for (SsdtPointer = CurrPtr;
172        SsdtPointer <= (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length);
173        SsdtPointer++
174       )
175   {
176     Signature = (UINT32 *) SsdtPointer;
177     if ((*Signature) == SIGNATURE_32 ('P', 'M', 'B', 'A')) {
178       switch (*(Signature+1)) {
179       case (SIGNATURE_32 ('L', 'V', 'L', '0')):
180         Signature[0] = PcdGet16(PcdPmbaIoBaseAddress);
181         Signature[1] = 0;
182         break;
183       case (SIGNATURE_32 ('L', 'V', 'L', '2')):
184         Signature[0] = PcdGet16(PcdPmbaIoLVL2);
185         Signature[1] = 0;
186         break;
187       }
188     }
189   }
190 }
191 
192 EFI_STATUS
LocateSupportProtocol(IN EFI_GUID * Protocol,OUT VOID ** Instance,IN UINT32 Type)193 LocateSupportProtocol (
194   IN  EFI_GUID                       *Protocol,
195   OUT VOID                           **Instance,
196   IN  UINT32                         Type
197   )
198 /*++
199 
200 Routine Description:
201 
202   Locate the first instance of a protocol.  If the protocol requested is an
203   FV protocol, then it will return the first FV that contains the ACPI table
204   storage file.
205 
206 Arguments:
207 
208   Protocol      The protocol to find.
209   Instance      Return pointer to the first instance of the protocol
210 
211 Returns:
212 
213   EFI_SUCCESS           The function completed successfully.
214   EFI_NOT_FOUND         The protocol could not be located.
215   EFI_OUT_OF_RESOURCES  There are not enough resources to find the protocol.
216 
217 --*/
218 {
219   EFI_STATUS              Status;
220   EFI_HANDLE              *HandleBuffer;
221   UINTN                   NumberOfHandles;
222   EFI_FV_FILETYPE         FileType;
223   UINT32                  FvStatus;
224   EFI_FV_FILE_ATTRIBUTES  Attributes;
225   UINTN                   Size;
226   UINTN                   i;
227 
228   FvStatus = 0;
229 
230   //
231   // Locate protocol.
232   //
233   Status = gBS->LocateHandleBuffer (
234                    ByProtocol,
235                    Protocol,
236                    NULL,
237                    &NumberOfHandles,
238                    &HandleBuffer
239                    );
240   if (EFI_ERROR (Status)) {
241 
242     //
243     // Defined errors at this time are not found and out of resources.
244     //
245     return Status;
246   }
247 
248 
249 
250   //
251   // Looking for FV with ACPI storage file
252   //
253 
254   for (i = 0; i < NumberOfHandles; i++) {
255     //
256     // Get the protocol on this handle
257     // This should not fail because of LocateHandleBuffer
258     //
259     Status = gBS->HandleProtocol (
260                      HandleBuffer[i],
261                      Protocol,
262                      Instance
263                      );
264     ASSERT_EFI_ERROR (Status);
265 
266     if (!Type) {
267       //
268       // Not looking for the FV protocol, so find the first instance of the
269       // protocol.  There should not be any errors because our handle buffer
270       // should always contain at least one or LocateHandleBuffer would have
271       // returned not found.
272       //
273       break;
274     }
275 
276     //
277     // See if it has the ACPI storage file
278     //
279 
280     Status = ((EFI_FIRMWARE_VOLUME2_PROTOCOL*) (*Instance))->ReadFile (*Instance,
281                                                               &gPowerManagementAcpiTableStorageGuid,
282                                                               NULL,
283                                                               &Size,
284                                                               &FileType,
285                                                               &Attributes,
286                                                               &FvStatus
287                                                               );
288 
289     //
290     // If we found it, then we are done
291     //
292     if (Status == EFI_SUCCESS) {
293       break;
294     }
295   }
296 
297   //
298   // Our exit status is determined by the success of the previous operations
299   // If the protocol was found, Instance already points to it.
300   //
301 
302   //
303   // Free any allocated buffers
304   //
305   gBS->FreePool (HandleBuffer);
306 
307   return Status;
308 }
309 
310 /**
311   This function is to load all the power management acpi tables and patch IST table.
312 **/
313 VOID
PpmLoadAndPatchPMTables(VOID)314 PpmLoadAndPatchPMTables (
315   VOID
316   )
317 {
318     EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
319     EFI_STATUS                    Status;
320     INTN                          Instance;
321   EFI_ACPI_COMMON_HEADER        *CurrentTable;
322   UINTN                         TableHandle;
323   UINT32                        FvStatus;
324   UINTN                         Size;
325    EFI_ACPI_TABLE_VERSION       Version;
326 
327     Status = LocateSupportProtocol (&gEfiFirmwareVolume2ProtocolGuid, (VOID**)&FwVol, 1);
328     if (EFI_ERROR (Status)) {
329     return;
330   }
331 
332   //
333   // Read tables from the storage file.
334   //
335   Instance = 0;
336   CurrentTable = NULL;
337 
338   while (Status == EFI_SUCCESS) {
339 
340     Status = FwVol->ReadSection (
341                       FwVol,
342                       &gPowerManagementAcpiTableStorageGuid,
343                       EFI_SECTION_RAW,
344                       Instance,
345                       (VOID**)&CurrentTable,
346                       &Size,
347                       &FvStatus
348                       );
349 
350     if (!EFI_ERROR(Status)) {
351         Version = EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0;
352 
353       if(((EFI_ACPI_DESCRIPTION_HEADER*) CurrentTable)->OemTableId == SIGNATURE_64 ('C', 'p', 'u', '0', 'I', 's', 't', 0)) {
354           Version = EFI_ACPI_TABLE_VERSION_NONE;
355       } else if(((EFI_ACPI_DESCRIPTION_HEADER*) CurrentTable)->OemTableId == SIGNATURE_64 ('C', 'p', 'u', '1', 'I', 's', 't', 0)) {
356           Version = EFI_ACPI_TABLE_VERSION_NONE;
357       }
358 
359       SsdtTableUpdate ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable);
360 
361       //
362       // Update the check sum
363       // It needs to be zeroed before the checksum calculation
364       //
365       ((EFI_ACPI_SDT_HEADER *)CurrentTable)->Checksum = 0;
366       ((EFI_ACPI_SDT_HEADER *)CurrentTable)->Checksum = (UINT8)
367         CalculateCheckSum8 ((VOID *)CurrentTable, CurrentTable->Length);
368 
369       //
370       // Add the table
371       //
372       TableHandle = 0;
373       Status = mAcpiTable->InstallAcpiTable (
374                               mAcpiTable,
375                               CurrentTable,
376                               CurrentTable->Length,
377                               &TableHandle
378                               );
379 
380       ASSERT_EFI_ERROR (Status);
381 
382       //
383       // Increment the instance
384       //
385       Instance++;
386       CurrentTable = NULL;
387     }
388   }
389 
390 }
391