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