Hi,
I send a patchset adding support for PciEmulation driver, based on similar solution for Omap35xx platform. It allows for enabling PCI drivers for platform devices, such as XHCI, AHCI, SDHCI, of which first two are enclosed. Although it's 7 patches, only first one comprise of bigger amount of code and it's fairly not complicated.
The patches can be found in the github: https://github.com/MarvellEmbeddedProcessors/edk2-open-platform/commits/opp-...
I'm looking forward to your comments or remarks.
Best regards, Marcin
Jan Dąbroś (7): Platforms/Marvell: Add PciEmulation driver Platforms/Marvell: Enable PciEmulation driver for Armada70x0 platform Platforms/Marvell: Enable USB stack for Armada70x0 platform Platforms/Marvell: Enable two xHCI ports for Armada70x0 board Platforms/Marvell: Enable SATA stack for Armada70x0 platform Platforms/Marvell: Add support for SATA devices in PciEmulation Platforms/Marvell: Enable SATA port for Armada70x0 board
.../Marvell/PortingGuide/PciEmulation.txt | 53 ++ Documentation/Marvell/PortingGuide/Sata.txt | 16 + Platforms/Marvell/Armada/Armada.dsc.inc | 17 + Platforms/Marvell/Armada/Armada70x0.dsc | 18 + Platforms/Marvell/Armada/Armada70x0.fdf | 17 + Platforms/Marvell/Marvell.dec | 17 +- Platforms/Marvell/PciEmulation/PciEmulation.c | 790 +++++++++++++++++++++ Platforms/Marvell/PciEmulation/PciEmulation.h | 277 ++++++++ Platforms/Marvell/PciEmulation/PciEmulation.inf | 67 ++ Platforms/Marvell/PciEmulation/PciRootBridgeIo.c | 314 ++++++++ 10 files changed, 1583 insertions(+), 3 deletions(-) create mode 100644 Documentation/Marvell/PortingGuide/PciEmulation.txt create mode 100644 Documentation/Marvell/PortingGuide/Sata.txt create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.c create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.h create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.inf create mode 100644 Platforms/Marvell/PciEmulation/PciRootBridgeIo.c
From: Jan Dąbroś jsd@semihalf.com
In order to use numerous UEFI drivers based on PCI bus, PciEmulation driver is implemented. This solution is based on Chips/TexasInstruments/Omap35xx/PciEmulation/ Configuring fake devices is performed via PCD.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- .../Marvell/PortingGuide/PciEmulation.txt | 53 ++ Platforms/Marvell/Marvell.dec | 8 + Platforms/Marvell/PciEmulation/PciEmulation.c | 678 +++++++++++++++++++++ Platforms/Marvell/PciEmulation/PciEmulation.h | 271 ++++++++ Platforms/Marvell/PciEmulation/PciEmulation.inf | 65 ++ Platforms/Marvell/PciEmulation/PciRootBridgeIo.c | 314 ++++++++++ 6 files changed, 1389 insertions(+) create mode 100644 Documentation/Marvell/PortingGuide/PciEmulation.txt create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.c create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.h create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.inf create mode 100644 Platforms/Marvell/PciEmulation/PciRootBridgeIo.c
diff --git a/Documentation/Marvell/PortingGuide/PciEmulation.txt b/Documentation/Marvell/PortingGuide/PciEmulation.txt new file mode 100644 index 0000000..5bb812a --- /dev/null +++ b/Documentation/Marvell/PortingGuide/PciEmulation.txt @@ -0,0 +1,53 @@ +PciEmulation configuration +-------------------------- +Instalation of various Pci devices via PciEmulation driver is performed via set +of PCDs. Following are available: + + gMarvellTokenSpaceGuid.PcdPciEDevCount + +Indicates how many fake Pci devices are placed on board. + +Next five PCDs are in unicode string, format containing settings for all devices +separated with semicolon. + + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress + +Indicates base address of Pci device register space. + + gMarvellTokenSpaceGuid.PcdPciEDevRegSize + +Indicates size of Pci device register space. + + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1 + +Indicates device subclass code. + + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2 + +Indicates device class code. + + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3 + +Indicates Pci device class code. + +Examples +-------- +Assuming that there are two fake Pci xHCI controllers with register space +0xF2500000 - 0xF2510000 and 0xF2510000 - 0xF2520000 following PCD values should +be set: + + gMarvellTokenSpaceGuid.PcdPciEDevCount|2 + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000" + gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000" + ## XHCI subclass + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30" + ## USB controller class + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03" + ## Serial bus controller Pci device class + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C" + +Notes +----- +1.In order to find proper values for Pci class codes, please refer to + PCI Local Bus Specification. +2.PCDs are configured via UNICODE strings - remember to add L marker. diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index db99230..f56987d 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -209,6 +209,14 @@ gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress|0|UINT64|0x3000031 gMarvellTokenSpaceGuid.PcdPp2XlgDevSize|0|UINT32|0x3000032
+#PciEmulation + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|{ 0x0 }|VOID*|0x30000058 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|{ 0x0 }|VOID*|0x30000059 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|{ 0x0 }|VOID*|0x30000060 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|{ 0x0 }|VOID*|0x30000061 + gMarvellTokenSpaceGuid.PcdPciEDevCount|0|UINT32|0x30000062 + gMarvellTokenSpaceGuid.PcdPciEDevRegSize|{ 0x0 }|VOID*|0x30000063 + #ResetLib gMarvellTokenSpaceGuid.PcdResetRegAddress|0|UINT64|0x40000050 gMarvellTokenSpaceGuid.PcdResetRegMask|0|UINT32|0x4000051 diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.c b/Platforms/Marvell/PciEmulation/PciEmulation.c new file mode 100644 index 0000000..a800bcb --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.c @@ -0,0 +1,678 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + Copyright (c) 2016, Marvell. All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD + License which 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 "PciEmulation.h" + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + PCI_DEVICE_PATH PciDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_IO_DEVICE_PATH; + +typedef struct { + UINT32 Signature; + EFI_PCI_IO_DEVICE_PATH DevicePath; + EFI_PCI_IO_PROTOCOL PciIoProtocol; + PCI_TYPE00 *ConfigSpace; + PCI_ROOT_BRIDGE RootBridge; + UINTN Segment; +} EFI_PCI_IO_PRIVATE_DATA; + +#define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o') +#define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_PCI_IO_PRIVATE_DATA, \ + PciIoProtocol, \ + EFI_PCI_IO_PRIVATE_DATA_SIGNATURE) + +EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate = +{ + { + { + ACPI_DEVICE_PATH, + ACPI_DP, + { + sizeof (ACPI_HID_DEVICE_PATH), + 0 + } + }, + EISA_PNP_ID(0x0A03), // HID + 0 // UID + }, + { + { + HARDWARE_DEVICE_PATH, + HW_PCI_DP, + { + sizeof (PCI_DEVICE_PATH), + 0 + } + }, + 0, + 0 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + sizeof (EFI_DEVICE_PATH_PROTOCOL), + 0 + } + } +}; + +EFI_STATUS +PciIoPollMem ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoPollIo ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINT64 Mask, + IN UINT64 Value, + IN UINT64 Delay, + OUT UINT64 *Result + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoMemRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This); + + return PciRootBridgeIoMemRead ( + &Private->RootBridge.Io, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Private->ConfigSpace->Device.Bar[BarIndex] + Offset, + Count, + Buffer + ); +} + +EFI_STATUS +PciIoMemWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This); + + return PciRootBridgeIoMemWrite ( + &Private->RootBridge.Io, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Private->ConfigSpace->Device.Bar[BarIndex] + Offset, + Count, + Buffer + ); +} + +EFI_STATUS +PciIoIoRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + ASSERT (FALSE); + + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoIoWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + ASSERT (FALSE); + + return EFI_UNSUPPORTED; +} + +/** + Enable a PCI driver to read PCI controller registers in + PCI configuration space. + + @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] Width Signifies the width of the memory operations. + @param[in] Offset The offset 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 Offset. + + @param[in out] Buffer The destination buffer to store the results. + + @retval EFI_SUCCESS The data was read from the PCI controller. + @retval EFI_INVALID_PARAMETER "Width" is invalid. + @retval EFI_INVALID_PARAMETER "Buffer" is NULL. + +**/ +EFI_STATUS +PciIoPciRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This); + + if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + return PciRootBridgeIoMemRW ( + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width, + Count, + TRUE, + (PTR)(UINTN)Buffer, + TRUE, + (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset) + ); +} + +/** + Enable a PCI driver to write PCI controller registers in + PCI configuration space. + + @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] Width Signifies the width of the memory operations. + @param[in] Offset The offset 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 Offset. + + @param[in out] Buffer The source buffer to write data from. + + @retval EFI_SUCCESS The data was read from the PCI controller. + @retval EFI_INVALID_PARAMETER "Width" is invalid. + @retval EFI_INVALID_PARAMETER "Buffer" is NULL. + +**/ +EFI_STATUS +PciIoPciWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This); + + if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + return PciRootBridgeIoMemRW ( + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Count, + TRUE, + (PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset), + TRUE, + (PTR)(UINTN)Buffer + ); +} + +EFI_STATUS +PciIoCopyMem ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 DestBarIndex, + IN UINT64 DestOffset, + IN UINT8 SrcBarIndex, + IN UINT64 SrcOffset, + IN UINTN Count + ) +{ + ASSERT (FALSE); + + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoMap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_OPERATION Operation, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ) +{ + DMA_MAP_OPERATION DmaOperation; + + if (Operation == EfiPciIoOperationBusMasterRead) { + DmaOperation = MapOperationBusMasterRead; + } else if (Operation == EfiPciIoOperationBusMasterWrite) { + DmaOperation = MapOperationBusMasterWrite; + } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) { + DmaOperation = MapOperationBusMasterCommonBuffer; + } else { + return EFI_INVALID_PARAMETER; + } + + return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping); +} + +EFI_STATUS +PciIoUnmap ( + IN EFI_PCI_IO_PROTOCOL *This, + IN VOID *Mapping + ) +{ + return DmaUnmap (Mapping); +} + +/** + Allocate pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer + mapping. + + @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] Type This parameter is not used and must be ignored. + @param[in] MemoryType The type of memory to allocate, EfiBootServicesData + or EfiRuntimeServicesData. + @param[in] Pages The number of pages to allocate. + @param[out] HostAddress A pointer to store the base system memory address of + the allocated range. + @param[in] Attributes The requested bit mask of attributes for the + allocated range. Only the attributes, + EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE and + EFI_PCI_ATTRIBUTE_MEMORY_CACHED may be used with + this function. If any other bits are set, then + EFI_UNSUPPORTED is returned. This function ignores + this bit mask. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_INVALID_PARAMETER HostAddress is NULL. + @retval EFI_INVALID_PARAMETER MemoryType is invalid. + @retval EFI_UNSUPPORTED Attributes is unsupported. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +EFI_STATUS +PciIoAllocateBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ) +{ + if (Attributes & (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) { + return EFI_UNSUPPORTED; + } + + return DmaAllocateBuffer (MemoryType, Pages, HostAddress); +} + + +EFI_STATUS +PciIoFreeBuffer ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ) +{ + return DmaFreeBuffer (Pages, HostAddress); +} + + +EFI_STATUS +PciIoFlush ( + IN EFI_PCI_IO_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} + +/** + Retrieves this PCI controller's current PCI bus number, device number, and + function number. + + @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[out] SegmentNumber The PCI controller's current PCI segment number. + @param[out] BusNumber The PCI controller's current PCI bus number. + @param[out] DeviceNumber The PCI controller's current PCI device number. + @param[out] FunctionNumber The PCI controller’s current PCI function number. + + @retval EFI_SUCCESS The PCI controller location was returned. + @retval EFI_INVALID_PARAMETER At least one out of the four output parameters + is a NULL pointer. +**/ +EFI_STATUS +PciIoGetLocation ( + IN EFI_PCI_IO_PROTOCOL *This, + OUT UINTN *SegmentNumber, + OUT UINTN *BusNumber, + OUT UINTN *DeviceNumber, + OUT UINTN *FunctionNumber + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This); + + if ((SegmentNumber == NULL) || (BusNumber == NULL) || + (DeviceNumber == NULL) || (FunctionNumber == NULL)) { + return EFI_INVALID_PARAMETER; + } + + *SegmentNumber = Private->Segment; + *BusNumber = 0xff; + *DeviceNumber = 0; + *FunctionNumber = 0; + + return EFI_SUCCESS; +} + +/** + Performs an operation on the attributes that this PCI controller supports. + + The operations include getting the set of supported attributes, retrieving + the current attributes, setting the current attributes, enabling attributes, + and disabling attributes. + + @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance. + @param[in] Operation The operation to perform on the attributes for this + PCI controller. + @param[in] Attributes The mask of attributes that are used for Set, + Enable and Disable operations. + @param[out] Result A pointer to the result mask of attributes that are + returned for the Get and Supported operations. This + is an optional parameter that may be NULL for the + Set, Enable, and Disable operations. + + @retval EFI_SUCCESS The operation on the PCI controller's + attributes was completed. If the operation + was Get or Supported, then the attribute mask + is returned in Result. + @retval EFI_INVALID_PARAMETER Operation is greater than or equal to + EfiPciIoAttributeOperationMaximum. + @retval EFI_INVALID_PARAMETER Operation is Get and Result is NULL. + @retval EFI_INVALID_PARAMETER Operation is Supported and Result is NULL. + +**/ +EFI_STATUS +PciIoAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, + IN UINT64 Attributes, + OUT UINT64 *Result OPTIONAL + ) +{ + switch (Operation) { + case EfiPciIoAttributeOperationGet: + case EfiPciIoAttributeOperationSupported: + if (Result == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // We are not a real PCI device so just say things we kind of do + // + *Result = EFI_PCI_DEVICE_ENABLE; + break; + + case EfiPciIoAttributeOperationSet: + case EfiPciIoAttributeOperationEnable: + case EfiPciIoAttributeOperationDisable: + if (Attributes & (~EFI_PCI_DEVICE_ENABLE)) { + return EFI_UNSUPPORTED; + } + + // + // Since we are not a real PCI device no enable/set or + // disable operations exist. + // + return EFI_SUCCESS; + + default: + return EFI_INVALID_PARAMETER; + }; + + return EFI_SUCCESS; +} + +EFI_STATUS +PciIoGetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT8 BarIndex, + OUT UINT64 *Supports, OPTIONAL + OUT VOID **Resources OPTIONAL + ) +{ + ASSERT (FALSE); + + return EFI_UNSUPPORTED; +} + +EFI_STATUS +PciIoSetBarAttributes ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN UINT8 BarIndex, + IN OUT UINT64 *Offset, + IN OUT UINT64 *Length + ) +{ + ASSERT (FALSE); + + return EFI_UNSUPPORTED; +} + +EFI_PCI_IO_PROTOCOL PciIoTemplate = +{ + PciIoPollMem, + PciIoPollIo, + { PciIoMemRead, PciIoMemWrite }, + { PciIoIoRead, PciIoIoWrite }, + { PciIoPciRead, PciIoPciWrite }, + PciIoCopyMem, + PciIoMap, + PciIoUnmap, + PciIoAllocateBuffer, + PciIoFreeBuffer, + PciIoFlush, + PciIoGetLocation, + PciIoAttributes, + PciIoGetBarAttributes, + PciIoSetBarAttributes, + 0, + 0 +}; + +STATIC +EFI_STATUS +EFIAPI +InstallDevices ( + IN UINTN DeviceId, + IN UINTN BaseAddr, + IN UINTN AddressSpaceSize, + IN UINTN ClassCode1, + IN UINTN ClassCode2, + IN UINTN ClassCode3 + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private; + EFI_STATUS Status; + EFI_HANDLE Handle; + + // Create a private structure + Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA)); + if (Private == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + + // Fill in signature + Private->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE; + + // Fake Root Bridge structure needs a signature too + Private->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE; + + // Get the register base + Private->RootBridge.MemoryStart = BaseAddr; + + // Default to segment zero + Private->Segment = 0; + + // Calculate the total size of device registers. + Private->RootBridge.MemorySize = AddressSpaceSize; + + // Create fake PCI config space. + Private->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00)); + if (Private->ConfigSpace == NULL) { + Status = EFI_OUT_OF_RESOURCES; + FreePool(Private); + return Status; + } + + // + // Configure PCI config space + // + + // Invalid vendor Id as it is not an actual device. + Private->ConfigSpace->Hdr.VendorId = 0xFFFF; + + // Not relevant as the vendor id is not valid. + Private->ConfigSpace->Hdr.DeviceId = 0x0000; + Private->ConfigSpace->Hdr.ClassCode[0] = ClassCode1; + Private->ConfigSpace->Hdr.ClassCode[1] = ClassCode2; + Private->ConfigSpace->Hdr.ClassCode[2] = ClassCode3; + Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart; + + Handle = NULL; + + // Unique device path. + CopyMem(&Private->DevicePath, &PciIoDevicePathTemplate, sizeof(PciIoDevicePathTemplate)); + Private->DevicePath.AcpiDevicePath.UID = 0; + Private->DevicePath.PciDevicePath.Device = DeviceId; + + // Copy protocol structure + CopyMem(&Private->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate)); + + Status = gBS->InstallMultipleProtocolInterfaces( + &Handle, + &gEfiPciIoProtocolGuid, + &Private->PciIoProtocol, + &gEfiDevicePathProtocolGuid, + &Private->DevicePath, + NULL + ); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: InstallMultipleProtocolInterfaces failed\n")); + } + + return Status; +} + +// +// Below function is used to parse devices information from PCD strings. +// +EFI_STATUS +EFIAPI +PciEmulationEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINT8 i, DevCount; + UINTN BaseAddrTable[PcdGet32 (PcdPciEDevCount)]; + UINTN RegSizeTable[PcdGet32 (PcdPciEDevCount)]; + UINTN DevClass1Table[PcdGet32 (PcdPciEDevCount)]; + UINTN DevClass2Table[PcdGet32 (PcdPciEDevCount)]; + UINTN DevClass3Table[PcdGet32 (PcdPciEDevCount)]; + + DevCount = PcdGet32 (PcdPciEDevCount); + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevBaseAddress), DevCount, BaseAddrTable, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevBaseAddress format\n")); + return EFI_INVALID_PARAMETER; + } + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevRegSize), DevCount, RegSizeTable, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevRegSize format\n")); + return EFI_INVALID_PARAMETER; + } + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode1), DevCount, DevClass1Table, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode1 format\n")); + return EFI_INVALID_PARAMETER; + } + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode2), DevCount, DevClass2Table, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode2 format\n")); + return EFI_INVALID_PARAMETER; + } + + Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode3), DevCount, DevClass3Table, NULL); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode3 format\n")); + return EFI_INVALID_PARAMETER; + } + + for (i = 0; i < DevCount; i++) { + Status = InstallDevices (i, BaseAddrTable[i], RegSizeTable[i], + DevClass1Table[i], DevClass2Table[i], DevClass3Table[i]); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "PciEmulation: Cannot install device with ID=%d\n", i)); + } + } + + return Status; +} diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.h b/Platforms/Marvell/PciEmulation/PciEmulation.h new file mode 100644 index 0000000..4f75539 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.h @@ -0,0 +1,271 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + Copyright (c) 2016, Marvell. All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD + License which 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. + +**/ + +#ifndef _PCI_ROOT_BRIDGE_H_ +#define _PCI_ROOT_BRIDGE_H_ + +#include <PiDxe.h> + +#include <IndustryStandard/Acpi.h> +#include <IndustryStandard/Pci22.h> +#include <IndustryStandard/PciCodeId.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/DmaLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/IoLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/ParsePcdLib.h> +#include <Library/PcdLib.h> +#include <Library/PciLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> + +#include <Protocol/DevicePath.h> +#include <Protocol/EmbeddedExternalDevice.h> +#include <Protocol/PciHostBridgeResourceAllocation.h> +#include <Protocol/PciIo.h> +#include <Protocol/PciRootBridgeIo.h> + +#define ACPI_CONFIG_IO 0 +#define ACPI_CONFIG_MMIO 1 +#define ACPI_CONFIG_BUS 2 + +#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('P', 'c', 'i', 'F') + +typedef struct { + ACPI_HID_DEVICE_PATH AcpiDevicePath; + EFI_DEVICE_PATH_PROTOCOL EndDevicePath; +} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; + +typedef struct { + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Desc[3]; + EFI_ACPI_END_TAG_DESCRIPTOR EndDesc; +} ACPI_CONFIG_INFO; + +typedef struct { + UINT32 Signature; + EFI_HANDLE Handle; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io; + EFI_PCI_ROOT_BRIDGE_DEVICE_PATH DevicePath; + + UINT8 StartBus; + UINT8 EndBus; + UINT16 Type; + UINT32 MemoryStart; + UINT32 MemorySize; + UINTN IoOffset; + UINT32 IoStart; + UINT32 IoSize; + UINT64 PciAttributes; + + ACPI_CONFIG_INFO *Config; + +} PCI_ROOT_BRIDGE; + +#define INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) CR (a, PCI_ROOT_BRIDGE, Io, PCI_ROOT_BRIDGE_SIGNATURE) + +typedef union { + UINT8 volatile *buf; + UINT8 volatile *ui8; + UINT16 volatile *ui16; + UINT32 volatile *ui32; + UINT64 volatile *ui64; + UINTN volatile ui; +} PTR; + +EFI_STATUS +EFIAPI +PciRootBridgeIoPollMem ( + 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 +PciRootBridgeIoPollIo ( + 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 +PciRootBridgeIoMemRead ( + 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 +PciRootBridgeIoMemWrite ( + 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 +PciRootBridgeIoIoRead ( + 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 +PciRootBridgeIoIoWrite ( + 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 +PciRootBridgeIoCopyMem ( + IN 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 +PciRootBridgeIoPciRead ( + 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 +PciRootBridgeIoPciWrite ( + 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 +PciRootBridgeIoMap ( + 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 +PciRootBridgeIoUnmap ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoAllocateBuffer ( + 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 +PciRootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoFlush ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoGetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT UINT64 *Supported, + OUT UINT64 *Attributes + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoSetAttributes ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINT64 Attributes, + IN OUT UINT64 *ResourceBase, + IN OUT UINT64 *ResourceLength + ); + +EFI_STATUS +EFIAPI +PciRootBridgeIoConfiguration ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + OUT VOID **Resources + ); + +// +// Private Function Prototypes +// +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN InStrideFlag, + IN PTR In, + IN BOOLEAN OutStrideFlag, + OUT PTR Out + ); + +BOOLEAN +PciIoMemAddressValid ( + IN EFI_PCI_IO_PROTOCOL *This, + IN UINT64 Address + ); +#endif diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.inf b/Platforms/Marvell/PciEmulation/PciEmulation.inf new file mode 100644 index 0000000..30ddfc2 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.inf @@ -0,0 +1,65 @@ +/** @file + + Copyright (c) 2009, Apple Inc. All rights reserved.<BR> + Copyright (c) 2016, Marvell. All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD + License which 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. + +**/ + +[Defines] + INF_VERSION = 0x00010019 + BASE_NAME = PciEmulation + FILE_GUID = 3dfa08da-923b-4841-9435-c77a604d7493 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = PciEmulationEntryPoint + +[Sources.common] + PciEmulation.c + PciRootBridgeIo.c + +[Packages] + ArmPkg/ArmPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + OpenPlatformPkg/Platforms/Marvell/Marvell.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseLib + DmaLib + DxeServicesTableLib + IoLib + ParsePcdLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + gEfiDevicePathProtocolGuid + gEfiPciHostBridgeResourceAllocationProtocolGuid + gEfiPciIoProtocolGuid + gEfiPciRootBridgeIoProtocolGuid + gEmbeddedExternalDeviceProtocolGuid + +[Pcd] + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3 + gMarvellTokenSpaceGuid.PcdPciEDevCount + gMarvellTokenSpaceGuid.PcdPciEDevRegSize + +[Depex] + TRUE diff --git a/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c b/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c new file mode 100644 index 0000000..dab26b6 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c @@ -0,0 +1,314 @@ +/** @file + + Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> + Copyright (c) 2016, Marvell. All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD + License which 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 "PciEmulation.h" + +BOOLEAN +PciRootBridgeMemAddressValid ( + IN PCI_ROOT_BRIDGE *Private, + IN UINT64 Address + ) +{ + if ((Address >= Private->MemoryStart) && + (Address < (Private->MemoryStart + Private->MemorySize))) { + return TRUE; + } + + return FALSE; +} + +EFI_STATUS +PciRootBridgeIoMemRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINTN Count, + IN BOOLEAN InStrideFlag, + IN PTR In, + IN BOOLEAN OutStrideFlag, + OUT PTR Out + ) +{ + UINTN Stride; + UINTN InStride; + UINTN OutStride; + + + Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03); + Stride = (UINTN)1 << Width; + InStride = InStrideFlag ? Stride : 0; + OutStride = OutStrideFlag ? Stride : 0; + + // + // Loop for each iteration and move the data + // + switch (Width) { + case EfiPciWidthUint8: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + *In.ui8 = *Out.ui8; + } + break; + case EfiPciWidthUint16: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + *In.ui16 = *Out.ui16; + } + break; + case EfiPciWidthUint32: + for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { + *In.ui32 = *Out.ui32; + } + break; + default: + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciRootBridgeIoPciRW ( + 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 + ) +{ + return EFI_SUCCESS; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge + memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack + of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRead ( + 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 *Private; + UINTN AlignMask; + PTR In; + PTR Out; + + if ( Buffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + if (!PciRootBridgeMemAddressValid (Private, Address)) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + In.buf = Buffer; + Out.buf = (VOID *)(UINTN) Address; + + switch (Width) { + case EfiPciWidthUint8: + case EfiPciWidthUint16: + case EfiPciWidthUint32: + case EfiPciWidthUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); + + case EfiPciWidthFifoUint8: + case EfiPciWidthFifoUint16: + case EfiPciWidthFifoUint32: + case EfiPciWidthFifoUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); + + case EfiPciWidthFillUint8: + case EfiPciWidthFillUint16: + case EfiPciWidthFillUint32: + case EfiPciWidthFillUint64: + return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); + + default: + break; + } + + return EFI_INVALID_PARAMETER; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack + of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemWrite ( + 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 *Private; + UINTN AlignMask; + PTR In; + PTR Out; + + if (Buffer == NULL ) { + return EFI_INVALID_PARAMETER; + } + + Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This); + + if (!PciRootBridgeMemAddressValid (Private, Address)) { + return EFI_INVALID_PARAMETER; + } + + AlignMask = (1 << (Width & 0x03)) - 1; + if (Address & AlignMask) { + return EFI_INVALID_PARAMETER; + } + + In.buf = (VOID *)(UINTN) Address; + Out.buf = Buffer; + + switch (Width) { + case EfiPciWidthUint8: + case EfiPciWidthUint16: + case EfiPciWidthUint32: + case EfiPciWidthUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); + + case EfiPciWidthFifoUint8: + case EfiPciWidthFifoUint16: + case EfiPciWidthFifoUint32: + case EfiPciWidthFifoUint64: + return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); + + case EfiPciWidthFillUint8: + case EfiPciWidthFillUint16: + case EfiPciWidthFillUint32: + case EfiPciWidthFillUint64: + return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); + + default: + break; + } + + return EFI_INVALID_PARAMETER; +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge + memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack + of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciRead ( + 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; + } + + return PciRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer); +} + +/** + Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space. + + @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL + @param Width Signifies the width of the memory operations. + @param Address The base address of the memory operations. + @param Count The number of memory operations to perform. + @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciWrite ( + 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; + } + + return PciRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer); +}
Hello Marcin,
On 28 October 2016 at 16:42, Marcin Wojtas mw@semihalf.com wrote:
From: Jan Dąbroś jsd@semihalf.com
In order to use numerous UEFI drivers based on PCI bus, PciEmulation driver is implemented. This solution is based on Chips/TexasInstruments/Omap35xx/PciEmulation/ Configuring fake devices is performed via PCD.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com
.../Marvell/PortingGuide/PciEmulation.txt | 53 ++ Platforms/Marvell/Marvell.dec | 8 + Platforms/Marvell/PciEmulation/PciEmulation.c | 678 +++++++++++++++++++++ Platforms/Marvell/PciEmulation/PciEmulation.h | 271 ++++++++ Platforms/Marvell/PciEmulation/PciEmulation.inf | 65 ++ Platforms/Marvell/PciEmulation/PciRootBridgeIo.c | 314 ++++++++++ 6 files changed, 1389 insertions(+) create mode 100644 Documentation/Marvell/PortingGuide/PciEmulation.txt create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.c create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.h create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.inf create mode 100644 Platforms/Marvell/PciEmulation/PciRootBridgeIo.c
diff --git a/Documentation/Marvell/PortingGuide/PciEmulation.txt b/Documentation/Marvell/PortingGuide/PciEmulation.txt new file mode 100644 index 0000000..5bb812a --- /dev/null +++ b/Documentation/Marvell/PortingGuide/PciEmulation.txt @@ -0,0 +1,53 @@ +PciEmulation configuration +-------------------------- +Instalation of various Pci devices via PciEmulation driver is performed via set +of PCDs. Following are available:
- gMarvellTokenSpaceGuid.PcdPciEDevCount
+Indicates how many fake Pci devices are placed on board.
+Next five PCDs are in unicode string, format containing settings for all devices +separated with semicolon.
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress
I must say, I quite dislike this way of putting ; delimited strings into PCDs and then parsing them at runtime. But I don't have anything better to propose, so this is OK for now. We do intend to improve the situation somewhat around PCI I/O emulation (which is a terrible name as well, by the way) but for now this is fine.
+Indicates base address of Pci device register space.
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize
+Indicates size of Pci device register space.
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1
+Indicates device subclass code.
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2
+Indicates device class code.
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3
+Indicates Pci device class code.
+Examples +-------- +Assuming that there are two fake Pci xHCI controllers with register space +0xF2500000 - 0xF2510000 and 0xF2510000 - 0xF2520000 following PCD values should +be set:
- gMarvellTokenSpaceGuid.PcdPciEDevCount|2
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000"
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000"
- ## XHCI subclass
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30"
- ## USB controller class
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03"
- ## Serial bus controller Pci device class
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C"
+Notes +----- +1.In order to find proper values for Pci class codes, please refer to
- PCI Local Bus Specification.
+2.PCDs are configured via UNICODE strings - remember to add L marker. diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index db99230..f56987d 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -209,6 +209,14 @@ gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress|0|UINT64|0x3000031 gMarvellTokenSpaceGuid.PcdPp2XlgDevSize|0|UINT32|0x3000032
+#PciEmulation
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|{ 0x0 }|VOID*|0x30000058
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|{ 0x0 }|VOID*|0x30000059
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|{ 0x0 }|VOID*|0x30000060
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|{ 0x0 }|VOID*|0x30000061
- gMarvellTokenSpaceGuid.PcdPciEDevCount|0|UINT32|0x30000062
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize|{ 0x0 }|VOID*|0x30000063
One potential issue with covering all PCI I/O emulated devices by a single driver is that they must all be coherent or non-coherent. There is no way for a single device to deviate in this respect. Did you take that into account for your platform?
#ResetLib gMarvellTokenSpaceGuid.PcdResetRegAddress|0|UINT64|0x40000050 gMarvellTokenSpaceGuid.PcdResetRegMask|0|UINT32|0x4000051 diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.c b/Platforms/Marvell/PciEmulation/PciEmulation.c new file mode 100644 index 0000000..a800bcb --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.c @@ -0,0 +1,678 @@ +/** @file
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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 "PciEmulation.h"
+typedef struct {
- ACPI_HID_DEVICE_PATH AcpiDevicePath;
- PCI_DEVICE_PATH PciDevicePath;
- EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_IO_DEVICE_PATH;
+typedef struct {
- UINT32 Signature;
- EFI_PCI_IO_DEVICE_PATH DevicePath;
- EFI_PCI_IO_PROTOCOL PciIoProtocol;
- PCI_TYPE00 *ConfigSpace;
- PCI_ROOT_BRIDGE RootBridge;
- UINTN Segment;
+} EFI_PCI_IO_PRIVATE_DATA;
+#define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o') +#define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_PCI_IO_PRIVATE_DATA, \
PciIoProtocol, \
EFI_PCI_IO_PRIVATE_DATA_SIGNATURE)
+EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate = +{
- {
- {
ACPI_DEVICE_PATH,
ACPI_DP,
{
sizeof (ACPI_HID_DEVICE_PATH),
0
}
- },
- EISA_PNP_ID(0x0A03), // HID
- 0 // UID
- },
- {
- {
HARDWARE_DEVICE_PATH,
HW_PCI_DP,
{
sizeof (PCI_DEVICE_PATH),
0
}
- },
- 0,
- 0
- },
- {
- END_DEVICE_PATH_TYPE,
- END_ENTIRE_DEVICE_PATH_SUBTYPE,
- {
sizeof (EFI_DEVICE_PATH_PROTOCOL),
0
- }
- }
+};
+EFI_STATUS +PciIoPollMem (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINT64 Mask,
- IN UINT64 Value,
- IN UINT64 Delay,
- OUT UINT64 *Result
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoPollIo (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINT64 Mask,
- IN UINT64 Value,
- IN UINT64 Delay,
- OUT UINT64 *Result
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoMemRead (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
- return PciRootBridgeIoMemRead (
&Private->RootBridge.Io,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
Count,
Buffer
);
+}
+EFI_STATUS +PciIoMemWrite (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
- return PciRootBridgeIoMemWrite (
&Private->RootBridge.Io,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
Count,
Buffer
);
+}
+EFI_STATUS +PciIoIoRead (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoIoWrite (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+/**
- Enable a PCI driver to read PCI controller registers in
- PCI configuration space.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Width Signifies the width of the memory operations.
- @param[in] Offset The offset 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 Offset.
- @param[in out] Buffer The destination buffer to store the results.
- @retval EFI_SUCCESS The data was read from the PCI controller.
- @retval EFI_INVALID_PARAMETER "Width" is invalid.
- @retval EFI_INVALID_PARAMETER "Buffer" is NULL.
+**/ +EFI_STATUS +PciIoPciRead (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT32 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
- if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- return PciRootBridgeIoMemRW (
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width,
Count,
TRUE,
(PTR)(UINTN)Buffer,
TRUE,
(PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset)
);
+}
+/**
- Enable a PCI driver to write PCI controller registers in
- PCI configuration space.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Width Signifies the width of the memory operations.
- @param[in] Offset The offset 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 Offset.
- @param[in out] Buffer The source buffer to write data from.
- @retval EFI_SUCCESS The data was read from the PCI controller.
- @retval EFI_INVALID_PARAMETER "Width" is invalid.
- @retval EFI_INVALID_PARAMETER "Buffer" is NULL.
+**/ +EFI_STATUS +PciIoPciWrite (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT32 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
- if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- return PciRootBridgeIoMemRW (
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Count,
TRUE,
(PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset),
TRUE,
(PTR)(UINTN)Buffer
);
+}
+EFI_STATUS +PciIoCopyMem (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 DestBarIndex,
- IN UINT64 DestOffset,
- IN UINT8 SrcBarIndex,
- IN UINT64 SrcOffset,
- IN UINTN Count
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoMap (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
- IN VOID *HostAddress,
- IN OUT UINTN *NumberOfBytes,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- )
+{
- DMA_MAP_OPERATION DmaOperation;
- if (Operation == EfiPciIoOperationBusMasterRead) {
- DmaOperation = MapOperationBusMasterRead;
- } else if (Operation == EfiPciIoOperationBusMasterWrite) {
- DmaOperation = MapOperationBusMasterWrite;
- } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
- DmaOperation = MapOperationBusMasterCommonBuffer;
- } else {
- return EFI_INVALID_PARAMETER;
- }
- return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);
Are all your peripherals 64-bit DMA capable? If not, you may have a problem here, given that NullDmaLib just returns the CPU address unmodified, so you may want to check the DeviceAddress if the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set. Another complication in the non-coherent case is that the buffer may be remapped by DmaLib, in which case you have no control over the final allocation, unless you perform the bounce buffering here.
+}
+EFI_STATUS +PciIoUnmap (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN VOID *Mapping
- )
+{
- return DmaUnmap (Mapping);
+}
+/**
- Allocate pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
- mapping.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Type This parameter is not used and must be ignored.
- @param[in] MemoryType The type of memory to allocate, EfiBootServicesData
or EfiRuntimeServicesData.
- @param[in] Pages The number of pages to allocate.
- @param[out] HostAddress A pointer to store the base system memory address of
the allocated range.
- @param[in] Attributes The requested bit mask of attributes for the
allocated range. Only the attributes,
EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE and
EFI_PCI_ATTRIBUTE_MEMORY_CACHED may be used with
this function. If any other bits are set, then
EFI_UNSUPPORTED is returned. This function ignores
this bit mask.
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_INVALID_PARAMETER HostAddress is NULL.
- @retval EFI_INVALID_PARAMETER MemoryType is invalid.
- @retval EFI_UNSUPPORTED Attributes is unsupported.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/ +EFI_STATUS +PciIoAllocateBuffer (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN Pages,
- OUT VOID **HostAddress,
- IN UINT64 Attributes
- )
+{
- if (Attributes & (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) {
- return EFI_UNSUPPORTED;
- }
- return DmaAllocateBuffer (MemoryType, Pages, HostAddress);
Same question: are all your peripherals 64-bit DMA capable? If the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set, you must ensure that you allocate below 4 GB (if your platform also has UEFI visible memory above 4 GB)
+}
+EFI_STATUS +PciIoFreeBuffer (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINTN Pages,
- IN VOID *HostAddress
- )
+{
- return DmaFreeBuffer (Pages, HostAddress);
+}
+EFI_STATUS +PciIoFlush (
- IN EFI_PCI_IO_PROTOCOL *This
- )
+{
- return EFI_SUCCESS;
+}
+/**
- Retrieves this PCI controller's current PCI bus number, device number, and
- function number.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[out] SegmentNumber The PCI controller's current PCI segment number.
- @param[out] BusNumber The PCI controller's current PCI bus number.
- @param[out] DeviceNumber The PCI controller's current PCI device number.
- @param[out] FunctionNumber The PCI controller’s current PCI function number.
- @retval EFI_SUCCESS The PCI controller location was returned.
- @retval EFI_INVALID_PARAMETER At least one out of the four output parameters
is a NULL pointer.
+**/ +EFI_STATUS +PciIoGetLocation (
- IN EFI_PCI_IO_PROTOCOL *This,
- OUT UINTN *SegmentNumber,
- OUT UINTN *BusNumber,
- OUT UINTN *DeviceNumber,
- OUT UINTN *FunctionNumber
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
- if ((SegmentNumber == NULL) || (BusNumber == NULL) ||
(DeviceNumber == NULL) || (FunctionNumber == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- *SegmentNumber = Private->Segment;
- *BusNumber = 0xff;
- *DeviceNumber = 0;
- *FunctionNumber = 0;
- return EFI_SUCCESS;
+}
+/**
- Performs an operation on the attributes that this PCI controller supports.
- The operations include getting the set of supported attributes, retrieving
- the current attributes, setting the current attributes, enabling attributes,
- and disabling attributes.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Operation The operation to perform on the attributes for this
PCI controller.
- @param[in] Attributes The mask of attributes that are used for Set,
Enable and Disable operations.
- @param[out] Result A pointer to the result mask of attributes that are
returned for the Get and Supported operations. This
is an optional parameter that may be NULL for the
Set, Enable, and Disable operations.
- @retval EFI_SUCCESS The operation on the PCI controller's
attributes was completed. If the operation
was Get or Supported, then the attribute mask
is returned in Result.
- @retval EFI_INVALID_PARAMETER Operation is greater than or equal to
EfiPciIoAttributeOperationMaximum.
- @retval EFI_INVALID_PARAMETER Operation is Get and Result is NULL.
- @retval EFI_INVALID_PARAMETER Operation is Supported and Result is NULL.
+**/ +EFI_STATUS +PciIoAttributes (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
- IN UINT64 Attributes,
- OUT UINT64 *Result OPTIONAL
- )
+{
- switch (Operation) {
- case EfiPciIoAttributeOperationGet:
- case EfiPciIoAttributeOperationSupported:
- if (Result == NULL) {
return EFI_INVALID_PARAMETER;
- }
- //
- // We are not a real PCI device so just say things we kind of do
- //
- *Result = EFI_PCI_DEVICE_ENABLE;
- break;
- case EfiPciIoAttributeOperationSet:
- case EfiPciIoAttributeOperationEnable:
- case EfiPciIoAttributeOperationDisable:
- if (Attributes & (~EFI_PCI_DEVICE_ENABLE)) {
return EFI_UNSUPPORTED;
- }
- //
- // Since we are not a real PCI device no enable/set or
- // disable operations exist.
- //
- return EFI_SUCCESS;
- default:
- return EFI_INVALID_PARAMETER;
- };
- return EFI_SUCCESS;
+}
+EFI_STATUS +PciIoGetBarAttributes (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINT8 BarIndex,
- OUT UINT64 *Supports, OPTIONAL
- OUT VOID **Resources OPTIONAL
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoSetBarAttributes (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINT64 Attributes,
- IN UINT8 BarIndex,
- IN OUT UINT64 *Offset,
- IN OUT UINT64 *Length
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_PCI_IO_PROTOCOL PciIoTemplate = +{
- PciIoPollMem,
- PciIoPollIo,
- { PciIoMemRead, PciIoMemWrite },
- { PciIoIoRead, PciIoIoWrite },
- { PciIoPciRead, PciIoPciWrite },
- PciIoCopyMem,
- PciIoMap,
- PciIoUnmap,
- PciIoAllocateBuffer,
- PciIoFreeBuffer,
- PciIoFlush,
- PciIoGetLocation,
- PciIoAttributes,
- PciIoGetBarAttributes,
- PciIoSetBarAttributes,
- 0,
- 0
+};
+STATIC +EFI_STATUS +EFIAPI +InstallDevices (
- IN UINTN DeviceId,
- IN UINTN BaseAddr,
- IN UINTN AddressSpaceSize,
- IN UINTN ClassCode1,
- IN UINTN ClassCode2,
- IN UINTN ClassCode3
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private;
- EFI_STATUS Status;
- EFI_HANDLE Handle;
- // Create a private structure
- Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA));
- if (Private == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- return Status;
- }
- // Fill in signature
- Private->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE;
- // Fake Root Bridge structure needs a signature too
- Private->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE;
- // Get the register base
- Private->RootBridge.MemoryStart = BaseAddr;
- // Default to segment zero
- Private->Segment = 0;
- // Calculate the total size of device registers.
- Private->RootBridge.MemorySize = AddressSpaceSize;
- // Create fake PCI config space.
- Private->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00));
- if (Private->ConfigSpace == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- FreePool(Private);
- return Status;
- }
- //
- // Configure PCI config space
- //
- // Invalid vendor Id as it is not an actual device.
- Private->ConfigSpace->Hdr.VendorId = 0xFFFF;
- // Not relevant as the vendor id is not valid.
- Private->ConfigSpace->Hdr.DeviceId = 0x0000;
- Private->ConfigSpace->Hdr.ClassCode[0] = ClassCode1;
- Private->ConfigSpace->Hdr.ClassCode[1] = ClassCode2;
- Private->ConfigSpace->Hdr.ClassCode[2] = ClassCode3;
- Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart;
- Handle = NULL;
- // Unique device path.
- CopyMem(&Private->DevicePath, &PciIoDevicePathTemplate, sizeof(PciIoDevicePathTemplate));
- Private->DevicePath.AcpiDevicePath.UID = 0;
- Private->DevicePath.PciDevicePath.Device = DeviceId;
- // Copy protocol structure
- CopyMem(&Private->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate));
- Status = gBS->InstallMultipleProtocolInterfaces(
&Handle,
&gEfiPciIoProtocolGuid,
&Private->PciIoProtocol,
&gEfiDevicePathProtocolGuid,
&Private->DevicePath,
NULL
);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: InstallMultipleProtocolInterfaces failed\n"));
- }
- return Status;
+}
+// +// Below function is used to parse devices information from PCD strings. +// +EFI_STATUS +EFIAPI +PciEmulationEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
+{
- EFI_STATUS Status;
- UINT8 i, DevCount;
- UINTN BaseAddrTable[PcdGet32 (PcdPciEDevCount)];
- UINTN RegSizeTable[PcdGet32 (PcdPciEDevCount)];
- UINTN DevClass1Table[PcdGet32 (PcdPciEDevCount)];
- UINTN DevClass2Table[PcdGet32 (PcdPciEDevCount)];
- UINTN DevClass3Table[PcdGet32 (PcdPciEDevCount)];
- DevCount = PcdGet32 (PcdPciEDevCount);
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevBaseAddress), DevCount, BaseAddrTable, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevBaseAddress format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevRegSize), DevCount, RegSizeTable, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevRegSize format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode1), DevCount, DevClass1Table, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode1 format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode2), DevCount, DevClass2Table, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode2 format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode3), DevCount, DevClass3Table, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode3 format\n"));
- return EFI_INVALID_PARAMETER;
- }
- for (i = 0; i < DevCount; i++) {
- Status = InstallDevices (i, BaseAddrTable[i], RegSizeTable[i],
DevClass1Table[i], DevClass2Table[i], DevClass3Table[i]);
- if (EFI_ERROR(Status)) {
DEBUG((DEBUG_ERROR, "PciEmulation: Cannot install device with ID=%d\n", i));
- }
- }
- return Status;
+} diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.h b/Platforms/Marvell/PciEmulation/PciEmulation.h new file mode 100644 index 0000000..4f75539 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.h @@ -0,0 +1,271 @@ +/** @file
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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.
+**/
+#ifndef _PCI_ROOT_BRIDGE_H_ +#define _PCI_ROOT_BRIDGE_H_
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h> +#include <IndustryStandard/Pci22.h> +#include <IndustryStandard/PciCodeId.h>
+#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/DmaLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/IoLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/ParsePcdLib.h> +#include <Library/PcdLib.h> +#include <Library/PciLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h>
+#include <Protocol/DevicePath.h> +#include <Protocol/EmbeddedExternalDevice.h> +#include <Protocol/PciHostBridgeResourceAllocation.h> +#include <Protocol/PciIo.h> +#include <Protocol/PciRootBridgeIo.h>
+#define ACPI_CONFIG_IO 0 +#define ACPI_CONFIG_MMIO 1 +#define ACPI_CONFIG_BUS 2
+#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('P', 'c', 'i', 'F')
+typedef struct {
- ACPI_HID_DEVICE_PATH AcpiDevicePath;
- EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+typedef struct {
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Desc[3];
- EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;
+} ACPI_CONFIG_INFO;
+typedef struct {
- UINT32 Signature;
- EFI_HANDLE Handle;
- EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io;
- EFI_PCI_ROOT_BRIDGE_DEVICE_PATH DevicePath;
- UINT8 StartBus;
- UINT8 EndBus;
- UINT16 Type;
- UINT32 MemoryStart;
- UINT32 MemorySize;
- UINTN IoOffset;
- UINT32 IoStart;
- UINT32 IoSize;
- UINT64 PciAttributes;
- ACPI_CONFIG_INFO *Config;
+} PCI_ROOT_BRIDGE;
+#define INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) CR (a, PCI_ROOT_BRIDGE, Io, PCI_ROOT_BRIDGE_SIGNATURE)
+typedef union {
- UINT8 volatile *buf;
- UINT8 volatile *ui8;
- UINT16 volatile *ui16;
- UINT32 volatile *ui32;
- UINT64 volatile *ui64;
- UINTN volatile ui;
+} PTR;
+EFI_STATUS +EFIAPI +PciRootBridgeIoPollMem (
- 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 +PciRootBridgeIoPollIo (
- 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 +PciRootBridgeIoMemRead (
- 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 +PciRootBridgeIoMemWrite (
- 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 +PciRootBridgeIoIoRead (
- 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 +PciRootBridgeIoIoWrite (
- 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 +PciRootBridgeIoCopyMem (
- IN 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 +PciRootBridgeIoPciRead (
- 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 +PciRootBridgeIoPciWrite (
- 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 +PciRootBridgeIoMap (
- 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 +PciRootBridgeIoUnmap (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- IN VOID *Mapping
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoAllocateBuffer (
- 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 +PciRootBridgeIoFreeBuffer (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- IN UINTN Pages,
- OUT VOID *HostAddress
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoFlush (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoGetAttributes (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- OUT UINT64 *Supported,
- OUT UINT64 *Attributes
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoSetAttributes (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- IN UINT64 Attributes,
- IN OUT UINT64 *ResourceBase,
- IN OUT UINT64 *ResourceLength
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoConfiguration (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- OUT VOID **Resources
- );
+// +// Private Function Prototypes +// +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRW (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
- IN UINTN Count,
- IN BOOLEAN InStrideFlag,
- IN PTR In,
- IN BOOLEAN OutStrideFlag,
- OUT PTR Out
- );
+BOOLEAN +PciIoMemAddressValid (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINT64 Address
- );
+#endif diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.inf b/Platforms/Marvell/PciEmulation/PciEmulation.inf new file mode 100644 index 0000000..30ddfc2 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.inf @@ -0,0 +1,65 @@ +/** @file
- Copyright (c) 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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.
+**/
+[Defines]
- INF_VERSION = 0x00010019
- BASE_NAME = PciEmulation
- FILE_GUID = 3dfa08da-923b-4841-9435-c77a604d7493
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 1.0
- ENTRY_POINT = PciEmulationEntryPoint
+[Sources.common]
- PciEmulation.c
- PciRootBridgeIo.c
+[Packages]
- ArmPkg/ArmPkg.dec
- EmbeddedPkg/EmbeddedPkg.dec
- IntelFrameworkPkg/IntelFrameworkPkg.dec
- MdeModulePkg/MdeModulePkg.dec
- MdePkg/MdePkg.dec
- OpenPlatformPkg/Platforms/Marvell/Marvell.dec
- ShellPkg/ShellPkg.dec
Why on earth do you need the ShellPkg in a DXE_DRIVER module?
+[LibraryClasses]
- BaseLib
- DmaLib
- DxeServicesTableLib
- IoLib
- ParsePcdLib
- UefiBootServicesTableLib
- UefiDriverEntryPoint
- UefiLib
- UefiRuntimeServicesTableLib
+[Protocols]
- gEfiDevicePathProtocolGuid
- gEfiPciHostBridgeResourceAllocationProtocolGuid
- gEfiPciIoProtocolGuid
- gEfiPciRootBridgeIoProtocolGuid
- gEmbeddedExternalDeviceProtocolGuid
+[Pcd]
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3
- gMarvellTokenSpaceGuid.PcdPciEDevCount
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize
+[Depex]
- TRUE
diff --git a/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c b/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c new file mode 100644 index 0000000..dab26b6 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c @@ -0,0 +1,314 @@ +/** @file
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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 "PciEmulation.h"
+BOOLEAN +PciRootBridgeMemAddressValid (
- IN PCI_ROOT_BRIDGE *Private,
- IN UINT64 Address
- )
+{
- if ((Address >= Private->MemoryStart) &&
(Address < (Private->MemoryStart + Private->MemorySize))) {
- return TRUE;
- }
- return FALSE;
+}
+EFI_STATUS +PciRootBridgeIoMemRW (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
- IN UINTN Count,
- IN BOOLEAN InStrideFlag,
- IN PTR In,
- IN BOOLEAN OutStrideFlag,
- OUT PTR Out
- )
+{
- UINTN Stride;
- UINTN InStride;
- UINTN OutStride;
- Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03);
- Stride = (UINTN)1 << Width;
- InStride = InStrideFlag ? Stride : 0;
- OutStride = OutStrideFlag ? Stride : 0;
- //
- // Loop for each iteration and move the data
- //
- switch (Width) {
- case EfiPciWidthUint8:
- for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
*In.ui8 = *Out.ui8;
- }
- break;
- case EfiPciWidthUint16:
- for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
*In.ui16 = *Out.ui16;
- }
- break;
- case EfiPciWidthUint32:
- for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
*In.ui32 = *Out.ui32;
- }
- break;
- default:
- return EFI_INVALID_PARAMETER;
- }
- return EFI_SUCCESS;
+}
+EFI_STATUS +PciRootBridgeIoPciRW (
- 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
- )
+{
- return EFI_SUCCESS;
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge
- memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRead (
- 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 *Private;
- UINTN AlignMask;
- PTR In;
- PTR Out;
- if ( Buffer == NULL ) {
- return EFI_INVALID_PARAMETER;
- }
- Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
- if (!PciRootBridgeMemAddressValid (Private, Address)) {
- return EFI_INVALID_PARAMETER;
- }
- AlignMask = (1 << (Width & 0x03)) - 1;
- if (Address & AlignMask) {
- return EFI_INVALID_PARAMETER;
- }
- In.buf = Buffer;
- Out.buf = (VOID *)(UINTN) Address;
- switch (Width) {
- case EfiPciWidthUint8:
- case EfiPciWidthUint16:
- case EfiPciWidthUint32:
- case EfiPciWidthUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out);
- case EfiPciWidthFifoUint8:
- case EfiPciWidthFifoUint16:
- case EfiPciWidthFifoUint32:
- case EfiPciWidthFifoUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out);
- case EfiPciWidthFillUint8:
- case EfiPciWidthFillUint16:
- case EfiPciWidthFillUint32:
- case EfiPciWidthFillUint64:
- return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out);
- default:
- break;
- }
- return EFI_INVALID_PARAMETER;
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemWrite (
- 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 *Private;
- UINTN AlignMask;
- PTR In;
- PTR Out;
- if (Buffer == NULL ) {
- return EFI_INVALID_PARAMETER;
- }
- Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
- if (!PciRootBridgeMemAddressValid (Private, Address)) {
- return EFI_INVALID_PARAMETER;
- }
- AlignMask = (1 << (Width & 0x03)) - 1;
- if (Address & AlignMask) {
- return EFI_INVALID_PARAMETER;
- }
- In.buf = (VOID *)(UINTN) Address;
- Out.buf = Buffer;
- switch (Width) {
- case EfiPciWidthUint8:
- case EfiPciWidthUint16:
- case EfiPciWidthUint32:
- case EfiPciWidthUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out);
- case EfiPciWidthFifoUint8:
- case EfiPciWidthFifoUint16:
- case EfiPciWidthFifoUint32:
- case EfiPciWidthFifoUint64:
- return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out);
- case EfiPciWidthFillUint8:
- case EfiPciWidthFillUint16:
- case EfiPciWidthFillUint32:
- case EfiPciWidthFillUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out);
- default:
- break;
- }
- return EFI_INVALID_PARAMETER;
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge
- memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciRead (
- 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;
- }
- return PciRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer);
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciWrite (
- 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;
- }
- return PciRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer);
+}
1.8.3.1
Hi Ard,
Thanks a lot for your remarks. Please find my answers inline.
Do you have any more comments regarding this and next commits in patchset? Did you have a chance to take a look at them?
Best Regards, Jan
+Next five PCDs are in unicode string, format containing settings for all devices +separated with semicolon.
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress
I must say, I quite dislike this way of putting ; delimited strings into PCDs and then parsing them at runtime. But I don't have anything better to propose, so this is OK for now. We do intend to improve the situation somewhat around PCI I/O emulation (which is a terrible name as well, by the way) but for now this is fine.
We also cannot find anything better - other PCI I/O emulation drivers are limited to single type of device (which are hardcoded by the way). Although it's not perfect, this approach gives us some flexibility and scalability.
+#PciEmulation
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|{ 0x0 }|VOID*|0x30000058
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|{ 0x0 }|VOID*|0x30000059
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|{ 0x0 }|VOID*|0x30000060
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|{ 0x0 }|VOID*|0x30000061
- gMarvellTokenSpaceGuid.PcdPciEDevCount|0|UINT32|0x30000062
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize|{ 0x0 }|VOID*|0x30000063
One potential issue with covering all PCI I/O emulated devices by a single driver is that they must all be coherent or non-coherent. There is no way for a single device to deviate in this respect. Did you take that into account for your platform?
All devices on our platform are coherent, so it isn't a problem in our case. I think that this driver may be improved in future in order to meet the requirements of another SoC, e.g support for coherent and non-coherent devices - however that's not the case with Armada70x0/80x0 family now. What do you think?
- if (Operation == EfiPciIoOperationBusMasterRead
) {
- DmaOperation = MapOperationBusMasterRead;
- } else if (Operation == EfiPciIoOperationBusMasterWrite) {
- DmaOperation = MapOperationBusMasterWrite;
- } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
- DmaOperation = MapOperationBusMasterCommonBuffer;
- } else {
- return EFI_INVALID_PARAMETER;
- }
- return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);
Are all your peripherals 64-bit DMA capable? If not, you may have a problem here, given that NullDmaLib just returns the CPU address unmodified, so you may want to check the DeviceAddress if the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set. Another complication in the non-coherent case is that the buffer may be remapped by DmaLib, in which case you have no control over the final allocation, unless you perform the bounce buffering here.
Since our platform has less than 4GB memory visible for UEFI, returned address shouldn't be above this region. We use ArmDmaLib not NullDmaLib as DmaLib implementation. As I wrote above, we are using cache-coherent devices, so the problem with remapped buffer couldn't happen here.
+EFI_STATUS +PciIoAllocateBuffer (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN Pages,
- OUT VOID **HostAddress,
- IN UINT64 Attributes
- )
+{
- if (Attributes & (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) {
- return EFI_UNSUPPORTED;
- }
- return DmaAllocateBuffer (MemoryType, Pages, HostAddress);
Same question: are all your peripherals 64-bit DMA capable? If the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set, you must ensure that you allocate below 4 GB (if your platform also has UEFI visible memory above 4 GB)
Since we have less than 4GB memory visible, there shouldn't be problem with allocation above this region.
+[Packages]
- ArmPkg/ArmPkg.dec
- EmbeddedPkg/EmbeddedPkg.dec
- IntelFrameworkPkg/IntelFrameworkPkg.dec
- MdeModulePkg/MdeModulePkg.dec
- MdePkg/MdePkg.dec
- OpenPlatformPkg/Platforms/Marvell/Marvell.dec
- ShellPkg/ShellPkg.dec
Why on earth do you need the ShellPkg in a DXE_DRIVER module?
It's definitely placed here by mistake. Will be removed on v2.
2016-10-28 18:19 GMT+02:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
Hello Marcin,
On 28 October 2016 at 16:42, Marcin Wojtas mw@semihalf.com wrote:
From: Jan Dąbroś jsd@semihalf.com
In order to use numerous UEFI drivers based on PCI bus, PciEmulation driver is implemented. This solution is based on Chips/TexasInstruments/Omap35xx/PciEmulation/ Configuring fake devices is performed via PCD.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com
.../Marvell/PortingGuide/PciEmulation.txt | 53 ++ Platforms/Marvell/Marvell.dec | 8 + Platforms/Marvell/PciEmulation/PciEmulation.c | 678 +++++++++++++++++++++ Platforms/Marvell/PciEmulation/PciEmulation.h | 271 ++++++++ Platforms/Marvell/PciEmulation/PciEmulation.inf | 65 ++ Platforms/Marvell/PciEmulation/PciRootBridgeIo.c | 314 ++++++++++ 6 files changed, 1389 insertions(+) create mode 100644 Documentation/Marvell/PortingGuide/PciEmulation.txt create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.c create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.h create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.inf create mode 100644 Platforms/Marvell/PciEmulation/PciRootBridgeIo.c
diff --git a/Documentation/Marvell/PortingGuide/PciEmulation.txt b/Documentation/Marvell/PortingGuide/PciEmulation.txt new file mode 100644 index 0000000..5bb812a --- /dev/null +++ b/Documentation/Marvell/PortingGuide/PciEmulation.txt @@ -0,0 +1,53 @@ +PciEmulation configuration +-------------------------- +Instalation of various Pci devices via PciEmulation driver is performed via set +of PCDs. Following are available:
- gMarvellTokenSpaceGuid.PcdPciEDevCount
+Indicates how many fake Pci devices are placed on board.
+Next five PCDs are in unicode string, format containing settings for all devices +separated with semicolon.
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress
I must say, I quite dislike this way of putting ; delimited strings into PCDs and then parsing them at runtime. But I don't have anything better to propose, so this is OK for now. We do intend to improve the situation somewhat around PCI I/O emulation (which is a terrible name as well, by the way) but for now this is fine.
+Indicates base address of Pci device register space.
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize
+Indicates size of Pci device register space.
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1
+Indicates device subclass code.
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2
+Indicates device class code.
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3
+Indicates Pci device class code.
+Examples +-------- +Assuming that there are two fake Pci xHCI controllers with register space +0xF2500000 - 0xF2510000 and 0xF2510000 - 0xF2520000 following PCD values should +be set:
- gMarvellTokenSpaceGuid.PcdPciEDevCount|2
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000"
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000"
- ## XHCI subclass
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30"
- ## USB controller class
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03"
- ## Serial bus controller Pci device class
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C"
+Notes +----- +1.In order to find proper values for Pci class codes, please refer to
- PCI Local Bus Specification.
+2.PCDs are configured via UNICODE strings - remember to add L marker. diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index db99230..f56987d 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -209,6 +209,14 @@ gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress|0|UINT64|0x3000031 gMarvellTokenSpaceGuid.PcdPp2XlgDevSize|0|UINT32|0x3000032
+#PciEmulation
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|{ 0x0 }|VOID*|0x30000058
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|{ 0x0 }|VOID*|0x30000059
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|{ 0x0 }|VOID*|0x30000060
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|{ 0x0 }|VOID*|0x30000061
- gMarvellTokenSpaceGuid.PcdPciEDevCount|0|UINT32|0x30000062
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize|{ 0x0 }|VOID*|0x30000063
One potential issue with covering all PCI I/O emulated devices by a single driver is that they must all be coherent or non-coherent. There is no way for a single device to deviate in this respect. Did you take that into account for your platform?
#ResetLib gMarvellTokenSpaceGuid.PcdResetRegAddress|0|UINT64|0x40000050 gMarvellTokenSpaceGuid.PcdResetRegMask|0|UINT32|0x4000051 diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.c b/Platforms/Marvell/PciEmulation/PciEmulation.c new file mode 100644 index 0000000..a800bcb --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.c @@ -0,0 +1,678 @@ +/** @file
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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 "PciEmulation.h"
+typedef struct {
- ACPI_HID_DEVICE_PATH AcpiDevicePath;
- PCI_DEVICE_PATH PciDevicePath;
- EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_IO_DEVICE_PATH;
+typedef struct {
- UINT32 Signature;
- EFI_PCI_IO_DEVICE_PATH DevicePath;
- EFI_PCI_IO_PROTOCOL PciIoProtocol;
- PCI_TYPE00 *ConfigSpace;
- PCI_ROOT_BRIDGE RootBridge;
- UINTN Segment;
+} EFI_PCI_IO_PRIVATE_DATA;
+#define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o') +#define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_PCI_IO_PRIVATE_DATA, \
PciIoProtocol, \
EFI_PCI_IO_PRIVATE_DATA_SIGNATURE)
+EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate = +{
- {
- {
ACPI_DEVICE_PATH,
ACPI_DP,
{
sizeof (ACPI_HID_DEVICE_PATH),
0
}
- },
- EISA_PNP_ID(0x0A03), // HID
- 0 // UID
- },
- {
- {
HARDWARE_DEVICE_PATH,
HW_PCI_DP,
{
sizeof (PCI_DEVICE_PATH),
0
}
- },
- 0,
- 0
- },
- {
- END_DEVICE_PATH_TYPE,
- END_ENTIRE_DEVICE_PATH_SUBTYPE,
- {
sizeof (EFI_DEVICE_PATH_PROTOCOL),
0
- }
- }
+};
+EFI_STATUS +PciIoPollMem (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINT64 Mask,
- IN UINT64 Value,
- IN UINT64 Delay,
- OUT UINT64 *Result
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoPollIo (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINT64 Mask,
- IN UINT64 Value,
- IN UINT64 Delay,
- OUT UINT64 *Result
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoMemRead (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
- return PciRootBridgeIoMemRead (
&Private->RootBridge.Io,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
Count,
Buffer
);
+}
+EFI_STATUS +PciIoMemWrite (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
- return PciRootBridgeIoMemWrite (
&Private->RootBridge.Io,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
Count,
Buffer
);
+}
+EFI_STATUS +PciIoIoRead (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoIoWrite (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+/**
- Enable a PCI driver to read PCI controller registers in
- PCI configuration space.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Width Signifies the width of the memory operations.
- @param[in] Offset The offset 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 Offset.
- @param[in out] Buffer The destination buffer to store the results.
- @retval EFI_SUCCESS The data was read from the PCI controller.
- @retval EFI_INVALID_PARAMETER "Width" is invalid.
- @retval EFI_INVALID_PARAMETER "Buffer" is NULL.
+**/ +EFI_STATUS +PciIoPciRead (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT32 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
- if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- return PciRootBridgeIoMemRW (
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width,
Count,
TRUE,
(PTR)(UINTN)Buffer,
TRUE,
(PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset)
);
+}
+/**
- Enable a PCI driver to write PCI controller registers in
- PCI configuration space.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Width Signifies the width of the memory operations.
- @param[in] Offset The offset 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 Offset.
- @param[in out] Buffer The source buffer to write data from.
- @retval EFI_SUCCESS The data was read from the PCI controller.
- @retval EFI_INVALID_PARAMETER "Width" is invalid.
- @retval EFI_INVALID_PARAMETER "Buffer" is NULL.
+**/ +EFI_STATUS +PciIoPciWrite (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT32 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
- if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- return PciRootBridgeIoMemRW (
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Count,
TRUE,
(PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset),
TRUE,
(PTR)(UINTN)Buffer
);
+}
+EFI_STATUS +PciIoCopyMem (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 DestBarIndex,
- IN UINT64 DestOffset,
- IN UINT8 SrcBarIndex,
- IN UINT64 SrcOffset,
- IN UINTN Count
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoMap (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
- IN VOID *HostAddress,
- IN OUT UINTN *NumberOfBytes,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- )
+{
- DMA_MAP_OPERATION DmaOperation;
- if (Operation == EfiPciIoOperationBusMasterRead) {
- DmaOperation = MapOperationBusMasterRead;
- } else if (Operation == EfiPciIoOperationBusMasterWrite) {
- DmaOperation = MapOperationBusMasterWrite;
- } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
- DmaOperation = MapOperationBusMasterCommonBuffer;
- } else {
- return EFI_INVALID_PARAMETER;
- }
- return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);
Are all your peripherals 64-bit DMA capable? If not, you may have a problem here, given that NullDmaLib just returns the CPU address unmodified, so you may want to check the DeviceAddress if the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set. Another complication in the non-coherent case is that the buffer may be remapped by DmaLib, in which case you have no control over the final allocation, unless you perform the bounce buffering here.
+}
+EFI_STATUS +PciIoUnmap (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN VOID *Mapping
- )
+{
- return DmaUnmap (Mapping);
+}
+/**
- Allocate pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
- mapping.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Type This parameter is not used and must be ignored.
- @param[in] MemoryType The type of memory to allocate, EfiBootServicesData
or EfiRuntimeServicesData.
- @param[in] Pages The number of pages to allocate.
- @param[out] HostAddress A pointer to store the base system memory address of
the allocated range.
- @param[in] Attributes The requested bit mask of attributes for the
allocated range. Only the attributes,
EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE and
EFI_PCI_ATTRIBUTE_MEMORY_CACHED may be used with
this function. If any other bits are set, then
EFI_UNSUPPORTED is returned. This function ignores
this bit mask.
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_INVALID_PARAMETER HostAddress is NULL.
- @retval EFI_INVALID_PARAMETER MemoryType is invalid.
- @retval EFI_UNSUPPORTED Attributes is unsupported.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/ +EFI_STATUS +PciIoAllocateBuffer (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN Pages,
- OUT VOID **HostAddress,
- IN UINT64 Attributes
- )
+{
- if (Attributes & (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) {
- return EFI_UNSUPPORTED;
- }
- return DmaAllocateBuffer (MemoryType, Pages, HostAddress);
Same question: are all your peripherals 64-bit DMA capable? If the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set, you must ensure that you allocate below 4 GB (if your platform also has UEFI visible memory above 4 GB)
+}
+EFI_STATUS +PciIoFreeBuffer (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINTN Pages,
- IN VOID *HostAddress
- )
+{
- return DmaFreeBuffer (Pages, HostAddress);
+}
+EFI_STATUS +PciIoFlush (
- IN EFI_PCI_IO_PROTOCOL *This
- )
+{
- return EFI_SUCCESS;
+}
+/**
- Retrieves this PCI controller's current PCI bus number, device number, and
- function number.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[out] SegmentNumber The PCI controller's current PCI segment number.
- @param[out] BusNumber The PCI controller's current PCI bus number.
- @param[out] DeviceNumber The PCI controller's current PCI device number.
- @param[out] FunctionNumber The PCI controller’s current PCI function number.
- @retval EFI_SUCCESS The PCI controller location was returned.
- @retval EFI_INVALID_PARAMETER At least one out of the four output parameters
is a NULL pointer.
+**/ +EFI_STATUS +PciIoGetLocation (
- IN EFI_PCI_IO_PROTOCOL *This,
- OUT UINTN *SegmentNumber,
- OUT UINTN *BusNumber,
- OUT UINTN *DeviceNumber,
- OUT UINTN *FunctionNumber
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
- if ((SegmentNumber == NULL) || (BusNumber == NULL) ||
(DeviceNumber == NULL) || (FunctionNumber == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- *SegmentNumber = Private->Segment;
- *BusNumber = 0xff;
- *DeviceNumber = 0;
- *FunctionNumber = 0;
- return EFI_SUCCESS;
+}
+/**
- Performs an operation on the attributes that this PCI controller supports.
- The operations include getting the set of supported attributes, retrieving
- the current attributes, setting the current attributes, enabling attributes,
- and disabling attributes.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Operation The operation to perform on the attributes for this
PCI controller.
- @param[in] Attributes The mask of attributes that are used for Set,
Enable and Disable operations.
- @param[out] Result A pointer to the result mask of attributes that are
returned for the Get and Supported operations. This
is an optional parameter that may be NULL for the
Set, Enable, and Disable operations.
- @retval EFI_SUCCESS The operation on the PCI controller's
attributes was completed. If the operation
was Get or Supported, then the attribute mask
is returned in Result.
- @retval EFI_INVALID_PARAMETER Operation is greater than or equal to
EfiPciIoAttributeOperationMaximum.
- @retval EFI_INVALID_PARAMETER Operation is Get and Result is NULL.
- @retval EFI_INVALID_PARAMETER Operation is Supported and Result is NULL.
+**/ +EFI_STATUS +PciIoAttributes (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
- IN UINT64 Attributes,
- OUT UINT64 *Result OPTIONAL
- )
+{
- switch (Operation) {
- case EfiPciIoAttributeOperationGet:
- case EfiPciIoAttributeOperationSupported:
- if (Result == NULL) {
return EFI_INVALID_PARAMETER;
- }
- //
- // We are not a real PCI device so just say things we kind of do
- //
- *Result = EFI_PCI_DEVICE_ENABLE;
- break;
- case EfiPciIoAttributeOperationSet:
- case EfiPciIoAttributeOperationEnable:
- case EfiPciIoAttributeOperationDisable:
- if (Attributes & (~EFI_PCI_DEVICE_ENABLE)) {
return EFI_UNSUPPORTED;
- }
- //
- // Since we are not a real PCI device no enable/set or
- // disable operations exist.
- //
- return EFI_SUCCESS;
- default:
- return EFI_INVALID_PARAMETER;
- };
- return EFI_SUCCESS;
+}
+EFI_STATUS +PciIoGetBarAttributes (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINT8 BarIndex,
- OUT UINT64 *Supports, OPTIONAL
- OUT VOID **Resources OPTIONAL
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoSetBarAttributes (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINT64 Attributes,
- IN UINT8 BarIndex,
- IN OUT UINT64 *Offset,
- IN OUT UINT64 *Length
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_PCI_IO_PROTOCOL PciIoTemplate = +{
- PciIoPollMem,
- PciIoPollIo,
- { PciIoMemRead, PciIoMemWrite },
- { PciIoIoRead, PciIoIoWrite },
- { PciIoPciRead, PciIoPciWrite },
- PciIoCopyMem,
- PciIoMap,
- PciIoUnmap,
- PciIoAllocateBuffer,
- PciIoFreeBuffer,
- PciIoFlush,
- PciIoGetLocation,
- PciIoAttributes,
- PciIoGetBarAttributes,
- PciIoSetBarAttributes,
- 0,
- 0
+};
+STATIC +EFI_STATUS +EFIAPI +InstallDevices (
- IN UINTN DeviceId,
- IN UINTN BaseAddr,
- IN UINTN AddressSpaceSize,
- IN UINTN ClassCode1,
- IN UINTN ClassCode2,
- IN UINTN ClassCode3
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private;
- EFI_STATUS Status;
- EFI_HANDLE Handle;
- // Create a private structure
- Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA));
- if (Private == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- return Status;
- }
- // Fill in signature
- Private->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE;
- // Fake Root Bridge structure needs a signature too
- Private->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE;
- // Get the register base
- Private->RootBridge.MemoryStart = BaseAddr;
- // Default to segment zero
- Private->Segment = 0;
- // Calculate the total size of device registers.
- Private->RootBridge.MemorySize = AddressSpaceSize;
- // Create fake PCI config space.
- Private->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00));
- if (Private->ConfigSpace == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- FreePool(Private);
- return Status;
- }
- //
- // Configure PCI config space
- //
- // Invalid vendor Id as it is not an actual device.
- Private->ConfigSpace->Hdr.VendorId = 0xFFFF;
- // Not relevant as the vendor id is not valid.
- Private->ConfigSpace->Hdr.DeviceId = 0x0000;
- Private->ConfigSpace->Hdr.ClassCode[0] = ClassCode1;
- Private->ConfigSpace->Hdr.ClassCode[1] = ClassCode2;
- Private->ConfigSpace->Hdr.ClassCode[2] = ClassCode3;
- Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart;
- Handle = NULL;
- // Unique device path.
- CopyMem(&Private->DevicePath, &PciIoDevicePathTemplate, sizeof(PciIoDevicePathTemplate));
- Private->DevicePath.AcpiDevicePath.UID = 0;
- Private->DevicePath.PciDevicePath.Device = DeviceId;
- // Copy protocol structure
- CopyMem(&Private->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate));
- Status = gBS->InstallMultipleProtocolInterfaces(
&Handle,
&gEfiPciIoProtocolGuid,
&Private->PciIoProtocol,
&gEfiDevicePathProtocolGuid,
&Private->DevicePath,
NULL
);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: InstallMultipleProtocolInterfaces failed\n"));
- }
- return Status;
+}
+// +// Below function is used to parse devices information from PCD strings. +// +EFI_STATUS +EFIAPI +PciEmulationEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
+{
- EFI_STATUS Status;
- UINT8 i, DevCount;
- UINTN BaseAddrTable[PcdGet32 (PcdPciEDevCount)];
- UINTN RegSizeTable[PcdGet32 (PcdPciEDevCount)];
- UINTN DevClass1Table[PcdGet32 (PcdPciEDevCount)];
- UINTN DevClass2Table[PcdGet32 (PcdPciEDevCount)];
- UINTN DevClass3Table[PcdGet32 (PcdPciEDevCount)];
- DevCount = PcdGet32 (PcdPciEDevCount);
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevBaseAddress), DevCount, BaseAddrTable, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevBaseAddress format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevRegSize), DevCount, RegSizeTable, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevRegSize format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode1), DevCount, DevClass1Table, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode1 format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode2), DevCount, DevClass2Table, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode2 format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode3), DevCount, DevClass3Table, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode3 format\n"));
- return EFI_INVALID_PARAMETER;
- }
- for (i = 0; i < DevCount; i++) {
- Status = InstallDevices (i, BaseAddrTable[i], RegSizeTable[i],
DevClass1Table[i], DevClass2Table[i], DevClass3Table[i]);
- if (EFI_ERROR(Status)) {
DEBUG((DEBUG_ERROR, "PciEmulation: Cannot install device with ID=%d\n", i));
- }
- }
- return Status;
+} diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.h b/Platforms/Marvell/PciEmulation/PciEmulation.h new file mode 100644 index 0000000..4f75539 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.h @@ -0,0 +1,271 @@ +/** @file
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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.
+**/
+#ifndef _PCI_ROOT_BRIDGE_H_ +#define _PCI_ROOT_BRIDGE_H_
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h> +#include <IndustryStandard/Pci22.h> +#include <IndustryStandard/PciCodeId.h>
+#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/DmaLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/IoLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/ParsePcdLib.h> +#include <Library/PcdLib.h> +#include <Library/PciLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h>
+#include <Protocol/DevicePath.h> +#include <Protocol/EmbeddedExternalDevice.h> +#include <Protocol/PciHostBridgeResourceAllocation.h> +#include <Protocol/PciIo.h> +#include <Protocol/PciRootBridgeIo.h>
+#define ACPI_CONFIG_IO 0 +#define ACPI_CONFIG_MMIO 1 +#define ACPI_CONFIG_BUS 2
+#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('P', 'c', 'i', 'F')
+typedef struct {
- ACPI_HID_DEVICE_PATH AcpiDevicePath;
- EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+typedef struct {
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Desc[3];
- EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;
+} ACPI_CONFIG_INFO;
+typedef struct {
- UINT32 Signature;
- EFI_HANDLE Handle;
- EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io;
- EFI_PCI_ROOT_BRIDGE_DEVICE_PATH DevicePath;
- UINT8 StartBus;
- UINT8 EndBus;
- UINT16 Type;
- UINT32 MemoryStart;
- UINT32 MemorySize;
- UINTN IoOffset;
- UINT32 IoStart;
- UINT32 IoSize;
- UINT64 PciAttributes;
- ACPI_CONFIG_INFO *Config;
+} PCI_ROOT_BRIDGE;
+#define INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) CR (a, PCI_ROOT_BRIDGE, Io, PCI_ROOT_BRIDGE_SIGNATURE)
+typedef union {
- UINT8 volatile *buf;
- UINT8 volatile *ui8;
- UINT16 volatile *ui16;
- UINT32 volatile *ui32;
- UINT64 volatile *ui64;
- UINTN volatile ui;
+} PTR;
+EFI_STATUS +EFIAPI +PciRootBridgeIoPollMem (
- 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 +PciRootBridgeIoPollIo (
- 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 +PciRootBridgeIoMemRead (
- 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 +PciRootBridgeIoMemWrite (
- 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 +PciRootBridgeIoIoRead (
- 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 +PciRootBridgeIoIoWrite (
- 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 +PciRootBridgeIoCopyMem (
- IN 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 +PciRootBridgeIoPciRead (
- 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 +PciRootBridgeIoPciWrite (
- 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 +PciRootBridgeIoMap (
- 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 +PciRootBridgeIoUnmap (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- IN VOID *Mapping
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoAllocateBuffer (
- 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 +PciRootBridgeIoFreeBuffer (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- IN UINTN Pages,
- OUT VOID *HostAddress
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoFlush (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoGetAttributes (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- OUT UINT64 *Supported,
- OUT UINT64 *Attributes
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoSetAttributes (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- IN UINT64 Attributes,
- IN OUT UINT64 *ResourceBase,
- IN OUT UINT64 *ResourceLength
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoConfiguration (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- OUT VOID **Resources
- );
+// +// Private Function Prototypes +// +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRW (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
- IN UINTN Count,
- IN BOOLEAN InStrideFlag,
- IN PTR In,
- IN BOOLEAN OutStrideFlag,
- OUT PTR Out
- );
+BOOLEAN +PciIoMemAddressValid (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINT64 Address
- );
+#endif diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.inf b/Platforms/Marvell/PciEmulation/PciEmulation.inf new file mode 100644 index 0000000..30ddfc2 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.inf @@ -0,0 +1,65 @@ +/** @file
- Copyright (c) 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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.
+**/
+[Defines]
- INF_VERSION = 0x00010019
- BASE_NAME = PciEmulation
- FILE_GUID = 3dfa08da-923b-4841-9435-c77a604d7493
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 1.0
- ENTRY_POINT = PciEmulationEntryPoint
+[Sources.common]
- PciEmulation.c
- PciRootBridgeIo.c
+[Packages]
- ArmPkg/ArmPkg.dec
- EmbeddedPkg/EmbeddedPkg.dec
- IntelFrameworkPkg/IntelFrameworkPkg.dec
- MdeModulePkg/MdeModulePkg.dec
- MdePkg/MdePkg.dec
- OpenPlatformPkg/Platforms/Marvell/Marvell.dec
- ShellPkg/ShellPkg.dec
Why on earth do you need the ShellPkg in a DXE_DRIVER module?
+[LibraryClasses]
- BaseLib
- DmaLib
- DxeServicesTableLib
- IoLib
- ParsePcdLib
- UefiBootServicesTableLib
- UefiDriverEntryPoint
- UefiLib
- UefiRuntimeServicesTableLib
+[Protocols]
- gEfiDevicePathProtocolGuid
- gEfiPciHostBridgeResourceAllocationProtocolGuid
- gEfiPciIoProtocolGuid
- gEfiPciRootBridgeIoProtocolGuid
- gEmbeddedExternalDeviceProtocolGuid
+[Pcd]
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3
- gMarvellTokenSpaceGuid.PcdPciEDevCount
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize
+[Depex]
- TRUE
diff --git a/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c b/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c new file mode 100644 index 0000000..dab26b6 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c @@ -0,0 +1,314 @@ +/** @file
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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 "PciEmulation.h"
+BOOLEAN +PciRootBridgeMemAddressValid (
- IN PCI_ROOT_BRIDGE *Private,
- IN UINT64 Address
- )
+{
- if ((Address >= Private->MemoryStart) &&
(Address < (Private->MemoryStart + Private->MemorySize))) {
- return TRUE;
- }
- return FALSE;
+}
+EFI_STATUS +PciRootBridgeIoMemRW (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
- IN UINTN Count,
- IN BOOLEAN InStrideFlag,
- IN PTR In,
- IN BOOLEAN OutStrideFlag,
- OUT PTR Out
- )
+{
- UINTN Stride;
- UINTN InStride;
- UINTN OutStride;
- Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03);
- Stride = (UINTN)1 << Width;
- InStride = InStrideFlag ? Stride : 0;
- OutStride = OutStrideFlag ? Stride : 0;
- //
- // Loop for each iteration and move the data
- //
- switch (Width) {
- case EfiPciWidthUint8:
- for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
*In.ui8 = *Out.ui8;
- }
- break;
- case EfiPciWidthUint16:
- for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
*In.ui16 = *Out.ui16;
- }
- break;
- case EfiPciWidthUint32:
- for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
*In.ui32 = *Out.ui32;
- }
- break;
- default:
- return EFI_INVALID_PARAMETER;
- }
- return EFI_SUCCESS;
+}
+EFI_STATUS +PciRootBridgeIoPciRW (
- 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
- )
+{
- return EFI_SUCCESS;
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge
- memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRead (
- 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 *Private;
- UINTN AlignMask;
- PTR In;
- PTR Out;
- if ( Buffer == NULL ) {
- return EFI_INVALID_PARAMETER;
- }
- Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
- if (!PciRootBridgeMemAddressValid (Private, Address)) {
- return EFI_INVALID_PARAMETER;
- }
- AlignMask = (1 << (Width & 0x03)) - 1;
- if (Address & AlignMask) {
- return EFI_INVALID_PARAMETER;
- }
- In.buf = Buffer;
- Out.buf = (VOID *)(UINTN) Address;
- switch (Width) {
- case EfiPciWidthUint8:
- case EfiPciWidthUint16:
- case EfiPciWidthUint32:
- case EfiPciWidthUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out);
- case EfiPciWidthFifoUint8:
- case EfiPciWidthFifoUint16:
- case EfiPciWidthFifoUint32:
- case EfiPciWidthFifoUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out);
- case EfiPciWidthFillUint8:
- case EfiPciWidthFillUint16:
- case EfiPciWidthFillUint32:
- case EfiPciWidthFillUint64:
- return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out);
- default:
- break;
- }
- return EFI_INVALID_PARAMETER;
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemWrite (
- 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 *Private;
- UINTN AlignMask;
- PTR In;
- PTR Out;
- if (Buffer == NULL ) {
- return EFI_INVALID_PARAMETER;
- }
- Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
- if (!PciRootBridgeMemAddressValid (Private, Address)) {
- return EFI_INVALID_PARAMETER;
- }
- AlignMask = (1 << (Width & 0x03)) - 1;
- if (Address & AlignMask) {
- return EFI_INVALID_PARAMETER;
- }
- In.buf = (VOID *)(UINTN) Address;
- Out.buf = Buffer;
- switch (Width) {
- case EfiPciWidthUint8:
- case EfiPciWidthUint16:
- case EfiPciWidthUint32:
- case EfiPciWidthUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out);
- case EfiPciWidthFifoUint8:
- case EfiPciWidthFifoUint16:
- case EfiPciWidthFifoUint32:
- case EfiPciWidthFifoUint64:
- return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out);
- case EfiPciWidthFillUint8:
- case EfiPciWidthFillUint16:
- case EfiPciWidthFillUint32:
- case EfiPciWidthFillUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out);
- default:
- break;
- }
- return EFI_INVALID_PARAMETER;
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge
- memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciRead (
- 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;
- }
- return PciRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer);
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciWrite (
- 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;
- }
- return PciRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer);
+}
1.8.3.1
On 31 October 2016 at 11:42, Jan Dąbroś jsd@semihalf.com wrote:
Hi Ard,
Thanks a lot for your remarks. Please find my answers inline.
Do you have any more comments regarding this and next commits in patchset? Did you have a chance to take a look at them?
No, not yet.
+Next five PCDs are in unicode string, format containing settings for all devices +separated with semicolon.
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress
I must say, I quite dislike this way of putting ; delimited strings into PCDs and then parsing them at runtime. But I don't have anything better to propose, so this is OK for now. We do intend to improve the situation somewhat around PCI I/O emulation (which is a terrible name as well, by the way) but for now this is fine.
We also cannot find anything better - other PCI I/O emulation drivers are limited to single type of device (which are hardcoded by the way). Although it's not perfect, this approach gives us some flexibility and scalability.
I see. As I said, I don't have anything better to propose, although I am working on a generic PCI emulation driver.
+#PciEmulation
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|{ 0x0 }|VOID*|0x30000058
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|{ 0x0 }|VOID*|0x30000059
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|{ 0x0 }|VOID*|0x30000060
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|{ 0x0 }|VOID*|0x30000061
- gMarvellTokenSpaceGuid.PcdPciEDevCount|0|UINT32|0x30000062
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize|{ 0x0 }|VOID*|0x30000063
One potential issue with covering all PCI I/O emulated devices by a single driver is that they must all be coherent or non-coherent. There is no way for a single device to deviate in this respect. Did you take that into account for your platform?
All devices on our platform are coherent, so it isn't a problem in our case. I think that this driver may be improved in future in order to meet the requirements of another SoC, e.g support for coherent and non-coherent devices - however that's not the case with Armada70x0/80x0 family now. What do you think?
If they are all coherent, I think this is fine, but you are using the wrong DMA lib instance. See below
- if (Operation == EfiPciIoOperationBusMasterRead
) {
- DmaOperation = MapOperationBusMasterRead;
- } else if (Operation == EfiPciIoOperationBusMasterWrite) {
- DmaOperation = MapOperationBusMasterWrite;
- } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
- DmaOperation = MapOperationBusMasterCommonBuffer;
- } else {
- return EFI_INVALID_PARAMETER;
- }
- return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);
Are all your peripherals 64-bit DMA capable? If not, you may have a problem here, given that NullDmaLib just returns the CPU address unmodified, so you may want to check the DeviceAddress if the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set. Another complication in the non-coherent case is that the buffer may be remapped by DmaLib, in which case you have no control over the final allocation, unless you perform the bounce buffering here.
Since our platform has less than 4GB memory visible for UEFI, returned address shouldn't be above this region. We use ArmDmaLib not NullDmaLib as DmaLib implementation. As I wrote above, we are using cache-coherent devices, so the problem with remapped buffer couldn't happen here.
You should be using NullDmaLib. ArmDmaLib is for non-coherent DMA only.
+EFI_STATUS +PciIoAllocateBuffer (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN Pages,
- OUT VOID **HostAddress,
- IN UINT64 Attributes
- )
+{
- if (Attributes & (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) {
- return EFI_UNSUPPORTED;
- }
- return DmaAllocateBuffer (MemoryType, Pages, HostAddress);
Same question: are all your peripherals 64-bit DMA capable? If the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set, you must ensure that you allocate below 4 GB (if your platform also has UEFI visible memory above 4 GB)
Since we have less than 4GB memory visible, there shouldn't be problem with allocation above this region.
OK, good to know.
+[Packages]
- ArmPkg/ArmPkg.dec
- EmbeddedPkg/EmbeddedPkg.dec
- IntelFrameworkPkg/IntelFrameworkPkg.dec
- MdeModulePkg/MdeModulePkg.dec
- MdePkg/MdePkg.dec
- OpenPlatformPkg/Platforms/Marvell/Marvell.dec
- ShellPkg/ShellPkg.dec
Why on earth do you need the ShellPkg in a DXE_DRIVER module?
It's definitely placed here by mistake. Will be removed on v2.
2016-10-28 18:19 GMT+02:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
Hello Marcin,
On 28 October 2016 at 16:42, Marcin Wojtas mw@semihalf.com wrote:
From: Jan Dąbroś jsd@semihalf.com
In order to use numerous UEFI drivers based on PCI bus, PciEmulation driver is implemented. This solution is based on Chips/TexasInstruments/Omap35xx/PciEmulation/ Configuring fake devices is performed via PCD.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com
.../Marvell/PortingGuide/PciEmulation.txt | 53 ++ Platforms/Marvell/Marvell.dec | 8 + Platforms/Marvell/PciEmulation/PciEmulation.c | 678 +++++++++++++++++++++ Platforms/Marvell/PciEmulation/PciEmulation.h | 271 ++++++++ Platforms/Marvell/PciEmulation/PciEmulation.inf | 65 ++ Platforms/Marvell/PciEmulation/PciRootBridgeIo.c | 314 ++++++++++ 6 files changed, 1389 insertions(+) create mode 100644 Documentation/Marvell/PortingGuide/PciEmulation.txt create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.c create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.h create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.inf create mode 100644 Platforms/Marvell/PciEmulation/PciRootBridgeIo.c
diff --git a/Documentation/Marvell/PortingGuide/PciEmulation.txt b/Documentation/Marvell/PortingGuide/PciEmulation.txt new file mode 100644 index 0000000..5bb812a --- /dev/null +++ b/Documentation/Marvell/PortingGuide/PciEmulation.txt @@ -0,0 +1,53 @@ +PciEmulation configuration +-------------------------- +Instalation of various Pci devices via PciEmulation driver is performed via set +of PCDs. Following are available:
- gMarvellTokenSpaceGuid.PcdPciEDevCount
+Indicates how many fake Pci devices are placed on board.
+Next five PCDs are in unicode string, format containing settings for all devices +separated with semicolon.
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress
I must say, I quite dislike this way of putting ; delimited strings into PCDs and then parsing them at runtime. But I don't have anything better to propose, so this is OK for now. We do intend to improve the situation somewhat around PCI I/O emulation (which is a terrible name as well, by the way) but for now this is fine.
+Indicates base address of Pci device register space.
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize
+Indicates size of Pci device register space.
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1
+Indicates device subclass code.
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2
+Indicates device class code.
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3
+Indicates Pci device class code.
+Examples +-------- +Assuming that there are two fake Pci xHCI controllers with register space +0xF2500000 - 0xF2510000 and 0xF2510000 - 0xF2520000 following PCD values should +be set:
- gMarvellTokenSpaceGuid.PcdPciEDevCount|2
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000"
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000"
- ## XHCI subclass
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30"
- ## USB controller class
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03"
- ## Serial bus controller Pci device class
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C"
+Notes +----- +1.In order to find proper values for Pci class codes, please refer to
- PCI Local Bus Specification.
+2.PCDs are configured via UNICODE strings - remember to add L marker. diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index db99230..f56987d 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -209,6 +209,14 @@ gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress|0|UINT64|0x3000031 gMarvellTokenSpaceGuid.PcdPp2XlgDevSize|0|UINT32|0x3000032
+#PciEmulation
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|{ 0x0 }|VOID*|0x30000058
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|{ 0x0 }|VOID*|0x30000059
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|{ 0x0 }|VOID*|0x30000060
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|{ 0x0 }|VOID*|0x30000061
- gMarvellTokenSpaceGuid.PcdPciEDevCount|0|UINT32|0x30000062
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize|{ 0x0 }|VOID*|0x30000063
One potential issue with covering all PCI I/O emulated devices by a single driver is that they must all be coherent or non-coherent. There is no way for a single device to deviate in this respect. Did you take that into account for your platform?
#ResetLib gMarvellTokenSpaceGuid.PcdResetRegAddress|0|UINT64|0x40000050 gMarvellTokenSpaceGuid.PcdResetRegMask|0|UINT32|0x4000051 diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.c b/Platforms/Marvell/PciEmulation/PciEmulation.c new file mode 100644 index 0000000..a800bcb --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.c @@ -0,0 +1,678 @@ +/** @file
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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 "PciEmulation.h"
+typedef struct {
- ACPI_HID_DEVICE_PATH AcpiDevicePath;
- PCI_DEVICE_PATH PciDevicePath;
- EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_IO_DEVICE_PATH;
+typedef struct {
- UINT32 Signature;
- EFI_PCI_IO_DEVICE_PATH DevicePath;
- EFI_PCI_IO_PROTOCOL PciIoProtocol;
- PCI_TYPE00 *ConfigSpace;
- PCI_ROOT_BRIDGE RootBridge;
- UINTN Segment;
+} EFI_PCI_IO_PRIVATE_DATA;
+#define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o') +#define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_PCI_IO_PRIVATE_DATA, \
PciIoProtocol, \
EFI_PCI_IO_PRIVATE_DATA_SIGNATURE)
+EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate = +{
- {
- {
ACPI_DEVICE_PATH,
ACPI_DP,
{
sizeof (ACPI_HID_DEVICE_PATH),
0
}
- },
- EISA_PNP_ID(0x0A03), // HID
- 0 // UID
- },
- {
- {
HARDWARE_DEVICE_PATH,
HW_PCI_DP,
{
sizeof (PCI_DEVICE_PATH),
0
}
- },
- 0,
- 0
- },
- {
- END_DEVICE_PATH_TYPE,
- END_ENTIRE_DEVICE_PATH_SUBTYPE,
- {
sizeof (EFI_DEVICE_PATH_PROTOCOL),
0
- }
- }
+};
+EFI_STATUS +PciIoPollMem (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINT64 Mask,
- IN UINT64 Value,
- IN UINT64 Delay,
- OUT UINT64 *Result
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoPollIo (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINT64 Mask,
- IN UINT64 Value,
- IN UINT64 Delay,
- OUT UINT64 *Result
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoMemRead (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
- return PciRootBridgeIoMemRead (
&Private->RootBridge.Io,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
Count,
Buffer
);
+}
+EFI_STATUS +PciIoMemWrite (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
- return PciRootBridgeIoMemWrite (
&Private->RootBridge.Io,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
Count,
Buffer
);
+}
+EFI_STATUS +PciIoIoRead (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoIoWrite (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+/**
- Enable a PCI driver to read PCI controller registers in
- PCI configuration space.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Width Signifies the width of the memory operations.
- @param[in] Offset The offset 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 Offset.
- @param[in out] Buffer The destination buffer to store the results.
- @retval EFI_SUCCESS The data was read from the PCI controller.
- @retval EFI_INVALID_PARAMETER "Width" is invalid.
- @retval EFI_INVALID_PARAMETER "Buffer" is NULL.
+**/ +EFI_STATUS +PciIoPciRead (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT32 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
- if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- return PciRootBridgeIoMemRW (
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width,
Count,
TRUE,
(PTR)(UINTN)Buffer,
TRUE,
(PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset)
);
+}
+/**
- Enable a PCI driver to write PCI controller registers in
- PCI configuration space.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Width Signifies the width of the memory operations.
- @param[in] Offset The offset 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 Offset.
- @param[in out] Buffer The source buffer to write data from.
- @retval EFI_SUCCESS The data was read from the PCI controller.
- @retval EFI_INVALID_PARAMETER "Width" is invalid.
- @retval EFI_INVALID_PARAMETER "Buffer" is NULL.
+**/ +EFI_STATUS +PciIoPciWrite (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT32 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
- if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- return PciRootBridgeIoMemRW (
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Count,
TRUE,
(PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset),
TRUE,
(PTR)(UINTN)Buffer
);
+}
+EFI_STATUS +PciIoCopyMem (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 DestBarIndex,
- IN UINT64 DestOffset,
- IN UINT8 SrcBarIndex,
- IN UINT64 SrcOffset,
- IN UINTN Count
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoMap (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
- IN VOID *HostAddress,
- IN OUT UINTN *NumberOfBytes,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- )
+{
- DMA_MAP_OPERATION DmaOperation;
- if (Operation == EfiPciIoOperationBusMasterRead) {
- DmaOperation = MapOperationBusMasterRead;
- } else if (Operation == EfiPciIoOperationBusMasterWrite) {
- DmaOperation = MapOperationBusMasterWrite;
- } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
- DmaOperation = MapOperationBusMasterCommonBuffer;
- } else {
- return EFI_INVALID_PARAMETER;
- }
- return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);
Are all your peripherals 64-bit DMA capable? If not, you may have a problem here, given that NullDmaLib just returns the CPU address unmodified, so you may want to check the DeviceAddress if the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set. Another complication in the non-coherent case is that the buffer may be remapped by DmaLib, in which case you have no control over the final allocation, unless you perform the bounce buffering here.
+}
+EFI_STATUS +PciIoUnmap (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN VOID *Mapping
- )
+{
- return DmaUnmap (Mapping);
+}
+/**
- Allocate pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
- mapping.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Type This parameter is not used and must be ignored.
- @param[in] MemoryType The type of memory to allocate, EfiBootServicesData
or EfiRuntimeServicesData.
- @param[in] Pages The number of pages to allocate.
- @param[out] HostAddress A pointer to store the base system memory address of
the allocated range.
- @param[in] Attributes The requested bit mask of attributes for the
allocated range. Only the attributes,
EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE and
EFI_PCI_ATTRIBUTE_MEMORY_CACHED may be used with
this function. If any other bits are set, then
EFI_UNSUPPORTED is returned. This function ignores
this bit mask.
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_INVALID_PARAMETER HostAddress is NULL.
- @retval EFI_INVALID_PARAMETER MemoryType is invalid.
- @retval EFI_UNSUPPORTED Attributes is unsupported.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/ +EFI_STATUS +PciIoAllocateBuffer (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN Pages,
- OUT VOID **HostAddress,
- IN UINT64 Attributes
- )
+{
- if (Attributes & (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) {
- return EFI_UNSUPPORTED;
- }
- return DmaAllocateBuffer (MemoryType, Pages, HostAddress);
Same question: are all your peripherals 64-bit DMA capable? If the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set, you must ensure that you allocate below 4 GB (if your platform also has UEFI visible memory above 4 GB)
+}
+EFI_STATUS +PciIoFreeBuffer (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINTN Pages,
- IN VOID *HostAddress
- )
+{
- return DmaFreeBuffer (Pages, HostAddress);
+}
+EFI_STATUS +PciIoFlush (
- IN EFI_PCI_IO_PROTOCOL *This
- )
+{
- return EFI_SUCCESS;
+}
+/**
- Retrieves this PCI controller's current PCI bus number, device number, and
- function number.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[out] SegmentNumber The PCI controller's current PCI segment number.
- @param[out] BusNumber The PCI controller's current PCI bus number.
- @param[out] DeviceNumber The PCI controller's current PCI device number.
- @param[out] FunctionNumber The PCI controller’s current PCI function number.
- @retval EFI_SUCCESS The PCI controller location was returned.
- @retval EFI_INVALID_PARAMETER At least one out of the four output parameters
is a NULL pointer.
+**/ +EFI_STATUS +PciIoGetLocation (
- IN EFI_PCI_IO_PROTOCOL *This,
- OUT UINTN *SegmentNumber,
- OUT UINTN *BusNumber,
- OUT UINTN *DeviceNumber,
- OUT UINTN *FunctionNumber
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
- if ((SegmentNumber == NULL) || (BusNumber == NULL) ||
(DeviceNumber == NULL) || (FunctionNumber == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- *SegmentNumber = Private->Segment;
- *BusNumber = 0xff;
- *DeviceNumber = 0;
- *FunctionNumber = 0;
- return EFI_SUCCESS;
+}
+/**
- Performs an operation on the attributes that this PCI controller supports.
- The operations include getting the set of supported attributes, retrieving
- the current attributes, setting the current attributes, enabling attributes,
- and disabling attributes.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Operation The operation to perform on the attributes for this
PCI controller.
- @param[in] Attributes The mask of attributes that are used for Set,
Enable and Disable operations.
- @param[out] Result A pointer to the result mask of attributes that are
returned for the Get and Supported operations. This
is an optional parameter that may be NULL for the
Set, Enable, and Disable operations.
- @retval EFI_SUCCESS The operation on the PCI controller's
attributes was completed. If the operation
was Get or Supported, then the attribute mask
is returned in Result.
- @retval EFI_INVALID_PARAMETER Operation is greater than or equal to
EfiPciIoAttributeOperationMaximum.
- @retval EFI_INVALID_PARAMETER Operation is Get and Result is NULL.
- @retval EFI_INVALID_PARAMETER Operation is Supported and Result is NULL.
+**/ +EFI_STATUS +PciIoAttributes (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
- IN UINT64 Attributes,
- OUT UINT64 *Result OPTIONAL
- )
+{
- switch (Operation) {
- case EfiPciIoAttributeOperationGet:
- case EfiPciIoAttributeOperationSupported:
- if (Result == NULL) {
return EFI_INVALID_PARAMETER;
- }
- //
- // We are not a real PCI device so just say things we kind of do
- //
- *Result = EFI_PCI_DEVICE_ENABLE;
- break;
- case EfiPciIoAttributeOperationSet:
- case EfiPciIoAttributeOperationEnable:
- case EfiPciIoAttributeOperationDisable:
- if (Attributes & (~EFI_PCI_DEVICE_ENABLE)) {
return EFI_UNSUPPORTED;
- }
- //
- // Since we are not a real PCI device no enable/set or
- // disable operations exist.
- //
- return EFI_SUCCESS;
- default:
- return EFI_INVALID_PARAMETER;
- };
- return EFI_SUCCESS;
+}
+EFI_STATUS +PciIoGetBarAttributes (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINT8 BarIndex,
- OUT UINT64 *Supports, OPTIONAL
- OUT VOID **Resources OPTIONAL
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoSetBarAttributes (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINT64 Attributes,
- IN UINT8 BarIndex,
- IN OUT UINT64 *Offset,
- IN OUT UINT64 *Length
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_PCI_IO_PROTOCOL PciIoTemplate = +{
- PciIoPollMem,
- PciIoPollIo,
- { PciIoMemRead, PciIoMemWrite },
- { PciIoIoRead, PciIoIoWrite },
- { PciIoPciRead, PciIoPciWrite },
- PciIoCopyMem,
- PciIoMap,
- PciIoUnmap,
- PciIoAllocateBuffer,
- PciIoFreeBuffer,
- PciIoFlush,
- PciIoGetLocation,
- PciIoAttributes,
- PciIoGetBarAttributes,
- PciIoSetBarAttributes,
- 0,
- 0
+};
+STATIC +EFI_STATUS +EFIAPI +InstallDevices (
- IN UINTN DeviceId,
- IN UINTN BaseAddr,
- IN UINTN AddressSpaceSize,
- IN UINTN ClassCode1,
- IN UINTN ClassCode2,
- IN UINTN ClassCode3
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private;
- EFI_STATUS Status;
- EFI_HANDLE Handle;
- // Create a private structure
- Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA));
- if (Private == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- return Status;
- }
- // Fill in signature
- Private->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE;
- // Fake Root Bridge structure needs a signature too
- Private->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE;
- // Get the register base
- Private->RootBridge.MemoryStart = BaseAddr;
- // Default to segment zero
- Private->Segment = 0;
- // Calculate the total size of device registers.
- Private->RootBridge.MemorySize = AddressSpaceSize;
- // Create fake PCI config space.
- Private->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00));
- if (Private->ConfigSpace == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- FreePool(Private);
- return Status;
- }
- //
- // Configure PCI config space
- //
- // Invalid vendor Id as it is not an actual device.
- Private->ConfigSpace->Hdr.VendorId = 0xFFFF;
- // Not relevant as the vendor id is not valid.
- Private->ConfigSpace->Hdr.DeviceId = 0x0000;
- Private->ConfigSpace->Hdr.ClassCode[0] = ClassCode1;
- Private->ConfigSpace->Hdr.ClassCode[1] = ClassCode2;
- Private->ConfigSpace->Hdr.ClassCode[2] = ClassCode3;
- Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart;
- Handle = NULL;
- // Unique device path.
- CopyMem(&Private->DevicePath, &PciIoDevicePathTemplate, sizeof(PciIoDevicePathTemplate));
- Private->DevicePath.AcpiDevicePath.UID = 0;
- Private->DevicePath.PciDevicePath.Device = DeviceId;
- // Copy protocol structure
- CopyMem(&Private->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate));
- Status = gBS->InstallMultipleProtocolInterfaces(
&Handle,
&gEfiPciIoProtocolGuid,
&Private->PciIoProtocol,
&gEfiDevicePathProtocolGuid,
&Private->DevicePath,
NULL
);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: InstallMultipleProtocolInterfaces failed\n"));
- }
- return Status;
+}
+// +// Below function is used to parse devices information from PCD strings. +// +EFI_STATUS +EFIAPI +PciEmulationEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
+{
- EFI_STATUS Status;
- UINT8 i, DevCount;
- UINTN BaseAddrTable[PcdGet32 (PcdPciEDevCount)];
- UINTN RegSizeTable[PcdGet32 (PcdPciEDevCount)];
- UINTN DevClass1Table[PcdGet32 (PcdPciEDevCount)];
- UINTN DevClass2Table[PcdGet32 (PcdPciEDevCount)];
- UINTN DevClass3Table[PcdGet32 (PcdPciEDevCount)];
- DevCount = PcdGet32 (PcdPciEDevCount);
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevBaseAddress), DevCount, BaseAddrTable, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevBaseAddress format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevRegSize), DevCount, RegSizeTable, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevRegSize format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode1), DevCount, DevClass1Table, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode1 format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode2), DevCount, DevClass2Table, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode2 format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode3), DevCount, DevClass3Table, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode3 format\n"));
- return EFI_INVALID_PARAMETER;
- }
- for (i = 0; i < DevCount; i++) {
- Status = InstallDevices (i, BaseAddrTable[i], RegSizeTable[i],
DevClass1Table[i], DevClass2Table[i], DevClass3Table[i]);
- if (EFI_ERROR(Status)) {
DEBUG((DEBUG_ERROR, "PciEmulation: Cannot install device with ID=%d\n", i));
- }
- }
- return Status;
+} diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.h b/Platforms/Marvell/PciEmulation/PciEmulation.h new file mode 100644 index 0000000..4f75539 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.h @@ -0,0 +1,271 @@ +/** @file
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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.
+**/
+#ifndef _PCI_ROOT_BRIDGE_H_ +#define _PCI_ROOT_BRIDGE_H_
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h> +#include <IndustryStandard/Pci22.h> +#include <IndustryStandard/PciCodeId.h>
+#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/DmaLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/IoLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/ParsePcdLib.h> +#include <Library/PcdLib.h> +#include <Library/PciLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h>
+#include <Protocol/DevicePath.h> +#include <Protocol/EmbeddedExternalDevice.h> +#include <Protocol/PciHostBridgeResourceAllocation.h> +#include <Protocol/PciIo.h> +#include <Protocol/PciRootBridgeIo.h>
+#define ACPI_CONFIG_IO 0 +#define ACPI_CONFIG_MMIO 1 +#define ACPI_CONFIG_BUS 2
+#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('P', 'c', 'i', 'F')
+typedef struct {
- ACPI_HID_DEVICE_PATH AcpiDevicePath;
- EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+typedef struct {
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Desc[3];
- EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;
+} ACPI_CONFIG_INFO;
+typedef struct {
- UINT32 Signature;
- EFI_HANDLE Handle;
- EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io;
- EFI_PCI_ROOT_BRIDGE_DEVICE_PATH DevicePath;
- UINT8 StartBus;
- UINT8 EndBus;
- UINT16 Type;
- UINT32 MemoryStart;
- UINT32 MemorySize;
- UINTN IoOffset;
- UINT32 IoStart;
- UINT32 IoSize;
- UINT64 PciAttributes;
- ACPI_CONFIG_INFO *Config;
+} PCI_ROOT_BRIDGE;
+#define INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) CR (a, PCI_ROOT_BRIDGE, Io, PCI_ROOT_BRIDGE_SIGNATURE)
+typedef union {
- UINT8 volatile *buf;
- UINT8 volatile *ui8;
- UINT16 volatile *ui16;
- UINT32 volatile *ui32;
- UINT64 volatile *ui64;
- UINTN volatile ui;
+} PTR;
+EFI_STATUS +EFIAPI +PciRootBridgeIoPollMem (
- 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 +PciRootBridgeIoPollIo (
- 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 +PciRootBridgeIoMemRead (
- 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 +PciRootBridgeIoMemWrite (
- 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 +PciRootBridgeIoIoRead (
- 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 +PciRootBridgeIoIoWrite (
- 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 +PciRootBridgeIoCopyMem (
- IN 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 +PciRootBridgeIoPciRead (
- 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 +PciRootBridgeIoPciWrite (
- 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 +PciRootBridgeIoMap (
- 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 +PciRootBridgeIoUnmap (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- IN VOID *Mapping
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoAllocateBuffer (
- 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 +PciRootBridgeIoFreeBuffer (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- IN UINTN Pages,
- OUT VOID *HostAddress
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoFlush (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoGetAttributes (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- OUT UINT64 *Supported,
- OUT UINT64 *Attributes
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoSetAttributes (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- IN UINT64 Attributes,
- IN OUT UINT64 *ResourceBase,
- IN OUT UINT64 *ResourceLength
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoConfiguration (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- OUT VOID **Resources
- );
+// +// Private Function Prototypes +// +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRW (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
- IN UINTN Count,
- IN BOOLEAN InStrideFlag,
- IN PTR In,
- IN BOOLEAN OutStrideFlag,
- OUT PTR Out
- );
+BOOLEAN +PciIoMemAddressValid (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINT64 Address
- );
+#endif diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.inf b/Platforms/Marvell/PciEmulation/PciEmulation.inf new file mode 100644 index 0000000..30ddfc2 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.inf @@ -0,0 +1,65 @@ +/** @file
- Copyright (c) 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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.
+**/
+[Defines]
- INF_VERSION = 0x00010019
- BASE_NAME = PciEmulation
- FILE_GUID = 3dfa08da-923b-4841-9435-c77a604d7493
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 1.0
- ENTRY_POINT = PciEmulationEntryPoint
+[Sources.common]
- PciEmulation.c
- PciRootBridgeIo.c
+[Packages]
- ArmPkg/ArmPkg.dec
- EmbeddedPkg/EmbeddedPkg.dec
- IntelFrameworkPkg/IntelFrameworkPkg.dec
- MdeModulePkg/MdeModulePkg.dec
- MdePkg/MdePkg.dec
- OpenPlatformPkg/Platforms/Marvell/Marvell.dec
- ShellPkg/ShellPkg.dec
Why on earth do you need the ShellPkg in a DXE_DRIVER module?
+[LibraryClasses]
- BaseLib
- DmaLib
- DxeServicesTableLib
- IoLib
- ParsePcdLib
- UefiBootServicesTableLib
- UefiDriverEntryPoint
- UefiLib
- UefiRuntimeServicesTableLib
+[Protocols]
- gEfiDevicePathProtocolGuid
- gEfiPciHostBridgeResourceAllocationProtocolGuid
- gEfiPciIoProtocolGuid
- gEfiPciRootBridgeIoProtocolGuid
- gEmbeddedExternalDeviceProtocolGuid
+[Pcd]
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3
- gMarvellTokenSpaceGuid.PcdPciEDevCount
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize
+[Depex]
- TRUE
diff --git a/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c b/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c new file mode 100644 index 0000000..dab26b6 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c @@ -0,0 +1,314 @@ +/** @file
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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 "PciEmulation.h"
+BOOLEAN +PciRootBridgeMemAddressValid (
- IN PCI_ROOT_BRIDGE *Private,
- IN UINT64 Address
- )
+{
- if ((Address >= Private->MemoryStart) &&
(Address < (Private->MemoryStart + Private->MemorySize))) {
- return TRUE;
- }
- return FALSE;
+}
+EFI_STATUS +PciRootBridgeIoMemRW (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
- IN UINTN Count,
- IN BOOLEAN InStrideFlag,
- IN PTR In,
- IN BOOLEAN OutStrideFlag,
- OUT PTR Out
- )
+{
- UINTN Stride;
- UINTN InStride;
- UINTN OutStride;
- Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03);
- Stride = (UINTN)1 << Width;
- InStride = InStrideFlag ? Stride : 0;
- OutStride = OutStrideFlag ? Stride : 0;
- //
- // Loop for each iteration and move the data
- //
- switch (Width) {
- case EfiPciWidthUint8:
- for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
*In.ui8 = *Out.ui8;
- }
- break;
- case EfiPciWidthUint16:
- for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
*In.ui16 = *Out.ui16;
- }
- break;
- case EfiPciWidthUint32:
- for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
*In.ui32 = *Out.ui32;
- }
- break;
- default:
- return EFI_INVALID_PARAMETER;
- }
- return EFI_SUCCESS;
+}
+EFI_STATUS +PciRootBridgeIoPciRW (
- 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
- )
+{
- return EFI_SUCCESS;
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge
- memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRead (
- 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 *Private;
- UINTN AlignMask;
- PTR In;
- PTR Out;
- if ( Buffer == NULL ) {
- return EFI_INVALID_PARAMETER;
- }
- Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
- if (!PciRootBridgeMemAddressValid (Private, Address)) {
- return EFI_INVALID_PARAMETER;
- }
- AlignMask = (1 << (Width & 0x03)) - 1;
- if (Address & AlignMask) {
- return EFI_INVALID_PARAMETER;
- }
- In.buf = Buffer;
- Out.buf = (VOID *)(UINTN) Address;
- switch (Width) {
- case EfiPciWidthUint8:
- case EfiPciWidthUint16:
- case EfiPciWidthUint32:
- case EfiPciWidthUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out);
- case EfiPciWidthFifoUint8:
- case EfiPciWidthFifoUint16:
- case EfiPciWidthFifoUint32:
- case EfiPciWidthFifoUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out);
- case EfiPciWidthFillUint8:
- case EfiPciWidthFillUint16:
- case EfiPciWidthFillUint32:
- case EfiPciWidthFillUint64:
- return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out);
- default:
- break;
- }
- return EFI_INVALID_PARAMETER;
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemWrite (
- 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 *Private;
- UINTN AlignMask;
- PTR In;
- PTR Out;
- if (Buffer == NULL ) {
- return EFI_INVALID_PARAMETER;
- }
- Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
- if (!PciRootBridgeMemAddressValid (Private, Address)) {
- return EFI_INVALID_PARAMETER;
- }
- AlignMask = (1 << (Width & 0x03)) - 1;
- if (Address & AlignMask) {
- return EFI_INVALID_PARAMETER;
- }
- In.buf = (VOID *)(UINTN) Address;
- Out.buf = Buffer;
- switch (Width) {
- case EfiPciWidthUint8:
- case EfiPciWidthUint16:
- case EfiPciWidthUint32:
- case EfiPciWidthUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out);
- case EfiPciWidthFifoUint8:
- case EfiPciWidthFifoUint16:
- case EfiPciWidthFifoUint32:
- case EfiPciWidthFifoUint64:
- return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out);
- case EfiPciWidthFillUint8:
- case EfiPciWidthFillUint16:
- case EfiPciWidthFillUint32:
- case EfiPciWidthFillUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out);
- default:
- break;
- }
- return EFI_INVALID_PARAMETER;
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge
- memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciRead (
- 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;
- }
- return PciRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer);
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciWrite (
- 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;
- }
- return PciRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer);
+}
1.8.3.1
Hi Ard,
I have a question regarding DmaLib implementation. We took a deeper look at AHCI controller and it will be coherent on newer SoC version - as for now, we have non-coherent one and it's not working with NullDmaLib, whereas everything is ok when ArmDmaLib is used. In the same time, tests show that XHCI works fine both with NullDmaLib and ArmDmaLib. My question is, what are the contraindications for using ArmDmaLib for coherent devices if it is working good on them also? This solution seems to be covering for every case (contrary to NullDmaLib).
Best Regards, Jan
2016-10-31 12:59 GMT+01:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
On 31 October 2016 at 11:42, Jan Dąbroś jsd@semihalf.com wrote:
Hi Ard,
Thanks a lot for your remarks. Please find my answers inline.
Do you have any more comments regarding this and next commits in patchset? Did you have a chance to take a look at them?
No, not yet.
+Next five PCDs are in unicode string, format containing settings for all devices +separated with semicolon.
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress
I must say, I quite dislike this way of putting ; delimited strings into PCDs and then parsing them at runtime. But I don't have anything better to propose, so this is OK for now. We do intend to improve the situation somewhat around PCI I/O emulation (which is a terrible name as well, by the way) but for now this is fine.
We also cannot find anything better - other PCI I/O emulation drivers are limited to single type of device (which are hardcoded by the way). Although it's not perfect, this approach gives us some flexibility and scalability.
I see. As I said, I don't have anything better to propose, although I am working on a generic PCI emulation driver.
+#PciEmulation
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|{ 0x0 }|VOID*|0x30000058
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|{ 0x0 }|VOID*|0x30000059
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|{ 0x0 }|VOID*|0x30000060
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|{ 0x0 }|VOID*|0x30000061
- gMarvellTokenSpaceGuid.PcdPciEDevCount|0|UINT32|0x30000062
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize|{ 0x0 }|VOID*|0x30000063
One potential issue with covering all PCI I/O emulated devices by a single driver is that they must all be coherent or non-coherent. There is no way for a single device to deviate in this respect. Did you take that into account for your platform?
All devices on our platform are coherent, so it isn't a problem in our case. I think that this driver may be improved in future in order to meet the requirements of another SoC, e.g support for coherent and non-coherent devices - however that's not the case with Armada70x0/80x0 family now. What do you think?
If they are all coherent, I think this is fine, but you are using the wrong DMA lib instance. See below
- if (Operation == EfiPciIoOperationBusMasterRead
) {
- DmaOperation = MapOperationBusMasterRead;
- } else if (Operation == EfiPciIoOperationBusMasterWrite) {
- DmaOperation = MapOperationBusMasterWrite;
- } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
- DmaOperation = MapOperationBusMasterCommonBuffer;
- } else {
- return EFI_INVALID_PARAMETER;
- }
- return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);
Are all your peripherals 64-bit DMA capable? If not, you may have a problem here, given that NullDmaLib just returns the CPU address unmodified, so you may want to check the DeviceAddress if the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set. Another complication in the non-coherent case is that the buffer may be remapped by DmaLib, in which case you have no control over the final allocation, unless you perform the bounce buffering here.
Since our platform has less than 4GB memory visible for UEFI, returned address shouldn't be above this region. We use ArmDmaLib not NullDmaLib as DmaLib implementation. As I wrote above, we are using cache-coherent devices, so the problem with remapped buffer couldn't happen here.
You should be using NullDmaLib. ArmDmaLib is for non-coherent DMA only.
+EFI_STATUS +PciIoAllocateBuffer (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN Pages,
- OUT VOID **HostAddress,
- IN UINT64 Attributes
- )
+{
- if (Attributes & (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) {
- return EFI_UNSUPPORTED;
- }
- return DmaAllocateBuffer (MemoryType, Pages, HostAddress);
Same question: are all your peripherals 64-bit DMA capable? If the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set, you must ensure that you allocate below 4 GB (if your platform also has UEFI visible memory above 4 GB)
Since we have less than 4GB memory visible, there shouldn't be problem with allocation above this region.
OK, good to know.
+[Packages]
- ArmPkg/ArmPkg.dec
- EmbeddedPkg/EmbeddedPkg.dec
- IntelFrameworkPkg/IntelFrameworkPkg.dec
- MdeModulePkg/MdeModulePkg.dec
- MdePkg/MdePkg.dec
- OpenPlatformPkg/Platforms/Marvell/Marvell.dec
- ShellPkg/ShellPkg.dec
Why on earth do you need the ShellPkg in a DXE_DRIVER module?
It's definitely placed here by mistake. Will be removed on v2.
2016-10-28 18:19 GMT+02:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
Hello Marcin,
On 28 October 2016 at 16:42, Marcin Wojtas mw@semihalf.com wrote:
From: Jan Dąbroś jsd@semihalf.com
In order to use numerous UEFI drivers based on PCI bus, PciEmulation driver is implemented. This solution is based on Chips/TexasInstruments/Omap35xx/PciEmulation/ Configuring fake devices is performed via PCD.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com
.../Marvell/PortingGuide/PciEmulation.txt | 53 ++ Platforms/Marvell/Marvell.dec | 8 + Platforms/Marvell/PciEmulation/PciEmulation.c | 678 +++++++++++++++++++++ Platforms/Marvell/PciEmulation/PciEmulation.h | 271 ++++++++ Platforms/Marvell/PciEmulation/PciEmulation.inf | 65 ++ Platforms/Marvell/PciEmulation/PciRootBridgeIo.c | 314 ++++++++++ 6 files changed, 1389 insertions(+) create mode 100644 Documentation/Marvell/PortingGuide/PciEmulation.txt create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.c create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.h create mode 100644 Platforms/Marvell/PciEmulation/PciEmulation.inf create mode 100644 Platforms/Marvell/PciEmulation/PciRootBridgeIo.c
diff --git a/Documentation/Marvell/PortingGuide/PciEmulation.txt b/Documentation/Marvell/PortingGuide/PciEmulation.txt new file mode 100644 index 0000000..5bb812a --- /dev/null +++ b/Documentation/Marvell/PortingGuide/PciEmulation.txt @@ -0,0 +1,53 @@ +PciEmulation configuration +-------------------------- +Instalation of various Pci devices via PciEmulation driver is performed via set +of PCDs. Following are available:
- gMarvellTokenSpaceGuid.PcdPciEDevCount
+Indicates how many fake Pci devices are placed on board.
+Next five PCDs are in unicode string, format containing settings for all devices +separated with semicolon.
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress
I must say, I quite dislike this way of putting ; delimited strings into PCDs and then parsing them at runtime. But I don't have anything better to propose, so this is OK for now. We do intend to improve the situation somewhat around PCI I/O emulation (which is a terrible name as well, by the way) but for now this is fine.
+Indicates base address of Pci device register space.
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize
+Indicates size of Pci device register space.
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1
+Indicates device subclass code.
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2
+Indicates device class code.
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3
+Indicates Pci device class code.
+Examples +-------- +Assuming that there are two fake Pci xHCI controllers with register space +0xF2500000 - 0xF2510000 and 0xF2510000 - 0xF2520000 following PCD values should +be set:
- gMarvellTokenSpaceGuid.PcdPciEDevCount|2
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000"
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000"
- ## XHCI subclass
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30"
- ## USB controller class
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03"
- ## Serial bus controller Pci device class
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C"
+Notes +----- +1.In order to find proper values for Pci class codes, please refer to
- PCI Local Bus Specification.
+2.PCDs are configured via UNICODE strings - remember to add L marker. diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index db99230..f56987d 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -209,6 +209,14 @@ gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress|0|UINT64|0x3000031 gMarvellTokenSpaceGuid.PcdPp2XlgDevSize|0|UINT32|0x3000032
+#PciEmulation
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|{ 0x0 }|VOID*|0x30000058
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|{ 0x0 }|VOID*|0x30000059
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|{ 0x0 }|VOID*|0x30000060
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|{ 0x0 }|VOID*|0x30000061
- gMarvellTokenSpaceGuid.PcdPciEDevCount|0|UINT32|0x30000062
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize|{ 0x0 }|VOID*|0x30000063
One potential issue with covering all PCI I/O emulated devices by a single driver is that they must all be coherent or non-coherent. There is no way for a single device to deviate in this respect. Did you take that into account for your platform?
#ResetLib gMarvellTokenSpaceGuid.PcdResetRegAddress|0|UINT64|0x40000050 gMarvellTokenSpaceGuid.PcdResetRegMask|0|UINT32|0x4000051 diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.c b/Platforms/Marvell/PciEmulation/PciEmulation.c new file mode 100644 index 0000000..a800bcb --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.c @@ -0,0 +1,678 @@ +/** @file
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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 "PciEmulation.h"
+typedef struct {
- ACPI_HID_DEVICE_PATH AcpiDevicePath;
- PCI_DEVICE_PATH PciDevicePath;
- EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_IO_DEVICE_PATH;
+typedef struct {
- UINT32 Signature;
- EFI_PCI_IO_DEVICE_PATH DevicePath;
- EFI_PCI_IO_PROTOCOL PciIoProtocol;
- PCI_TYPE00 *ConfigSpace;
- PCI_ROOT_BRIDGE RootBridge;
- UINTN Segment;
+} EFI_PCI_IO_PRIVATE_DATA;
+#define EFI_PCI_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32('p', 'c', 'i', 'o') +#define EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(a) CR(a, EFI_PCI_IO_PRIVATE_DATA, \
PciIoProtocol, \
EFI_PCI_IO_PRIVATE_DATA_SIGNATURE)
+EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate = +{
- {
- {
ACPI_DEVICE_PATH,
ACPI_DP,
{
sizeof (ACPI_HID_DEVICE_PATH),
0
}
- },
- EISA_PNP_ID(0x0A03), // HID
- 0 // UID
- },
- {
- {
HARDWARE_DEVICE_PATH,
HW_PCI_DP,
{
sizeof (PCI_DEVICE_PATH),
0
}
- },
- 0,
- 0
- },
- {
- END_DEVICE_PATH_TYPE,
- END_ENTIRE_DEVICE_PATH_SUBTYPE,
- {
sizeof (EFI_DEVICE_PATH_PROTOCOL),
0
- }
- }
+};
+EFI_STATUS +PciIoPollMem (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINT64 Mask,
- IN UINT64 Value,
- IN UINT64 Delay,
- OUT UINT64 *Result
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoPollIo (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINT64 Mask,
- IN UINT64 Value,
- IN UINT64 Delay,
- OUT UINT64 *Result
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoMemRead (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
- return PciRootBridgeIoMemRead (
&Private->RootBridge.Io,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
Count,
Buffer
);
+}
+EFI_STATUS +PciIoMemWrite (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
- return PciRootBridgeIoMemWrite (
&Private->RootBridge.Io,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Private->ConfigSpace->Device.Bar[BarIndex] + Offset,
Count,
Buffer
);
+}
+EFI_STATUS +PciIoIoRead (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoIoWrite (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 BarIndex,
- IN UINT64 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+/**
- Enable a PCI driver to read PCI controller registers in
- PCI configuration space.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Width Signifies the width of the memory operations.
- @param[in] Offset The offset 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 Offset.
- @param[in out] Buffer The destination buffer to store the results.
- @retval EFI_SUCCESS The data was read from the PCI controller.
- @retval EFI_INVALID_PARAMETER "Width" is invalid.
- @retval EFI_INVALID_PARAMETER "Buffer" is NULL.
+**/ +EFI_STATUS +PciIoPciRead (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT32 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
- if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- return PciRootBridgeIoMemRW (
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)Width,
Count,
TRUE,
(PTR)(UINTN)Buffer,
TRUE,
(PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset)
);
+}
+/**
- Enable a PCI driver to write PCI controller registers in
- PCI configuration space.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Width Signifies the width of the memory operations.
- @param[in] Offset The offset 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 Offset.
- @param[in out] Buffer The source buffer to write data from.
- @retval EFI_SUCCESS The data was read from the PCI controller.
- @retval EFI_INVALID_PARAMETER "Width" is invalid.
- @retval EFI_INVALID_PARAMETER "Buffer" is NULL.
+**/ +EFI_STATUS +PciIoPciWrite (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT32 Offset,
- IN UINTN Count,
- IN OUT VOID *Buffer
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
- if ((Width < 0) || (Width >= EfiPciIoWidthMaximum) || (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- return PciRootBridgeIoMemRW (
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Count,
TRUE,
(PTR)(UINTN)(((UINT8 *)Private->ConfigSpace) + Offset),
TRUE,
(PTR)(UINTN)Buffer
);
+}
+EFI_STATUS +PciIoCopyMem (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
- IN UINT8 DestBarIndex,
- IN UINT64 DestOffset,
- IN UINT8 SrcBarIndex,
- IN UINT64 SrcOffset,
- IN UINTN Count
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoMap (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
- IN VOID *HostAddress,
- IN OUT UINTN *NumberOfBytes,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
- OUT VOID **Mapping
- )
+{
- DMA_MAP_OPERATION DmaOperation;
- if (Operation == EfiPciIoOperationBusMasterRead) {
- DmaOperation = MapOperationBusMasterRead;
- } else if (Operation == EfiPciIoOperationBusMasterWrite) {
- DmaOperation = MapOperationBusMasterWrite;
- } else if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
- DmaOperation = MapOperationBusMasterCommonBuffer;
- } else {
- return EFI_INVALID_PARAMETER;
- }
- return DmaMap (DmaOperation, HostAddress, NumberOfBytes, DeviceAddress, Mapping);
Are all your peripherals 64-bit DMA capable? If not, you may have a problem here, given that NullDmaLib just returns the CPU address unmodified, so you may want to check the DeviceAddress if the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set. Another complication in the non-coherent case is that the buffer may be remapped by DmaLib, in which case you have no control over the final allocation, unless you perform the bounce buffering here.
+}
+EFI_STATUS +PciIoUnmap (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN VOID *Mapping
- )
+{
- return DmaUnmap (Mapping);
+}
+/**
- Allocate pages that are suitable for an EfiPciIoOperationBusMasterCommonBuffer
- mapping.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Type This parameter is not used and must be ignored.
- @param[in] MemoryType The type of memory to allocate, EfiBootServicesData
or EfiRuntimeServicesData.
- @param[in] Pages The number of pages to allocate.
- @param[out] HostAddress A pointer to store the base system memory address of
the allocated range.
- @param[in] Attributes The requested bit mask of attributes for the
allocated range. Only the attributes,
EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE and
EFI_PCI_ATTRIBUTE_MEMORY_CACHED may be used with
this function. If any other bits are set, then
EFI_UNSUPPORTED is returned. This function ignores
this bit mask.
- @retval EFI_SUCCESS The requested memory pages were allocated.
- @retval EFI_INVALID_PARAMETER HostAddress is NULL.
- @retval EFI_INVALID_PARAMETER MemoryType is invalid.
- @retval EFI_UNSUPPORTED Attributes is unsupported.
- @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/ +EFI_STATUS +PciIoAllocateBuffer (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_ALLOCATE_TYPE Type,
- IN EFI_MEMORY_TYPE MemoryType,
- IN UINTN Pages,
- OUT VOID **HostAddress,
- IN UINT64 Attributes
- )
+{
- if (Attributes & (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) {
- return EFI_UNSUPPORTED;
- }
- return DmaAllocateBuffer (MemoryType, Pages, HostAddress);
Same question: are all your peripherals 64-bit DMA capable? If the EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE attribute is not set, you must ensure that you allocate below 4 GB (if your platform also has UEFI visible memory above 4 GB)
+}
+EFI_STATUS +PciIoFreeBuffer (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINTN Pages,
- IN VOID *HostAddress
- )
+{
- return DmaFreeBuffer (Pages, HostAddress);
+}
+EFI_STATUS +PciIoFlush (
- IN EFI_PCI_IO_PROTOCOL *This
- )
+{
- return EFI_SUCCESS;
+}
+/**
- Retrieves this PCI controller's current PCI bus number, device number, and
- function number.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[out] SegmentNumber The PCI controller's current PCI segment number.
- @param[out] BusNumber The PCI controller's current PCI bus number.
- @param[out] DeviceNumber The PCI controller's current PCI device number.
- @param[out] FunctionNumber The PCI controller’s current PCI function number.
- @retval EFI_SUCCESS The PCI controller location was returned.
- @retval EFI_INVALID_PARAMETER At least one out of the four output parameters
is a NULL pointer.
+**/ +EFI_STATUS +PciIoGetLocation (
- IN EFI_PCI_IO_PROTOCOL *This,
- OUT UINTN *SegmentNumber,
- OUT UINTN *BusNumber,
- OUT UINTN *DeviceNumber,
- OUT UINTN *FunctionNumber
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS (This);
- if ((SegmentNumber == NULL) || (BusNumber == NULL) ||
(DeviceNumber == NULL) || (FunctionNumber == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- *SegmentNumber = Private->Segment;
- *BusNumber = 0xff;
- *DeviceNumber = 0;
- *FunctionNumber = 0;
- return EFI_SUCCESS;
+}
+/**
- Performs an operation on the attributes that this PCI controller supports.
- The operations include getting the set of supported attributes, retrieving
- the current attributes, setting the current attributes, enabling attributes,
- and disabling attributes.
- @param[in] This A pointer to the EFI_PCI_IO_PROTOCOL instance.
- @param[in] Operation The operation to perform on the attributes for this
PCI controller.
- @param[in] Attributes The mask of attributes that are used for Set,
Enable and Disable operations.
- @param[out] Result A pointer to the result mask of attributes that are
returned for the Get and Supported operations. This
is an optional parameter that may be NULL for the
Set, Enable, and Disable operations.
- @retval EFI_SUCCESS The operation on the PCI controller's
attributes was completed. If the operation
was Get or Supported, then the attribute mask
is returned in Result.
- @retval EFI_INVALID_PARAMETER Operation is greater than or equal to
EfiPciIoAttributeOperationMaximum.
- @retval EFI_INVALID_PARAMETER Operation is Get and Result is NULL.
- @retval EFI_INVALID_PARAMETER Operation is Supported and Result is NULL.
+**/ +EFI_STATUS +PciIoAttributes (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
- IN UINT64 Attributes,
- OUT UINT64 *Result OPTIONAL
- )
+{
- switch (Operation) {
- case EfiPciIoAttributeOperationGet:
- case EfiPciIoAttributeOperationSupported:
- if (Result == NULL) {
return EFI_INVALID_PARAMETER;
- }
- //
- // We are not a real PCI device so just say things we kind of do
- //
- *Result = EFI_PCI_DEVICE_ENABLE;
- break;
- case EfiPciIoAttributeOperationSet:
- case EfiPciIoAttributeOperationEnable:
- case EfiPciIoAttributeOperationDisable:
- if (Attributes & (~EFI_PCI_DEVICE_ENABLE)) {
return EFI_UNSUPPORTED;
- }
- //
- // Since we are not a real PCI device no enable/set or
- // disable operations exist.
- //
- return EFI_SUCCESS;
- default:
- return EFI_INVALID_PARAMETER;
- };
- return EFI_SUCCESS;
+}
+EFI_STATUS +PciIoGetBarAttributes (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINT8 BarIndex,
- OUT UINT64 *Supports, OPTIONAL
- OUT VOID **Resources OPTIONAL
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_STATUS +PciIoSetBarAttributes (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINT64 Attributes,
- IN UINT8 BarIndex,
- IN OUT UINT64 *Offset,
- IN OUT UINT64 *Length
- )
+{
- ASSERT (FALSE);
- return EFI_UNSUPPORTED;
+}
+EFI_PCI_IO_PROTOCOL PciIoTemplate = +{
- PciIoPollMem,
- PciIoPollIo,
- { PciIoMemRead, PciIoMemWrite },
- { PciIoIoRead, PciIoIoWrite },
- { PciIoPciRead, PciIoPciWrite },
- PciIoCopyMem,
- PciIoMap,
- PciIoUnmap,
- PciIoAllocateBuffer,
- PciIoFreeBuffer,
- PciIoFlush,
- PciIoGetLocation,
- PciIoAttributes,
- PciIoGetBarAttributes,
- PciIoSetBarAttributes,
- 0,
- 0
+};
+STATIC +EFI_STATUS +EFIAPI +InstallDevices (
- IN UINTN DeviceId,
- IN UINTN BaseAddr,
- IN UINTN AddressSpaceSize,
- IN UINTN ClassCode1,
- IN UINTN ClassCode2,
- IN UINTN ClassCode3
- )
+{
- EFI_PCI_IO_PRIVATE_DATA *Private;
- EFI_STATUS Status;
- EFI_HANDLE Handle;
- // Create a private structure
- Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA));
- if (Private == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- return Status;
- }
- // Fill in signature
- Private->Signature = EFI_PCI_IO_PRIVATE_DATA_SIGNATURE;
- // Fake Root Bridge structure needs a signature too
- Private->RootBridge.Signature = PCI_ROOT_BRIDGE_SIGNATURE;
- // Get the register base
- Private->RootBridge.MemoryStart = BaseAddr;
- // Default to segment zero
- Private->Segment = 0;
- // Calculate the total size of device registers.
- Private->RootBridge.MemorySize = AddressSpaceSize;
- // Create fake PCI config space.
- Private->ConfigSpace = AllocateZeroPool(sizeof(PCI_TYPE00));
- if (Private->ConfigSpace == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- FreePool(Private);
- return Status;
- }
- //
- // Configure PCI config space
- //
- // Invalid vendor Id as it is not an actual device.
- Private->ConfigSpace->Hdr.VendorId = 0xFFFF;
- // Not relevant as the vendor id is not valid.
- Private->ConfigSpace->Hdr.DeviceId = 0x0000;
- Private->ConfigSpace->Hdr.ClassCode[0] = ClassCode1;
- Private->ConfigSpace->Hdr.ClassCode[1] = ClassCode2;
- Private->ConfigSpace->Hdr.ClassCode[2] = ClassCode3;
- Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart;
- Handle = NULL;
- // Unique device path.
- CopyMem(&Private->DevicePath, &PciIoDevicePathTemplate, sizeof(PciIoDevicePathTemplate));
- Private->DevicePath.AcpiDevicePath.UID = 0;
- Private->DevicePath.PciDevicePath.Device = DeviceId;
- // Copy protocol structure
- CopyMem(&Private->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate));
- Status = gBS->InstallMultipleProtocolInterfaces(
&Handle,
&gEfiPciIoProtocolGuid,
&Private->PciIoProtocol,
&gEfiDevicePathProtocolGuid,
&Private->DevicePath,
NULL
);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: InstallMultipleProtocolInterfaces failed\n"));
- }
- return Status;
+}
+// +// Below function is used to parse devices information from PCD strings. +// +EFI_STATUS +EFIAPI +PciEmulationEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
+{
- EFI_STATUS Status;
- UINT8 i, DevCount;
- UINTN BaseAddrTable[PcdGet32 (PcdPciEDevCount)];
- UINTN RegSizeTable[PcdGet32 (PcdPciEDevCount)];
- UINTN DevClass1Table[PcdGet32 (PcdPciEDevCount)];
- UINTN DevClass2Table[PcdGet32 (PcdPciEDevCount)];
- UINTN DevClass3Table[PcdGet32 (PcdPciEDevCount)];
- DevCount = PcdGet32 (PcdPciEDevCount);
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevBaseAddress), DevCount, BaseAddrTable, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevBaseAddress format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevRegSize), DevCount, RegSizeTable, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevRegSize format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode1), DevCount, DevClass1Table, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode1 format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode2), DevCount, DevClass2Table, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode2 format\n"));
- return EFI_INVALID_PARAMETER;
- }
- Status = ParsePcdString ((CHAR16 *) PcdGetPtr (PcdPciEDevClassCode3), DevCount, DevClass3Table, NULL);
- if (EFI_ERROR(Status)) {
- DEBUG((DEBUG_ERROR, "PciEmulation: Wrong PcdPciEDevClassCode3 format\n"));
- return EFI_INVALID_PARAMETER;
- }
- for (i = 0; i < DevCount; i++) {
- Status = InstallDevices (i, BaseAddrTable[i], RegSizeTable[i],
DevClass1Table[i], DevClass2Table[i], DevClass3Table[i]);
- if (EFI_ERROR(Status)) {
DEBUG((DEBUG_ERROR, "PciEmulation: Cannot install device with ID=%d\n", i));
- }
- }
- return Status;
+} diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.h b/Platforms/Marvell/PciEmulation/PciEmulation.h new file mode 100644 index 0000000..4f75539 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.h @@ -0,0 +1,271 @@ +/** @file
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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.
+**/
+#ifndef _PCI_ROOT_BRIDGE_H_ +#define _PCI_ROOT_BRIDGE_H_
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h> +#include <IndustryStandard/Pci22.h> +#include <IndustryStandard/PciCodeId.h>
+#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/DmaLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/IoLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/ParsePcdLib.h> +#include <Library/PcdLib.h> +#include <Library/PciLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h>
+#include <Protocol/DevicePath.h> +#include <Protocol/EmbeddedExternalDevice.h> +#include <Protocol/PciHostBridgeResourceAllocation.h> +#include <Protocol/PciIo.h> +#include <Protocol/PciRootBridgeIo.h>
+#define ACPI_CONFIG_IO 0 +#define ACPI_CONFIG_MMIO 1 +#define ACPI_CONFIG_BUS 2
+#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('P', 'c', 'i', 'F')
+typedef struct {
- ACPI_HID_DEVICE_PATH AcpiDevicePath;
- EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+typedef struct {
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR Desc[3];
- EFI_ACPI_END_TAG_DESCRIPTOR EndDesc;
+} ACPI_CONFIG_INFO;
+typedef struct {
- UINT32 Signature;
- EFI_HANDLE Handle;
- EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io;
- EFI_PCI_ROOT_BRIDGE_DEVICE_PATH DevicePath;
- UINT8 StartBus;
- UINT8 EndBus;
- UINT16 Type;
- UINT32 MemoryStart;
- UINT32 MemorySize;
- UINTN IoOffset;
- UINT32 IoStart;
- UINT32 IoSize;
- UINT64 PciAttributes;
- ACPI_CONFIG_INFO *Config;
+} PCI_ROOT_BRIDGE;
+#define INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) CR (a, PCI_ROOT_BRIDGE, Io, PCI_ROOT_BRIDGE_SIGNATURE)
+typedef union {
- UINT8 volatile *buf;
- UINT8 volatile *ui8;
- UINT16 volatile *ui16;
- UINT32 volatile *ui32;
- UINT64 volatile *ui64;
- UINTN volatile ui;
+} PTR;
+EFI_STATUS +EFIAPI +PciRootBridgeIoPollMem (
- 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 +PciRootBridgeIoPollIo (
- 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 +PciRootBridgeIoMemRead (
- 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 +PciRootBridgeIoMemWrite (
- 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 +PciRootBridgeIoIoRead (
- 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 +PciRootBridgeIoIoWrite (
- 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 +PciRootBridgeIoCopyMem (
- IN 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 +PciRootBridgeIoPciRead (
- 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 +PciRootBridgeIoPciWrite (
- 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 +PciRootBridgeIoMap (
- 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 +PciRootBridgeIoUnmap (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- IN VOID *Mapping
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoAllocateBuffer (
- 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 +PciRootBridgeIoFreeBuffer (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- IN UINTN Pages,
- OUT VOID *HostAddress
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoFlush (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoGetAttributes (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- OUT UINT64 *Supported,
- OUT UINT64 *Attributes
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoSetAttributes (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- IN UINT64 Attributes,
- IN OUT UINT64 *ResourceBase,
- IN OUT UINT64 *ResourceLength
- );
+EFI_STATUS +EFIAPI +PciRootBridgeIoConfiguration (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
- OUT VOID **Resources
- );
+// +// Private Function Prototypes +// +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRW (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
- IN UINTN Count,
- IN BOOLEAN InStrideFlag,
- IN PTR In,
- IN BOOLEAN OutStrideFlag,
- OUT PTR Out
- );
+BOOLEAN +PciIoMemAddressValid (
- IN EFI_PCI_IO_PROTOCOL *This,
- IN UINT64 Address
- );
+#endif diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.inf b/Platforms/Marvell/PciEmulation/PciEmulation.inf new file mode 100644 index 0000000..30ddfc2 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciEmulation.inf @@ -0,0 +1,65 @@ +/** @file
- Copyright (c) 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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.
+**/
+[Defines]
- INF_VERSION = 0x00010019
- BASE_NAME = PciEmulation
- FILE_GUID = 3dfa08da-923b-4841-9435-c77a604d7493
- MODULE_TYPE = DXE_DRIVER
- VERSION_STRING = 1.0
- ENTRY_POINT = PciEmulationEntryPoint
+[Sources.common]
- PciEmulation.c
- PciRootBridgeIo.c
+[Packages]
- ArmPkg/ArmPkg.dec
- EmbeddedPkg/EmbeddedPkg.dec
- IntelFrameworkPkg/IntelFrameworkPkg.dec
- MdeModulePkg/MdeModulePkg.dec
- MdePkg/MdePkg.dec
- OpenPlatformPkg/Platforms/Marvell/Marvell.dec
- ShellPkg/ShellPkg.dec
Why on earth do you need the ShellPkg in a DXE_DRIVER module?
+[LibraryClasses]
- BaseLib
- DmaLib
- DxeServicesTableLib
- IoLib
- ParsePcdLib
- UefiBootServicesTableLib
- UefiDriverEntryPoint
- UefiLib
- UefiRuntimeServicesTableLib
+[Protocols]
- gEfiDevicePathProtocolGuid
- gEfiPciHostBridgeResourceAllocationProtocolGuid
- gEfiPciIoProtocolGuid
- gEfiPciRootBridgeIoProtocolGuid
- gEmbeddedExternalDeviceProtocolGuid
+[Pcd]
- gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode1
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode2
- gMarvellTokenSpaceGuid.PcdPciEDevClassCode3
- gMarvellTokenSpaceGuid.PcdPciEDevCount
- gMarvellTokenSpaceGuid.PcdPciEDevRegSize
+[Depex]
- TRUE
diff --git a/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c b/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c new file mode 100644 index 0000000..dab26b6 --- /dev/null +++ b/Platforms/Marvell/PciEmulation/PciRootBridgeIo.c @@ -0,0 +1,314 @@ +/** @file
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- Copyright (c) 2016, Marvell. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD
- License which 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 "PciEmulation.h"
+BOOLEAN +PciRootBridgeMemAddressValid (
- IN PCI_ROOT_BRIDGE *Private,
- IN UINT64 Address
- )
+{
- if ((Address >= Private->MemoryStart) &&
(Address < (Private->MemoryStart + Private->MemorySize))) {
- return TRUE;
- }
- return FALSE;
+}
+EFI_STATUS +PciRootBridgeIoMemRW (
- IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
- IN UINTN Count,
- IN BOOLEAN InStrideFlag,
- IN PTR In,
- IN BOOLEAN OutStrideFlag,
- OUT PTR Out
- )
+{
- UINTN Stride;
- UINTN InStride;
- UINTN OutStride;
- Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03);
- Stride = (UINTN)1 << Width;
- InStride = InStrideFlag ? Stride : 0;
- OutStride = OutStrideFlag ? Stride : 0;
- //
- // Loop for each iteration and move the data
- //
- switch (Width) {
- case EfiPciWidthUint8:
- for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
*In.ui8 = *Out.ui8;
- }
- break;
- case EfiPciWidthUint16:
- for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
*In.ui16 = *Out.ui16;
- }
- break;
- case EfiPciWidthUint32:
- for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
*In.ui32 = *Out.ui32;
- }
- break;
- default:
- return EFI_INVALID_PARAMETER;
- }
- return EFI_SUCCESS;
+}
+EFI_STATUS +PciRootBridgeIoPciRW (
- 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
- )
+{
- return EFI_SUCCESS;
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge
- memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemRead (
- 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 *Private;
- UINTN AlignMask;
- PTR In;
- PTR Out;
- if ( Buffer == NULL ) {
- return EFI_INVALID_PARAMETER;
- }
- Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
- if (!PciRootBridgeMemAddressValid (Private, Address)) {
- return EFI_INVALID_PARAMETER;
- }
- AlignMask = (1 << (Width & 0x03)) - 1;
- if (Address & AlignMask) {
- return EFI_INVALID_PARAMETER;
- }
- In.buf = Buffer;
- Out.buf = (VOID *)(UINTN) Address;
- switch (Width) {
- case EfiPciWidthUint8:
- case EfiPciWidthUint16:
- case EfiPciWidthUint32:
- case EfiPciWidthUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out);
- case EfiPciWidthFifoUint8:
- case EfiPciWidthFifoUint16:
- case EfiPciWidthFifoUint32:
- case EfiPciWidthFifoUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out);
- case EfiPciWidthFillUint8:
- case EfiPciWidthFillUint16:
- case EfiPciWidthFillUint32:
- case EfiPciWidthFillUint64:
- return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out);
- default:
- break;
- }
- return EFI_INVALID_PARAMETER;
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoMemWrite (
- 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 *Private;
- UINTN AlignMask;
- PTR In;
- PTR Out;
- if (Buffer == NULL ) {
- return EFI_INVALID_PARAMETER;
- }
- Private = INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
- if (!PciRootBridgeMemAddressValid (Private, Address)) {
- return EFI_INVALID_PARAMETER;
- }
- AlignMask = (1 << (Width & 0x03)) - 1;
- if (Address & AlignMask) {
- return EFI_INVALID_PARAMETER;
- }
- In.buf = (VOID *)(UINTN) Address;
- Out.buf = Buffer;
- switch (Width) {
- case EfiPciWidthUint8:
- case EfiPciWidthUint16:
- case EfiPciWidthUint32:
- case EfiPciWidthUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out);
- case EfiPciWidthFifoUint8:
- case EfiPciWidthFifoUint16:
- case EfiPciWidthFifoUint32:
- case EfiPciWidthFifoUint64:
- return PciRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out);
- case EfiPciWidthFillUint8:
- case EfiPciWidthFillUint16:
- case EfiPciWidthFillUint32:
- case EfiPciWidthFillUint64:
- return PciRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out);
- default:
- break;
- }
- return EFI_INVALID_PARAMETER;
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge
- memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciRead (
- 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;
- }
- return PciRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer);
+}
+/**
- Enables a PCI driver to access PCI controller registers in the PCI root bridge memory space.
- @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
- @param Width Signifies the width of the memory operations.
- @param Address The base address of the memory operations.
- @param Count The number of memory operations to perform.
- @param 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_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
- @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+**/ +EFI_STATUS +EFIAPI +PciRootBridgeIoPciWrite (
- 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;
- }
- return PciRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer);
+}
1.8.3.1
On 2 November 2016 at 20:02, Jan Dąbroś jsd@semihalf.com wrote:
Hi Ard,
I have a question regarding DmaLib implementation. We took a deeper look at AHCI controller and it will be coherent on newer SoC version - as for now, we have non-coherent one and it's not working with NullDmaLib, whereas everything is ok when ArmDmaLib is used. In the same time, tests show that XHCI works fine both with NullDmaLib and ArmDmaLib. My question is, what are the contraindications for using ArmDmaLib for coherent devices if it is working good on them also? This solution seems to be covering for every case (contrary to NullDmaLib).
No, ArmDmaLib is fundamentally incompatible with coherent devices. The code performs a cache invalidate for data written by the bus master, since on non-coherent systems, this may be necessary to get rid of stale cachelines that shadow the incoming data. On coherent devices, the device will write to the cache, not to main memory, and so this cache invalidation will discard the data coming from the device.
Hi Ard,
2016-11-02 21:55 GMT+01:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
On 2 November 2016 at 20:02, Jan Dąbroś jsd@semihalf.com wrote:
Hi Ard,
I have a question regarding DmaLib implementation. We took a deeper look at AHCI controller and it will be coherent on newer SoC version - as for now, we have non-coherent one and it's not working with NullDmaLib, whereas everything is ok when ArmDmaLib is used. In the same time, tests show that XHCI works fine both with NullDmaLib and ArmDmaLib. My question is, what are the contraindications for using ArmDmaLib for coherent devices if it is working good on them also? This solution seems to be covering for every case (contrary to NullDmaLib).
No, ArmDmaLib is fundamentally incompatible with coherent devices. The code performs a cache invalidate for data written by the bus master, since on non-coherent systems, this may be necessary to get rid of stale cachelines that shadow the incoming data. On coherent devices, the device will write to the cache, not to main memory, and so this cache invalidation will discard the data coming from the device.
Could you help understand then, how come a coherent device (XHCI) can work both with ArmDmaLib/NullDmaLib, whereas non-coherent device (AHCI) can work only with ArmDmaLib? In other words, how do you suggest to proceed here?
In case we switch to NullDmaLib, what's suggested solution of handling non-coherent devices? Do you know of any reference PciEmulation driver that deals with such situation?
Best regards, Marcin
On 2 November 2016 at 21:52, Marcin Wojtas mw@semihalf.com wrote:
Hi Ard,
2016-11-02 21:55 GMT+01:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
On 2 November 2016 at 20:02, Jan Dąbroś jsd@semihalf.com wrote:
Hi Ard,
I have a question regarding DmaLib implementation. We took a deeper look at AHCI controller and it will be coherent on newer SoC version - as for now, we have non-coherent one and it's not working with NullDmaLib, whereas everything is ok when ArmDmaLib is used. In the same time, tests show that XHCI works fine both with NullDmaLib and ArmDmaLib. My question is, what are the contraindications for using ArmDmaLib for coherent devices if it is working good on them also? This solution seems to be covering for every case (contrary to NullDmaLib).
No, ArmDmaLib is fundamentally incompatible with coherent devices. The code performs a cache invalidate for data written by the bus master, since on non-coherent systems, this may be necessary to get rid of stale cachelines that shadow the incoming data. On coherent devices, the device will write to the cache, not to main memory, and so this cache invalidation will discard the data coming from the device.
Could you help understand then, how come a coherent device (XHCI) can work both with ArmDmaLib/NullDmaLib, whereas non-coherent device (AHCI) can work only with ArmDmaLib? In other words, how do you suggest to proceed here?
In case we switch to NullDmaLib, what's suggested solution of handling non-coherent devices? Do you know of any reference PciEmulation driver that deals with such situation?
I am working on a generic solution for this: https://lists.01.org/pipermail/edk2-devel/2016-October/003842.html
2016-11-02 22:56 GMT+01:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
On 2 November 2016 at 21:52, Marcin Wojtas mw@semihalf.com wrote:
Hi Ard,
2016-11-02 21:55 GMT+01:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
On 2 November 2016 at 20:02, Jan Dąbroś jsd@semihalf.com wrote:
Hi Ard,
I have a question regarding DmaLib implementation. We took a deeper look at AHCI controller and it will be coherent on newer SoC version - as for now, we have non-coherent one and it's not working with NullDmaLib, whereas everything is ok when ArmDmaLib is used. In the same time, tests show that XHCI works fine both with NullDmaLib and ArmDmaLib. My question is, what are the contraindications for using ArmDmaLib for coherent devices if it is working good on them also? This solution seems to be covering for every case (contrary to NullDmaLib).
No, ArmDmaLib is fundamentally incompatible with coherent devices. The code performs a cache invalidate for data written by the bus master, since on non-coherent systems, this may be necessary to get rid of stale cachelines that shadow the incoming data. On coherent devices, the device will write to the cache, not to main memory, and so this cache invalidation will discard the data coming from the device.
Could you help understand then, how come a coherent device (XHCI) can work both with ArmDmaLib/NullDmaLib, whereas non-coherent device (AHCI) can work only with ArmDmaLib? In other words, how do you suggest to proceed here?
In case we switch to NullDmaLib, what's suggested solution of handling non-coherent devices? Do you know of any reference PciEmulation driver that deals with such situation?
I am working on a generic solution for this: https://lists.01.org/pipermail/edk2-devel/2016-October/003842.html
Great, thanks! It seems like all we need is there. I have a dillema now - since it's under review on EDK2 lists, I have doubts if there is any reason for adding similar solution in OPP. It may be a good moment to adjust to your solution and test - if everything is fine, we can drop our driver - what do you think? I know it's hard to predict, but when do you expect to get it merged? It's important due to tight schedule we have:/ In case of problems we will try to enhance OPP driver to be accepted and later replace solution, once it's ready - we still have almost a month to go.
I have a couple of questions: 1. Is it possible to use it with multiple devices? 2. Is there any exaple of usage? 3. Sata in current silicone revision has some quirks (non-dma coherent, +2 other minor stuff, which was avoided by substituting PciIoMemRead/Write with custom functions). Is there any backdoor in your design for creating sort of wrappers? 4. Do you have some branch in public repo, so that it would be easier to obtain the patches?
Best regards, Marcin
On Wed, Nov 02, 2016 at 11:39:43PM +0100, Marcin Wojtas wrote:
2016-11-02 22:56 GMT+01:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
On 2 November 2016 at 21:52, Marcin Wojtas mw@semihalf.com wrote:
Hi Ard,
2016-11-02 21:55 GMT+01:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
On 2 November 2016 at 20:02, Jan Dąbroś jsd@semihalf.com wrote:
Hi Ard,
I have a question regarding DmaLib implementation. We took a deeper look at AHCI controller and it will be coherent on newer SoC version - as for now, we have non-coherent one and it's not working with NullDmaLib, whereas everything is ok when ArmDmaLib is used. In the same time, tests show that XHCI works fine both with NullDmaLib and ArmDmaLib. My question is, what are the contraindications for using ArmDmaLib for coherent devices if it is working good on them also? This solution seems to be covering for every case (contrary to NullDmaLib).
No, ArmDmaLib is fundamentally incompatible with coherent devices. The code performs a cache invalidate for data written by the bus master, since on non-coherent systems, this may be necessary to get rid of stale cachelines that shadow the incoming data. On coherent devices, the device will write to the cache, not to main memory, and so this cache invalidation will discard the data coming from the device.
Could you help understand then, how come a coherent device (XHCI) can work both with ArmDmaLib/NullDmaLib, whereas non-coherent device (AHCI) can work only with ArmDmaLib? In other words, how do you suggest to proceed here?
In case we switch to NullDmaLib, what's suggested solution of handling non-coherent devices? Do you know of any reference PciEmulation driver that deals with such situation?
I am working on a generic solution for this: https://lists.01.org/pipermail/edk2-devel/2016-October/003842.html
Great, thanks! It seems like all we need is there. I have a dillema now - since it's under review on EDK2 lists, I have doubts if there is any reason for adding similar solution in OPP.
I would very much prefer to not add your implementation to OPP only to delete it again a week or two later.
It may be a good moment to adjust to your solution and test - if everything is fine, we can drop our driver - what do you think?
Yes, that sounds good.
I know it's hard to predict, but when do you expect to get it merged? It's important due to tight schedule we have:/ In case of problems we will try to enhance OPP driver to be accepted and later replace solution, once it's ready - we still have almost a month to go.
I am not overly concerned by this. Worst case, we could add Ard's generic solution to OPP as a stop-gap solution.
I have a couple of questions:
- Is it possible to use it with multiple devices?
Yes.
- Is there any exaple of usage?
See Ard's recent posts to linaro-uefi for moving the AMD platforms onto this infrastructure.
- Sata in current silicone revision has some quirks (non-dma
coherent, +2 other minor stuff, which was avoided by substituting PciIoMemRead/Write with custom functions). Is there any backdoor in your design for creating sort of wrappers?
(pass, I'll let Ard answer)
- Do you have some branch in public repo, so that it would be easier
to obtain the patches?
Again, see Ard's recent posts to edk2-devel and linaro-uefi.
https://git.linaro.org/people/ard.biesheuvel/uefi-next.git/log/?h=pciio-emu
Regards,
Leif
Hi Leif,
Thanks for your answer. We'll check AMD and try to adjust our platform to it. Hopefully everything works fine. We have only USB/SATA/SD left - all of them users of PciIO stuff. We have to finalize adaptation, submit patches that can work with Ard's solution.
My preferable scenario is following: let's achieve state that we have ready-to-go, accepted patches in November. Their merge to OPP would be gated only by Ard's PciIO merge to EDK2. This would allow to fulfill our commitments and also prevent from creating mess in the repo. What do you think?
Best regards, Marcin
2016-11-02 23:49 GMT+01:00 Leif Lindholm leif.lindholm@linaro.org:
On Wed, Nov 02, 2016 at 11:39:43PM +0100, Marcin Wojtas wrote:
2016-11-02 22:56 GMT+01:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
On 2 November 2016 at 21:52, Marcin Wojtas mw@semihalf.com wrote:
Hi Ard,
2016-11-02 21:55 GMT+01:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
On 2 November 2016 at 20:02, Jan Dąbroś jsd@semihalf.com wrote:
Hi Ard,
I have a question regarding DmaLib implementation. We took a deeper look at AHCI controller and it will be coherent on newer SoC version - as for now, we have non-coherent one and it's not working with NullDmaLib, whereas everything is ok when ArmDmaLib is used. In the same time, tests show that XHCI works fine both with NullDmaLib and ArmDmaLib. My question is, what are the contraindications for using ArmDmaLib for coherent devices if it is working good on them also? This solution seems to be covering for every case (contrary to NullDmaLib).
No, ArmDmaLib is fundamentally incompatible with coherent devices. The code performs a cache invalidate for data written by the bus master, since on non-coherent systems, this may be necessary to get rid of stale cachelines that shadow the incoming data. On coherent devices, the device will write to the cache, not to main memory, and so this cache invalidation will discard the data coming from the device.
Could you help understand then, how come a coherent device (XHCI) can work both with ArmDmaLib/NullDmaLib, whereas non-coherent device (AHCI) can work only with ArmDmaLib? In other words, how do you suggest to proceed here?
In case we switch to NullDmaLib, what's suggested solution of handling non-coherent devices? Do you know of any reference PciEmulation driver that deals with such situation?
I am working on a generic solution for this: https://lists.01.org/pipermail/edk2-devel/2016-October/003842.html
Great, thanks! It seems like all we need is there. I have a dillema now - since it's under review on EDK2 lists, I have doubts if there is any reason for adding similar solution in OPP.
I would very much prefer to not add your implementation to OPP only to delete it again a week or two later.
It may be a good moment to adjust to your solution and test - if everything is fine, we can drop our driver - what do you think?
Yes, that sounds good.
I know it's hard to predict, but when do you expect to get it merged? It's important due to tight schedule we have:/ In case of problems we will try to enhance OPP driver to be accepted and later replace solution, once it's ready - we still have almost a month to go.
I am not overly concerned by this. Worst case, we could add Ard's generic solution to OPP as a stop-gap solution.
I have a couple of questions:
- Is it possible to use it with multiple devices?
Yes.
- Is there any exaple of usage?
See Ard's recent posts to linaro-uefi for moving the AMD platforms onto this infrastructure.
- Sata in current silicone revision has some quirks (non-dma
coherent, +2 other minor stuff, which was avoided by substituting PciIoMemRead/Write with custom functions). Is there any backdoor in your design for creating sort of wrappers?
(pass, I'll let Ard answer)
- Do you have some branch in public repo, so that it would be easier
to obtain the patches?
Again, see Ard's recent posts to edk2-devel and linaro-uefi.
https://git.linaro.org/people/ard.biesheuvel/uefi-next.git/log/?h=pciio-emu
Regards,
Leif
(On my phone, apologies for brevity.)
On 2 Nov 2016 17:09, "Marcin Wojtas" mw@semihalf.com wrote:
Hi Leif,
Thanks for your answer. We'll check AMD and try to adjust our platform to it. Hopefully everything works fine. We have only USB/SATA/SD left
- all of them users of PciIO stuff. We have to finalize adaptation,
submit patches that can work with Ard's solution.
My preferable scenario is following: let's achieve state that we have ready-to-go, accepted patches in November. Their merge to OPP would be gated only by Ard's PciIO merge to EDK2. This would allow to fulfill our commitments and also prevent from creating mess in the repo. What do you think?
Yes, this sounds good. But I'm also serious about pushing Ard's set into OPP temporarily if needed (and tester).
Best regards, Marcin
2016-11-02 23:49 GMT+01:00 Leif Lindholm leif.lindholm@linaro.org:
On Wed, Nov 02, 2016 at 11:39:43PM +0100, Marcin Wojtas wrote:
2016-11-02 22:56 GMT+01:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
On 2 November 2016 at 21:52, Marcin Wojtas mw@semihalf.com wrote:
Hi Ard,
2016-11-02 21:55 GMT+01:00 Ard Biesheuvel <ard.biesheuvel@linaro.org
:
On 2 November 2016 at 20:02, Jan Dąbroś jsd@semihalf.com wrote: > Hi Ard, > > I have a question regarding DmaLib implementation. We took a
deeper
> look at AHCI controller and it will be coherent on newer SoC
version -
> as for now, we have non-coherent one and it's not working with > NullDmaLib, whereas everything is ok when ArmDmaLib is used. In
the
> same time, tests show that XHCI works fine both with > NullDmaLib and ArmDmaLib. > My question is, what are the contraindications for using
ArmDmaLib for
> coherent devices if it is working good on them also? This solution > seems to be covering for every case (contrary to NullDmaLib). >
No, ArmDmaLib is fundamentally incompatible with coherent devices.
The
code performs a cache invalidate for data written by the bus
master,
since on non-coherent systems, this may be necessary to get rid of stale cachelines that shadow the incoming data. On coherent
devices,
the device will write to the cache, not to main memory, and so this cache invalidation will discard the data coming from the device.
Could you help understand then, how come a coherent device (XHCI)
can
work both with ArmDmaLib/NullDmaLib, whereas non-coherent device (AHCI) can work only with ArmDmaLib? In other words, how do you suggest to proceed here?
In case we switch to NullDmaLib, what's suggested solution of
handling
non-coherent devices? Do you know of any reference PciEmulation
driver
that deals with such situation?
I am working on a generic solution for this: https://lists.01.org/pipermail/edk2-devel/2016-October/003842.html
Great, thanks! It seems like all we need is there. I have a dillema now - since it's under review on EDK2 lists, I have doubts if there is any reason for adding similar solution in OPP.
I would very much prefer to not add your implementation to OPP only to delete it again a week or two later.
It may be a good moment to adjust to your solution and test - if everything is fine, we can drop our driver - what do you think?
Yes, that sounds good.
I know it's hard to predict, but when do you expect to get it merged? It's important due to tight schedule we have:/ In case of problems we will try to enhance OPP driver to be accepted and later replace solution, once it's ready - we still have almost a month to go.
I am not overly concerned by this. Worst case, we could add Ard's generic solution to OPP as a stop-gap solution.
I have a couple of questions:
- Is it possible to use it with multiple devices?
Yes.
- Is there any exaple of usage?
See Ard's recent posts to linaro-uefi for moving the AMD platforms onto this infrastructure.
- Sata in current silicone revision has some quirks (non-dma
coherent, +2 other minor stuff, which was avoided by substituting PciIoMemRead/Write with custom functions). Is there any backdoor in your design for creating sort of wrappers?
(pass, I'll let Ard answer)
- Do you have some branch in public repo, so that it would be easier
to obtain the patches?
Again, see Ard's recent posts to edk2-devel and linaro-uefi.
https://git.linaro.org/people/ard.biesheuvel/uefi-next.git/log/?h=pciio-emu
Regards,
Leif
On 2 November 2016 at 22:49, Leif Lindholm leif.lindholm@linaro.org wrote:
On Wed, Nov 02, 2016 at 11:39:43PM +0100, Marcin Wojtas wrote:
2016-11-02 22:56 GMT+01:00 Ard Biesheuvel ard.biesheuvel@linaro.org:
[...]
Great, thanks! It seems like all we need is there. I have a dillema now - since it's under review on EDK2 lists, I have doubts if there is any reason for adding similar solution in OPP.
I would very much prefer to not add your implementation to OPP only to delete it again a week or two later.
It may be a good moment to adjust to your solution and test - if everything is fine, we can drop our driver - what do you think?
Yes, that sounds good.
I know it's hard to predict, but when do you expect to get it merged? It's important due to tight schedule we have:/ In case of problems we will try to enhance OPP driver to be accepted and later replace solution, once it's ready - we still have almost a month to go.
I am not overly concerned by this. Worst case, we could add Ard's generic solution to OPP as a stop-gap solution.
I have a couple of questions:
- Is it possible to use it with multiple devices?
Yes.
- Is there any exaple of usage?
See Ard's recent posts to linaro-uefi for moving the AMD platforms onto this infrastructure.
- Sata in current silicone revision has some quirks (non-dma
coherent, +2 other minor stuff, which was avoided by substituting PciIoMemRead/Write with custom functions). Is there any backdoor in your design for creating sort of wrappers?
(pass, I'll let Ard answer)
No, not currently. And if this issue is fixed in recent silicon revisions, I would prefer not to merge the workaround at all.
- Do you have some branch in public repo, so that it would be easier
to obtain the patches?
Again, see Ard's recent posts to edk2-devel and linaro-uefi.
https://git.linaro.org/people/ard.biesheuvel/uefi-next.git/log/?h=pciio-emu
Note that there is discussion about moving this into MdeModulePkg, and renaming and/or modifying core parts of the infrastructure, so at the moment, this is somewhat of a moving target. However, I would be *very* interested in understanding the issues and/or limitations that you run into when using this code, so please don't hesitate to ping me with questions and/or comments (ardb on #linaro-enterprise)
Thanks, Ard.
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada.dsc.inc | 2 ++ Platforms/Marvell/Armada/Armada70x0.fdf | 3 +++ 2 files changed, 5 insertions(+)
diff --git a/Platforms/Marvell/Armada/Armada.dsc.inc b/Platforms/Marvell/Armada/Armada.dsc.inc index 76c5d6d..8886892 100644 --- a/Platforms/Marvell/Armada/Armada.dsc.inc +++ b/Platforms/Marvell/Armada/Armada.dsc.inc @@ -417,6 +417,8 @@ EmbeddedPkg/RealTimeClockRuntimeDxe/RealTimeClockRuntimeDxe.inf EmbeddedPkg/MetronomeDxe/MetronomeDxe.inf
+ OpenPlatformPkg/Platforms/Marvell/PciEmulation/PciEmulation.inf + # Console packages MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf diff --git a/Platforms/Marvell/Armada/Armada70x0.fdf b/Platforms/Marvell/Armada/Armada70x0.fdf index 64c3440..63ba5b3 100644 --- a/Platforms/Marvell/Armada/Armada70x0.fdf +++ b/Platforms/Marvell/Armada/Armada70x0.fdf @@ -123,6 +123,9 @@ FvNameGuid = 5eda4200-2c5f-43cb-9da3-0baf74b1b30c INF OpenPlatformPkg/Drivers/Net/Phy/MvPhyDxe/MvPhyDxe.inf INF OpenPlatformPkg/Drivers/Net/Pp2Dxe/Pp2Dxe.inf
+ # PciEmulation + INF OpenPlatformPkg/Platforms/Marvell/PciEmulation/PciEmulation.inf + # Multiple Console IO support INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada.dsc.inc | 5 +++++ Platforms/Marvell/Armada/Armada70x0.fdf | 5 +++++ 2 files changed, 10 insertions(+)
diff --git a/Platforms/Marvell/Armada/Armada.dsc.inc b/Platforms/Marvell/Armada/Armada.dsc.inc index 8886892..a32d68b 100644 --- a/Platforms/Marvell/Armada/Armada.dsc.inc +++ b/Platforms/Marvell/Armada/Armada.dsc.inc @@ -419,6 +419,11 @@
OpenPlatformPkg/Platforms/Marvell/PciEmulation/PciEmulation.inf
+ # USB + MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf + MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf + MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf + # Console packages MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf diff --git a/Platforms/Marvell/Armada/Armada70x0.fdf b/Platforms/Marvell/Armada/Armada70x0.fdf index 63ba5b3..5342ba6 100644 --- a/Platforms/Marvell/Armada/Armada70x0.fdf +++ b/Platforms/Marvell/Armada/Armada70x0.fdf @@ -126,6 +126,11 @@ FvNameGuid = 5eda4200-2c5f-43cb-9da3-0baf74b1b30c # PciEmulation INF OpenPlatformPkg/Platforms/Marvell/PciEmulation/PciEmulation.inf
+ # USB + INF MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf + INF MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf + INF MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf + # Multiple Console IO support INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada70x0.dsc | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/Platforms/Marvell/Armada/Armada70x0.dsc b/Platforms/Marvell/Armada/Armada70x0.dsc index 2f2b278..22b58aa 100644 --- a/Platforms/Marvell/Armada/Armada70x0.dsc +++ b/Platforms/Marvell/Armada/Armada70x0.dsc @@ -139,6 +139,18 @@ gMarvellTokenSpaceGuid.PcdPp2XlgBaseAddress|0xf2130f00 gMarvellTokenSpaceGuid.PcdPp2XlgDevSize|0x1000
+ #PciEmulation + gMarvellTokenSpaceGuid.PcdPciEDevCount|2 + ## XHCI1 XHCI2 + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000" + ## ClassCode1 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30" + ## ClassCode2 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03" + ## ClassCode3 + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C" + gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000" + #ResetLib gMarvellTokenSpaceGuid.PcdResetRegAddress|0xf06f0084 gMarvellTokenSpaceGuid.PcdResetRegMask|0x1
From: Jan Dąbroś jsd@semihalf.com
Improve PciEmulation driver in order to support SATA controllers. This patch also adds workaround for Cp110 chip, where SATA controller isn't fully compatible with AHCI standard. This patch introduces quirk with AE bit not being set in Global HBA Control register (AHCI Specification section 3.1.2).
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Documentation/Marvell/PortingGuide/Sata.txt | 16 ++++ Platforms/Marvell/Marvell.dec | 9 +- Platforms/Marvell/PciEmulation/PciEmulation.c | 114 +++++++++++++++++++++++- Platforms/Marvell/PciEmulation/PciEmulation.h | 6 ++ Platforms/Marvell/PciEmulation/PciEmulation.inf | 2 + 5 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 Documentation/Marvell/PortingGuide/Sata.txt
diff --git a/Documentation/Marvell/PortingGuide/Sata.txt b/Documentation/Marvell/PortingGuide/Sata.txt new file mode 100644 index 0000000..00df49f --- /dev/null +++ b/Documentation/Marvell/PortingGuide/Sata.txt @@ -0,0 +1,16 @@ +SATA configuration +------------------ +In order to add new SATA device, please refer to document describing +PciEmulation - /path/to/opp/Documenation/Marvell/PortingGuide/PciEmulation.txt + +There are also two additional PCDs: + + gMarvellTokenSpaceGuid.PcdSataBaseAddress + +Base address of SATA controller register space - used in SATA ComPhy init +sequence. + + gMarvellTokenSpaceGuid.PcdSataMapPortAddress + +Boolean indicating if controller on platform needs specific address mapping for +SATA ports. Setting this flag is necessary for CP110-A0 revisions. diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec index f56987d..cf7b555 100644 --- a/Platforms/Marvell/Marvell.dec +++ b/Platforms/Marvell/Marvell.dec @@ -175,9 +175,6 @@ gMarvellTokenSpaceGuid.PcdChip3ComPhySpeeds|{ 0x0 }|VOID*|0x30000176 gMarvellTokenSpaceGuid.PcdChip3ComPhyInvFlags|{ 0x0 }|VOID*|0x30000177
-#SATA - gMarvellTokenSpaceGuid.PcdSataBaseAddress|0|UINT32|0x4000052 - #UtmiPhy gMarvellTokenSpaceGuid.PcdUtmiPhyCount|0|UINT32|0x30000205 gMarvellTokenSpaceGuid.PcdUtmiPhyRegUsbCfg|{ 0x0 }|VOID*|0x30000206 @@ -221,6 +218,12 @@ gMarvellTokenSpaceGuid.PcdResetRegAddress|0|UINT64|0x40000050 gMarvellTokenSpaceGuid.PcdResetRegMask|0|UINT32|0x4000051
+#SATA + gMarvellTokenSpaceGuid.PcdSataBaseAddress|0|UINT32|0x4000052 + +[PcdsFeatureFlag.common] + gMarvellTokenSpaceGuid.PcdSataMapPortAddress|FALSE|BOOLEAN|0x4000053 + [Protocols] gMarvellEepromProtocolGuid = { 0x71954bda, 0x60d3, 0x4ef8, { 0x8e, 0x3c, 0x0e, 0x33, 0x9f, 0x3b, 0xc2, 0x2b }} gMarvellMdioProtocolGuid = { 0x40010b03, 0x5f08, 0x496a, { 0xa2, 0x64, 0x10, 0x5e, 0x72, 0xd3, 0x71, 0xaa }} diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.c b/Platforms/Marvell/PciEmulation/PciEmulation.c index a800bcb..7cfab89 100644 --- a/Platforms/Marvell/PciEmulation/PciEmulation.c +++ b/Platforms/Marvell/PciEmulation/PciEmulation.c @@ -71,6 +71,30 @@ EFI_PCI_IO_DEVICE_PATH PciIoDevicePathTemplate = } };
+STATIC +UINT64 +MapSataPortAddress ( + IN UINT64 Offset + ) +{ + + // + // Since AHCI controller in CP110 isn't compatible with AHCI specification, + // below workaround is necessary. It maps PORT address' offsets. + // + // PORT | AHCI port offset | CP110 port offset + // -------------------------------------------------------- + // 1 | 100h - 180h | 10000h - 10080h + // 2 | 180h - 260h | 20000h - 20080h + // + if ((Offset >= 0x100) && (Offset < 0x180)) + Offset = (Offset - 0x100) + 0x10000; + if ((Offset >= 0x180) && (Offset < 0x260)) + Offset = (Offset - 0x180) + 0x20000; + + return Offset; +} + EFI_STATUS PciIoPollMem ( IN EFI_PCI_IO_PROTOCOL *This, @@ -125,6 +149,43 @@ PciIoMemRead ( }
EFI_STATUS +PciIoSataMemRead ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This); + EFI_STATUS Status; + UINT32 *TmpBuffer; + + if (FeaturePcdGet (PcdSataMapPortAddress)) { + Offset = MapSataPortAddress (Offset); + } + + Status = PciRootBridgeIoMemRead (&Private->RootBridge.Io, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Private->ConfigSpace->Device.Bar[BarIndex] + Offset, + Count, + Buffer); + + // + // AE bit in Global HBA Control register is set only if SAM bit is cleared in + // CAP register. Below quirk makes PciIoMemRead to return value in this + // register with SAM bit unset. + // + if (Offset == 0) { + TmpBuffer = (UINT32 *) Buffer; + *TmpBuffer &= ~(1<<18); + } + + return Status; +} + +EFI_STATUS PciIoMemWrite ( IN EFI_PCI_IO_PROTOCOL *This, IN EFI_PCI_IO_PROTOCOL_WIDTH Width, @@ -136,6 +197,37 @@ PciIoMemWrite ( { EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This);
+ if (FeaturePcdGet (PcdSataMapPortAddress)) { + if (BarIndex == EFI_AHCI_BAR_INDEX) { + Offset = MapSataPortAddress (Offset); + } + } + + return PciRootBridgeIoMemWrite ( + &Private->RootBridge.Io, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Private->ConfigSpace->Device.Bar[BarIndex] + Offset, + Count, + Buffer + ); +} + +EFI_STATUS +PciIoSataMemWrite ( + IN EFI_PCI_IO_PROTOCOL *This, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT8 BarIndex, + IN UINT64 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + EFI_PCI_IO_PRIVATE_DATA *Private = EFI_PCI_IO_PRIVATE_DATA_FROM_THIS(This); + + if (FeaturePcdGet (PcdSataMapPortAddress)) { + Offset = MapSataPortAddress (Offset); + } + return PciRootBridgeIoMemWrite ( &Private->RootBridge.Io, (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, @@ -545,6 +637,7 @@ InstallDevices ( EFI_PCI_IO_PRIVATE_DATA *Private; EFI_STATUS Status; EFI_HANDLE Handle; + UINT32 ClassCodes;
// Create a private structure Private = AllocatePool(sizeof(EFI_PCI_IO_PRIVATE_DATA)); @@ -588,7 +681,6 @@ InstallDevices ( Private->ConfigSpace->Hdr.ClassCode[0] = ClassCode1; Private->ConfigSpace->Hdr.ClassCode[1] = ClassCode2; Private->ConfigSpace->Hdr.ClassCode[2] = ClassCode3; - Private->ConfigSpace->Device.Bar[0] = Private->RootBridge.MemoryStart;
Handle = NULL;
@@ -600,6 +692,26 @@ InstallDevices ( // Copy protocol structure CopyMem(&Private->PciIoProtocol, &PciIoTemplate, sizeof(PciIoTemplate));
+ // + // Concatenate ClassCodes into single number, which will be next used to + // recognize device and fill proper BAR + // + ClassCodes = (ClassCode1 << 16) + (ClassCode2 << 8) + ClassCode3; + + switch (ClassCodes) { + case XHCI_PCI_CLASS_CODE_NR: + Private->ConfigSpace->Device.Bar[EFI_XHCI_BAR_INDEX] = Private->RootBridge.MemoryStart; + break; + case AHCI_PCI_CLASS_CODE_NR: + Private->ConfigSpace->Device.Bar[EFI_AHCI_BAR_INDEX] = Private->RootBridge.MemoryStart; + Private->PciIoProtocol.Mem.Read = PciIoSataMemRead; + Private->PciIoProtocol.Mem.Write = PciIoSataMemWrite; + break; + default: + DEBUG((DEBUG_ERROR, "PciEmulation: Unknown PCI device. Abort.\n")); + return EFI_INVALID_PARAMETER; + } + Status = gBS->InstallMultipleProtocolInterfaces( &Handle, &gEfiPciIoProtocolGuid, diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.h b/Platforms/Marvell/PciEmulation/PciEmulation.h index 4f75539..2323962 100644 --- a/Platforms/Marvell/PciEmulation/PciEmulation.h +++ b/Platforms/Marvell/PciEmulation/PciEmulation.h @@ -47,6 +47,12 @@
#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('P', 'c', 'i', 'F')
+#define XHCI_PCI_CLASS_CODE_NR 0x30030C +#define AHCI_PCI_CLASS_CODE_NR 0x010601 + +#define EFI_XHCI_BAR_INDEX 0x0 +#define EFI_AHCI_BAR_INDEX 0x5 + typedef struct { ACPI_HID_DEVICE_PATH AcpiDevicePath; EFI_DEVICE_PATH_PROTOCOL EndDevicePath; diff --git a/Platforms/Marvell/PciEmulation/PciEmulation.inf b/Platforms/Marvell/PciEmulation/PciEmulation.inf index 30ddfc2..1651715 100644 --- a/Platforms/Marvell/PciEmulation/PciEmulation.inf +++ b/Platforms/Marvell/PciEmulation/PciEmulation.inf @@ -61,5 +61,7 @@ gMarvellTokenSpaceGuid.PcdPciEDevCount gMarvellTokenSpaceGuid.PcdPciEDevRegSize
+ gMarvellTokenSpaceGuid.PcdSataMapPortAddress + [Depex] TRUE
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada.dsc.inc | 10 ++++++++++ Platforms/Marvell/Armada/Armada70x0.fdf | 9 +++++++++ 2 files changed, 19 insertions(+)
diff --git a/Platforms/Marvell/Armada/Armada.dsc.inc b/Platforms/Marvell/Armada/Armada.dsc.inc index a32d68b..8ccaee2 100644 --- a/Platforms/Marvell/Armada/Armada.dsc.inc +++ b/Platforms/Marvell/Armada/Armada.dsc.inc @@ -82,6 +82,7 @@ ArmPlatformStackLib|ArmPlatformPkg/Library/ArmPlatformStackLib/ArmPlatformStackLib.inf ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf TimerLib|ArmPkg/Library/ArmArchTimerLib/ArmArchTimerLib.inf + UefiScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf
# Serial port libraries SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf @@ -419,6 +420,15 @@
OpenPlatformPkg/Platforms/Marvell/PciEmulation/PciEmulation.inf
+ # SCSI + MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf + MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf + + # SATA + MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf + MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf + OvmfPkg/SataControllerDxe/SataControllerDxe.inf + # USB MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf diff --git a/Platforms/Marvell/Armada/Armada70x0.fdf b/Platforms/Marvell/Armada/Armada70x0.fdf index 5342ba6..7a673a4 100644 --- a/Platforms/Marvell/Armada/Armada70x0.fdf +++ b/Platforms/Marvell/Armada/Armada70x0.fdf @@ -125,6 +125,15 @@ FvNameGuid = 5eda4200-2c5f-43cb-9da3-0baf74b1b30c
# PciEmulation INF OpenPlatformPkg/Platforms/Marvell/PciEmulation/PciEmulation.inf + + # SCSI + INF MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf + INF MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf + + # SATA + INF MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf + INF MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf + INF OvmfPkg/SataControllerDxe/SataControllerDxe.inf
# USB INF MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
From: Jan Dąbroś jsd@semihalf.com
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jan Dabros jsd@semihalf.com Signed-off-by: Marcin Wojtas mw@semihalf.com --- Platforms/Marvell/Armada/Armada70x0.dsc | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/Platforms/Marvell/Armada/Armada70x0.dsc b/Platforms/Marvell/Armada/Armada70x0.dsc index 22b58aa..e9e30de 100644 --- a/Platforms/Marvell/Armada/Armada70x0.dsc +++ b/Platforms/Marvell/Armada/Armada70x0.dsc @@ -140,17 +140,23 @@ gMarvellTokenSpaceGuid.PcdPp2XlgDevSize|0x1000
#PciEmulation - gMarvellTokenSpaceGuid.PcdPciEDevCount|2 - ## XHCI1 XHCI2 - gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000" + gMarvellTokenSpaceGuid.PcdPciEDevCount|3 + ## XHCI1 XHCI2 SATA + gMarvellTokenSpaceGuid.PcdPciEDevBaseAddress|L"0xF2500000;0xF2510000;0xF2540000" ## ClassCode1 - gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30" + gMarvellTokenSpaceGuid.PcdPciEDevClassCode1|L"0x30;0x30;0x01" ## ClassCode2 - gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03" + gMarvellTokenSpaceGuid.PcdPciEDevClassCode2|L"0x03;0x03;0x06" ## ClassCode3 - gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C" - gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000" + gMarvellTokenSpaceGuid.PcdPciEDevClassCode3|L"0x0C;0x0C;0x01" + gMarvellTokenSpaceGuid.PcdPciEDevRegSize|L"0x10000;0x10000;0x30000"
#ResetLib gMarvellTokenSpaceGuid.PcdResetRegAddress|0xf06f0084 gMarvellTokenSpaceGuid.PcdResetRegMask|0x1 + + #SATA + gMarvellTokenSpaceGuid.PcdSataBaseAddress|0xF2540000 + +[PcdsFeatureFlag.common] + gMarvellTokenSpaceGuid.PcdSataMapPortAddress|TRUE