Home | History | Annotate | Download | only in SmmPowerManagement
      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
     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
     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
     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
    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
    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
    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