diff options
Diffstat (limited to 'Platform/Intel/PurleyOpenBoardPkg/Pci/PciPlatform/PciPlatformHooks.c')
-rw-r--r-- | Platform/Intel/PurleyOpenBoardPkg/Pci/PciPlatform/PciPlatformHooks.c | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/Platform/Intel/PurleyOpenBoardPkg/Pci/PciPlatform/PciPlatformHooks.c b/Platform/Intel/PurleyOpenBoardPkg/Pci/PciPlatform/PciPlatformHooks.c new file mode 100644 index 0000000000..9310df3e67 --- /dev/null +++ b/Platform/Intel/PurleyOpenBoardPkg/Pci/PciPlatform/PciPlatformHooks.c @@ -0,0 +1,533 @@ +/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/IioUds.h>
+#include <PciPlatform.h>
+#include <PciPlatformHooks.h>
+#include <PciSupportLib.h>
+#include <IoApic.h>
+#include <Library/S3BootScriptLib.h>
+#include <Protocol/IioSystem.h>
+
+EFI_IIO_UDS_PROTOCOL *mIioUds = NULL;
+EFI_IIO_SYSTEM_PROTOCOL *IioSystemProtocol = NULL;
+IIO_GLOBALS *IioGlobalData = NULL;
+
+VOID
+ChipsetCallback (
+ IN EFI_HANDLE RootBridgeHandle,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_ENUMERATION_PHASE Phase,
+ EFI_PCI_CALLBACK_CONTEXT *Context
+ )
+{
+ EFI_LIST_ENTRY *NodeEntry;
+ PCI_CALLBACK_DATA *PciCallbackData;
+
+ //
+ // Check if the node has been added
+ //
+ // DEBUG ((DEBUG_ERROR, "PCI Callback (%d,%d,%d)\n",PciAddress.Bus, PciAddress.Device, PciAddress.Function ));
+ //
+ Context->PciRootBridgeIo = mPciPrivateData.PciRootBridgeIo;
+ NodeEntry = GetFirstNode (&mPciPrivateData.PciCallbackList);
+ while (!IsNull (&mPciPrivateData.PciCallbackList, NodeEntry)) {
+ PciCallbackData = PCI_CALLBACK_DATA_FROM_LINK (NodeEntry);
+ if (PciCallbackData->Phase & Phase) {
+ (PciCallbackData->Function) (RootBridgeHandle, PciAddress, Phase, Context);
+ }
+
+ NodeEntry = GetNextNode (&mPciPrivateData.PciCallbackList, NodeEntry);
+ }
+}
+
+/**
+
+ GC_TODO: add routine description
+
+ @param StartBus - GC_TODO: add arg description
+
+ @retval EFI_SUCCESS - GC_TODO: add retval description
+
+**/
+EFI_STATUS
+PciTreeTraverse (
+ IN UINT8 StartBus
+ )
+{
+ UINT64 PciAddress;
+ UINT8 Device;
+ UINT8 Func;
+ UINT8 SecondaryBus;
+ BOOLEAN MultiFunc;
+
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ MultiFunc = FALSE;
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+ if (IsPciDevicePresent (
+ mPciPrivateData.PciRootBridgeIo,
+ &mPciPrivateData.Context.PciHeader,
+ StartBus,
+ Device,
+ Func
+ )) {
+ if ((Func == 0) && IS_PCI_MULTI_FUNC(&(mPciPrivateData.Context.PciHeader))) {
+ MultiFunc = TRUE;
+ }
+ PciAddress = EFI_PCI_ADDRESS (StartBus, Device, Func, 0);
+ ChipsetCallback (
+ mPciPrivateData.RootBridgeHandle,
+ *(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &PciAddress,
+ mPciPrivateData.PciEnumerationPhase,
+ &(mPciPrivateData.Context)
+ );
+ if (IS_PCI_BRIDGE (&(mPciPrivateData.Context.PciHeader))) {
+ PciAddress = EFI_PCI_ADDRESS (StartBus, Device, Func, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ mPciPrivateData.PciRootBridgeIo->Pci.Read (
+ mPciPrivateData.PciRootBridgeIo,
+ EfiPciWidthUint8,
+ *(UINT64 *) &PciAddress,
+ 1,
+ &SecondaryBus
+ );
+ if ((SecondaryBus > 0) && (SecondaryBus < 0xFF)) {
+ PciTreeTraverse (SecondaryBus);
+ }
+ }
+ }
+
+ if (MultiFunc == FALSE) {
+ //
+ // Skip sub functions, this is not a multi function device
+ //
+ Func = PCI_MAX_FUNC;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Program Io Apic Id
+
+ @param IoApicAddress and IoApicId
+
+ @retval None
+
+**/
+VOID
+ProgramIoApicId (
+ IN UINT32 IoApicAddress,
+ IN UINT8 IoApicId
+ )
+{
+
+ UINT32 Data;
+
+ mPciPrivateData.CpuIo->Mem.Read (
+ mPciPrivateData.CpuIo,
+ EfiCpuIoWidthUint32,
+ IoApicAddress + EFI_IO_APIC_INDEX_OFFSET,
+ 1,
+ &Data
+ );
+
+ //
+ // IOAPIC is not there
+ //
+ if (Data == (UINT32) -1) {
+ return ;
+ }
+ //
+ // Set up IO APIC ID and enable FSB delivery
+ // Use CPU IO protocol since the IO APIC ranges
+ // are not included in PCI apertures
+ //
+ Data = EFI_IO_APIC_ID_REGISTER;
+ mPciPrivateData.CpuIo->Mem.Write (
+ mPciPrivateData.CpuIo,
+ EfiCpuIoWidthUint32,
+ IoApicAddress + EFI_IO_APIC_INDEX_OFFSET,
+ 1,
+ &Data
+ );
+
+ Data = IoApicId << EFI_IO_APIC_ID_BITSHIFT;
+ mPciPrivateData.CpuIo->Mem.Write (
+ mPciPrivateData.CpuIo,
+ EfiCpuIoWidthUint32,
+ IoApicAddress + EFI_IO_APIC_DATA_OFFSET,
+ 1,
+ &Data
+ );
+
+ Data = EFI_IO_APIC_BOOT_CONFIG_REGISTER;
+ mPciPrivateData.CpuIo->Mem.Write (
+ mPciPrivateData.CpuIo,
+ EfiCpuIoWidthUint32,
+ IoApicAddress + EFI_IO_APIC_INDEX_OFFSET,
+ 1,
+ &Data
+ );
+
+ Data = EFI_IO_APIC_FSB_INT_DELIVERY;
+ mPciPrivateData.CpuIo->Mem.Write (
+ mPciPrivateData.CpuIo,
+ EfiCpuIoWidthUint32,
+ IoApicAddress + EFI_IO_APIC_DATA_OFFSET,
+ 1,
+ &Data
+ );
+}
+
+#ifdef EFI_PCI_IOV_SUPPORT
+/**
+
+ Initialize the Pci Iov Platform Data.
+
+ @param ImageHandle - Handle to the image.
+ @param SystemTable - Handle to System Table.
+
+ @retval EFI_STATUS - Status of the function calling.
+
+**/
+EFI_STATUS
+EFIAPI
+PciPlatformInitPciIovData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IOV_PLATFORM_POLICY PciIovPolicy;
+ UINT32 SystemPageSize;
+ EFI_PCI_IOV_PLATFORM_PROTOCOL *gPciIovPlatformProtocol;
+
+ Status = gBS->LocateProtocol (
+ &gEfiPciIovPlatformProtocolGuid,
+ NULL,
+ &gPciIovPlatformProtocol
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gPciIovPlatformProtocol->GetSystemLowestPageSize (
+ gPciIovPlatformProtocol,
+ &SystemPageSize
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PcdSet32S (PcdSrIovSystemPageSize, (1 << SystemPageSize));
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) return Status;
+ } else {
+ return Status;
+ }
+ Status = gPciIovPlatformProtocol->GetPlatformPolicy (
+ gPciIovPlatformProtocol,
+ &PciIovPolicy
+ );
+ if (!EFI_ERROR (Status)) {
+ if (PciIovPolicy & EFI_PCI_IOV_POLICY_ARI) {
+ Status = PcdSetBoolS (PcdAriSupport, TRUE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) return Status;
+ } else {
+ Status = PcdSetBoolS (PcdAriSupport, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) return Status;
+ }
+ if (PciIovPolicy & EFI_PCI_IOV_POLICY_SRIOV) {
+ Status = PcdSetBoolS (PcdSrIovSupport, TRUE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) return Status;
+ } else {
+ Status = PcdSetBoolS (PcdSrIovSupport, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) return Status;
+ }
+ if (PciIovPolicy & EFI_PCI_IOV_POLICY_MRIOV) {
+ Status = PcdSetBoolS (PcdMrIovSupport, TRUE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) return Status;
+ } else {
+ Status = PcdSetBoolS (PcdMrIovSupport, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) return Status;
+ }
+ } else {
+ return Status;
+ }
+ DEBUG ((
+ EFI_D_INFO,
+ " Initialized SR-IOV Platform Data: PCIIovPolicy = 0x%x; SystemPageSize = 0x%x;\n",
+ PciIovPolicy, SystemPageSize
+ ));
+ } else {
+ DEBUG ((
+ EFI_D_INFO,
+ " Using default values for SystemPageSize;\n"
+ ));
+ }
+ return Status;
+}
+#endif
+
+/**
+
+ Platform Pci Express init.
+
+ @param HostBridgeInstance - Pointer to Host Bridge private data
+ does not support 64 bit memory addresses.
+
+ @retval EFI_SUCCESS - Success.
+
+**/
+EFI_STATUS
+PciPlatformEarlyInit (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ //
+ // Locate the IIO Protocol Interface
+ //
+ Status = gBS->LocateProtocol (&gEfiIioUdsProtocolGuid,NULL,&mIioUds);
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->LocateProtocol (&gEfiIioSystemProtocolGuid, NULL, &IioSystemProtocol);
+ ASSERT_EFI_ERROR (Status);
+
+ IioGlobalData = IioSystemProtocol->IioGlobalData;
+
+#ifdef EFI_PCI_IOV_SUPPORT
+ Status = PciPlatformInitPciIovData(); // Update IOV PCD values
+#endif
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ Init pci device registers after the device resources have been allocated, so
+ that devices behind a bus could be accessed.
+
+ @param HostBridgeInstance - PCI_HOST_BRIDGE_INSTANCE.
+
+ @retval EFI_SUCCESS - Function has completed successfully.
+
+**/
+EFI_STATUS
+PciPlatformPostInit (
+ VOID
+ )
+{
+ //
+ // Program all the IOAPIC in system
+ //
+ UINT8 Socket, Stack, IoApicId;
+ UINT8 Step;
+ UINT8 MaxSocket;
+
+#if MAX_SOCKET <= 4
+ Step = 6;
+ MaxSocket = 4;
+#else
+ Step = 4;
+ MaxSocket = 8;
+#endif
+
+ Stack = 0;
+ IoApicId = 0;
+ ProgramIoApicId (mIioUds->IioUdsPtr->PlatformData.IIO_resource[0].StackRes[0].IoApicBase, PcdGet8(PcdIoApicId));
+ for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+ if (!(mIioUds->IioUdsPtr->SystemStatus.socketPresentBitMap & (1 << Socket)))
+ continue;
+
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack)))
+ continue;
+
+ if ((Socket < MaxSocket) && (Stack < Step)) {
+ IoApicId = PcdGet8(PcdPcIoApicIdBase) + Step * Socket + Stack;
+ }
+
+ if ((Socket == 0) && (Stack == 0)) {
+ ProgramIoApicId ((mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].IoApicBase + 0x1000), IoApicId);
+ } else {
+ ProgramIoApicId (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].IoApicBase, IoApicId);
+ }
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+
+ The PlatformPrepController() function can be used to notify the platform driver so that
+ it can perform platform-specific actions. No specific actions are required.
+ Several notification points are defined at this time. More synchronization points may be
+ added as required in the future. The PCI bus driver calls the platform driver twice for
+ every PCI controller-once before the PCI Host Bridge Resource Allocation Protocol driver
+ is notified, and once after the PCI Host Bridge Resource Allocation Protocol driver has
+ been notified.
+ This member function may not perform any error checking on the input parameters. It also
+ does not return any error codes. If this member function detects any error condition, it
+ needs to handle those errors on its own because there is no way to surface any errors to
+ the caller.
+
+ @param This - Pointer to the EFI_PCI_PLATFORM_PROTOCOL instance.
+ @param HostBridge - The associated PCI host bridge handle.
+ @param RootBridge - The associated PCI root bridge handle.
+ @param PciAddress - The address of the PCI device on the PCI bus.
+ @param Phase - The phase of the PCI controller enumeration.
+ @param ChipsetPhase - Defines the execution phase of the PCI chipset driver.
+
+ @retval EFI_SUCCESS - The function completed successfully.
+ @retval EFI_UNSUPPORTED - Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformPrepController (
+ IN EFI_PCI_PLATFORM_PROTOCOL *This,
+ IN EFI_HANDLE HostBridge,
+ IN EFI_HANDLE RootBridge,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase,
+ IN EFI_PCI_CHIPSET_EXECUTION_PHASE ChipsetPhase
+ )
+{
+ if (mPciPrivateData.RootBridgeHandle == NULL) {
+ mPciPrivateData.RootBridgeHandle = RootBridge;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Perform initialization by the phase indicated.
+
+ @param This - Pointer to the EFI_PCI_PLATFORM_PROTOCOL instance.
+ @param HostBridge - The associated PCI host bridge handle.
+ @param Phase - The phase of the PCI controller enumeration.
+ @param ChipsetPhase - Defines the execution phase of the PCI chipset driver.
+
+ @retval EFI_SUCCESS - Must return with success.
+
+**/
+EFI_STATUS
+EFIAPI
+PhaseNotify (
+ IN EFI_PCI_PLATFORM_PROTOCOL *This,
+ IN EFI_HANDLE HostBridge,
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase,
+ IN EFI_PCI_CHIPSET_EXECUTION_PHASE ChipsetPhase
+ )
+{
+ EFI_STATUS Status;
+ UINT8 i;
+ UINT8 Stack;
+
+ if (ChipsetPhase == ChipsetEntry) {
+ return EFI_SUCCESS;
+ }
+ //
+ // If for multiple host bridges, need special consideration
+ //
+ switch (Phase) {
+
+ case EfiPciHostBridgeBeginEnumeration:
+ //
+ // Pre-initialization before PCI bus enumeration
+ // No bus number and no PCI resource
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ &(mPciPrivateData.PciRootBridgeIo)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (
+ &gEfiCpuIo2ProtocolGuid,
+ NULL,
+ &(mPciPrivateData.CpuIo)
+ );
+ ASSERT_EFI_ERROR (Status);
+ mPciPrivateData.Context.CpuIo = mPciPrivateData.CpuIo;
+
+ DEBUG ((DEBUG_ERROR, "PCI Platform Pre-Initialization (Before bus scanning)\n"));
+ PciPlatformEarlyInit ();
+ break;
+
+ case EfiPciHostBridgeEndBusAllocation:
+ //
+ // There are two rounds PCI bus scanning
+ // First round will initilize the PCI hotplug device
+ // Second round will be the final one
+ //
+ if (mPciPrivateData.BusAssignedTime == 0) {
+ mPciPrivateData.PciEnumerationPhase = EfiPciEnumerationDeviceScanning;
+ for (i = 0 ; i < MaxIIO ; i++) {
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[i].Valid) {
+ for(Stack = 0; Stack < MAX_IIO_STACK; Stack ++) {
+ PciTreeTraverse (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[i].StackBus[Stack]);
+ }
+ }
+ }
+ mPciPrivateData.BusAssignedTime++;
+ DEBUG ((DEBUG_ERROR, "PCI Platform bus assigned\n"));
+ }
+ break;
+
+ case EfiPciHostBridgeBeginResourceAllocation:
+ //
+ // PCI bus number has been assigned, but resource is still empty
+ //
+ DEBUG ((DEBUG_ERROR, "PCI Platform Mid-Initialization (After bus number assignment)\n"));
+ mPciPrivateData.PciEnumerationPhase = EfiPciEnumerationBusNumberAssigned;
+ for (i = 0 ; i < MaxIIO ; i++) {
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[i].Valid) {
+ for(Stack = 0; Stack < MAX_IIO_STACK; Stack ++) {
+ PciTreeTraverse (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[i].StackBus[Stack]);
+ }
+ }
+ }
+ //PciPlatformMidInit ();
+ break;
+
+ case EfiPciHostBridgeEndResourceAllocation:
+ //
+ // Resource enumeration is done.
+ // Both bus number and resource have been assigned
+ // Do any post initialization.
+ //
+ DEBUG ((DEBUG_ERROR, "PCI Platform Post-Initialization (After resource alloction)\n"));
+ mPciPrivateData.PciEnumerationPhase = EfiPciEnumerationResourceAssigned;
+ for (i = 0 ; i < MaxIIO ; i++) {
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[i].Valid) {
+ for(Stack = 0; Stack < MAX_IIO_STACK; Stack ++) {
+ PciTreeTraverse (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[i].StackBus[Stack]);
+ }
+ }
+ }
+ PciPlatformPostInit ();
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
|