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