Home | History | Annotate | Download | only in AcpiPlatform
      1 /** @file
      2 
      3   Copyright (c) 2004  - 2014, Intel Corporation. All rights reserved.<BR>
      4 
      5   This program and the accompanying materials are licensed and made available under
      7   the terms and conditions of the BSD License that accompanies this distribution.
      9   The full text of the license may be found at
     11   http://opensource.org/licenses/bsd-license.php.
     13 
     15   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     17   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     19 
     21 
     23 Module Name:
     24 
     25   AcpiPlatformHooks.c
     26 
     27 Abstract:
     28 
     29   ACPI Platform Driver Hooks
     30 
     31 --*/
     32 
     33 //
     34 // Statements that include other files.
     35 //
     36 #include "AcpiPlatform.h"
     37 #include "AcpiPlatformHooks.h"
     38 #include "Platform.h"
     39 
     40 //
     41 // Prototypes of the various hook functions.
     42 //
     43 #include "AcpiPlatformHooksLib.h"
     44 
     45 extern EFI_GLOBAL_NVS_AREA_PROTOCOL  mGlobalNvsArea;
     46 extern SYSTEM_CONFIGURATION             mSystemConfiguration;
     47 
     48 ENHANCED_SPEEDSTEP_PROTOCOL             *mEistProtocol  = NULL;
     49 
     50 EFI_CPU_ID_MAP              mCpuApicIdAcpiIdMapTable[MAX_CPU_NUM];
     51 
     52 EFI_STATUS
     53 AppendCpuMapTableEntry (
     54   IN EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE   *AcpiLocalApic
     55   )
     56 {
     57   BOOLEAN Added;
     58   UINTN   Index;
     59 
     60   for (Index = 0; Index < MAX_CPU_NUM; Index++) {
     61     if ((mCpuApicIdAcpiIdMapTable[Index].ApicId == AcpiLocalApic->ApicId) && mCpuApicIdAcpiIdMapTable[Index].Flags) {
     62       return EFI_SUCCESS;
     63     }
     64   }
     65 
     66   Added = FALSE;
     67   for (Index = 0; Index < MAX_CPU_NUM; Index++) {
     68       if (!mCpuApicIdAcpiIdMapTable[Index].Flags) {
     69         mCpuApicIdAcpiIdMapTable[Index].Flags           = 1;
     70         mCpuApicIdAcpiIdMapTable[Index].ApicId          = AcpiLocalApic->ApicId;
     71         mCpuApicIdAcpiIdMapTable[Index].AcpiProcessorId = AcpiLocalApic->AcpiProcessorId;
     72       Added = TRUE;
     73       break;
     74     }
     75   }
     76 
     77   ASSERT (Added);
     78   return EFI_SUCCESS;
     79 }
     80 
     81 UINT32
     82 ProcessorId2ApicId (
     83   UINT32  AcpiProcessorId
     84   )
     85 {
     86   UINTN Index;
     87 
     88   ASSERT (AcpiProcessorId < MAX_CPU_NUM);
     89   for (Index = 0; Index < MAX_CPU_NUM; Index++) {
     90     if (mCpuApicIdAcpiIdMapTable[Index].Flags && (mCpuApicIdAcpiIdMapTable[Index].AcpiProcessorId == AcpiProcessorId)) {
     91       return mCpuApicIdAcpiIdMapTable[Index].ApicId;
     92     }
     93   }
     94 
     95   return (UINT32) -1;
     96 }
     97 
     98 UINT8
     99 GetProcNumberInPackage (
    100   IN UINT8  Package
    101   )
    102 {
    103   UINTN Index;
    104   UINT8 Number;
    105 
    106   Number = 0;
    107   for (Index = 0; Index < MAX_CPU_NUM; Index++) {
    108     if (mCpuApicIdAcpiIdMapTable[Index].Flags && (((mCpuApicIdAcpiIdMapTable[Index].ApicId >> 0x04) & 0x01) == Package)) {
    109       Number++;
    110     }
    111   }
    112 
    113   return Number;
    114 }
    115 
    116 EFI_STATUS
    117 LocateCpuEistProtocol (
    118   IN UINT32                           CpuIndex,
    119   OUT ENHANCED_SPEEDSTEP_PROTOCOL     **EistProtocol
    120   )
    121 {
    122   UINTN                       HandleCount;
    123   EFI_HANDLE                  *HandleBuffer;
    124   ENHANCED_SPEEDSTEP_PROTOCOL *EistProt;
    125   UINTN                       Index;
    126   UINT32                      ApicId;
    127   EFI_STATUS                  Status;
    128 
    129   HandleCount = 0;
    130   gBS->LocateHandleBuffer (
    131          ByProtocol,
    132          &gEnhancedSpeedstepProtocolGuid,
    133          NULL,
    134          &HandleCount,
    135          &HandleBuffer
    136          );
    137 
    138   Index     = 0;
    139   EistProt  = NULL;
    140   Status    = EFI_NOT_FOUND;
    141   while (Index < HandleCount) {
    142     gBS->HandleProtocol (
    143            HandleBuffer[Index],
    144            &gEnhancedSpeedstepProtocolGuid,
    145           (VOID **) &EistProt
    146            );
    147     //
    148     // Adjust the CpuIndex by +1 due to the AcpiProcessorId is 1 based.
    149     //
    150     ApicId = ProcessorId2ApicId (CpuIndex+1);
    151     if (ApicId == (UINT32) -1) {
    152       break;
    153     }
    154 
    155     if (EistProt->ProcApicId == ApicId) {
    156       Status = EFI_SUCCESS;
    157       break;
    158     }
    159 
    160     Index++;
    161   }
    162 
    163   if (HandleBuffer != NULL) {
    164     gBS->FreePool (HandleBuffer);
    165   }
    166 
    167   if (!EFI_ERROR (Status)) {
    168     *EistProtocol = EistProt;
    169   } else {
    170     *EistProtocol = NULL;
    171   }
    172 
    173   return Status;
    174 }
    175 
    176 EFI_STATUS
    177 PlatformHookInit (
    178   VOID
    179   )
    180 {
    181   EFI_STATUS  Status;
    182 
    183   Status = gBS->LocateProtocol (
    184                   &gEnhancedSpeedstepProtocolGuid,
    185                   NULL,
    186                   (VOID **) &mEistProtocol
    187                   );
    188 
    189   ASSERT_EFI_ERROR (Status);
    190 
    191   return Status;
    192 }
    193 
    194 /**
    195   Called for every ACPI table found in the BIOS flash.
    196   Returns whether a table is active or not. Inactive tables
    197   are not published in the ACPI table list.
    198 
    199   This hook can be used to implement optional SSDT tables or
    200   enabling/disabling specific functionality (e.g. SPCR table)
    201   based on a setup switch or platform preference. In case of
    202   optional SSDT tables,the platform flash will include all the
    203   SSDT tables but will return EFI_SUCCESS only for those tables
    204   that need to be published.
    205 
    206   @param[in]  *Table         Pointer to the active table.
    207 
    208   @retval  EFI_SUCCESS       if the table is active.
    209   @retval  EFI_UNSUPPORTED   if the table is not active.
    210 
    211 **/
    212 EFI_STATUS
    213 AcpiPlatformHooksIsActiveTable (
    214   IN OUT EFI_ACPI_COMMON_HEADER     *Table
    215   )
    216 {
    217   EFI_ACPI_DESCRIPTION_HEADER *TableHeader;
    218 
    219   TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table;
    220 
    221   if (TableHeader->Signature == EFI_ACPI_2_0_STATIC_RESOURCE_AFFINITY_TABLE_SIGNATURE) {
    222 
    223   }
    224 
    225   if ((mSystemConfiguration.ENDBG2 == 0) && (CompareMem (&TableHeader->OemTableId, "INTLDBG2", 8) == 0)) {
    226     return EFI_UNSUPPORTED;
    227   }
    228   return EFI_SUCCESS;
    229 }
    230 
    231 /**
    232     Update the GV3 SSDT table.
    233 
    234     @param[in][out]  *TableHeader   The table to be set.
    235 
    236     @retval  EFI_SUCCESS            Returns Success.
    237 
    238 **/
    239 EFI_STATUS
    240 PatchGv3SsdtTable (
    241   IN OUT   EFI_ACPI_DESCRIPTION_HEADER  *TableHeader
    242   )
    243 {
    244   EFI_STATUS                  Status;
    245   UINT8                       *CurrPtr;
    246   UINT8                       *SsdtPointer;
    247   UINT32                      Signature;
    248   UINT32                      CpuFixes;
    249   UINT32                      NpssFixes;
    250   UINT32                      SpssFixes;
    251   UINT32                      CpuIndex;
    252   UINT32                      PackageSize;
    253   UINT32                      NewPackageSize;
    254   UINT32                      AdjustSize;
    255   UINTN                       EntryIndex;
    256   UINTN                       TableIndex;
    257   EFI_ACPI_NAME_COMMAND       *PssTable;
    258   EFI_PSS_PACKAGE             *PssTableItemPtr;
    259   ENHANCED_SPEEDSTEP_PROTOCOL *EistProt;
    260   EIST_INFORMATION            *EistInfo;
    261   EFI_ACPI_CPU_PSS_STATE      *PssState;
    262   EFI_ACPI_NAMEPACK_DWORD     *NamePtr;
    263   //
    264   // Loop through the ASL looking for values that we must fix up.
    265   //
    266   NpssFixes = 0;
    267   SpssFixes = 0;
    268   CpuFixes  = 0;
    269   CpuIndex  = 0;
    270   CurrPtr   = (UINT8 *) TableHeader;
    271 
    272   EistProt  = NULL;
    273   for (SsdtPointer = CurrPtr; SsdtPointer <= (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length); SsdtPointer++) {
    274     Signature = *(UINT32 *) SsdtPointer;
    275     switch (Signature) {
    276 
    277     case SIGNATURE_32 ('_', 'P', 'R', '_'):
    278       //
    279       // _CPUX ('0' to '0xF')
    280       //
    281       CpuIndex = *(SsdtPointer + 7);
    282       if (CpuIndex >= '0' && CpuIndex <= '9') {
    283         CpuIndex -= '0';
    284       } else {
    285         if (CpuIndex > '9') {
    286           CpuIndex -= '7';
    287         }
    288       }
    289 
    290       CpuFixes++;
    291       LocateCpuEistProtocol (CpuIndex, &EistProt);
    292       break;
    293 
    294     case SIGNATURE_32 ('D', 'O', 'M', 'N'):
    295 
    296       NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (SsdtPointer);
    297       if (NamePtr->StartByte != AML_NAME_OP) {
    298         continue;
    299       }
    300 
    301       if (NamePtr->Size != AML_NAME_DWORD_SIZE) {
    302         continue;
    303       }
    304 
    305       NamePtr->Value = 0;
    306 
    307         if (mCpuApicIdAcpiIdMapTable[CpuIndex].Flags) {
    308           NamePtr->Value = (mCpuApicIdAcpiIdMapTable[CpuIndex].ApicId >> 0x04) & 0x01;
    309       }
    310       break;
    311 
    312     case SIGNATURE_32 ('N', 'C', 'P', 'U'):
    313 
    314       NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (SsdtPointer);
    315       if (NamePtr->StartByte != AML_NAME_OP) {
    316         continue;
    317       }
    318 
    319       if (NamePtr->Size != AML_NAME_DWORD_SIZE) {
    320         continue;
    321       }
    322 
    323         NamePtr->Value = 0;
    324         if (mCpuApicIdAcpiIdMapTable[CpuIndex].Flags) {
    325           NamePtr->Value = GetProcNumberInPackage ((mCpuApicIdAcpiIdMapTable[CpuIndex].ApicId >> 0x04) & 0x01);
    326       }
    327       break;
    328 
    329     case SIGNATURE_32 ('N', 'P', 'S', 'S'):
    330     case SIGNATURE_32 ('S', 'P', 'S', 'S'):
    331       if (EistProt == NULL) {
    332         continue;
    333       }
    334 
    335       PssTable = ACPI_NAME_COMMAND_FROM_NAME_STR (SsdtPointer);
    336       if (PssTable->StartByte != AML_NAME_OP) {
    337         continue;
    338       }
    339 
    340       Status      = EistProt->GetEistTable (EistProt, &EistInfo, (VOID **) &PssState);
    341 
    342       AdjustSize  = PssTable->NumEntries * sizeof (EFI_PSS_PACKAGE);
    343       AdjustSize -= EistInfo->NumStates * sizeof (EFI_PSS_PACKAGE);
    344       PackageSize     = (PssTable->Size & 0xF) + ((PssTable->Size & 0xFF00) >> 4);
    345       NewPackageSize  = PackageSize - AdjustSize;
    346       PssTable->Size  = (UINT16) ((NewPackageSize & 0xF) + ((NewPackageSize & 0x0FF0) << 4));
    347 
    348       //
    349       // Set most significant two bits of byte zero to 01, meaning two bytes used.
    350       //
    351       PssTable->Size |= 0x40;
    352 
    353       //
    354       // Set unused table to Noop Code.
    355       //
    356       SetMem( (UINT8 *) PssTable + NewPackageSize + AML_NAME_PREFIX_SIZE, AdjustSize, AML_NOOP_OP);
    357       PssTable->NumEntries  = (UINT8) EistInfo->NumStates;
    358       PssTableItemPtr       = (EFI_PSS_PACKAGE *) ((UINT8 *) PssTable + sizeof (EFI_ACPI_NAME_COMMAND));
    359 
    360       //
    361       // Update the size.
    362       //
    363       for (TableIndex = 0; TableIndex < EistInfo->NumStates; TableIndex++) {
    364         EntryIndex                = EistInfo->NumStates - TableIndex - 1;
    365         PssTableItemPtr->CoreFreq = PssState[EntryIndex].CoreFrequency * PssState[EntryIndex].Control;
    366         PssTableItemPtr->Power    = PssState[EntryIndex].Power * 1000;
    367         if (PssTable->NameStr == SIGNATURE_32 ('N', 'P', 'S', 'S')) {
    368           PssTableItemPtr->BMLatency    = PssState[EntryIndex].BusMasterLatency;
    369           PssTableItemPtr->TransLatency = PssState[EntryIndex].TransitionLatency;
    370         } else {
    371           //
    372           // This method should be supported by SMM PPM Handler.
    373           //
    374           PssTableItemPtr->BMLatency    = PssState[EntryIndex].BusMasterLatency * 2;
    375           PssTableItemPtr->TransLatency = PssState[EntryIndex].TransitionLatency * 10;
    376         }
    377 
    378         PssTableItemPtr->Control  = PssState[EntryIndex].Control;
    379         PssTableItemPtr->Status   = PssState[EntryIndex].Status;
    380         PssTableItemPtr++;
    381       }
    382 
    383       if (PssTable->NameStr == SIGNATURE_32 ('N', 'P', 'S', 'S')) {
    384         NpssFixes++;
    385       } else {
    386         SpssFixes++;
    387       }
    388 
    389       SsdtPointer = (UINT8 *) PssTable + PackageSize;
    390       break;
    391     }
    392   }
    393 
    394   //
    395   // N fixes together currently.
    396   //
    397   ASSERT (CpuFixes == (UINT32) MAX_CPU_NUM);
    398   ASSERT (SpssFixes == NpssFixes);
    399   ASSERT (CpuFixes >= SpssFixes);
    400 
    401   return EFI_SUCCESS;
    402 }
    403 
    404 /**
    405     Update the DSDT table.
    406 
    407     @param[in][out]  *TableHeader   The table to be set.
    408 
    409     @retval  EFI_SUCCESS            Returns EFI_SUCCESS.
    410 
    411 **/
    412 EFI_STATUS
    413 PatchDsdtTable (
    414   IN OUT   EFI_ACPI_DESCRIPTION_HEADER  *TableHeader
    415   )
    416 {
    417 
    418   UINT8                              *CurrPtr;
    419   UINT8                              *DsdtPointer;
    420   UINT32                             *Signature;
    421   UINT8                              *EndPtr;
    422   UINT8   *Operation;
    423   UINT32  *Address;
    424   UINT16  *Size;
    425 
    426   //
    427   // Fix PCI32 resource "FIX0" -- PSYS system status area
    428   //
    429   CurrPtr = (UINT8*) &((EFI_ACPI_DESCRIPTION_HEADER*) TableHeader)[0];
    430   EndPtr = (UINT8*) TableHeader;
    431   EndPtr = EndPtr + TableHeader->Length;
    432   while (CurrPtr < (EndPtr-2)) {
    433     //
    434     // Removed the _S3 tag to indicate that we do not support S3. The 4th byte is blank space
    435     // since there are only 3 char "_S3".
    436     //
    437     if (mSystemConfiguration.AcpiSuspendState == 0) {
    438       //
    439       // For iasl compiler version 20061109.
    440       //
    441       if ((CurrPtr[0] == '_') && (CurrPtr[1] == 'S') && (CurrPtr[2] == '3') && (CurrPtr[3] == '_')) {
    442         break;
    443       }
    444       //
    445       // For iasl compiler version 20040527.
    446       //
    447       if ((CurrPtr[0] == '\\') && (CurrPtr[1] == '_') && (CurrPtr[2] == 'S') && (CurrPtr[3] == '3')) {
    448         break;
    449       }
    450     }
    451     CurrPtr++;
    452   }
    453   CurrPtr = (UINT8*) &((EFI_ACPI_DESCRIPTION_HEADER*) TableHeader)[0];
    454   EndPtr = (UINT8*) TableHeader;
    455   EndPtr = EndPtr + TableHeader->Length;
    456   while (CurrPtr < (EndPtr-2)) {
    457     //
    458     // For mipi dsi port select _DEP.
    459     //
    460     if (mSystemConfiguration.MipiDsi== 1) {
    461       //
    462       // For iasl compiler version 20061109.
    463       //
    464       if ((CurrPtr[0] == 'N') && (CurrPtr[1] == 'D') && (CurrPtr[2] == 'E') && (CurrPtr[3] == 'P')) {
    465         CurrPtr[0] = '_';
    466         break;
    467       }
    468 
    469     } else {
    470       if ((CurrPtr[0] == 'P') && (CurrPtr[1] == 'D') && (CurrPtr[2] == 'E') && (CurrPtr[3] == 'P')) {
    471         CurrPtr[0] = '_';
    472         break;
    473       }
    474 
    475     }
    476     CurrPtr++;
    477   }
    478   //
    479   // Loop through the ASL looking for values that we must fix up.
    480   //
    481   CurrPtr = (UINT8 *) TableHeader;
    482   for (DsdtPointer = CurrPtr; DsdtPointer <= (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length); DsdtPointer++) {
    483     Signature = (UINT32 *) DsdtPointer;
    484 
    485     switch (*Signature) {
    486     //
    487     // GNVS operation region.
    488     //
    489     case (SIGNATURE_32 ('G', 'N', 'V', 'S')):
    490       //
    491       // Conditional match.  For Region Objects, the Operator will always be the
    492       // byte immediately before the specific name.  Therefore, subtract 1 to check
    493       // the Operator.
    494       //
    495       Operation = DsdtPointer - 1;
    496       if (*Operation == AML_OPREGION_OP) {
    497         Address   = (UINT32 *) (DsdtPointer + 6);
    498         *Address  = (UINT32) (UINTN) mGlobalNvsArea.Area;
    499         Size      = (UINT16 *) (DsdtPointer + 11);
    500         *Size     = sizeof (EFI_GLOBAL_NVS_AREA);
    501       }
    502       break;
    503     default:
    504       break;
    505     }
    506   }
    507   return EFI_SUCCESS;
    508 }
    509 
    510