summaryrefslogtreecommitdiff
path: root/Silicon/Intel/PurleyRcPkg/Library/UsraAccessLib/PcieAccess.c
diff options
context:
space:
mode:
Diffstat (limited to 'Silicon/Intel/PurleyRcPkg/Library/UsraAccessLib/PcieAccess.c')
-rw-r--r--Silicon/Intel/PurleyRcPkg/Library/UsraAccessLib/PcieAccess.c360
1 files changed, 360 insertions, 0 deletions
diff --git a/Silicon/Intel/PurleyRcPkg/Library/UsraAccessLib/PcieAccess.c b/Silicon/Intel/PurleyRcPkg/Library/UsraAccessLib/PcieAccess.c
new file mode 100644
index 0000000000..5af2c5953a
--- /dev/null
+++ b/Silicon/Intel/PurleyRcPkg/Library/UsraAccessLib/PcieAccess.c
@@ -0,0 +1,360 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UsraAccessLib.h"
+
+#define MAX_IO_PORT_ADDRESS 0xFFFF
+
+//
+// Lookup table for increment values based on transfer widths
+//
+UINT8 mInStride[] = {
+ 1, // UsraWidth8
+ 2, // UsraWidth16
+ 4, // UsraWidth32
+ 8, // UsraWidth64
+ 0, // UsraWidthFifo8
+ 0, // UsraWidthFifo16
+ 0, // UsraWidthFifo32
+ 0, // UsraWidthFifo64
+ 1, // UsraWidthFill8
+ 2, // UsraWidthFill16
+ 4, // UsraWidthFill32
+ 8 // UsraWidthFill64
+};
+
+//
+// Lookup table for increment values based on transfer widths
+//
+UINT8 mOutStride[] = {
+ 1, // UsraWidth8
+ 2, // UsraWidth16
+ 4, // UsraWidth32
+ 8, // UsraWidth64
+ 1, // UsraWidthFifo8
+ 2, // UsraWidthFifo16
+ 4, // UsraWidthFifo32
+ 8, // UsraWidthFifo64
+ 0, // UsraWidthFill8
+ 0, // UsraWidthFill16
+ 0, // UsraWidthFill32
+ 0 // UsraWidthFill64
+};
+
+
+/**
+ This API gets the Pcie address from the given USRA Address.
+
+ @param[in] Global Global pointer
+ @param[in] Virtual Virtual address
+ @param[in] Address A pointer of the address of the USRA Address Structure
+ @param[out] AlignedAddress A pointer of aligned address converted from USRA address
+
+ @retval NONE
+**/
+VOID
+GetPcieAccessAddress (
+ IN VOID *Global,
+ IN BOOLEAN Virtual,
+ IN USRA_ADDRESS *Address,
+ OUT UINTN *AlignedAddress
+ )
+{
+ INTN MmCfgBase;
+
+ MmCfgBase = GetPcieSegMmcfgBaseAddress(Address);
+ // TODO: add Error Check for NULL later
+ *AlignedAddress = MmCfgBase + (UINTN)(Address->Attribute.RawData32[0] & 0x0fffffff);
+}
+
+/**
+ This API performs 8-bit, 16-bit, 32-bit or 64-bit Pcie silicon register read operations.
+ It transfers data from a register into a naturally aligned data buffer.
+
+ @param[in] Address A pointer of the address of the USRA Address Structure to be read out
+ @param[in] Buffer A pointer of buffer for the value read from the register
+
+ @retval RETURN_SUCCESS The function completed successfully.
+**/
+RETURN_STATUS
+PcieRegisterRead (
+ IN USRA_ADDRESS *Address,
+ IN VOID *Buffer
+ )
+{
+ UINTN AlignedAddress;
+
+ GetPcieAccessAddress (NULL, 0, Address, &AlignedAddress);
+ UsraRegAlignedRead((UINT32)Address->Attribute.AccessWidth, AlignedAddress, Buffer);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Check parameters to PcieBlkRegisterRead() function 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
+ UsraWidth64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ @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 Buffer is NULL.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @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
+RETURN_STATUS
+CpuIoCheckParameter (
+ IN BOOLEAN MmioOperation,
+ IN USRA_ACCESS_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) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see if Width is in the valid range
+ //
+ if ((UINT32)Width >= UsraWidthMaximum) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // For FIFO type, the target address won't increase during the access,
+ // so treat Count as 1
+ //
+ if (Width >= UsraWidthFifo8 && Width <= UsraWidthFifo64) {
+ Count = 1;
+ }
+
+ //
+ // Check to see if Width is in the valid range for I/O Port operations
+ //
+ Width = (USRA_ACCESS_WIDTH) (Width & 0x03);
+ if (!MmioOperation && (Width == UsraWidth64)) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see if Address is aligned
+ //
+ if ((Address & (UINT64)(mInStride[Width] - 1)) != 0) {
+ return RETURN_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.
+ //
+ // The following form of the range check is equivalent but assumes that
+ // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
+ //
+ Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);
+ if (Count == 0) {
+ if (Address > Limit) {
+ return RETURN_UNSUPPORTED;
+ }
+ } else {
+ MaxCount = RShiftU64 (Limit, Width);
+ if (MaxCount < (Count - 1)) {
+ return RETURN_UNSUPPORTED;
+ }
+ if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {
+ return RETURN_UNSUPPORTED;
+ }
+ }
+
+ //
+ // Check to see if Buffer is aligned
+ // (IA-32 allows UINT64 and INT64 data types to be 32-bit aligned.)
+ //
+ if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width]) - 1))) != 0) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ This API performs 8-bit, 16-bit, 32-bit or 64-bit Pcie block silicon register read operations.
+ It transfers data from a register into a naturally aligned data buffer.
+
+ @param[in] Address A pointer of the address of the USRA Address Structure to be read out
+ @param[in] Buffer A pointer of buffer for the value read from the register
+
+ @retval RETURN_SUCCESS The function completed successfully.
+ @retval Others Some error occurs when executing CpuIoCheckParameter function.
+**/
+RETURN_STATUS
+PcieBlkRegisterRead (
+ IN USRA_ADDRESS *Address,
+ IN VOID *Buffer
+ )
+{
+ UINT8 InStride;
+ UINT8 OutStride;
+ RETURN_STATUS Status;
+ UINTN AlignedAddress;
+ UINT32 ReadCount = Address->PcieBlk.Count;
+ UINT8 *UINT8Buffer;
+
+ GetPcieAccessAddress (NULL, 0, Address, &AlignedAddress);
+ Status = CpuIoCheckParameter (TRUE, Address->Attribute.AccessWidth, AlignedAddress, ReadCount, Buffer);
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+
+ InStride = mInStride[Address->Attribute.AccessWidth];
+ OutStride = mOutStride[Address->Attribute.AccessWidth];
+ for (UINT8Buffer = Buffer; ReadCount > 0; AlignedAddress += InStride, UINT8Buffer += OutStride, ReadCount--) {
+ UsraRegAlignedRead((USRA_ACCESS_WIDTH) (Address->Attribute.AccessWidth & 0x03), AlignedAddress, (VOID *)UINT8Buffer);
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ This API performs 8-bit, 16-bit, 32-bit or 64-bit Pcie silicon register write operations.
+ It transfers data from a naturally aligned data buffer into a register.
+
+ @param[in] Address A pointer of the address of the USRA Address Structure to be written
+ @param[in] Buffer A pointer of buffer for the value write to the register
+
+ @retval RETURN_SUCCESS The function completed successfully.
+**/
+RETURN_STATUS
+PcieRegisterWrite (
+ IN USRA_ADDRESS *Address,
+ OUT VOID *Buffer
+ )
+{
+ UINTN AlignedAddress;
+
+ GetPcieAccessAddress(NULL, 0, Address, &AlignedAddress);
+ UsraRegAlignedWrite((UINT32)Address->Attribute.AccessWidth, AlignedAddress, Buffer);
+
+ if (FeaturePcdGet (PcdUsraSupportS3))
+ {
+ if(Address->Attribute.S3Enable)
+ {
+ S3BootScriptSaveMemWrite ((S3_BOOT_SCRIPT_LIB_WIDTH)Address->Attribute.AccessWidth, (UINT64)AlignedAddress, 1, Buffer);
+ }
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ This API performs 8-bit, 16-bit, 32-bit or 64-bit Pcie block silicon register write operations.
+ It transfers data from a naturally aligned data buffer into a register.
+
+ @param[in] Address A pointer of the address of the USRA Address Structure to be written
+ @param[in] Buffer A pointer of buffer for the value write to the register
+
+ @retval RETURN_SUCCESS The function completed successfully.
+ @retval Others Some error occurs when executing CpuIoCheckParameter function.
+**/
+RETURN_STATUS
+PcieBlkRegisterWrite (
+ IN USRA_ADDRESS *Address,
+ OUT VOID *Buffer
+ )
+{
+ UINT8 InStride;
+ UINT8 OutStride;
+ RETURN_STATUS Status;
+ UINTN AlignedAddress;
+ UINT32 WriteCount = Address->PcieBlk.Count;
+ UINT8 *UINT8Buffer;
+
+ GetPcieAccessAddress (NULL, 0, Address, &AlignedAddress);
+ Status = CpuIoCheckParameter (TRUE, Address->Attribute.AccessWidth, AlignedAddress, WriteCount, Buffer);
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+
+ InStride = mInStride[Address->Attribute.AccessWidth];
+ OutStride = mOutStride[Address->Attribute.AccessWidth];
+ for (UINT8Buffer = Buffer; WriteCount > 0; AlignedAddress += InStride, UINT8Buffer += OutStride, WriteCount--) {
+ UsraRegAlignedWrite((USRA_ACCESS_WIDTH) (Address->Attribute.AccessWidth & 0x03), AlignedAddress, (VOID *)UINT8Buffer);
+
+ if (FeaturePcdGet (PcdUsraSupportS3)) {
+ if(Address->Attribute.S3Enable) {
+ S3BootScriptSaveMemWrite ((S3_BOOT_SCRIPT_LIB_WIDTH)(Address->Attribute.AccessWidth & 0x03), (UINT64)AlignedAddress, 1, (VOID *)UINT8Buffer);
+ }
+ }
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ This API performs 8-bit, 16-bit, 32-bit or 64-bit Pcie silicon register AND then OR operations. It read data from a
+ register, And it with the AndBuffer, then Or it with the OrBuffer, and write the result back to the register
+
+ @param[in] Address A pointer of the address of the silicon register to be modified
+ @param[in] AndBuffer A pointer of buffer for the value used for AND operation
+ A NULL pointer means no AND operation. RegisterModify() equivalents to RegisterOr()
+ @param[in] OrBuffer A pointer of buffer for the value used for OR operation
+ A NULL pointer means no OR operation. RegisterModify() equivalents to RegisterAnd()
+
+ @retval RETURN_SUCCESS The function completed successfully.
+**/
+RETURN_STATUS
+PcieRegisterModify (
+ IN USRA_ADDRESS *Address,
+ IN VOID *AndBuffer,
+ IN VOID *OrBuffer
+ )
+{
+ UINT64 Data;
+ UINT8 WidthTable[] = {1,2,4,8};
+
+ PcieRegisterRead(Address, &Data);
+ DataAndOr (&Data, AndBuffer, OrBuffer, WidthTable[(UINT8)Address->Attribute.AccessWidth]);
+ PcieRegisterWrite(Address, &Data);
+
+ return RETURN_SUCCESS;
+}
+