Home | History | Annotate | Download | only in Dxe
      1 /** @file
      2 QuarkNcSocId module initialization module
      3 
      4 Copyright (c) 2013-2015 Intel Corporation.
      5 
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 #include "CommonHeader.h"
     16 
     17 #include "LegacyRegion.h"
     18 #include "DxeQNCSmbus.h"
     19 
     20 #include "QNCInit.h"
     21 
     22 //
     23 // Definitions
     24 //
     25 #define QNC_RESERVED_ITEM_IO         0
     26 #define QNC_RESERVED_ITEM_MEMORYIO   1
     27 #define DXE_DEVICE_DISABLED 0
     28 #define DXE_DEVICE_ENABLED 1
     29 
     30 typedef struct _QNC_SPACE_TABLE_ITEM {
     31    UINTN                   IoOrMemory;
     32    UINTN                   Type;
     33    EFI_PHYSICAL_ADDRESS    BaseAddress;
     34    UINT64                  Length;
     35    UINTN                   Alignment;
     36    BOOLEAN                 RuntimeOrNot;
     37 } QNC_SPACE_TABLE_ITEM;
     38 
     39 typedef struct {
     40   ACPI_CPU_DATA       AcpuCpuData;
     41   MTRR_SETTINGS       MtrrTable;
     42   IA32_DESCRIPTOR     GdtrProfile;
     43   IA32_DESCRIPTOR     IdtrProfile;
     44   CPU_REGISTER_TABLE  RegisterTable;
     45   CPU_REGISTER_TABLE  PreSmmInitRegisterTable;
     46 } ACPI_CPU_DATA_EX;
     47 
     48 //
     49 // Spaces to be reserved in GCD
     50 // Expand it to add more
     51 //
     52 const QNC_SPACE_TABLE_ITEM  mQNCReservedSpaceTable[] = {
     53   {
     54     QNC_RESERVED_ITEM_MEMORYIO,
     55     EfiGcdMemoryTypeMemoryMappedIo,
     56     FixedPcdGet64 (PcdIoApicBaseAddress),
     57     FixedPcdGet64 (PcdIoApicSize),
     58     0,
     59     FALSE
     60   },
     61   {
     62     QNC_RESERVED_ITEM_MEMORYIO,
     63     EfiGcdMemoryTypeMemoryMappedIo,
     64     FixedPcdGet64 (PcdHpetBaseAddress),
     65     FixedPcdGet64 (PcdHpetSize),
     66     0,
     67     FALSE
     68   }
     69 };
     70 
     71 //
     72 // Global variable for ImageHandle of QNCInit driver
     73 //
     74 EFI_HANDLE gQNCInitImageHandle;
     75 QNC_DEVICE_ENABLES    mQNCDeviceEnables;
     76 
     77 
     78 VOID
     79 QNCInitializeResource (
     80   VOID
     81   );
     82 
     83 EFI_STATUS
     84 InitializeQNCPolicy (
     85   VOID
     86   );
     87 
     88 /**
     89   Allocate EfiACPIMemoryNVS below 4G memory address.
     90 
     91   This function allocates EfiACPIMemoryNVS below 4G memory address.
     92 
     93   @param Size   Size of memory to allocate.
     94 
     95   @return       Allocated address for output.
     96 
     97 **/
     98 VOID *
     99 AllocateAcpiNvsMemoryBelow4G (
    100   IN UINTN  Size
    101   )
    102 {
    103   UINTN                 Pages;
    104   EFI_PHYSICAL_ADDRESS  Address;
    105   EFI_STATUS            Status;
    106   VOID*                 Buffer;
    107 
    108   Pages = EFI_SIZE_TO_PAGES (Size);
    109   Address = 0xffffffff;
    110 
    111   Status  = gBS->AllocatePages (
    112                    AllocateMaxAddress,
    113                    EfiACPIMemoryNVS,
    114                    Pages,
    115                    &Address
    116                    );
    117   if (EFI_ERROR (Status)) {
    118     return NULL;
    119   }
    120 
    121   Buffer = (VOID *) (UINTN) Address;
    122   ZeroMem (Buffer, Size);
    123 
    124   return Buffer;
    125 }
    126 
    127 /**
    128   Prepare ACPI NVS memory below 4G memory for use of S3 resume.
    129 
    130   This function allocates ACPI NVS memory below 4G memory for use of S3 resume,
    131   and saves data into the memory region.
    132 
    133 **/
    134 VOID
    135 SaveCpuS3Data (
    136   VOID
    137   )
    138 {
    139   EFI_STATUS        Status;
    140   ACPI_CPU_DATA_EX  *AcpiCpuDataEx;
    141   ACPI_CPU_DATA     *AcpiCpuData;
    142   UINTN             GdtSize;
    143   UINTN             IdtSize;
    144   VOID              *Gdt;
    145   VOID              *Idt;
    146 
    147   //
    148   // Allocate ACPI NVS memory below 4G memory for use of S3 resume.
    149   //
    150   AcpiCpuDataEx = AllocateAcpiNvsMemoryBelow4G (sizeof (ACPI_CPU_DATA_EX));
    151   AcpiCpuData = &AcpiCpuDataEx->AcpuCpuData;
    152 
    153   //
    154   //
    155   //
    156   AcpiCpuData->NumberOfCpus              = 1;
    157   AcpiCpuData->StackSize                 = PcdGet32 (PcdCpuApStackSize);
    158   AcpiCpuData->ApMachineCheckHandlerBase = 0;
    159   AcpiCpuData->ApMachineCheckHandlerSize = 0;
    160   AcpiCpuData->GdtrProfile               = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->GdtrProfile;
    161   AcpiCpuData->IdtrProfile               = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->IdtrProfile;
    162   AcpiCpuData->MtrrTable                 = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->MtrrTable;
    163   AcpiCpuData->RegisterTable             = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->RegisterTable;
    164   AcpiCpuData->PreSmmInitRegisterTable   = (EFI_PHYSICAL_ADDRESS) (UINTN) &AcpiCpuDataEx->PreSmmInitRegisterTable;
    165 
    166   //
    167   // Allocate stack space for all CPUs
    168   //
    169   AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateAcpiNvsMemoryBelow4G (AcpiCpuData->NumberOfCpus * AcpiCpuData->StackSize);
    170 
    171   //
    172   // Get MTRR settings from currently executing CPU
    173   //
    174   MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);
    175 
    176   //
    177   // Get the BSP's data of GDT and IDT
    178   //
    179   AsmReadGdtr ((IA32_DESCRIPTOR *) &AcpiCpuDataEx->GdtrProfile);
    180   AsmReadIdtr ((IA32_DESCRIPTOR *) &AcpiCpuDataEx->IdtrProfile);
    181 
    182   //
    183   // Allocate GDT and IDT in ACPI NVS and copy in current GDT and IDT contents
    184   //
    185   GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;
    186   IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;
    187   Gdt = AllocateAcpiNvsMemoryBelow4G (GdtSize + IdtSize);
    188   Idt = (VOID *)((UINTN)Gdt + GdtSize);
    189   CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);
    190   CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);
    191   AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;
    192   AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;
    193 
    194   //
    195   // No RegisterTable entries
    196   //
    197   AcpiCpuDataEx->RegisterTable.TableLength = 0;
    198 
    199   //
    200   // No PreSmmInitRegisterTable entries
    201   //
    202   AcpiCpuDataEx->PreSmmInitRegisterTable.TableLength = 0;
    203 
    204   //
    205   // Set the base address of CPU S3 data to PcdCpuS3DataAddress
    206   //
    207   Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);
    208   ASSERT_EFI_ERROR (Status);
    209 }
    210 
    211 /**
    212    The entry function for QNCInit driver.
    213 
    214    This function just call initialization function for PciHostBridge,
    215    LegacyRegion and QNCSmmAccess module.
    216 
    217    @param ImageHandle   The driver image handle for GmchInit driver
    218    @param SystemTable   The pointer to System Table
    219 
    220    @retval EFI_SUCCESS  Success to initialize every module for GMCH driver.
    221    @return EFI_STATUS   The status of initialization work.
    222 
    223 **/
    224 EFI_STATUS
    225 EFIAPI
    226 QNCInit (
    227   IN EFI_HANDLE         ImageHandle,
    228   IN EFI_SYSTEM_TABLE   *SystemTable
    229   )
    230 {
    231   EFI_STATUS  Status;
    232 
    233   S3BootScriptSaveInformationAsciiString (
    234     "QNCInitDxeEntryBegin"
    235     );
    236 
    237   gQNCInitImageHandle = ImageHandle;
    238 
    239   mQNCDeviceEnables.Uint32 = PcdGet32 (PcdDeviceEnables);
    240 
    241 
    242   //
    243   // Initialize PCIE root ports
    244   //
    245   Status = QncInitRootPorts ();
    246   if (EFI_ERROR (Status)) {
    247     DEBUG ((EFI_D_ERROR, "QNC Root Port initialization is failed!\n"));
    248     return Status;
    249   }
    250 
    251   Status = LegacyRegionInit ();
    252   if (EFI_ERROR (Status)) {
    253     DEBUG ((EFI_D_ERROR, "QNC LegacyRegion initialization is failed!\n"));
    254     return Status;
    255   }
    256 
    257 
    258   Status = InitializeQNCPolicy ();
    259   if (EFI_ERROR (Status)) {
    260     DEBUG ((EFI_D_ERROR, "QNC Policy initialization is failed!\n"));
    261     return Status;
    262   }
    263 
    264   Status = InitializeQNCSmbus (ImageHandle,SystemTable);
    265   if (EFI_ERROR (Status)) {
    266     DEBUG ((EFI_D_ERROR, "QNC Smbus driver is failed!\n"));
    267     return Status;
    268   }
    269 
    270   QNCInitializeResource ();
    271 
    272   SaveCpuS3Data ();
    273 
    274   S3BootScriptSaveInformationAsciiString (
    275     "QNCInitDxeEntryEnd"
    276     );
    277 
    278   return EFI_SUCCESS;
    279 }
    280 
    281 
    282 /**
    283   Reserve I/O or memory space in GCD
    284 
    285   @param  IoOrMemory    Switch of I/O or memory.
    286   @param  GcdType       Type of the space.
    287   @param  BaseAddress   Base address of the space.
    288   @param  Length        Length of the space.
    289   @param  Alignment     Align with 2^Alignment
    290   @param  RuntimeOrNot  For runtime usage or not
    291   @param  ImageHandle   Handle for the image of this driver.
    292 
    293   @retval EFI_SUCCESS   Reserve successful
    294 **/
    295 EFI_STATUS
    296 QNCReserveSpaceInGcd(
    297   IN UINTN                 IoOrMemory,
    298   IN UINTN                 GcdType,
    299   IN EFI_PHYSICAL_ADDRESS  BaseAddress,
    300   IN UINT64                Length,
    301   IN UINTN                 Alignment,
    302   IN BOOLEAN               RuntimeOrNot,
    303   IN EFI_HANDLE            ImageHandle
    304   )
    305 {
    306   EFI_STATUS               Status;
    307 
    308   if (IoOrMemory == QNC_RESERVED_ITEM_MEMORYIO) {
    309     Status = gDS->AddMemorySpace (
    310                     GcdType,
    311                     BaseAddress,
    312                     Length,
    313                     EFI_MEMORY_UC
    314                     );
    315     if (EFI_ERROR (Status)) {
    316       DEBUG ((
    317         EFI_D_ERROR,
    318         "Failed to add memory space :0x%x 0x%x\n",
    319         BaseAddress,
    320         Length
    321         ));
    322     }
    323     ASSERT_EFI_ERROR (Status);
    324     Status = gDS->AllocateMemorySpace (
    325                     EfiGcdAllocateAddress,
    326                     GcdType,
    327                     Alignment,
    328                     Length,
    329                     &BaseAddress,
    330                     ImageHandle,
    331                     NULL
    332                     );
    333     ASSERT_EFI_ERROR (Status);
    334     if (RuntimeOrNot) {
    335       Status = gDS->SetMemorySpaceAttributes (
    336                       BaseAddress,
    337                       Length,
    338                       EFI_MEMORY_RUNTIME | EFI_MEMORY_UC
    339                      );
    340       ASSERT_EFI_ERROR (Status);
    341     }
    342   } else {
    343     Status = gDS->AddIoSpace (
    344                     GcdType,
    345                     BaseAddress,
    346                     Length
    347                     );
    348     ASSERT_EFI_ERROR (Status);
    349     Status = gDS->AllocateIoSpace (
    350                     EfiGcdAllocateAddress,
    351                     GcdType,
    352                     Alignment,
    353                     Length,
    354                     &BaseAddress,
    355                     ImageHandle,
    356                     NULL
    357                     );
    358     ASSERT_EFI_ERROR (Status);
    359   }
    360   return Status;
    361 }
    362 
    363 
    364 /**
    365   Initialize the memory and io resource which belong to QNC.
    366   1) Report and allocate all BAR's memory to GCD.
    367   2) Report PCI memory and I/O space to GCD.
    368   3) Set memory attribute for <1M memory space.
    369 **/
    370 VOID
    371 QNCInitializeResource (
    372   )
    373 {
    374   EFI_PHYSICAL_ADDRESS            BaseAddress;
    375   EFI_STATUS                      Status;
    376   UINT64                          ExtraRegionLength;
    377   EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
    378   UINTN                           Index;
    379 
    380   // Report TSEG range
    381   // This range maybe has been reportted in PEI phase via Resource Hob.
    382   //
    383   QNCGetTSEGMemoryRange (&BaseAddress, &ExtraRegionLength);
    384   if (ExtraRegionLength != 0) {
    385     Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &Descriptor);
    386     if (Status == EFI_NOT_FOUND) {
    387       Status = gDS->AddMemorySpace (
    388                       EfiGcdMemoryTypeReserved,
    389                       BaseAddress,
    390                       ExtraRegionLength,
    391                       EFI_MEMORY_UC
    392                       );
    393     }
    394   }
    395 
    396   //
    397   // < 1M resource setting. The memory ranges <1M has been added into GCD via
    398   // resource hob produced by PEI phase. Here will set memory attribute of these
    399   // ranges for DXE phase.
    400   //
    401 
    402   //
    403   // Dos Area (0 ~ 0x9FFFFh)
    404   //
    405   Status = gDS->GetMemorySpaceDescriptor (0, &Descriptor);
    406   DEBUG ((
    407     EFI_D_INFO,
    408     "DOS Area Memory: base = 0x%x, length = 0x%x, attribute = 0x%x\n",
    409     Descriptor.BaseAddress,
    410     Descriptor.Length,
    411     Descriptor.Attributes
    412     ));
    413   ASSERT_EFI_ERROR (Status);
    414   Status = gDS->SetMemorySpaceAttributes(
    415                   0,
    416                   0xA0000,
    417                   EFI_MEMORY_WB
    418                   );
    419   ASSERT_EFI_ERROR (Status);
    420 
    421   //
    422   // Default SMRAM UnCachable until SMBASE relocated.
    423   //
    424   Status = gDS->SetMemorySpaceAttributes(
    425                   0x30000,
    426                   0x10000,
    427                   EFI_MEMORY_UC
    428                   );
    429   ASSERT_EFI_ERROR (Status);
    430 
    431   //
    432   // Default SMM ABSEG area. (0xA0000 ~ 0xBFFFF)
    433   //
    434   Status = gDS->GetMemorySpaceDescriptor (0xA0000, &Descriptor);
    435   DEBUG ((
    436     EFI_D_INFO,
    437     "ABSEG Memory: base = 0x%x, length = 0x%x, attribute = 0x%x\n",
    438     Descriptor.BaseAddress,
    439     Descriptor.Length,
    440     Descriptor.Attributes
    441     ));
    442   ASSERT_EFI_ERROR (Status);
    443   Status = gDS->SetMemorySpaceAttributes(
    444                   0xA0000,
    445                   0x20000,
    446                   EFI_MEMORY_UC
    447                   );
    448   ASSERT_EFI_ERROR (Status);
    449 
    450   //
    451   // Expansion BIOS area.
    452   //
    453   Status = gDS->GetMemorySpaceDescriptor (0xC0000, &Descriptor);
    454   DEBUG ((
    455     EFI_D_INFO,
    456     "Memory base = 0x%x, length = 0x%x, attribute = 0x%x\n",
    457     Descriptor.BaseAddress,
    458     Descriptor.Length,
    459     Descriptor.Attributes
    460     ));
    461   ASSERT_EFI_ERROR (Status);
    462   Status = gDS->SetMemorySpaceAttributes(
    463                   0xC0000,
    464                   0x30000,
    465                   EFI_MEMORY_UC
    466                   );
    467   ASSERT_EFI_ERROR (Status);
    468 
    469   //
    470   // Report other IO resources from mQNCReservedSpaceTable in GCD
    471   //
    472   for (Index = 0; Index < sizeof (mQNCReservedSpaceTable) / sizeof (QNC_SPACE_TABLE_ITEM); Index++) {
    473     Status = QNCReserveSpaceInGcd (
    474                mQNCReservedSpaceTable[Index].IoOrMemory,
    475                mQNCReservedSpaceTable[Index].Type,
    476                mQNCReservedSpaceTable[Index].BaseAddress,
    477                mQNCReservedSpaceTable[Index].Length,
    478                mQNCReservedSpaceTable[Index].Alignment,
    479                mQNCReservedSpaceTable[Index].RuntimeOrNot,
    480                gQNCInitImageHandle
    481                );
    482     ASSERT_EFI_ERROR (Status);
    483   }
    484 
    485   //
    486   // Report unused PCIe config space as reserved.
    487   //
    488   if (PcdGet64 (PcdPciExpressSize) < SIZE_256MB) {
    489     Status = QNCReserveSpaceInGcd (
    490                QNC_RESERVED_ITEM_MEMORYIO,
    491                EfiGcdMemoryTypeMemoryMappedIo,
    492                (PcdGet64(PcdPciExpressBaseAddress) + PcdGet64(PcdPciExpressSize)),
    493                (SIZE_256MB - PcdGet64(PcdPciExpressSize)),
    494                0,
    495                FALSE,
    496                gQNCInitImageHandle
    497                );
    498     ASSERT_EFI_ERROR (Status);
    499   }
    500 }
    501 
    502 /**
    503   Use the platform PCD to initialize devices in the QNC
    504 
    505   @param  ImageHandle   Handle for the image of this driver.
    506   @retval EFI_SUCCESS   Initialize successful
    507 **/
    508 EFI_STATUS
    509 InitializeQNCPolicy (
    510   )
    511 {
    512   UINT32       PciD31F0RegBase;  // LPC
    513 
    514   PciD31F0RegBase = PciDeviceMmBase (PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, PCI_FUNCTION_NUMBER_QNC_LPC);
    515 
    516   //
    517   // Disable for smbus
    518   //
    519   if (mQNCDeviceEnables.Bits.Smbus == DXE_DEVICE_DISABLED) {
    520     S3MmioAnd32 (PciD31F0RegBase + R_QNC_LPC_SMBUS_BASE, (~B_QNC_LPC_SMBUS_BASE_EN));
    521   }
    522 
    523   return EFI_SUCCESS;
    524 }
    525