From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web12.9988.1590140529002643320 for ; Fri, 22 May 2020 02:42:09 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: arm.com, ip: 217.140.110.172, mailfrom: ard.biesheuvel@arm.com) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4F9BA30E; Fri, 22 May 2020 02:42:08 -0700 (PDT) Received: from [192.168.1.81] (unknown [10.37.8.250]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 56F413F305; Fri, 22 May 2020 02:42:06 -0700 (PDT) Subject: Re: [PATCH edk2-platforms 13/16] Silicon/NXP/Drivers: Implement PciCpuIo2Dxe Driver To: Wasim Khan , devel@edk2.groups.io, meenakshi.aggarwal@nxp.com, vabhav.sharma@nxp.com, V.Sethi@nxp.com, leif@nuviainc.com, jon@solid-run.com Cc: Wasim Khan References: <1590102139-16588-1-git-send-email-wasim.khan@oss.nxp.com> <1590102139-16588-14-git-send-email-wasim.khan@oss.nxp.com> From: "Ard Biesheuvel" Message-ID: <4411743c-13ea-b120-2985-985397c492f4@arm.com> Date: Fri, 22 May 2020 11:42:04 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.7.0 MIME-Version: 1.0 In-Reply-To: <1590102139-16588-14-git-send-email-wasim.khan@oss.nxp.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit On 5/22/20 1:02 AM, Wasim Khan wrote: > From: Wasim Khan > > NXP SoC has multiple PCIe RCs and there is no fix translation > offset between I/O port accesses and MMIO accesses. > Add PciCpuIo2Dxe driver to implement EFI_CPU_IO2_PROTOCOL > to add the translation for different RCs for IO access. > > Signed-off-by: Wasim Khan Reviewed-by: Ard Biesheuvel > --- > Silicon/NXP/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf | 40 ++ > Silicon/NXP/Include/Pcie.h | 19 + > Silicon/NXP/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c | 628 ++++++++++++++++++++++ > 3 files changed, 687 insertions(+) > create mode 100755 Silicon/NXP/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf > create mode 100755 Silicon/NXP/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c > > diff --git a/Silicon/NXP/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf b/Silicon/NXP/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf > new file mode 100755 > index 000000000000..0ee470e41d5e > --- /dev/null > +++ b/Silicon/NXP/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.inf > @@ -0,0 +1,40 @@ > +## @file > +# Produces the CPU I/O 2 Protocol by using the services of the I/O Library. > +# > +# Copyright 2018, 2020 NXP > +# > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION = 0x0001001A > + BASE_NAME = PciCpuIo2Dxe > + FILE_GUID = 7bff18d7-9aae-434b-9c06-f10a7e157eac > + MODULE_TYPE = DXE_DRIVER > + VERSION_STRING = 1.0 > + ENTRY_POINT = PciCpuIo2Initialize > + > +[Sources] > + PciCpuIo2Dxe.c > + > +[Packages] > + MdePkg/MdePkg.dec > + Silicon/NXP/NxpQoriqLs.dec > + > +[LibraryClasses] > + BaseLib > + DebugLib > + IoLib > + UefiBootServicesTableLib > + UefiDriverEntryPoint > + > +[Pcd] > + gNxpQoriqLsTokenSpaceGuid.PcdPciExp1BaseAddr > + gNxpQoriqLsTokenSpaceGuid.PcdNumPciController > + > +[Protocols] > + gEfiCpuIo2ProtocolGuid ## PRODUCES > + > +[Depex] > + TRUE > diff --git a/Silicon/NXP/Include/Pcie.h b/Silicon/NXP/Include/Pcie.h > index bc35570f79bc..b561d0e3ba11 100755 > --- a/Silicon/NXP/Include/Pcie.h > +++ b/Silicon/NXP/Include/Pcie.h > @@ -39,6 +39,25 @@ > #define PCI_SEG0_PHY_MEM_BASE PCI_SEG0_MMIO_MEMBASE + SEG_MEM_BASE > #define PCI_SEG0_PHY_MEM64_BASE PCI_SEG0_MMIO_MEMBASE + SEG_MEM64_BASE > #define PCI_SEG0_PHY_IO_BASE PCI_SEG0_MMIO_MEMBASE + SEG_IO_BASE > +#define PCI_SEG0_PORTIO_MIN 0x0 > +#define PCI_SEG0_PORTIO_MAX 0xffff > +#define PCI_SEG0_PORTIO_OFFSET 0x0 > +#define PCI_SEG1_PORTIO_MIN 0x0 > +#define PCI_SEG1_PORTIO_MAX 0xffff > +#define PCI_SEG1_PORTIO_OFFSET 0x10000 > +#define PCI_SEG2_PORTIO_MIN 0x0 > +#define PCI_SEG2_PORTIO_MAX 0xffff > +#define PCI_SEG2_PORTIO_OFFSET 0x20000 > +#define PCI_SEG3_PORTIO_MIN 0x0 > +#define PCI_SEG3_PORTIO_MAX 0xffff > +#define PCI_SEG3_PORTIO_OFFSET 0x30000 > +#define PCI_SEG4_PORTIO_MIN 0x0 > +#define PCI_SEG4_PORTIO_MAX 0xffff > +#define PCI_SEG4_PORTIO_OFFSET 0x40000 > +#define PCI_SEG5_PORTIO_MIN 0x0 > +#define PCI_SEG5_PORTIO_MAX 0xffff > +#define PCI_SEG5_PORTIO_OFFSET 0x50000 > +#define PCI_SEG_PORTIO_LIMIT PCI_SEG5_PORTIO_MAX + PCI_SEG5_PORTIO_OFFSET > > // PCIe Controller configuration > #define NUM_PCIE_CONTROLLER FixedPcdGet32 (PcdNumPciController) > diff --git a/Silicon/NXP/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c b/Silicon/NXP/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c > new file mode 100755 > index 000000000000..17db44a8b510 > --- /dev/null > +++ b/Silicon/NXP/Drivers/PciCpuIo2Dxe/PciCpuIo2Dxe.c > @@ -0,0 +1,628 @@ > +/** @file > + Produces the CPU I/O 2 Protocol. > + > + Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.
> + Copyright (c) 2016, Linaro Ltd. All rights reserved.
> + Copyright 2018-2020 NXP > + > + SPDX-License-Identifier: BSD-2-Clause-Patent > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define MAX_IO_PORT_ADDRESS PCI_SEG_PORTIO_LIMIT > + > +// > +// Handle for the CPU I/O 2 Protocol > +// > +STATIC EFI_HANDLE mHandle = NULL; > + > +// > +// Lookup table for increment values based on transfer widths > +// > +STATIC CONST UINT8 mInStride[] = { > + 1, // EfiCpuIoWidthUint8 > + 2, // EfiCpuIoWidthUint16 > + 4, // EfiCpuIoWidthUint32 > + 8, // EfiCpuIoWidthUint64 > + 0, // EfiCpuIoWidthFifoUint8 > + 0, // EfiCpuIoWidthFifoUint16 > + 0, // EfiCpuIoWidthFifoUint32 > + 0, // EfiCpuIoWidthFifoUint64 > + 1, // EfiCpuIoWidthFillUint8 > + 2, // EfiCpuIoWidthFillUint16 > + 4, // EfiCpuIoWidthFillUint32 > + 8 // EfiCpuIoWidthFillUint64 > +}; > + > +// > +// Lookup table for increment values based on transfer widths > +// > +STATIC CONST UINT8 mOutStride[] = { > + 1, // EfiCpuIoWidthUint8 > + 2, // EfiCpuIoWidthUint16 > + 4, // EfiCpuIoWidthUint32 > + 8, // EfiCpuIoWidthUint64 > + 1, // EfiCpuIoWidthFifoUint8 > + 2, // EfiCpuIoWidthFifoUint16 > + 4, // EfiCpuIoWidthFifoUint32 > + 8, // EfiCpuIoWidthFifoUint64 > + 0, // EfiCpuIoWidthFillUint8 > + 0, // EfiCpuIoWidthFillUint16 > + 0, // EfiCpuIoWidthFillUint32 > + 0 // EfiCpuIoWidthFillUint64 > +}; > + > +/** > + Check parameters to a CPU I/O 2 Protocol service request. > + > + The I/O operations are carried out exactly as requested. The caller is responsible > + for satisfying any alignment and I/O width restrictions that a PI System on a > + platform might require. For example on some platforms, width requests of > + EfiCpuIoWidthUint64 do not work. > + > + @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation. > + @param[in] Width Signifies the width of the I/O or Memory operation. > + @param[in] Address The base address of the I/O operation. > + @param[in] Count The number of I/O operations to perform. The number of > + bytes moved is Width size * Count, starting at Address. > + @param[in] Buffer For read operations, the destination buffer to store the results. > + For write operations, the source buffer from which to write data. > + > + @retval EFI_SUCCESS The parameters for this request pass the checks. > + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. > + @retval EFI_INVALID_PARAMETER Buffer is NULL. > + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. > + @retval EFI_UNSUPPORTED The address range specified by Address, Width, > + and Count is not valid for this PI system. > + > +**/ > +STATIC > +EFI_STATUS > +CpuIoCheckParameter ( > + IN BOOLEAN MmioOperation, > + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, > + IN UINT64 Address, > + IN UINTN Count, > + IN VOID *Buffer > + ) > +{ > + UINT64 MaxCount; > + UINT64 Limit; > + > + // > + // Check to see if Buffer is NULL > + // > + if (Buffer == NULL) { > + ASSERT (FALSE); > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check to see if Width is in the valid range > + // > + if ((UINT32)Width >= EfiCpuIoWidthMaximum) { > + ASSERT (FALSE); > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // For FIFO type, the target address won't increase during the access, > + // so treat Count as 1 > + // > + if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) { > + Count = 1; > + } > + > + // > + // Check to see if Width is in the valid range for I/O Port operations > + // > + Width = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03); > + if (!MmioOperation && (Width == EfiCpuIoWidthUint64)) { > + ASSERT (FALSE); > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Check to see if Address is aligned > + // > + if ((Address & (UINT64)(mInStride[Width] - 1)) != 0) { > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > + } > + > + // > + // Check to see if any address associated with this transfer exceeds the maximum > + // allowed address. The maximum address implied by the parameters passed in is > + // Address + Size * Count. If the following condition is met, then the transfer > + // is not supported. > + // > + // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1 > + // > + // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count > + // can also be the maximum integer value supported by the CPU, this range > + // check must be adjusted to avoid all oveflow conditions. > + // > + Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS); > + if (Count == 0) { > + if (Address > Limit) { > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > + } > + } else { > + MaxCount = RShiftU64 (Limit, Width); > + if (MaxCount < (Count - 1)) { > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > + } > + if (Address > LShiftU64 (MaxCount - Count + 1, Width)) { > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > + } > + } > + > + // > + // Check to see if Buffer is aligned > + // > + if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width]) - 1))) != 0) { > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Reads memory-mapped registers. > + > + The I/O operations are carried out exactly as requested. The caller is responsible > + for satisfying any alignment and I/O width restrictions that a PI System on a > + platform might require. For example on some platforms, width requests of > + EfiCpuIoWidthUint64 do not work. > + > + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, > + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for > + each of the Count operations that is performed. > + > + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, > + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is > + incremented for each of the Count operations that is performed. The read or > + write operation is performed Count times on the same Address. > + > + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, > + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is > + incremented for each of the Count operations that is performed. The read or > + write operation is performed Count times from the first element of Buffer. > + > + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. > + @param[in] Width Signifies the width of the I/O or Memory operation. > + @param[in] Address The base address of the I/O operation. > + @param[in] Count The number of I/O operations to perform. The number of > + bytes moved is Width size * Count, starting at Address. > + @param[out] Buffer For read operations, the destination buffer to store the results. > + For write operations, the source buffer from which to write data. > + > + @retval EFI_SUCCESS The data was read from or written to the PI system. > + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. > + @retval EFI_INVALID_PARAMETER Buffer is NULL. > + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. > + @retval EFI_UNSUPPORTED The address range specified by Address, Width, > + and Count is not valid for this PI system. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +CpuMemoryServiceRead ( > + IN EFI_CPU_IO2_PROTOCOL *This, > + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, > + IN UINT64 Address, > + IN UINTN Count, > + OUT VOID *Buffer > + ) > +{ > + EFI_STATUS Status; > + UINT8 InStride; > + UINT8 OutStride; > + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; > + UINT8 *Uint8Buffer; > + > + Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Select loop based on the width of the transfer > + // > + InStride = mInStride[Width]; > + OutStride = mOutStride[Width]; > + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); > + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { > + if (OperationWidth == EfiCpuIoWidthUint8) { > + *Uint8Buffer = MmioRead8 ((UINTN)Address); > + } else if (OperationWidth == EfiCpuIoWidthUint16) { > + *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address); > + } else if (OperationWidth == EfiCpuIoWidthUint32) { > + *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address); > + } else if (OperationWidth == EfiCpuIoWidthUint64) { > + *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address); > + } > + } > + return EFI_SUCCESS; > +} > + > +/** > + Writes memory-mapped registers. > + > + The I/O operations are carried out exactly as requested. The caller is responsible > + for satisfying any alignment and I/O width restrictions that a PI System on a > + platform might require. For example on some platforms, width requests of > + EfiCpuIoWidthUint64 do not work. > + > + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, > + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for > + each of the Count operations that is performed. > + > + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, > + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is > + incremented for each of the Count operations that is performed. The read or > + write operation is performed Count times on the same Address. > + > + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, > + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is > + incremented for each of the Count operations that is performed. The read or > + write operation is performed Count times from the first element of Buffer. > + > + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. > + @param[in] Width Signifies the width of the I/O or Memory operation. > + @param[in] Address The base address of the I/O operation. > + @param[in] Count The number of I/O operations to perform. The number of > + bytes moved is Width size * Count, starting at Address. > + @param[in] Buffer For read operations, the destination buffer to store the results. > + For write operations, the source buffer from which to write data. > + > + @retval EFI_SUCCESS The data was read from or written to the PI system. > + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. > + @retval EFI_INVALID_PARAMETER Buffer is NULL. > + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. > + @retval EFI_UNSUPPORTED The address range specified by Address, Width, > + and Count is not valid for this PI system. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +CpuMemoryServiceWrite ( > + IN EFI_CPU_IO2_PROTOCOL *This, > + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, > + IN UINT64 Address, > + IN UINTN Count, > + IN VOID *Buffer > + ) > +{ > + EFI_STATUS Status; > + UINT8 InStride; > + UINT8 OutStride; > + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; > + UINT8 *Uint8Buffer; > + > + Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Select loop based on the width of the transfer > + // > + InStride = mInStride[Width]; > + OutStride = mOutStride[Width]; > + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); > + for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) { > + if (OperationWidth == EfiCpuIoWidthUint8) { > + MmioWrite8 ((UINTN)Address, *Uint8Buffer); > + } else if (OperationWidth == EfiCpuIoWidthUint16) { > + MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); > + } else if (OperationWidth == EfiCpuIoWidthUint32) { > + MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); > + } else if (OperationWidth == EfiCpuIoWidthUint64) { > + MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer)); > + } > + } > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +TranslateIoAddress ( > + IN OUT UINT64 *Address > + ) > +{ > + UINT64 Start; > + UINT64 End; > + UINT64 Shift; > + UINT64 SegIoHostAddressBase; > + > + SegIoHostAddressBase = PCI_SEG0_PHY_IO_BASE; > + Start = PCI_SEG0_PORTIO_MIN + PCI_SEG0_PORTIO_OFFSET; > + End = PCI_SEG0_PORTIO_MAX + PCI_SEG0_PORTIO_OFFSET; > + Shift = SegIoHostAddressBase - PCI_SEG0_PORTIO_OFFSET; > + > + if (*Address >= Start && *Address <= End) { > + *Address += Shift; > + return EFI_SUCCESS; > + } > + > + Start = PCI_SEG1_PORTIO_MIN + PCI_SEG1_PORTIO_OFFSET; > + End = PCI_SEG1_PORTIO_MAX + PCI_SEG1_PORTIO_OFFSET; > + Shift = (SegIoHostAddressBase + (PCI_BASE_DIFF * 1)) - PCI_SEG1_PORTIO_OFFSET; > + > + if (*Address >= Start && *Address <= End) { > + *Address += Shift; > + return EFI_SUCCESS; > + } > + > + Start = PCI_SEG2_PORTIO_MIN + PCI_SEG2_PORTIO_OFFSET; > + End = PCI_SEG2_PORTIO_MAX + PCI_SEG2_PORTIO_OFFSET; > + Shift = (SegIoHostAddressBase + (PCI_BASE_DIFF * 2)) - PCI_SEG2_PORTIO_OFFSET; > + > + if (*Address >= Start && *Address <= End) { > + *Address += Shift; > + return EFI_SUCCESS; > + } > + > + Start = PCI_SEG3_PORTIO_MIN + PCI_SEG3_PORTIO_OFFSET; > + End = PCI_SEG3_PORTIO_MAX + PCI_SEG3_PORTIO_OFFSET; > + Shift = (SegIoHostAddressBase + (PCI_BASE_DIFF * 3)) - PCI_SEG3_PORTIO_OFFSET; > + > + if (*Address >= Start && *Address <= End) { > + *Address += Shift; > + return EFI_SUCCESS; > + } > + > + Start = PCI_SEG4_PORTIO_MIN + PCI_SEG4_PORTIO_OFFSET; > + End = PCI_SEG4_PORTIO_MAX + PCI_SEG4_PORTIO_OFFSET; > + Shift = (SegIoHostAddressBase + (PCI_BASE_DIFF * 4)) - PCI_SEG4_PORTIO_OFFSET; > + > + if (*Address >= Start && *Address <= End) { > + *Address += Shift; > + return EFI_SUCCESS; > + } > + > + Start = PCI_SEG5_PORTIO_MIN + PCI_SEG5_PORTIO_OFFSET; > + End = PCI_SEG5_PORTIO_MAX + PCI_SEG5_PORTIO_OFFSET; > + Shift = (SegIoHostAddressBase + (PCI_BASE_DIFF * 5)) - PCI_SEG5_PORTIO_OFFSET; > + > + if (*Address >= Start && *Address <= End) { > + *Address += Shift; > + return EFI_SUCCESS; > + } > + ASSERT (FALSE); > + return EFI_INVALID_PARAMETER; > +} > + > +/** > + Reads I/O registers. > + > + The I/O operations are carried out exactly as requested. The caller is responsible > + for satisfying any alignment and I/O width restrictions that a PI System on a > + platform might require. For example on some platforms, width requests of > + EfiCpuIoWidthUint64 do not work. > + > + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, > + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for > + each of the Count operations that is performed. > + > + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, > + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is > + incremented for each of the Count operations that is performed. The read or > + write operation is performed Count times on the same Address. > + > + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, > + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is > + incremented for each of the Count operations that is performed. The read or > + write operation is performed Count times from the first element of Buffer. > + > + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. > + @param[in] Width Signifies the width of the I/O or Memory operation. > + @param[in] Address The base address of the I/O operation. > + @param[in] Count The number of I/O operations to perform. The number of > + bytes moved is Width size * Count, starting at Address. > + @param[out] Buffer For read operations, the destination buffer to store the results. > + For write operations, the source buffer from which to write data. > + > + @retval EFI_SUCCESS The data was read from or written to the PI system. > + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. > + @retval EFI_INVALID_PARAMETER Buffer is NULL. > + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. > + @retval EFI_UNSUPPORTED The address range specified by Address, Width, > + and Count is not valid for this PI system. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +CpuIoServiceRead ( > + IN EFI_CPU_IO2_PROTOCOL *This, > + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, > + IN UINT64 Address, > + IN UINTN Count, > + OUT VOID *Buffer > + ) > +{ > + EFI_STATUS Status; > + UINT8 InStride; > + UINT8 OutStride; > + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; > + UINT8 *Uint8Buffer; > + > + Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status = TranslateIoAddress (&Address); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Select loop based on the width of the transfer > + // > + InStride = mInStride[Width]; > + OutStride = mOutStride[Width]; > + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH)(Width & 0x03); > + > + for (Uint8Buffer = Buffer; Count > 0; > + Address += InStride, Uint8Buffer += OutStride, Count--) { > + if (OperationWidth == EfiCpuIoWidthUint8) { > + *Uint8Buffer = MmioRead8 ((UINTN)Address); > + } else if (OperationWidth == EfiCpuIoWidthUint16) { > + *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address); > + } else if (OperationWidth == EfiCpuIoWidthUint32) { > + *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address); > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Write I/O registers. > + > + The I/O operations are carried out exactly as requested. The caller is responsible > + for satisfying any alignment and I/O width restrictions that a PI System on a > + platform might require. For example on some platforms, width requests of > + EfiCpuIoWidthUint64 do not work. > + > + If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32, > + or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for > + each of the Count operations that is performed. > + > + If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16, > + EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is > + incremented for each of the Count operations that is performed. The read or > + write operation is performed Count times on the same Address. > + > + If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16, > + EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is > + incremented for each of the Count operations that is performed. The read or > + write operation is performed Count times from the first element of Buffer. > + > + @param[in] This A pointer to the EFI_CPU_IO2_PROTOCOL instance. > + @param[in] Width Signifies the width of the I/O or Memory operation. > + @param[in] Address The base address of the I/O operation. > + @param[in] Count The number of I/O operations to perform. The number of > + bytes moved is Width size * Count, starting at Address. > + @param[in] Buffer For read operations, the destination buffer to store the results. > + For write operations, the source buffer from which to write data. > + > + @retval EFI_SUCCESS The data was read from or written to the PI system. > + @retval EFI_INVALID_PARAMETER Width is invalid for this PI system. > + @retval EFI_INVALID_PARAMETER Buffer is NULL. > + @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width. > + @retval EFI_UNSUPPORTED The address range specified by Address, Width, > + and Count is not valid for this PI system. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +CpuIoServiceWrite ( > + IN EFI_CPU_IO2_PROTOCOL *This, > + IN EFI_CPU_IO_PROTOCOL_WIDTH Width, > + IN UINT64 Address, > + IN UINTN Count, > + IN VOID *Buffer > + ) > +{ > + EFI_STATUS Status; > + UINT8 InStride; > + UINT8 OutStride; > + EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth; > + UINT8 *Uint8Buffer; > + > + // > + // Make sure the parameters are valid > + // > + Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + Status = TranslateIoAddress (&Address); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Select loop based on the width of the transfer > + // > + InStride = mInStride[Width]; > + OutStride = mOutStride[Width]; > + OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03); > + > + for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; > + Address += InStride, Uint8Buffer += OutStride, Count--) { > + if (OperationWidth == EfiCpuIoWidthUint8) { > + MmioWrite8 ((UINTN)Address, *Uint8Buffer); > + } else if (OperationWidth == EfiCpuIoWidthUint16) { > + MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer)); > + } else if (OperationWidth == EfiCpuIoWidthUint32) { > + MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer)); > + } > + } > + > + return EFI_SUCCESS; > +} > + > +// > +// CPU I/O 2 Protocol instance > +// > +STATIC EFI_CPU_IO2_PROTOCOL mCpuIo2 = { > + { > + CpuMemoryServiceRead, > + CpuMemoryServiceWrite > + }, > + { > + CpuIoServiceRead, > + CpuIoServiceWrite > + } > +}; > + > + > +/** > + The user Entry Point for module CpuIo2Dxe. The user code starts with this function. > + > + @param[in] ImageHandle The firmware allocated handle for the EFI image. > + @param[in] SystemTable A pointer to the EFI System Table. > + > + @retval EFI_SUCCESS The entry point is executed successfully. > + @retval other Some error occurs when executing this entry point. > + > +**/ > +EFI_STATUS > +EFIAPI > +PciCpuIo2Initialize ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + > + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIo2ProtocolGuid); > + Status = gBS->InstallMultipleProtocolInterfaces ( > + &mHandle, > + &gEfiCpuIo2ProtocolGuid, &mCpuIo2, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + > + return Status; > +} >