From b7c51c9cf4864df6aabb99a1ae843becd577237c Mon Sep 17 00:00:00 2001 From: raywu Date: Fri, 15 Jun 2018 00:00:50 +0800 Subject: init. 1AQQW051 --- .../PciHostBridge/Dxe/PciRootBridgeIo.c | 1515 ++++++++++++++++++++ 1 file changed, 1515 insertions(+) create mode 100644 ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciRootBridgeIo.c (limited to 'ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciRootBridgeIo.c') diff --git a/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciRootBridgeIo.c b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciRootBridgeIo.c new file mode 100644 index 0000000..a3a0447 --- /dev/null +++ b/ReferenceCode/Chipset/SystemAgent/PciHostBridge/Dxe/PciRootBridgeIo.c @@ -0,0 +1,1515 @@ +/** @file + EFI Memory Controller PCI Root Bridge Io Protocol + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "PciRootBridge.h" +#include "Pci22.h" + +typedef struct { + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR SpaceDesp[TypeMax]; + EFI_ACPI_END_TAG_DESCRIPTOR EndDesp; +} RESOURCE_CONFIGURATION; + +RESOURCE_CONFIGURATION Configuration = { + { + { + 0x8A, + 0x2B, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }, + { + 0x8A, + 0x2B, + 0, + 0, + 0, + 32, + 0, + 0, + 0, + 0 + }, + { + 0x8A, + 0x2B, + 0, + 0, + 6, + 32, + 0, + 0, + 0, + 0 + }, + { + 0x8A, + 0x2B, + 0, + 0, + 0, + 64, + 0, + 0, + 0, + 0 + }, + { + 0x8A, + 0x2B, + 0, + 0, + 6, + 64, + 0, + 0, + 0, + 0 + }, + { + 0x8A, + 0x2B, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + } + }, + { + 0x79, + 0 + } +}; + +/// +/// Protocol Member Function Prototypes +/// +EFI_STATUS +EFIAPI +RootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +RootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ); + +EFI_STATUS +EFIAPI +RootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +RootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +RootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +RootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +EFI_STATUS +EFIAPI +RootBridgeIoCopyMem ( + IN struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ); + +EFI_STATUS +EFIAPI +RootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +RootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +EFI_STATUS +EFIAPI +RootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +EFI_STATUS +EFIAPI +RootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +EFI_STATUS +EFIAPI +RootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +EFI_STATUS +EFIAPI +RootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ); + +EFI_STATUS +EFIAPI +RootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +RootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ); + +EFI_STATUS +EFIAPI +RootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ); + +EFI_STATUS +EFIAPI +RootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ); + +/// +/// Sub Function Prototypes +/// +typedef union { + UINT8 VOLATILE *buf; + UINT8 VOLATILE *ui8; + UINT16 VOLATILE *ui16; + UINT32 VOLATILE *ui32; + UINT64 VOLATILE *ui64; + UINTN VOLATILE ui; +} PTR; + +STATIC +EFI_STATUS +RootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ); + +/// +/// Memory Controller Pci Root Bridge Io Module Variables +/// +EFI_METRONOME_ARCH_PROTOCOL *mMetronome; +EFI_CPU_IO_PROTOCOL *mCpuIo; + +/** + Construct the Pci Root Bridge Io protocol + + @param Protocol - Point to protocol instance + @param HostBridgeHandle - Handle of host bridge + @param Attri - Attribute of host bridge + @param ResAperture - ResourceAperture for host bridge + + @retval EFI_SUCCESS - Success to initialize the Pci Root Bridge. +**/ +EFI_STATUS +RootBridgeConstructor ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol, + IN EFI_HANDLE HostBridgeHandle, + IN UINT64 Attri, + IN PCI_ROOT_BRIDGE_RESOURCE_APERTURE *ResAperture + ) +{ + EFI_STATUS Status; + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + PCI_RESOURCE_TYPE Index; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (Protocol); + + /// + /// The host to pci bridge, the host memory and io addresses are + /// direct mapped to pci addresses, so no need translate, set bases to 0. + /// + PrivateData->MemBase = ResAperture->MemBase; + PrivateData->IoBase = ResAperture->IoBase; + + /// + /// The host bridge only supports 32bit addressing for memory + /// and standard IA32 16bit io + /// + PrivateData->MemLimit = ResAperture->MemLimit; + PrivateData->IoLimit = ResAperture->IoLimit; + + /// + /// Bus Aperture for this Root Bridge (Possible Range) + /// + PrivateData->BusBase = ResAperture->BusBase; + PrivateData->BusLimit = ResAperture->BusLimit; + + /// + /// Specific for this chipset + /// + for (Index = TypeIo; Index < TypeMax; Index++) { + PrivateData->ResAllocNode[Index].Type = Index; + PrivateData->ResAllocNode[Index].Base = 0; + PrivateData->ResAllocNode[Index].Length = 0; + PrivateData->ResAllocNode[Index].Status = ResNone; + } + + EfiInitializeLock (&PrivateData->PciLock, EFI_TPL_HIGH_LEVEL); + PrivateData->PciAddress = 0xCF8; + PrivateData->PciData = 0xCFC; + PrivateData->RootBridgeAttrib = Attri; + PrivateData->Attributes = 0; + /// + /// Set both ISA_IO and ISA_IO_16 / VGA_IO and VGA_IO_16 to co-work + /// with EDK and EDK2 PCI bus driver. + /// + PrivateData->Supports = EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO | + EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | + EFI_PCI_ATTRIBUTE_ISA_IO | + EFI_PCI_ATTRIBUTE_ISA_IO_16 | + EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | + EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16 | + EFI_PCI_ATTRIBUTE_VGA_MEMORY | + EFI_PCI_ATTRIBUTE_VGA_IO | + EFI_PCI_ATTRIBUTE_VGA_IO_16; + Protocol->ParentHandle = HostBridgeHandle; + Protocol->PollMem = RootBridgeIoPollMem; + Protocol->PollIo = RootBridgeIoPollIo; + Protocol->Mem.Read = RootBridgeIoMemRead; + Protocol->Mem.Write = RootBridgeIoMemWrite; + Protocol->Io.Read = RootBridgeIoIoRead; + Protocol->Io.Write = RootBridgeIoIoWrite; + Protocol->CopyMem = RootBridgeIoCopyMem; + Protocol->Pci.Read = RootBridgeIoPciRead; + Protocol->Pci.Write = RootBridgeIoPciWrite; + Protocol->Map = RootBridgeIoMap; + Protocol->Unmap = RootBridgeIoUnmap; + Protocol->AllocateBuffer = RootBridgeIoAllocateBuffer; + Protocol->FreeBuffer = RootBridgeIoFreeBuffer; + Protocol->Flush = RootBridgeIoFlush; + Protocol->GetAttributes = RootBridgeIoGetAttributes; + Protocol->SetAttributes = RootBridgeIoSetAttributes; + Protocol->Configuration = RootBridgeIoConfiguration; + Protocol->SegmentNumber = 0; + Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **) &mMetronome); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiCpuIoProtocolGuid, NULL, (VOID **) &mCpuIo); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +/** + Polls an address in memory mapped I/O space until an exit condition is met, or + a timeout occurs. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operations. + @param[in] Address - The base address of the memory operations. The caller is + responsible for aligning Address if required. + @param[in] Mask - Mask used for the polling criteria. Bytes above Width in Mask + are ignored. The bits in the bytes below Width which are zero in + Mask are ignored when polling the memory address. + @param[in] Value - The comparison value used for the polling exit criteria. + @param[in] Delay - The number of 100 ns units to poll. Note that timer available may + be of poorer granularity. + @param[out] Result - Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS - The last data returned from the access matched the poll exit criteria. + @retval EFI_INVALID_PARAMETER - Width is invalid or Result is NULL.. + @retval EFI_TIMEOUT - Delay expired before a match occurred. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPollMem ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + EFI_STATUS Status; + UINT64 NumberOfTicks; + UINT32 Remainder; + + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + /// + /// No matter what, always do a single poll. + /// + Status = This->Mem.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) == Value) { + return EFI_SUCCESS; + } + + if (Delay == 0) { + return EFI_SUCCESS; + } else { + /// + /// Determine the proper # of metronome ticks to wait for polling the + /// location. The nuber of ticks is Roundup (Delay / mMetronome->TickPeriod)+1 + /// The "+1" to account for the possibility of the first tick being short + /// because we started in the middle of a tick. + /// + NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod, &Remainder); + if (Remainder != 0) { + NumberOfTicks += 1; + } + + NumberOfTicks += 1; + while (NumberOfTicks) { + mMetronome->WaitForTick (mMetronome, 1); + Status = This->Mem.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) == Value) { + return EFI_SUCCESS; + } + + NumberOfTicks -= 1; + } + } + + return EFI_TIMEOUT; +} + +/** + Reads from the I/O space of a PCI Root Bridge. Returns when either the polling exit criteria is + satisfied or after a defined duration. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the I/O operations. + @param[in] Address - The base address of the I/O operations. The caller is responsible + for aligning Address if required. + @param[in] Mask - Mask used for the polling criteria. Bytes above Width in Mask + are ignored. The bits in the bytes below Width which are zero in + Mask are ignored when polling the I/O address. + @param[in] Value - The comparison value used for the polling exit criteria. + @param[in] Delay - The number of 100 ns units to poll. Note that timer available may + be of poorer granularity. + @param[out] Result - Pointer to the last value read from the memory location. + + @retval EFI_SUCCESS - The last data returned from the access matched the poll exit criteria. + @retval EFI_INVALID_PARAMETER - Width is invalid or Result is NULL. + @retval EFI_TIMEOUT - Delay expired before a match occurred. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPollIo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + EFI_STATUS Status; + UINT64 NumberOfTicks; + UINT32 Remainder; + + /// + /// No matter what, always do a single poll. + /// + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + Status = This->Io.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) == Value) { + return EFI_SUCCESS; + } + + if (Delay == 0) { + return EFI_SUCCESS; + } else { + /// + /// Determine the proper # of metronome ticks to wait for polling the + /// location. The number of ticks is Roundup (Delay / mMetronome->TickPeriod)+1 + /// The "+1" to account for the possibility of the first tick being short + /// because we started in the middle of a tick. + /// + NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod, &Remainder); + if (Remainder != 0) { + NumberOfTicks += 1; + } + + NumberOfTicks += 1; + while (NumberOfTicks) { + mMetronome->WaitForTick (mMetronome, 1); + Status = This->Io.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) == Value) { + return EFI_SUCCESS; + } + + NumberOfTicks -= 1; + } + } + + return EFI_TIMEOUT; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operation. + @param[in] Address - The base address of the memory operation. The caller is + responsible for aligning the Address if required. + @param[in] Count - The number of memory operations to perform. Bytes moved is + Width size * Count, starting at Address. + @param[in, out] Buffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoMemRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OldWidth; + UINTN OldCount; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + +// AMI_OVERRIDE (EIP#106042+)>> + // Fix Fpt.efi not work, accessing Rom decode region could cause AEL bit + // be set, and, Pci Resource should not be inside rom decode region. + if ((Address >= 0xff000000) && (Address <= 0xffffffff)) { + return EFI_INVALID_PARAMETER; + } +// AMI_OVERRIDE << + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + /// + /// Check memory access limit + /// + if (Address < PrivateData->MemBase) { + return EFI_INVALID_PARAMETER; + } + + OldWidth = Width; + OldCount = Count; + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + Count = 1; + } + + Width &= 0x03; + if (Address + MultU64x32 (LShiftU64 (1, Width), (UINT32) Count) - 1 > PrivateData->MemLimit) { + return EFI_INVALID_PARAMETER; + } + + return mCpuIo->Mem.Read ( + mCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth, + Address, + OldCount, + Buffer + ); +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operation. + @param[in] Address - The base address of the memory operation. The caller is + responsible for aligning the Address if required. + @param[in] Count - The number of memory operations to perform. Bytes moved is + Width size * Count, starting at Address. + @param[in, out] Buffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoMemWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OldWidth; + UINTN OldCount; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + /// + /// Check memory access limit + /// + if (Address < PrivateData->MemBase) { + return EFI_INVALID_PARAMETER; + } + + OldWidth = Width; + OldCount = Count; + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + Count = 1; + } + + Width &= 0x03; + if (Address + MultU64x32 (LShiftU64 (1, Width), (UINT32) Count) - 1 > PrivateData->MemLimit) { + return EFI_INVALID_PARAMETER; + } + + return mCpuIo->Mem.Write ( + mCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth, + Address, + OldCount, + Buffer + ); +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge I/O space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operations. + @param[in] UserAddress - The base address of the I/O operation. The caller is responsible for + aligning the Address if required. + @param[in] Count - The number of I/O operations to perform. Bytes moved is Width + size * Count, starting at Address. + @param[in, out] UserBuffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + + UINTN AlignMask; + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OldWidth; + UINTN OldCount; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + /// + /// AlignMask = (1 << Width) - 1; + /// + AlignMask = (1 << (Width & 0x03)) - 1; + + /// + /// Check Io access limit + /// + if (Address < PrivateData->IoBase) { + return EFI_INVALID_PARAMETER; + } + + OldWidth = Width; + OldCount = Count; + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + Count = 1; + } + + Width &= 0x03; + if (Address + MultU64x32 (LShiftU64 (1, Width), (UINT32) Count) - 1 >= PrivateData->IoLimit) { + return EFI_INVALID_PARAMETER; + } + + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + return mCpuIo->Io.Read ( + mCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth, + Address, + OldCount, + Buffer + ); +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge I/O space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operations. + @param[in] UserAddress - The base address of the I/O operation. The caller is responsible for + aligning the Address if required. + @param[in] Count - The number of I/O operations to perform. Bytes moved is Width + size * Count, starting at Address. + @param[in, out] UserBuffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + UINTN AlignMask; + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OldWidth; + UINTN OldCount; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + /// + /// AlignMask = (1 << Width) - 1; + /// + AlignMask = (1 << (Width & 0x03)) - 1; + + /// + /// Check Io access limit + /// + if (Address < PrivateData->IoBase) { + return EFI_INVALID_PARAMETER; + } + + OldWidth = Width; + OldCount = Count; + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + Count = 1; + } + + Width &= 0x03; + if (Address + MultU64x32 (LShiftU64 (1, Width), (UINT32) Count) - 1 >= PrivateData->IoLimit) { + return EFI_INVALID_PARAMETER; + } + + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + return mCpuIo->Io.Write ( + mCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth, + Address, + OldCount, + Buffer + ); +} + +/** + Enables a PCI driver to copy one region of PCI root bridge memory space to another region of PCI + root bridge memory space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance. + @param[in] Width - Signifies the width of the memory operations. + @param[in] DestAddress - The destination address of the memory operation. The caller is + responsible for aligning the DestAddress if required. + @param[in] SrcAddress - The source address of the memory operation. The caller is + responsible for aligning the SrcAddress if required. + @param[in] Count - The number of memory operations to perform. Bytes moved is + Width size * Count, starting at DestAddress and SrcAddress. + + @retval EFI_SUCCESS - The data was copied from one memory region to another memory region. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoCopyMem ( + IN struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 DestAddress, + IN UINT64 SrcAddress, + IN UINTN Count + ) +{ + EFI_STATUS Status; + BOOLEAN Direction; + UINTN Stride; + UINTN Index; + UINT64 Result; + + if (Width < 0 || Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + if (DestAddress == SrcAddress) { + return EFI_SUCCESS; + } + + Stride = (UINTN) (LShiftU64 (1, Width)); + Direction = TRUE; + if ((DestAddress > SrcAddress) && (DestAddress < (SrcAddress + Count * Stride))) { + Direction = FALSE; + SrcAddress = SrcAddress + (Count - 1) * Stride; + DestAddress = DestAddress + (Count - 1) * Stride; + } + + for (Index = 0; Index < Count; Index++) { + Status = RootBridgeIoMemRead ( + This, + Width, + SrcAddress, + 1, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = RootBridgeIoMemWrite ( + This, + Width, + DestAddress, + 1, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Direction) { + SrcAddress += Stride; + DestAddress += Stride; + } else { + SrcAddress -= Stride; + DestAddress -= Stride; + } + } + + return EFI_SUCCESS; +} + +/** + Enables a PCI driver to access PCI controller registers in a PCI root bridge's configuration space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operations. + @param[in] Address - The address within the PCI configuration space for the PCI controller. + @param[in] Count - The number of PCI configuration operations to perform. Bytes + moved is Width size * Count, starting at Address. + @param[in, out] Buffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPciRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + /// + /// Read Pci configuration space + /// + return RootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer); +} + +/** + Enables a PCI driver to access PCI controller registers in a PCI root bridge's configuration space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Width - Signifies the width of the memory operations. + @param[in] Address - The address within the PCI configuration space for the PCI controller. + @param[in] Count - The number of PCI configuration operations to perform. Bytes + moved is Width size * Count, starting at Address. + @param[in, out] Buffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoPciWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + /// + /// Write Pci configuration space + /// + return RootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer); +} + +/** + Provides the PCI controller-specific addresses required to access system memory from a + DMA bus master. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Operation - Indicates if the bus master is going to read or write to system memory. + @param[in] HostAddress - The system memory address to map to the PCI controller. + @param[in, out] NumberOfBytes - On input the number of bytes to map. On output the number of bytes that were mapped. + @param[out] DeviceAddress - The resulting map address for the bus master PCI controller to use + to access the system memory's HostAddress. + @param[out] Mapping - The value to pass to Unmap() when the bus master DMA operation is complete. + + @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes. + @retval EFI_INVALID_PARAMETER - Operation is invalid. + @retval EFI_INVALID_PARAMETER - HostAddress or NumberOfBytes or DeviceAddress or Mapping is NULL. + @retval EFI_UNSUPPORTED - The HostAddress cannot be mapped as a common buffer. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoMap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + MAP_INFO *MapInfo; + + if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) { + return EFI_INVALID_PARAMETER; + } + /// + /// Initialize the return values to their defaults + /// + *Mapping = NULL; + + /// + /// Make sure that Operation is valid + /// + if (Operation < 0 || Operation >= EfiPciOperationMaximum) { + return EFI_INVALID_PARAMETER; + } + /// + /// Most PCAT like chipsets can not handle performing DMA above 4GB. + /// If any part of the DMA transfer being mapped is above 4GB, then + /// map the DMA transfer to a buffer below 4GB. + /// + PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress; + if ((PhysicalAddress +*NumberOfBytes) > 0x100000000) { + /// + /// Common Buffer operations can not be remapped. If the common buffer + /// if above 4GB, then it is not possible to generate a mapping, so return + /// an error. + /// + if (Operation == EfiPciOperationBusMasterCommonBuffer || Operation == EfiPciOperationBusMasterCommonBuffer64) { + return EFI_UNSUPPORTED; + } + /// + /// Allocate a MAP_INFO structure to remember the mapping when Unmap() is + /// called later. + /// + Status = (gBS->AllocatePool) (EfiBootServicesData, sizeof (MAP_INFO), (VOID **) &MapInfo); + if (EFI_ERROR (Status)) { + *NumberOfBytes = 0; + return Status; + } + /// + /// Return a pointer to the MAP_INFO structure in Mapping + /// + *Mapping = MapInfo; + + /// + /// Initialize the MAP_INFO structure + /// + MapInfo->Operation = Operation; + MapInfo->NumberOfBytes = *NumberOfBytes; + MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes); + MapInfo->HostAddress = PhysicalAddress; + MapInfo->MappedHostAddress = 0x00000000ffffffff; + + /// + /// Allocate a buffer below 4GB to map the transfer to. + /// + Status = (gBS->AllocatePages) (AllocateMaxAddress, EfiBootServicesData, MapInfo->NumberOfPages, &MapInfo->MappedHostAddress); + if (EFI_ERROR (Status)) { + (gBS->FreePool) (MapInfo); + *NumberOfBytes = 0; + return Status; + } + /// + /// If this is a read operation from the Bus Master's point of view, + /// then copy the contents of the real buffer into the mapped buffer + /// so the Bus Master can read the contents of the real buffer. + /// + if (Operation == EfiPciOperationBusMasterRead || Operation == EfiPciOperationBusMasterRead64) { + CopyMem ( + (VOID *) (UINTN) MapInfo->MappedHostAddress, + (VOID *) (UINTN) MapInfo->HostAddress, + MapInfo->NumberOfBytes + ); + } + /// + /// The DeviceAddress is the address of the maped buffer below 4GB + /// + *DeviceAddress = MapInfo->MappedHostAddress; + } else { + /// + /// The transfer is below 4GB, so the DeviceAddress is simply the HostAddress + /// + *DeviceAddress = PhysicalAddress; + } + + return EFI_SUCCESS; +} + +/** + Completes the Map() operation and releases any corresponding resources. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Mapping - The mapping value returned from Map(). + + @retval EFI_SUCCESS - The range was unmapped. + @retval EFI_INVALID_PARAMETER - Mapping is not a value that was returned by Map(). +**/ +EFI_STATUS +EFIAPI +RootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ) +{ + MAP_INFO *MapInfo; + + /// + /// See if the Map() operation associated with this Unmap() required a mapping buffer. + /// If a mapping buffer was not required, then this function simply returns EFI_SUCCESS. + /// + if (Mapping != NULL) { + /// + /// Get the MAP_INFO structure from Mapping + /// + MapInfo = (MAP_INFO *) Mapping; + + /// + /// If this is a write operation from the Bus Master's point of view, + /// then copy the contents of the mapped buffer into the real buffer + /// so the processor can read the contents of the real buffer. + /// + if (MapInfo->Operation == EfiPciOperationBusMasterWrite || MapInfo->Operation == EfiPciOperationBusMasterWrite64) { + CopyMem ( + (VOID *) (UINTN) MapInfo->HostAddress, + (VOID *) (UINTN) MapInfo->MappedHostAddress, + MapInfo->NumberOfBytes + ); + } + /// + /// Free the mapped buffer and the MAP_INFO structure. + /// + (gBS->FreePages) (MapInfo->MappedHostAddress, MapInfo->NumberOfPages); + (gBS->FreePool) (Mapping); + } + + return EFI_SUCCESS; +} + +/** + Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer or + EfiPciOperationBusMasterCommonBuffer64 mapping. + + @param This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Type - This parameter is not used and must be ignored. + @param MemoryType - The type of memory to allocate, EfiBootServicesData or EfiRuntimeServicesData. + @param Pages - The number of pages to allocate. + @param HostAddress - A pointer to store the base system memory address of the allocated range. + @param Attributes - The requested bit mask of attributes for the allocated range. Only + the attributes EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE, EFI_PCI_ATTRIBUTE_MEMORY_CACHED, + and EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE may be used with this function. + + @retval EFI_SUCCESS - The requested memory pages were allocated. + @retval EFI_INVALID_PARAMETER - MemoryType is invalid or HostAddress is NULL. + @retval EFI_UNSUPPORTED - Attributes is unsupported. The only legal attribute bits are + MEMORY_WRITE_COMBINE, MEMORY_CACHED, and DUAL_ADDRESS_CYCLE. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoAllocateBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + + /// + /// Validate Attributes + /// + if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) { + return EFI_UNSUPPORTED; + } + /// + /// Check for invalid inputs + /// + if (HostAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + /// + /// The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData + /// + if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) { + return EFI_INVALID_PARAMETER; + } + /// + /// Limit allocations to memory below 4GB + /// + PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (0xffffffff); + Status = (gBS->AllocatePages) (AllocateMaxAddress, MemoryType, Pages, &PhysicalAddress); + if (EFI_ERROR (Status)) { + return Status; + } + + *HostAddress = (VOID *) (UINTN) PhysicalAddress; + return EFI_SUCCESS; +} + +/** + Frees memory that was allocated with AllocateBuffer(). + + The FreeBuffer() function frees memory that was allocated with AllocateBuffer(). + + @param This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Pages - The number of pages to free. + @param HostAddress - The base system memory address of the allocated range. + + @retval EFI_SUCCESS - The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER - The memory range specified by HostAddress and Pages + was not allocated with AllocateBuffer(). +**/ +EFI_STATUS +EFIAPI +RootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ) +{ + return (gBS->FreePages) ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages); +} + +/** + Flushes all PCI posted write transactions from a PCI host bridge to system memory. + + @param This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + + @retval EFI_SUCCESS - The PCI posted write transactions were flushed from the PCI host + bridge to system memory. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ) +{ + /// + /// not supported yet + /// + return EFI_SUCCESS; +} + +/** + Gets the attributes that a PCI root bridge supports setting with SetAttributes(), and the + attributes that a PCI root bridge is currently using. + + @param This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Supported - A pointer to the mask of attributes that this PCI root bridge + supports setting with SetAttributes(). + @param Attributes - A pointer to the mask of attributes that this PCI root bridge is + currently using. + + @retval EFI_SUCCESS - If Supports is not NULL, then the attributes that the PCI root + bridge supports is returned in Supports. If Attributes is + not NULL, then the attributes that the PCI root bridge is currently + using is returned in Attributes. + @retval EFI_INVALID_PARAMETER - Both Supports and Attributes are NULL. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ) +{ + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + if (Attributes == NULL && Supported == NULL) { + return EFI_INVALID_PARAMETER; + } + /// + /// Set the return value for Supported and Attributes + /// + if (Supported) { + *Supported = PrivateData->Supports; + } + + if (Attributes) { + *Attributes = PrivateData->Attributes; + } + + return EFI_SUCCESS; +} + +/** + Sets attributes for a resource range on a PCI root bridge. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Attributes - The mask of attributes to set. If the attribute bit + MEMORY_WRITE_COMBINE, MEMORY_CACHED, or + MEMORY_DISABLE is set, then the resource range is specified by + ResourceBase and ResourceLength. If + MEMORY_WRITE_COMBINE, MEMORY_CACHED, and + MEMORY_DISABLE are not set, then ResourceBase and + ResourceLength are ignored, and may be NULL. + @param[in, out] ResourceBase - A pointer to the base address of the resource range to be modified + by the attributes specified by Attributes. + @param[in, out] ResourceLength - A pointer to the length of the resource range to be modified by the + attributes specified by Attributes. + + @retval EFI_SUCCESS - The current configuration of this PCI root bridge was returned in Resources. + @retval EFI_UNSUPPORTED - The current configuration of this PCI root bridge could not be retrieved. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ) +{ + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + if (Attributes) { + if ((Attributes & (~(PrivateData->Supports))) != 0) { + return EFI_UNSUPPORTED; + } + } + + if (Attributes == PrivateData->Attributes) { + return EFI_SUCCESS; + } + /// + /// It is just a trick for some attribute can only be enabled or disabled + /// otherwise it can impact on other devices + /// + PrivateData->Attributes = Attributes; + return EFI_SUCCESS; +} + +/** + Retrieves the current resource settings of this PCI root bridge in the form of a set of ACPI 2.0 + resource descriptors. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[out] Resources - A pointer to the ACPI 2.0 resource descriptors that describe the + current configuration of this PCI root bridge. The storage for the + ACPI 2.0 resource descriptors is allocated by this function. The + caller must treat the return buffer as read-only data, and the buffer + must not be freed by the caller. + + @retval EFI_SUCCESS - The current configuration of this PCI root bridge was returned in Resources. +**/ +EFI_STATUS +EFIAPI +RootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ) +{ + PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + UINTN Index; + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + for (Index = 0; Index < TypeMax; Index++) { + if (PrivateData->ResAllocNode[Index].Status == ResAllocated) { + Configuration.SpaceDesp[Index].AddrRangeMin = PrivateData->ResAllocNode[Index].Base; + Configuration.SpaceDesp[Index].AddrRangeMax = PrivateData->ResAllocNode[Index].Base + + PrivateData->ResAllocNode[Index].Length - + 1; + Configuration.SpaceDesp[Index].AddrLen = PrivateData->ResAllocNode[Index].Length; + } + } + + *Resources = &Configuration; + return EFI_SUCCESS; +} + +/** + Internal help function for read and write PCI configuration space. + + @param[in] This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param[in] Write - Switch value for Read or Write. + @param[in] Width - Signifies the width of the memory operations. + @param[in] UserAddress - The address within the PCI configuration space for the PCI controller. + @param[in] Count - The number of PCI configuration operations to perform. Bytes + moved is Width size * Count, starting at Address. + @param[in, out] UserBuffer - For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS - The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER - Width is invalid for this PCI root bridge or Buffer is NULL. +**/ +STATIC +EFI_STATUS +RootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + UINT32 InStride; + UINT32 OutStride; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *PciRbAddr; + UINT8 *PcieRegAddr; + + if ((Width & 0x03) >= EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { + InStride = 0; + } + + if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) { + OutStride = 0; + } + + PciRbAddr = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &UserAddress; + PcieRegAddr = (UINT8 *) MmPciAddress ( + 0, /// No segment support + PciRbAddr->Bus, + PciRbAddr->Device, + PciRbAddr->Function, + 0 /// Register is added next + ); + + /// + /// Add the register offset to the address + /// + if (PciRbAddr->ExtendedRegister != 0) { + PcieRegAddr += PciRbAddr->ExtendedRegister; + } else { + PcieRegAddr += PciRbAddr->Register; + } + + while (Count) { + if (Write) { + This->Mem.Write (This, Width, (UINTN) PcieRegAddr, 1, UserBuffer); + } else { + This->Mem.Read (This, Width, (UINTN) PcieRegAddr, 1, UserBuffer); + } + + UserBuffer = ((UINT8 *) UserBuffer) + OutStride; + PcieRegAddr += InStride; + Count -= 1; + } + + return EFI_SUCCESS; +} -- cgit v1.2.3