aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeepak Pandey <Deepak.Pandey@arm.com>2019-03-07 14:30:26 +0530
committerDeepak Pandey <Deepak.Pandey@arm.com>2019-04-03 15:29:12 +0530
commit776e55978fdb13e45dbd6db155b098bdcb112064 (patch)
tree7fb2b44238c17e630f950cf43dfde58284510ad4
parente724bb53ada23bf4d66cacfbb897e07222e8b837 (diff)
add quirk patch files for the following components:N1SDP-ALPHA1-19.04
-scp -edk2-platforms -linux These quirk patches mitigates the PCIE EP enumeration issue in N1SDP platform Signed-off-by: Deepak Pandey <Deepak.Pandey@arm.com>
-rwxr-xr-xedk2-platforms/0001-Platform-ARM-N1Sdp-fix-to-prevent-PCIe-SLVERR.patch1678
-rwxr-xr-xlinux/0001-N1SDP-PCIe-Enablement-Quirks-for-N1SDP-PCie-controll.patch254
-rwxr-xr-xpatch_apply.sh21
-rwxr-xr-xscp/0001-n1sdp-add-workaround-for-PCIe-to-avoid-SLVERR-fault.patch396
4 files changed, 2349 insertions, 0 deletions
diff --git a/edk2-platforms/0001-Platform-ARM-N1Sdp-fix-to-prevent-PCIe-SLVERR.patch b/edk2-platforms/0001-Platform-ARM-N1Sdp-fix-to-prevent-PCIe-SLVERR.patch
new file mode 100755
index 0000000..f249a4c
--- /dev/null
+++ b/edk2-platforms/0001-Platform-ARM-N1Sdp-fix-to-prevent-PCIe-SLVERR.patch
@@ -0,0 +1,1678 @@
+From ec9980983527138897c3d50785fba241ed070002 Mon Sep 17 00:00:00 2001
+From: Deepak Pandey <Deepak.Pandey@arm.com>
+Date: Fri, 16 Nov 2018 18:00:03 +0530
+Subject: [PATCH] Platform/ARM/N1Sdp: fix to prevent PCIe SLVERR
+
+SLVERR is encountered when host accesses the config space of
+non-available device / unimplemented function in a given bus.
+
+This patch returns 0xFFFFFFFF in software for such
+devices/functions.
+
+Change-Id: I4880e7354253fc98aaa33e6645e5496fb3782bc3
+Signed-off-by: Deepak Pandey <Deepak.Pandey@arm.com>
+---
+ .../N1SdpPkg/Library/PciExpressLib/PciExpressLib.c | 1548 ++++++++++++++++++++
+ .../Library/PciExpressLib/PciExpressLib.inf | 51 +
+ .../Library/PciExpressLib/PciExpressLib.uni | 22 +
+ Platform/ARM/N1SdpPkg/N1SdpPlatform.dsc | 2 +-
+ 4 files changed, 1622 insertions(+), 1 deletion(-)
+ create mode 100644 Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.c
+ create mode 100644 Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.inf
+ create mode 100644 Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.uni
+
+diff --git a/Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.c b/Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.c
+new file mode 100644
+index 0000000..8efcfde
+--- /dev/null
++++ b/Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.c
+@@ -0,0 +1,1548 @@
++/** @file
++ Functions in this library instance make use of MMIO functions in IoLib to
++ access memory mapped PCI configuration space.
++
++ All assertions for I/O operations are handled in MMIO functions in the IoLib
++ Library.
++
++ Copyright (c) 2006 - 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
++ 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 <Base.h>
++
++#include <Library/BaseLib.h>
++#include <Library/PciExpressLib.h>
++#include <Library/IoLib.h>
++#include <Library/DebugLib.h>
++#include <Library/PcdLib.h>
++#include <N1SdpPlatform.h>
++
++
++/**
++ Assert the validity of a PCI address. A valid PCI address should contain 1's
++ only in the low 28 bits.
++
++ @param A The address to validate.
++
++**/
++#define ASSERT_INVALID_PCI_ADDRESS(A) \
++ ASSERT (((A) & ~0xfffffff) == 0)
++
++#define EFI_PCIE_ADDRESS(bus, dev, func, reg) \
++ (UINT64) ( \
++ (((UINTN) bus) << 20) | \
++ (((UINTN) dev) << 15) | \
++ (((UINTN) func) << 12) | \
++ (((UINTN) (reg)) < 4096 ? ((UINTN) (reg)) : (UINT64) (LShiftU64 ((UINT64) (reg), 32))))
++
++#define BDF_TABLE_ENTRY_SIZE 4
++// Root port Entry,BDF Entries Count
++#define BDF_TABLE_HEADER_COUNT 2
++
++/**
++ BDF Table structure : (Header + BDF Entries)
++ -------------------
++ ROOT PORT ADDRESS
++ BDF ENTRIES COUNT
++ BDF ENTRY 0
++ BDF ENTRY 1
++ BDF ENTRY 2
++ BDF ENTRY 3
++ BDF ENTRY 4...
++ ------------------
++**/
++
++
++UINTN DummyPciData = 0xffffffff;
++
++/**
++ Registers a PCI device so PCI configuration registers may be accessed after
++ SetVirtualAddressMap().
++
++ Registers the PCI device specified by Address so all the PCI configuration
++ registers associated with that PCI device may be accessed after SetVirtualAddressMap()
++ is called.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++
++ @retval RETURN_SUCCESS The PCI device was registered for runtime access.
++ @retval RETURN_UNSUPPORTED An attempt was made to call this function
++ after ExitBootServices().
++ @retval RETURN_UNSUPPORTED The resources required to access the PCI device
++ at runtime could not be mapped.
++ @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
++ complete the registration.
++
++**/
++RETURN_STATUS
++EFIAPI
++PciExpressRegisterForRuntimeAccess (
++ IN UINTN Address
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return RETURN_UNSUPPORTED;
++}
++
++/**
++ Checks if the incoming PCI address is a valid BDF address.
++
++ SCP performs the initial bus scan and prepares a table of valid BDF addresses
++ and shares them through non-trusted SRAM. This function validates if the PCI
++ address from any PCI request falls within the table of valid entries. If not,
++ this function will return 0xFFFFFFFF. This is a workaround to avoid bus fault
++ that happens when accessing unavailable PCI device due to RTL bug.
++
++ @return The base address of PCI Express.
++
++**/
++UINTN
++CheckBdfValidity (
++ IN UINTN Address
++ )
++{
++ UINTN BdfCount;
++ UINTN BdfValue;
++ UINTN Count;
++
++ BdfCount = MmioRead32(N1SDP_NON_SECURE_SRAM_BASE + BDF_TABLE_ENTRY_SIZE);
++
++ //Start from the second entry where the Bu
++ for (Count = BDF_TABLE_HEADER_COUNT; Count < (BdfCount + BDF_TABLE_HEADER_COUNT); Count++) {
++ BdfValue = MmioRead32(N1SDP_NON_SECURE_SRAM_BASE + (Count * BDF_TABLE_ENTRY_SIZE));
++ if (BdfValue == Address)
++ break;
++ }
++
++ if (Count == (BdfCount + BDF_TABLE_HEADER_COUNT))
++ return 0xffffffff;
++ else
++ return Address;
++}
++
++/**
++ Gets the base address of PCI Express.
++
++ This internal functions retrieves PCI Express Base Address via a PCD entry
++ PcdPciExpressBaseAddress.
++
++ @return The base address of PCI Express.
++
++**/
++VOID*
++GetPciExpressAddress (
++ IN UINTN Address
++ )
++{
++
++ UINT8 Bus;
++ UINT8 Device;
++ UINT8 Function;
++ UINT16 Register;
++ UINTN ConvAddress;
++
++ // Get the EFI notation
++ Bus = (Address>>20) & 0xff;
++ Device = (Address>>15) & 0x1f;
++ Function = (Address>>12) & 0x07;
++ Register = (Address) & 0xfff;
++ if( (Bus == 0) && (Device == 0) && (Function == 0) ) {
++ ConvAddress = (UINTN) PcdGet32 (PcdPcieRootPortConfigBaseAddress + EFI_PCIE_ADDRESS(Bus, Device, Function, Register));
++ } else {
++ if (CheckBdfValidity(EFI_PCIE_ADDRESS(Bus, Device, Function, 0)) == 0xffffffff) {
++ ConvAddress = (UINTN) &DummyPciData;
++ } else {
++ ConvAddress = (UINTN) PcdGet32 (PcdPcieExpressBaseAddress + EFI_PCIE_ADDRESS(Bus, Device, Function, Register));
++ }
++ }
++ return (VOID*)ConvAddress;
++}
++
++/**
++ Reads an 8-bit PCI configuration register.
++
++ Reads and returns the 8-bit PCI configuration register specified by Address.
++ This function must guarantee that all PCI read and write operations are
++ serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++
++ @return The read value from the PCI configuration register.
++
++**/
++UINT8
++EFIAPI
++PciExpressRead8 (
++ IN UINTN Address
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioRead8 ((UINTN) GetPciExpressAddress (Address));
++}
++
++/**
++ Writes an 8-bit PCI configuration register.
++
++ Writes the 8-bit PCI configuration register specified by Address with the
++ value specified by Value. Value is returned. This function must guarantee
++ that all PCI read and write operations are serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++ @param Value The value to write.
++
++ @return The value written to the PCI configuration register.
++
++**/
++UINT8
++EFIAPI
++PciExpressWrite8 (
++ IN UINTN Address,
++ IN UINT8 Value
++ )
++{
++ UINT32 Data;
++ UINT8 Offset;
++ UINT8 Bus;
++ UINT8 Device;
++ UINT8 Function;
++
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++
++ // Get the EFI notation
++ Bus = (Address>>20) & 0xff;
++ Device = (Address>>15) & 0x1f;
++ Function = (Address>>12) & 0x07;
++
++ if( (Bus == 0) && (Device == 0) && (Function == 0) ) {
++ Data = MmioRead32((UINTN) GetPciExpressAddress (Address & 0xFFFFFFFC));
++ Offset = Address & 0x3;
++ Data |= (Value << (8 * Offset));
++ MmioWrite32 ((UINTN) GetPciExpressAddress (Address & 0xFFFFFFFC), Data);
++ } else {
++ MmioWrite8 ((UINTN) GetPciExpressAddress (Address), Value);
++ }
++ return Value;
++}
++
++/**
++ Performs a bitwise OR of an 8-bit PCI configuration register with
++ an 8-bit value.
++
++ Reads the 8-bit PCI configuration register specified by Address, performs a
++ bitwise OR between the read result and the value specified by
++ OrData, and writes the result to the 8-bit PCI configuration register
++ specified by Address. The value written to the PCI configuration register is
++ returned. This function must guarantee that all PCI read and write operations
++ are serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++ @param OrData The value to OR with the PCI configuration register.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT8
++EFIAPI
++PciExpressOr8 (
++ IN UINTN Address,
++ IN UINT8 OrData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioOr8 ((UINTN) GetPciExpressAddress (Address), OrData);
++}
++
++/**
++ Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit
++ value.
++
++ Reads the 8-bit PCI configuration register specified by Address, performs a
++ bitwise AND between the read result and the value specified by AndData, and
++ writes the result to the 8-bit PCI configuration register specified by
++ Address. The value written to the PCI configuration register is returned.
++ This function must guarantee that all PCI read and write operations are
++ serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++ @param AndData The value to AND with the PCI configuration register.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT8
++EFIAPI
++PciExpressAnd8 (
++ IN UINTN Address,
++ IN UINT8 AndData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioAnd8 ((UINTN) GetPciExpressAddress (Address), AndData);
++}
++
++/**
++ Performs a bitwise AND of an 8-bit PCI configuration register with an 8-bit
++ value, followed a bitwise OR with another 8-bit value.
++
++ Reads the 8-bit PCI configuration register specified by Address, performs a
++ bitwise AND between the read result and the value specified by AndData,
++ performs a bitwise OR between the result of the AND operation and
++ the value specified by OrData, and writes the result to the 8-bit PCI
++ configuration register specified by Address. The value written to the PCI
++ configuration register is returned. This function must guarantee that all PCI
++ read and write operations are serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++ @param AndData The value to AND with the PCI configuration register.
++ @param OrData The value to OR with the result of the AND operation.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT8
++EFIAPI
++PciExpressAndThenOr8 (
++ IN UINTN Address,
++ IN UINT8 AndData,
++ IN UINT8 OrData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioAndThenOr8 (
++ (UINTN) GetPciExpressAddress (Address),
++ AndData,
++ OrData
++ );
++}
++
++/**
++ Reads a bit field of a PCI configuration register.
++
++ Reads the bit field in an 8-bit PCI configuration register. The bit field is
++ specified by the StartBit and the EndBit. The value of the bit field is
++ returned.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If StartBit is greater than 7, then ASSERT().
++ If EndBit is greater than 7, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++
++ @param Address The PCI configuration register to read.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..7.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..7.
++
++ @return The value of the bit field read from the PCI configuration register.
++
++**/
++UINT8
++EFIAPI
++PciExpressBitFieldRead8 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldRead8 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit
++ );
++}
++
++/**
++ Writes a bit field to a PCI configuration register.
++
++ Writes Value to the bit field of the PCI configuration register. The bit
++ field is specified by the StartBit and the EndBit. All other bits in the
++ destination PCI configuration register are preserved. The new value of the
++ 8-bit register is returned.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If StartBit is greater than 7, then ASSERT().
++ If EndBit is greater than 7, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++
++ @param Address The PCI configuration register to write.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..7.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..7.
++ @param Value The new value of the bit field.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT8
++EFIAPI
++PciExpressBitFieldWrite8 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit,
++ IN UINT8 Value
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldWrite8 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit,
++ Value
++ );
++}
++
++/**
++ Reads a bit field in an 8-bit PCI configuration, performs a bitwise OR, and
++ writes the result back to the bit field in the 8-bit port.
++
++ Reads the 8-bit PCI configuration register specified by Address, performs a
++ bitwise OR between the read result and the value specified by
++ OrData, and writes the result to the 8-bit PCI configuration register
++ specified by Address. The value written to the PCI configuration register is
++ returned. This function must guarantee that all PCI read and write operations
++ are serialized. Extra left bits in OrData are stripped.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If StartBit is greater than 7, then ASSERT().
++ If EndBit is greater than 7, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++
++ @param Address The PCI configuration register to write.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..7.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..7.
++ @param OrData The value to OR with the PCI configuration register.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT8
++EFIAPI
++PciExpressBitFieldOr8 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit,
++ IN UINT8 OrData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldOr8 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit,
++ OrData
++ );
++}
++
++/**
++ Reads a bit field in an 8-bit PCI configuration register, performs a bitwise
++ AND, and writes the result back to the bit field in the 8-bit register.
++
++ Reads the 8-bit PCI configuration register specified by Address, performs a
++ bitwise AND between the read result and the value specified by AndData, and
++ writes the result to the 8-bit PCI configuration register specified by
++ Address. The value written to the PCI configuration register is returned.
++ This function must guarantee that all PCI read and write operations are
++ serialized. Extra left bits in AndData are stripped.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If StartBit is greater than 7, then ASSERT().
++ If EndBit is greater than 7, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++
++ @param Address The PCI configuration register to write.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..7.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..7.
++ @param AndData The value to AND with the PCI configuration register.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT8
++EFIAPI
++PciExpressBitFieldAnd8 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit,
++ IN UINT8 AndData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldAnd8 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit,
++ AndData
++ );
++}
++
++/**
++ Reads a bit field in an 8-bit port, performs a bitwise AND followed by a
++ bitwise OR, and writes the result back to the bit field in the
++ 8-bit port.
++
++ Reads the 8-bit PCI configuration register specified by Address, performs a
++ bitwise AND followed by a bitwise OR between the read result and
++ the value specified by AndData, and writes the result to the 8-bit PCI
++ configuration register specified by Address. The value written to the PCI
++ configuration register is returned. This function must guarantee that all PCI
++ read and write operations are serialized. Extra left bits in both AndData and
++ OrData are stripped.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If StartBit is greater than 7, then ASSERT().
++ If EndBit is greater than 7, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++
++ @param Address The PCI configuration register to write.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..7.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..7.
++ @param AndData The value to AND with the PCI configuration register.
++ @param OrData The value to OR with the result of the AND operation.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT8
++EFIAPI
++PciExpressBitFieldAndThenOr8 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit,
++ IN UINT8 AndData,
++ IN UINT8 OrData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldAndThenOr8 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit,
++ AndData,
++ OrData
++ );
++}
++
++/**
++ Reads a 16-bit PCI configuration register.
++
++ Reads and returns the 16-bit PCI configuration register specified by Address.
++ This function must guarantee that all PCI read and write operations are
++ serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 16-bit boundary, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++
++ @return The read value from the PCI configuration register.
++
++**/
++UINT16
++EFIAPI
++PciExpressRead16 (
++ IN UINTN Address
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioRead16 ((UINTN) GetPciExpressAddress (Address));
++}
++
++/**
++ Writes a 16-bit PCI configuration register.
++
++ Writes the 16-bit PCI configuration register specified by Address with the
++ value specified by Value. Value is returned. This function must guarantee
++ that all PCI read and write operations are serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 16-bit boundary, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++ @param Value The value to write.
++
++ @return The value written to the PCI configuration register.
++
++**/
++UINT16
++EFIAPI
++PciExpressWrite16 (
++ IN UINTN Address,
++ IN UINT16 Value
++ )
++{
++ UINT32 Data;
++ UINT8 Offset;
++ UINT8 Bus;
++ UINT8 Device;
++ UINT8 Function;
++
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++
++ // Get the EFI notation
++ Bus = (Address>>20) & 0xff;
++ Device = (Address>>15) & 0x1f;
++ Function = (Address>>12) & 0x07;
++
++ if( (Bus == 0) && (Device == 0) && (Function == 0) ) {
++ Data = MmioRead32((UINTN) GetPciExpressAddress (Address & 0xFFFFFFFC));
++ Offset = Address & 0x3;
++ Data |= (Value << (8 * Offset));
++ MmioWrite32 ((UINTN) GetPciExpressAddress (Address & 0xFFFFFFFC), Data);
++ } else {
++ MmioWrite16 ((UINTN) GetPciExpressAddress (Address), Value);
++ }
++ return Value;
++}
++
++/**
++ Performs a bitwise OR of a 16-bit PCI configuration register with
++ a 16-bit value.
++
++ Reads the 16-bit PCI configuration register specified by Address, performs a
++ bitwise OR between the read result and the value specified by
++ OrData, and writes the result to the 16-bit PCI configuration register
++ specified by Address. The value written to the PCI configuration register is
++ returned. This function must guarantee that all PCI read and write operations
++ are serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 16-bit boundary, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++ @param OrData The value to OR with the PCI configuration register.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT16
++EFIAPI
++PciExpressOr16 (
++ IN UINTN Address,
++ IN UINT16 OrData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioOr16 ((UINTN) GetPciExpressAddress (Address), OrData);
++}
++
++/**
++ Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit
++ value.
++
++ Reads the 16-bit PCI configuration register specified by Address, performs a
++ bitwise AND between the read result and the value specified by AndData, and
++ writes the result to the 16-bit PCI configuration register specified by
++ Address. The value written to the PCI configuration register is returned.
++ This function must guarantee that all PCI read and write operations are
++ serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 16-bit boundary, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++ @param AndData The value to AND with the PCI configuration register.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT16
++EFIAPI
++PciExpressAnd16 (
++ IN UINTN Address,
++ IN UINT16 AndData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioAnd16 ((UINTN) GetPciExpressAddress (Address), AndData);
++}
++
++/**
++ Performs a bitwise AND of a 16-bit PCI configuration register with a 16-bit
++ value, followed a bitwise OR with another 16-bit value.
++
++ Reads the 16-bit PCI configuration register specified by Address, performs a
++ bitwise AND between the read result and the value specified by AndData,
++ performs a bitwise OR between the result of the AND operation and
++ the value specified by OrData, and writes the result to the 16-bit PCI
++ configuration register specified by Address. The value written to the PCI
++ configuration register is returned. This function must guarantee that all PCI
++ read and write operations are serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 16-bit boundary, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++ @param AndData The value to AND with the PCI configuration register.
++ @param OrData The value to OR with the result of the AND operation.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT16
++EFIAPI
++PciExpressAndThenOr16 (
++ IN UINTN Address,
++ IN UINT16 AndData,
++ IN UINT16 OrData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioAndThenOr16 (
++ (UINTN) GetPciExpressAddress (Address),
++ AndData,
++ OrData
++ );
++}
++
++/**
++ Reads a bit field of a PCI configuration register.
++
++ Reads the bit field in a 16-bit PCI configuration register. The bit field is
++ specified by the StartBit and the EndBit. The value of the bit field is
++ returned.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 16-bit boundary, then ASSERT().
++ If StartBit is greater than 15, then ASSERT().
++ If EndBit is greater than 15, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++
++ @param Address The PCI configuration register to read.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..15.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..15.
++
++ @return The value of the bit field read from the PCI configuration register.
++
++**/
++UINT16
++EFIAPI
++PciExpressBitFieldRead16 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldRead16 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit
++ );
++}
++
++/**
++ Writes a bit field to a PCI configuration register.
++
++ Writes Value to the bit field of the PCI configuration register. The bit
++ field is specified by the StartBit and the EndBit. All other bits in the
++ destination PCI configuration register are preserved. The new value of the
++ 16-bit register is returned.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 16-bit boundary, then ASSERT().
++ If StartBit is greater than 15, then ASSERT().
++ If EndBit is greater than 15, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++
++ @param Address The PCI configuration register to write.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..15.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..15.
++ @param Value The new value of the bit field.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT16
++EFIAPI
++PciExpressBitFieldWrite16 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit,
++ IN UINT16 Value
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldWrite16 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit,
++ Value
++ );
++}
++
++/**
++ Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, and
++ writes the result back to the bit field in the 16-bit port.
++
++ Reads the 16-bit PCI configuration register specified by Address, performs a
++ bitwise OR between the read result and the value specified by
++ OrData, and writes the result to the 16-bit PCI configuration register
++ specified by Address. The value written to the PCI configuration register is
++ returned. This function must guarantee that all PCI read and write operations
++ are serialized. Extra left bits in OrData are stripped.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 16-bit boundary, then ASSERT().
++ If StartBit is greater than 15, then ASSERT().
++ If EndBit is greater than 15, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++
++ @param Address The PCI configuration register to write.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..15.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..15.
++ @param OrData The value to OR with the PCI configuration register.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT16
++EFIAPI
++PciExpressBitFieldOr16 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit,
++ IN UINT16 OrData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldOr16 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit,
++ OrData
++ );
++}
++
++/**
++ Reads a bit field in a 16-bit PCI configuration register, performs a bitwise
++ AND, and writes the result back to the bit field in the 16-bit register.
++
++ Reads the 16-bit PCI configuration register specified by Address, performs a
++ bitwise AND between the read result and the value specified by AndData, and
++ writes the result to the 16-bit PCI configuration register specified by
++ Address. The value written to the PCI configuration register is returned.
++ This function must guarantee that all PCI read and write operations are
++ serialized. Extra left bits in AndData are stripped.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 16-bit boundary, then ASSERT().
++ If StartBit is greater than 15, then ASSERT().
++ If EndBit is greater than 15, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++
++ @param Address The PCI configuration register to write.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..15.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..15.
++ @param AndData The value to AND with the PCI configuration register.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT16
++EFIAPI
++PciExpressBitFieldAnd16 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit,
++ IN UINT16 AndData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldAnd16 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit,
++ AndData
++ );
++}
++
++/**
++ Reads a bit field in a 16-bit port, performs a bitwise AND followed by a
++ bitwise OR, and writes the result back to the bit field in the
++ 16-bit port.
++
++ Reads the 16-bit PCI configuration register specified by Address, performs a
++ bitwise AND followed by a bitwise OR between the read result and
++ the value specified by AndData, and writes the result to the 16-bit PCI
++ configuration register specified by Address. The value written to the PCI
++ configuration register is returned. This function must guarantee that all PCI
++ read and write operations are serialized. Extra left bits in both AndData and
++ OrData are stripped.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 16-bit boundary, then ASSERT().
++ If StartBit is greater than 15, then ASSERT().
++ If EndBit is greater than 15, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++
++ @param Address The PCI configuration register to write.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..15.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..15.
++ @param AndData The value to AND with the PCI configuration register.
++ @param OrData The value to OR with the result of the AND operation.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT16
++EFIAPI
++PciExpressBitFieldAndThenOr16 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit,
++ IN UINT16 AndData,
++ IN UINT16 OrData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldAndThenOr16 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit,
++ AndData,
++ OrData
++ );
++}
++
++/**
++ Reads a 32-bit PCI configuration register.
++
++ Reads and returns the 32-bit PCI configuration register specified by Address.
++ This function must guarantee that all PCI read and write operations are
++ serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 32-bit boundary, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++
++ @return The read value from the PCI configuration register.
++
++**/
++UINT32
++EFIAPI
++PciExpressRead32 (
++ IN UINTN Address
++ )
++{
++ UINTN address;
++ UINT32 value;
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ address = (UINTN) GetPciExpressAddress (Address);
++ value = MmioRead32 (address);
++ return value;
++}
++
++/**
++ Writes a 32-bit PCI configuration register.
++
++ Writes the 32-bit PCI configuration register specified by Address with the
++ value specified by Value. Value is returned. This function must guarantee
++ that all PCI read and write operations are serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 32-bit boundary, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++ @param Value The value to write.
++
++ @return The value written to the PCI configuration register.
++
++**/
++UINT32
++EFIAPI
++PciExpressWrite32 (
++ IN UINTN Address,
++ IN UINT32 Value
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioWrite32 ((UINTN) GetPciExpressAddress (Address), Value);
++}
++
++/**
++ Performs a bitwise OR of a 32-bit PCI configuration register with
++ a 32-bit value.
++
++ Reads the 32-bit PCI configuration register specified by Address, performs a
++ bitwise OR between the read result and the value specified by
++ OrData, and writes the result to the 32-bit PCI configuration register
++ specified by Address. The value written to the PCI configuration register is
++ returned. This function must guarantee that all PCI read and write operations
++ are serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 32-bit boundary, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++ @param OrData The value to OR with the PCI configuration register.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT32
++EFIAPI
++PciExpressOr32 (
++ IN UINTN Address,
++ IN UINT32 OrData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioOr32 ((UINTN) GetPciExpressAddress (Address), OrData);
++}
++
++/**
++ Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit
++ value.
++
++ Reads the 32-bit PCI configuration register specified by Address, performs a
++ bitwise AND between the read result and the value specified by AndData, and
++ writes the result to the 32-bit PCI configuration register specified by
++ Address. The value written to the PCI configuration register is returned.
++ This function must guarantee that all PCI read and write operations are
++ serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 32-bit boundary, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++ @param AndData The value to AND with the PCI configuration register.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT32
++EFIAPI
++PciExpressAnd32 (
++ IN UINTN Address,
++ IN UINT32 AndData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioAnd32 ((UINTN) GetPciExpressAddress (Address), AndData);
++}
++
++/**
++ Performs a bitwise AND of a 32-bit PCI configuration register with a 32-bit
++ value, followed a bitwise OR with another 32-bit value.
++
++ Reads the 32-bit PCI configuration register specified by Address, performs a
++ bitwise AND between the read result and the value specified by AndData,
++ performs a bitwise OR between the result of the AND operation and
++ the value specified by OrData, and writes the result to the 32-bit PCI
++ configuration register specified by Address. The value written to the PCI
++ configuration register is returned. This function must guarantee that all PCI
++ read and write operations are serialized.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 32-bit boundary, then ASSERT().
++
++ @param Address The address that encodes the PCI Bus, Device, Function and
++ Register.
++ @param AndData The value to AND with the PCI configuration register.
++ @param OrData The value to OR with the result of the AND operation.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT32
++EFIAPI
++PciExpressAndThenOr32 (
++ IN UINTN Address,
++ IN UINT32 AndData,
++ IN UINT32 OrData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioAndThenOr32 (
++ (UINTN) GetPciExpressAddress (Address),
++ AndData,
++ OrData
++ );
++}
++
++/**
++ Reads a bit field of a PCI configuration register.
++
++ Reads the bit field in a 32-bit PCI configuration register. The bit field is
++ specified by the StartBit and the EndBit. The value of the bit field is
++ returned.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 32-bit boundary, then ASSERT().
++ If StartBit is greater than 31, then ASSERT().
++ If EndBit is greater than 31, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++
++ @param Address The PCI configuration register to read.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..31.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..31.
++
++ @return The value of the bit field read from the PCI configuration register.
++
++**/
++UINT32
++EFIAPI
++PciExpressBitFieldRead32 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldRead32 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit
++ );
++}
++
++/**
++ Writes a bit field to a PCI configuration register.
++
++ Writes Value to the bit field of the PCI configuration register. The bit
++ field is specified by the StartBit and the EndBit. All other bits in the
++ destination PCI configuration register are preserved. The new value of the
++ 32-bit register is returned.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 32-bit boundary, then ASSERT().
++ If StartBit is greater than 31, then ASSERT().
++ If EndBit is greater than 31, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++ If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++
++ @param Address The PCI configuration register to write.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..31.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..31.
++ @param Value The new value of the bit field.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT32
++EFIAPI
++PciExpressBitFieldWrite32 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit,
++ IN UINT32 Value
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldWrite32 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit,
++ Value
++ );
++}
++
++/**
++ Reads a bit field in a 32-bit PCI configuration, performs a bitwise OR, and
++ writes the result back to the bit field in the 32-bit port.
++
++ Reads the 32-bit PCI configuration register specified by Address, performs a
++ bitwise OR between the read result and the value specified by
++ OrData, and writes the result to the 32-bit PCI configuration register
++ specified by Address. The value written to the PCI configuration register is
++ returned. This function must guarantee that all PCI read and write operations
++ are serialized. Extra left bits in OrData are stripped.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 32-bit boundary, then ASSERT().
++ If StartBit is greater than 31, then ASSERT().
++ If EndBit is greater than 31, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++
++ @param Address The PCI configuration register to write.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..31.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..31.
++ @param OrData The value to OR with the PCI configuration register.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT32
++EFIAPI
++PciExpressBitFieldOr32 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit,
++ IN UINT32 OrData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldOr32 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit,
++ OrData
++ );
++}
++
++/**
++ Reads a bit field in a 32-bit PCI configuration register, performs a bitwise
++ AND, and writes the result back to the bit field in the 32-bit register.
++
++ Reads the 32-bit PCI configuration register specified by Address, performs a
++ bitwise AND between the read result and the value specified by AndData, and
++ writes the result to the 32-bit PCI configuration register specified by
++ Address. The value written to the PCI configuration register is returned.
++ This function must guarantee that all PCI read and write operations are
++ serialized. Extra left bits in AndData are stripped.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 32-bit boundary, then ASSERT().
++ If StartBit is greater than 31, then ASSERT().
++ If EndBit is greater than 31, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++
++ @param Address The PCI configuration register to write.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..31.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..31.
++ @param AndData The value to AND with the PCI configuration register.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT32
++EFIAPI
++PciExpressBitFieldAnd32 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit,
++ IN UINT32 AndData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldAnd32 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit,
++ AndData
++ );
++}
++
++/**
++ Reads a bit field in a 32-bit port, performs a bitwise AND followed by a
++ bitwise OR, and writes the result back to the bit field in the
++ 32-bit port.
++
++ Reads the 32-bit PCI configuration register specified by Address, performs a
++ bitwise AND followed by a bitwise OR between the read result and
++ the value specified by AndData, and writes the result to the 32-bit PCI
++ configuration register specified by Address. The value written to the PCI
++ configuration register is returned. This function must guarantee that all PCI
++ read and write operations are serialized. Extra left bits in both AndData and
++ OrData are stripped.
++
++ If Address > 0x0FFFFFFF, then ASSERT().
++ If Address is not aligned on a 32-bit boundary, then ASSERT().
++ If StartBit is greater than 31, then ASSERT().
++ If EndBit is greater than 31, then ASSERT().
++ If EndBit is less than StartBit, then ASSERT().
++ If AndData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++ If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT().
++
++ @param Address The PCI configuration register to write.
++ @param StartBit The ordinal of the least significant bit in the bit field.
++ Range 0..31.
++ @param EndBit The ordinal of the most significant bit in the bit field.
++ Range 0..31.
++ @param AndData The value to AND with the PCI configuration register.
++ @param OrData The value to OR with the result of the AND operation.
++
++ @return The value written back to the PCI configuration register.
++
++**/
++UINT32
++EFIAPI
++PciExpressBitFieldAndThenOr32 (
++ IN UINTN Address,
++ IN UINTN StartBit,
++ IN UINTN EndBit,
++ IN UINT32 AndData,
++ IN UINT32 OrData
++ )
++{
++ ASSERT_INVALID_PCI_ADDRESS (Address);
++ return MmioBitFieldAndThenOr32 (
++ (UINTN) GetPciExpressAddress (Address),
++ StartBit,
++ EndBit,
++ AndData,
++ OrData
++ );
++}
++
++/**
++ Reads a range of PCI configuration registers into a caller supplied buffer.
++
++ Reads the range of PCI configuration registers specified by StartAddress and
++ Size into the buffer specified by Buffer. This function only allows the PCI
++ configuration registers from a single PCI function to be read. Size is
++ returned. When possible 32-bit PCI configuration read cycles are used to read
++ from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit
++ and 16-bit PCI configuration read cycles may be used at the beginning and the
++ end of the range.
++
++ If StartAddress > 0x0FFFFFFF, then ASSERT().
++ If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
++ If Size > 0 and Buffer is NULL, then ASSERT().
++
++ @param StartAddress The starting address that encodes the PCI Bus, Device,
++ Function and Register.
++ @param Size The size in bytes of the transfer.
++ @param Buffer The pointer to a buffer receiving the data read.
++
++ @return Size read data from StartAddress.
++
++**/
++UINTN
++EFIAPI
++PciExpressReadBuffer (
++ IN UINTN StartAddress,
++ IN UINTN Size,
++ OUT VOID *Buffer
++ )
++{
++ UINTN ReturnValue;
++
++ ASSERT_INVALID_PCI_ADDRESS (StartAddress);
++ ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
++
++ if (Size == 0) {
++ return Size;
++ }
++
++ ASSERT (Buffer != NULL);
++
++ //
++ // Save Size for return
++ //
++ ReturnValue = Size;
++
++ if ((StartAddress & 1) != 0) {
++ //
++ // Read a byte if StartAddress is byte aligned
++ //
++ *(volatile UINT8 *)Buffer = PciExpressRead8 (StartAddress);
++ StartAddress += sizeof (UINT8);
++ Size -= sizeof (UINT8);
++ Buffer = (UINT8*)Buffer + 1;
++ }
++
++ if (Size >= sizeof (UINT16) && (StartAddress & 2) != 0) {
++ //
++ // Read a word if StartAddress is word aligned
++ //
++ WriteUnaligned16 ((UINT16 *) Buffer, (UINT16) PciExpressRead16 (StartAddress));
++
++ StartAddress += sizeof (UINT16);
++ Size -= sizeof (UINT16);
++ Buffer = (UINT16*)Buffer + 1;
++ }
++
++ while (Size >= sizeof (UINT32)) {
++ //
++ // Read as many double words as possible
++ //
++ WriteUnaligned32 ((UINT32 *) Buffer, (UINT32) PciExpressRead32 (StartAddress));
++
++ StartAddress += sizeof (UINT32);
++ Size -= sizeof (UINT32);
++ Buffer = (UINT32*)Buffer + 1;
++ }
++
++ if (Size >= sizeof (UINT16)) {
++ //
++ // Read the last remaining word if exist
++ //
++ WriteUnaligned16 ((UINT16 *) Buffer, (UINT16) PciExpressRead16 (StartAddress));
++ StartAddress += sizeof (UINT16);
++ Size -= sizeof (UINT16);
++ Buffer = (UINT16*)Buffer + 1;
++ }
++
++ if (Size >= sizeof (UINT8)) {
++ //
++ // Read the last remaining byte if exist
++ //
++ *(volatile UINT8 *)Buffer = PciExpressRead8 (StartAddress);
++ }
++
++ return ReturnValue;
++}
++
++/**
++ Copies the data in a caller supplied buffer to a specified range of PCI
++ configuration space.
++
++ Writes the range of PCI configuration registers specified by StartAddress and
++ Size from the buffer specified by Buffer. This function only allows the PCI
++ configuration registers from a single PCI function to be written. Size is
++ returned. When possible 32-bit PCI configuration write cycles are used to
++ write from StartAdress to StartAddress + Size. Due to alignment restrictions,
++ 8-bit and 16-bit PCI configuration write cycles may be used at the beginning
++ and the end of the range.
++
++ If StartAddress > 0x0FFFFFFF, then ASSERT().
++ If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT().
++ If Size > 0 and Buffer is NULL, then ASSERT().
++
++ @param StartAddress The starting address that encodes the PCI Bus, Device,
++ Function and Register.
++ @param Size The size in bytes of the transfer.
++ @param Buffer The pointer to a buffer containing the data to write.
++
++ @return Size written to StartAddress.
++
++**/
++UINTN
++EFIAPI
++PciExpressWriteBuffer (
++ IN UINTN StartAddress,
++ IN UINTN Size,
++ IN VOID *Buffer
++ )
++{
++ UINTN ReturnValue;
++
++ ASSERT_INVALID_PCI_ADDRESS (StartAddress);
++ ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000);
++
++ if (Size == 0) {
++ return 0;
++ }
++
++ ASSERT (Buffer != NULL);
++
++ //
++ // Save Size for return
++ //
++ ReturnValue = Size;
++
++ if ((StartAddress & 1) != 0) {
++ //
++ // Write a byte if StartAddress is byte aligned
++ //
++ PciExpressWrite8 (StartAddress, *(UINT8*)Buffer);
++ StartAddress += sizeof (UINT8);
++ Size -= sizeof (UINT8);
++ Buffer = (UINT8*)Buffer + 1;
++ }
++
++ if (Size >= sizeof (UINT16) && (StartAddress & 2) != 0) {
++ //
++ // Write a word if StartAddress is word aligned
++ //
++ PciExpressWrite16 (StartAddress, ReadUnaligned16 ((UINT16*)Buffer));
++ StartAddress += sizeof (UINT16);
++ Size -= sizeof (UINT16);
++ Buffer = (UINT16*)Buffer + 1;
++ }
++
++ while (Size >= sizeof (UINT32)) {
++ //
++ // Write as many double words as possible
++ //
++ PciExpressWrite32 (StartAddress, ReadUnaligned32 ((UINT32*)Buffer));
++ StartAddress += sizeof (UINT32);
++ Size -= sizeof (UINT32);
++ Buffer = (UINT32*)Buffer + 1;
++ }
++
++ if (Size >= sizeof (UINT16)) {
++ //
++ // Write the last remaining word if exist
++ //
++ PciExpressWrite16 (StartAddress, ReadUnaligned16 ((UINT16*)Buffer));
++ StartAddress += sizeof (UINT16);
++ Size -= sizeof (UINT16);
++ Buffer = (UINT16*)Buffer + 1;
++ }
++
++ if (Size >= sizeof (UINT8)) {
++ //
++ // Write the last remaining byte if exist
++ //
++ PciExpressWrite8 (StartAddress, *(UINT8*)Buffer);
++ }
++
++ return ReturnValue;
++}
+diff --git a/Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.inf b/Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.inf
+new file mode 100644
+index 0000000..059d240
+--- /dev/null
++++ b/Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.inf
+@@ -0,0 +1,51 @@
++## @file
++# Instance of PCI Express Library using the 256 MB PCI Express MMIO window.
++#
++# PCI Express Library that uses the 256 MB PCI Express MMIO window to perform
++# PCI Configuration cycles. Layers on top of an I/O Library instance.
++#
++# Copyright (c) 2007 - 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
++# 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 = 0x00010005
++ BASE_NAME = BasePciExpressLib
++ MODULE_UNI_FILE = BasePciExpressLib.uni
++ FILE_GUID = 52c06b64-a45e-4906-b9ee-abe1acc286bb
++ MODULE_TYPE = BASE
++ VERSION_STRING = 1.0
++ LIBRARY_CLASS = PciExpressLib
++
++#
++# VALID_ARCHITECTURES = IA32 X64 EBC
++#
++
++[Sources]
++ PciExpressLib.c
++
++[Packages]
++ MdePkg/MdePkg.dec
++ Platform/ARM/N1SdpPkg/N1SdpPlatform.dec
++
++[FixedPcd]
++ gArmN1SdpTokenSpaceGuid.PcdPcieRootPortConfigBaseAddress
++ gArmN1SdpTokenSpaceGuid.PcdPcieRootPortConfigBaseSize
++
++[LibraryClasses]
++ BaseLib
++ PcdLib
++ DebugLib
++ IoLib
++
++[Pcd]
++ gArmN1SdpTokenSpaceGuid.PcdPcieExpressBaseAddress ## CONSUMES
++
+diff --git a/Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.uni b/Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.uni
+new file mode 100644
+index 0000000..b04bd0e
+--- /dev/null
++++ b/Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.uni
+@@ -0,0 +1,22 @@
++// /** @file
++// Instance of PCI Express Library using the 256 MB PCI Express MMIO window.
++//
++// PCI Express Library that uses the 256 MB PCI Express MMIO window to perform
++// PCI Configuration cycles. Layers on top of an I/O Library instance.
++//
++// Copyright (c) 2007 - 2014, 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
++// 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.
++//
++// **/
++
++
++#string STR_MODULE_ABSTRACT #language en-US "Instance of PCI Express Library using the 256 MB PCI Express MMIO window"
++
++#string STR_MODULE_DESCRIPTION #language en-US "PCI Express Library that uses the 256 MB PCI Express MMIO window to perform PCI Configuration cycles. Layers on top of an I/O Library instance."
++
+diff --git a/Platform/ARM/N1SdpPkg/N1SdpPlatform.dsc b/Platform/ARM/N1SdpPkg/N1SdpPlatform.dsc
+index 9d4f84e..58ac905 100644
+--- a/Platform/ARM/N1SdpPkg/N1SdpPlatform.dsc
++++ b/Platform/ARM/N1SdpPkg/N1SdpPlatform.dsc
+@@ -81,7 +81,7 @@
+ PciHostBridgeLib|Platform/ARM/N1SdpPkg/Library/PciHostBridgeLib/PciHostBridgeLib.inf
+ PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
+ PciLib|MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.inf
+- PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf
++ PciExpressLib|Platform/ARM/N1SdpPkg/Library/PciExpressLib/PciExpressLib.inf
+
+ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+--
+2.7.4
+
diff --git a/linux/0001-N1SDP-PCIe-Enablement-Quirks-for-N1SDP-PCie-controll.patch b/linux/0001-N1SDP-PCIe-Enablement-Quirks-for-N1SDP-PCie-controll.patch
new file mode 100755
index 0000000..b007da4
--- /dev/null
+++ b/linux/0001-N1SDP-PCIe-Enablement-Quirks-for-N1SDP-PCie-controll.patch
@@ -0,0 +1,254 @@
+From 959a905131086e8a32974ecb5740ff84e4e9cca8 Mon Sep 17 00:00:00 2001
+From: Sudipto Paul <sudipto.paul@arm.com>
+Date: Wed, 21 Nov 2018 18:53:12 +0000
+Subject: [PATCH] N1SDP PCIe Enablement: Quirks for N1SDP PCie controller
+
+-PCIe Host Controller with MCFG quirk for Bus Map
+-PCIe Slave Error Mitigation
+
+Change-Id: I88ab886799a16fcf35f3a4162ac4387036c567f5
+Signed-off-by: Sudipto Paul <sudipto.paul@arm.com>
+---
+ arch/arm64/configs/defconfig | 2 +
+ drivers/acpi/pci_mcfg.c | 6 ++
+ drivers/pci/controller/Kconfig | 8 ++
+ drivers/pci/controller/Makefile | 1 +
+ drivers/pci/controller/pcie-n1sdp.c | 145 ++++++++++++++++++++++++++++++++++++
+ include/linux/pci-ecam.h | 1 +
+ 6 files changed, 163 insertions(+)
+ create mode 100644 drivers/pci/controller/pcie-n1sdp.c
+
+diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
+index c8432e2..fe0c0e0 100644
+--- a/arch/arm64/configs/defconfig
++++ b/arch/arm64/configs/defconfig
+@@ -69,6 +69,7 @@ CONFIG_ARCH_ZX=y
+ CONFIG_ARCH_ZYNQMP=y
+ CONFIG_PCI=y
+ CONFIG_PCIEPORTBUS=y
++CONFIG_PCI_QUIRKS=y
+ CONFIG_PCI_IOV=y
+ CONFIG_HOTPLUG_PCI=y
+ CONFIG_HOTPLUG_PCI_ACPI=y
+@@ -86,6 +87,7 @@ CONFIG_PCIE_QCOM=y
+ CONFIG_PCIE_ARMADA_8K=y
+ CONFIG_PCIE_KIRIN=y
+ CONFIG_PCIE_HISI_STB=y
++CONFIG_PCIE_HOST_N1SDP_ECAM=y
+ CONFIG_ARM64_VA_BITS_48=y
+ CONFIG_SCHED_MC=y
+ CONFIG_NUMA=y
+diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
+index a4e8432..50d3d76 100644
+--- a/drivers/acpi/pci_mcfg.c
++++ b/drivers/acpi/pci_mcfg.c
+@@ -141,6 +141,12 @@ static struct mcfg_fixup mcfg_quirks[] = {
+ XGENE_V2_ECAM_MCFG(4, 0),
+ XGENE_V2_ECAM_MCFG(4, 1),
+ XGENE_V2_ECAM_MCFG(4, 2),
++
++#define N1SDP_ECAM_MCFG(rev, seg, ops) \
++ {"ARMLTD", "ARMN1SDP", rev, seg, MCFG_BUS_ANY, ops }
++ /* N1SDP SoC with v1 PCIe controller */
++ N1SDP_ECAM_MCFG(0x20181101, 0, &pci_n1sdp_ecam_ops),
++ N1SDP_ECAM_MCFG(0x20181101, 1, &pci_n1sdp_ecam_ops),
+ };
+
+ static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
+diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
+index 6671946..682ea85 100644
+--- a/drivers/pci/controller/Kconfig
++++ b/drivers/pci/controller/Kconfig
+@@ -65,6 +65,14 @@ config PCI_FTPCI100
+ depends on OF
+ default ARCH_GEMINI
+
++config PCIE_HOST_N1SDP_ECAM
++ bool "ARM N1SDP PCIe Controller"
++ depends on ARM64
++ depends on OF || (ACPI && PCI_QUIRKS)
++ select PCI_HOST_COMMON
++ help
++ Say Y here if you want PCIe support for N1SDP platform.
++
+ config PCI_TEGRA
+ bool "NVIDIA Tegra PCIe controller"
+ depends on ARCH_TEGRA || COMPILE_TEST
+diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
+index d56a507..1531d90 100644
+--- a/drivers/pci/controller/Makefile
++++ b/drivers/pci/controller/Makefile
+@@ -29,6 +29,7 @@ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
+ obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
+ obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
+ obj-$(CONFIG_VMD) += vmd.o
++obj-$(CONFIG_PCIE_HOST_N1SDP_ECAM) += pcie-n1sdp.o
+ # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
+ obj-y += dwc/
+
+diff --git a/drivers/pci/controller/pcie-n1sdp.c b/drivers/pci/controller/pcie-n1sdp.c
+new file mode 100644
+index 0000000..3a6a68c
+--- /dev/null
++++ b/drivers/pci/controller/pcie-n1sdp.c
+@@ -0,0 +1,145 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2018 ARM Ltd
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/of_pci.h>
++#include <linux/of.h>
++#include <linux/pci-ecam.h>
++#include <linux/platform_device.h>
++
++#if defined(CONFIG_PCIE_HOST_N1SDP_ECAM) || (defined(CONFIG_ACPI) \
++&& defined(CONFIG_PCI_QUIRKS))
++
++#define AP_NS_SHARED_MEM_BASE 0x06000000
++#define AP_NS_SHARED_MEM_SZ 0x00080000
++#define DATA_WIDTH 4
++#define CONFIG_SPACE (DATA_WIDTH * 1024)
++
++typedef struct {
++u32 PcieRC_addr;
++u32 bdf_entry_count;
++} Discover_data_header;
++
++Discover_data_header *DiscoveryData_header;
++unsigned int *DiscoveryData;
++void *DiscoverySharedMemoryBase;
++void __iomem *rc_remapped_addr;
++
++/*
++ * This quirk is created to mask the following issues:
++ * PCIE SLVERR issue and MCFG BDF mapping
++ * The low level F/W creates a discovery table with the Root Complex
++ * base address and BDF values
++ * Linux responds only to the EP listed in this table and for rest returns NULL
++ *
++ * Shared Memory layout
++ * ----
++ * Dicover data header --> RC base address
++ * |
++ * --> BDF Count
++ * Discover data --> BDF 0...n
++ * ----
++ *
++ * When the Config Read/Write is called it will call the bus map to get the
++ * address of the Config register
++ *
++ * For the first time map the PCIe Shared Memory
++ * (Non-Secure RAM Location 0x0600_0000)
++ * Read the list of BDFs supported and create a remap for each of these
++ * devices for later processing
++ */
++
++static void __iomem *pci_n1sdp_map_bus(struct pci_bus *bus, unsigned int devfn,
++ int where)
++{
++ struct pci_config_window *cfg = bus->sysdata;
++ unsigned int devfn_shift = cfg->ops->bus_shift - 8;
++ unsigned int busn = bus->number;
++ unsigned int bdf_addr;
++ unsigned int index;
++ void __iomem *remapped_addr;
++ unsigned int table_count = DiscoveryData_header->bdf_entry_count;
++
++ if ( busn < cfg->busr.start || busn > cfg->busr.end )
++ return NULL;
++
++ if (busn == 0 && devfn == 0) {
++ return (rc_remapped_addr + where);
++ }
++ else {
++ bdf_addr = ((busn << cfg->ops->bus_shift)
++ |(devfn << devfn_shift));
++ for (index = 0; index < table_count; index++) {
++ if (bdf_addr == DiscoveryData[index])
++ break;
++ }
++ remapped_addr = (index == table_count)
++ ? NULL : cfg->win + bdf_addr + where;
++ return remapped_addr;
++ }
++}
++static int pci_n1sdp_init(struct pci_config_window *cfg)
++{
++ phys_addr_t TableBase = (phys_addr_t)AP_NS_SHARED_MEM_BASE;
++
++ TableBase = (phys_addr_t) AP_NS_SHARED_MEM_BASE;
++ if(!request_mem_region(TableBase, AP_NS_SHARED_MEM_SZ,
++ "NonSecureMemory")) {
++ printk(KERN_ERR "Region request failed \n");
++ return -ENOMEM;
++ }
++ DiscoverySharedMemoryBase = (void *)ioremap_nocache(TableBase,
++ AP_NS_SHARED_MEM_SZ);
++ if(DiscoverySharedMemoryBase == NULL) return -ENOMEM;
++
++ /* Allocate memory to hold the discover data header from the
++ shared memory */
++ DiscoveryData_header = (Discover_data_header *)
++ kmalloc(sizeof(Discover_data_header),
++ GFP_KERNEL);
++ if(DiscoveryData_header == NULL) {
++ printk(KERN_ERR "Failed to allocate the Discovery \
++ data header struct \n");
++ return -ENOMEM;
++ }
++ memcpy_fromio((void *)DiscoveryData_header,
++ (void *)DiscoverySharedMemoryBase,
++ sizeof(Discover_data_header));
++
++ /* Allocate memory to hold the bdf entry and populate from the
++ shared memory */
++ DiscoveryData = (unsigned int *)
++ kmalloc(DiscoveryData_header->bdf_entry_count
++ *sizeof(u32), GFP_KERNEL);
++ if(DiscoveryData == NULL) {
++ printk(KERN_ERR "Failed to allocate the BDF table memory \n");
++ return -ENOMEM;
++ }
++ memcpy_fromio((void *)DiscoveryData, (void *)DiscoverySharedMemoryBase +
++ sizeof(Discover_data_header),
++ DiscoveryData_header->bdf_entry_count*sizeof(u32));
++
++ rc_remapped_addr = ioremap_nocache(DiscoveryData_header->PcieRC_addr,
++ CONFIG_SPACE);
++ if (rc_remapped_addr == NULL) {
++ printk(KERN_ERR "Cannot remap root \
++ port base\n");
++ return -ENOMEM;
++ }
++ return 0;
++}
++
++struct pci_ecam_ops pci_n1sdp_ecam_ops = {
++ .bus_shift = 20,
++ .init = pci_n1sdp_init,
++ .pci_ops = {
++ .map_bus = pci_n1sdp_map_bus,
++ .read = pci_generic_config_read32,
++ .write = pci_generic_config_write32,
++ }
++};
++#endif
+diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
+index 29efa09..be89f5e 100644
+--- a/include/linux/pci-ecam.h
++++ b/include/linux/pci-ecam.h
+@@ -56,6 +56,7 @@ extern struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 1.x & 2.x */
+ extern struct pci_ecam_ops pci_thunder_ecam_ops; /* Cavium ThunderX 1.x */
+ extern struct pci_ecam_ops xgene_v1_pcie_ecam_ops; /* APM X-Gene PCIe v1 */
+ extern struct pci_ecam_ops xgene_v2_pcie_ecam_ops; /* APM X-Gene PCIe v2.x */
++extern struct pci_ecam_ops pci_n1sdp_ecam_ops; /* APM N1SDP PCIe */
+ #endif
+
+ #ifdef CONFIG_PCI_HOST_COMMON
+--
+2.7.4
+
diff --git a/patch_apply.sh b/patch_apply.sh
new file mode 100755
index 0000000..e1047cf
--- /dev/null
+++ b/patch_apply.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+echo "******************************************"
+echo "Applying the PCIe quirks in edk2-platforms"
+echo "******************************************"
+pushd ../uefi/edk2/edk2-platforms/
+git am ../../../n1sdp-pcie-quirk/edk2-platforms/*.patch
+popd
+echo "******************************************"
+echo "Applying the PCIe quirks in linux"
+echo "******************************************"
+pushd ../linux
+git am ../n1sdp-pcie-quirk/linux/*.patch
+popd
+echo "******************************************"
+echo "Applying the PCIe quirks in scp"
+echo "******************************************"
+pushd ../scp
+git am ../n1sdp-pcie-quirk/scp/*.patch
+popd
+
diff --git a/scp/0001-n1sdp-add-workaround-for-PCIe-to-avoid-SLVERR-fault.patch b/scp/0001-n1sdp-add-workaround-for-PCIe-to-avoid-SLVERR-fault.patch
new file mode 100755
index 0000000..c57338f
--- /dev/null
+++ b/scp/0001-n1sdp-add-workaround-for-PCIe-to-avoid-SLVERR-fault.patch
@@ -0,0 +1,396 @@
+From 728b849efe7a46816fbffc7ded17258743da3998 Mon Sep 17 00:00:00 2001
+From: Sudipto Paul <sudipto.paul@arm.com>
+Date: Thu, 24 Jan 2019 22:35:33 +0000
+Subject: [PATCH] n1sdp: add workaround for PCIe to avoid SLVERR fault
+
+This patch adds a pcie quirk where scp performs PCIe bus enumeration
+and identifies BDF addresses of all connected devices. Then a table
+is created and placed in non secure SRAM memory and passed to
+application software for further PCIe enumeration/setup.
+
+Change-Id: Ia1664ce336896a3e784df100c8d7daef8450386f
+Signed-off-by: Sudipto Paul <sudipto.paul@arm.com>
+---
+ arch/src/armv7-m/exceptions.c | 36 ++-
+ product/n1sdp/module/n1sdp_pcie/src/Makefile | 2 +-
+ .../module/n1sdp_pcie/src/mod_n1sdp_pcie.c | 6 +-
+ .../module/n1sdp_pcie/src/pcie_enumeration.c | 270 ++++++++++++++++++
+ 4 files changed, 308 insertions(+), 6 deletions(-)
+ create mode 100755 product/n1sdp/module/n1sdp_pcie/src/pcie_enumeration.c
+
+diff --git a/arch/src/armv7-m/exceptions.c b/arch/src/armv7-m/exceptions.c
+index 46469e6..56ef324 100644
+--- a/arch/src/armv7-m/exceptions.c
++++ b/arch/src/armv7-m/exceptions.c
+@@ -1,6 +1,6 @@
+ /*
+ * Arm SCP/MCP Software
+- * Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
++ * Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+@@ -60,10 +60,38 @@ noreturn void arm_exception_reset(void)
+ #endif
+ }
+
+-noreturn void arm_exception_invalid(void)
++static volatile uint32_t exception_count = 0;
++volatile bool return_from_exception = false;
++
++uint32_t get_exception_count(void)
+ {
+- while (true)
+- __WFI();
++ return exception_count;
++}
++
++void scp_dev_fault(uint32_t *stack)
++{
++ /* Move PC ahead by 4 to try to continue execution. */
++ stack[6] += 4;
++
++ /* Increment exception count. */
++ exception_count++;
++}
++
++void arm_exception_invalid(void)
++{
++ if (return_from_exception) {
++ __asm__ ( "tst lr, #4;"
++ "ite eq;"
++ "mrseq r0, msp;"
++ "mrsne r0, psp;"
++ "push {lr};"
++ "b scp_dev_fault;"
++ "pop {pc};"
++ );
++ } else {
++ while (true)
++ __WFI();
++ }
+ }
+
+ enum {
+diff --git a/product/n1sdp/module/n1sdp_pcie/src/Makefile b/product/n1sdp/module/n1sdp_pcie/src/Makefile
+index d3b06f2..6061a9d 100644
+--- a/product/n1sdp/module/n1sdp_pcie/src/Makefile
++++ b/product/n1sdp/module/n1sdp_pcie/src/Makefile
+@@ -6,6 +6,6 @@
+ #
+
+ BS_LIB_NAME := "N1SDP PCIe"
+-BS_LIB_SOURCES = n1sdp_pcie.c mod_n1sdp_pcie.c
++BS_LIB_SOURCES = n1sdp_pcie.c pcie_enumeration.c mod_n1sdp_pcie.c
+
+ include $(BS_DIR)/lib.mk
+diff --git a/product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c b/product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c
+index 1725e7d..5b618cb 100644
+--- a/product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c
++++ b/product/n1sdp/module/n1sdp_pcie/src/mod_n1sdp_pcie.c
+@@ -24,6 +24,9 @@
+ #include <n1sdp_scp_pik.h>
+ #include <internal/pcie_ctrl_apb_reg.h>
+
++int pcie_bus_enumeration(struct n1sdp_pcie_dev_config *config);
++void pcie_init_bdf_table(struct n1sdp_pcie_dev_config *config);
++
+ /*
+ * Device context
+ */
+@@ -161,6 +164,7 @@ static int n1sdp_pcie_setup(struct n1sdp_pcie_dev_ctx *dev_ctx)
+ PCIE_INIT_STAGE_LINK_TRNG);
+ if (status != FWK_SUCCESS) {
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Timeout!\n");
++ pcie_init_bdf_table(dev_ctx->config);
+ return status;
+ }
+ pcie_ctx.log_api->log(MOD_LOG_GROUP_INFO, "Done\n");
+@@ -291,7 +295,7 @@ static int n1sdp_pcie_setup(struct n1sdp_pcie_dev_ctx *dev_ctx)
+ TYPE1_PREF_IO_BAR_ENABLE_MASK |
+ TYPE1_PREF_IO_BAR_SIZE_32BIT_MASK);
+
+- return FWK_SUCCESS;
++ return pcie_bus_enumeration(dev_ctx->config);
+ }
+
+ /*
+diff --git a/product/n1sdp/module/n1sdp_pcie/src/pcie_enumeration.c b/product/n1sdp/module/n1sdp_pcie/src/pcie_enumeration.c
+new file mode 100755
+index 0000000..2e6216d
+--- /dev/null
++++ b/product/n1sdp/module/n1sdp_pcie/src/pcie_enumeration.c
+@@ -0,0 +1,270 @@
++/*
++ * Arm SCP/MCP Software
++ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <stddef.h>
++#include <stdint.h>
++#include <fwk_assert.h>
++#include <fwk_errno.h>
++#include <fwk_macros.h>
++#include <mod_n1sdp_pcie.h>
++#include <n1sdp_pcie.h>
++#include <n1sdp_scp_mmap.h>
++
++/* PCIe configuration space offset definitions */
++#define PCIE_HEADER_TYPE_OFFSET 0xE
++#define PCIE_PRIMARY_BUS_NUM_OFFSET 0x18
++#define PCIE_SECONDARY_BUS_NUM_OFFSET 0x19
++#define PCIE_SUBORDINATE_BUS_NUM_OFFSET 0x1A
++
++#define PCIE_HEADER_TYPE_MASK 0x7F
++#define PCIE_HEADER_TYPE_ENDPOINT 0
++#define PCIE_HEADER_TYPE_BRIDGE 1
++
++/* BDF table offsets for PCIe & CCIX controllers */
++#define PCIE_BDF_TABLE_OFFSET 0
++#define CCIX_BDF_TABLE_OFFSET (16 * FWK_KIB)
++
++/* PCIe standard definitions */
++#define PCIE_BUS_NUM_MAX 0xFF
++#define DEVICES_PER_BUS_MAX 32
++#define FUNCTIONS_PER_DEVICE_MAX 8
++
++#define BDF_ADDR_SHIFT_BUS 20
++#define BDF_ADDR_SHIFT_DEVICE 15
++#define BDF_ADDR_SHIFT_FUNCTION 12
++
++/* Initial bus number definitions */
++#define PCIE_PRIMARY_BUS_NUM_START 1
++#define PCIE_SECONDARY_BUS_NUM_START 2
++
++#define CCIX_PRIMARY_BUS_NUM_START 33
++#define CCIX_SECONDARY_BUS_NUM_START 34
++
++/* Structure defining the BDF table */
++struct bdf_table {
++ /* Base address of Root Port's configuration space */
++ uint32_t rp_config_base_addr;
++ /* Total valid BDF entries found during bus enumeration */
++ uint32_t bdf_count;
++ /* BDF table entries */
++ uint32_t table_data[];
++};
++
++/*
++ * Global variables used during bus enumeration
++ * for BDF table generation
++ */
++uint32_t *bdf_table_ptr;
++uint32_t bdf_count;
++
++/*
++ * By default, SCPv2's exception handler will make the core enter
++ * into an indefinite while loop when an exception happens.
++ * The exception handler is modified such that if return_from_exception
++ * is set to true then the exception handler increments a global
++ * variabe (exception_count) and will return back to the application code.
++ * During PCIe bus enumeration, when a device is not connected, accessing
++ * its configuration space should return 0xFFFFFFFF. However, due to
++ * a bug in the PCIe controller, bus fault is asserted instead of returning
++ * 0xFFFFFFFF. To avoid bus fault errors in AP cores, SCP will perform
++ * a bus enumeration, identifying valid endpoints connected based on the
++ * exception_count.
++ * This variable will be set to true before starting bus enumeration
++ * to detect if an exception has happened or not. Once the enumeration is
++ * completed, this variable will be set to false so that the exception
++ * handler will behave in its default way.
++ */
++extern bool return_from_exception;
++
++/* Function to get current exception_count value */
++uint32_t get_exception_count(void);
++
++/*
++ * This function is called if link training failed to initialize the
++ * BDF table with RP base address and zero BDF count such that UEFI/Linux
++ * will not read garbage table values.
++ */
++void pcie_init_bdf_table(struct n1sdp_pcie_dev_config *config)
++{
++ assert(config != NULL);
++ struct bdf_table *table;
++
++ /* Set BDF table pointer based on the root complex */
++ if (config->ccix_capable)
++ table = (struct bdf_table *)(SCP_NONTRUSTED_RAM_BASE +
++ CCIX_BDF_TABLE_OFFSET);
++ else
++ table = (struct bdf_table *)(SCP_NONTRUSTED_RAM_BASE +
++ PCIE_BDF_TABLE_OFFSET);
++
++ table->rp_config_base_addr = config->global_config_base -
++ SCP_AP_AXI_OFFSET;
++ table->bdf_count = 0;
++}
++
++static uint8_t pcie_bus_scan(uint32_t ecam_addr,
++ uint8_t pri_bnum,
++ uint8_t sec_bnum)
++{
++ int dev_num, fn_num;
++ uint32_t bdf_addr;
++ uint32_t vid;
++ uint32_t config_addr;
++ uint8_t header_type;
++ uint8_t sub_bnum = pri_bnum;
++ volatile uint32_t count, new_count;
++
++ /* Loop over all devices on pri_bnum bus */
++ for (dev_num = 0; dev_num < DEVICES_PER_BUS_MAX; dev_num++) {
++ /*
++ * Special case:
++ * Ignore dev_num > 0 on bus 1 because the controller returns
++ * config space of device 0 for all other device numbers on bus 1
++ */
++ if (((pri_bnum == PCIE_PRIMARY_BUS_NUM_START) && (dev_num != 0)) ||
++ ((pri_bnum == CCIX_PRIMARY_BUS_NUM_START) && (dev_num != 0)))
++ break;
++ /* Loop over all functions on dev_num device */
++ for (fn_num = 0; fn_num < FUNCTIONS_PER_DEVICE_MAX; fn_num++) {
++ bdf_addr = (pri_bnum << BDF_ADDR_SHIFT_BUS) |
++ (dev_num << BDF_ADDR_SHIFT_DEVICE) |
++ (fn_num << BDF_ADDR_SHIFT_FUNCTION);
++ config_addr = ecam_addr + bdf_addr;
++
++ /* Check if exception has occurred */
++ count = get_exception_count();
++ vid = *(uint32_t *)(config_addr);
++ new_count = get_exception_count();
++ if (count != new_count) {
++ /*
++ * Exception occurred.
++ * Ignore this bus-device-function and move to next function.
++ */
++ continue;
++ }
++
++ /* Valid device is identified so fill the BDF table */
++ bdf_count++;
++ *bdf_table_ptr++ = bdf_addr;
++
++ /* If function 0 of any device has invalid VID break the loop */
++ if ((vid & 0xFFFF) == 0xFFFF) {
++ if (fn_num == 0)
++ break;
++ else
++ continue;
++ }
++
++ /*
++ * Read the header type to identify if the device
++ * is an endpoint or a PCI-PCI bridge.
++ */
++ header_type = *(uint8_t *)(config_addr + PCIE_HEADER_TYPE_OFFSET);
++ if ((header_type &
++ PCIE_HEADER_TYPE_MASK) == PCIE_HEADER_TYPE_BRIDGE) {
++ /*
++ * PCI-PCI bridge is identified. Set primary and secondary bus
++ * numbers. Let subordinate bus number be max possible bus
++ * number as we need to further identify devices downstream.
++ */
++ *(uint8_t *)(config_addr +
++ PCIE_PRIMARY_BUS_NUM_OFFSET) = pri_bnum;
++ *(uint8_t *)(config_addr +
++ PCIE_SECONDARY_BUS_NUM_OFFSET) = sec_bnum;
++ *(uint8_t *)(config_addr +
++ PCIE_SUBORDINATE_BUS_NUM_OFFSET) = PCIE_BUS_NUM_MAX;
++ /*
++ * Recursively call the scan function with incremented
++ * primary and secondary bus numbers.
++ */
++ sub_bnum = pcie_bus_scan(ecam_addr, sec_bnum, sec_bnum + 1);
++ /*
++ * The recursive call has returned from an endpoint
++ * identification so use the returned bus number as the
++ * bridge's subordinate bus number.
++ */
++ *(uint8_t *)(config_addr +
++ PCIE_SUBORDINATE_BUS_NUM_OFFSET) = sub_bnum;
++ sec_bnum++;
++ } else {
++ /*
++ * Endpoint is identified. Proceed to other functions &
++ * devices in this bus and return to previous recursive call.
++ */
++ sub_bnum = sec_bnum - 1;
++ }
++ }
++ }
++ /* Return the subordinate bus number to previous recursive call */
++ return sub_bnum;
++}
++
++int pcie_bus_enumeration(struct n1sdp_pcie_dev_config *config)
++{
++ assert(config != NULL);
++
++ uint32_t ecam_base_addr = config->axi_slave_base32;
++ uint8_t pri_bnum, sec_bnum, sub_bnum;
++ struct bdf_table *table;
++
++ /* Set BDF table pointer based on the root complex */
++ if (config->ccix_capable)
++ table = (struct bdf_table *)(SCP_NONTRUSTED_RAM_BASE +
++ CCIX_BDF_TABLE_OFFSET);
++ else
++ table = (struct bdf_table *)(SCP_NONTRUSTED_RAM_BASE +
++ PCIE_BDF_TABLE_OFFSET);
++
++ pcie_init_bdf_table(config);
++
++ bdf_count = 0;
++ bdf_table_ptr = table->table_data;
++ return_from_exception = true;
++
++ /* Start with bus number 1 as bus 0 is root bus internal to the device */
++ if (config->ccix_capable) {
++ pri_bnum = CCIX_PRIMARY_BUS_NUM_START;
++ sec_bnum = CCIX_SECONDARY_BUS_NUM_START;
++ } else {
++ pri_bnum = PCIE_PRIMARY_BUS_NUM_START;
++ sec_bnum = PCIE_SECONDARY_BUS_NUM_START;
++ }
++
++ /*
++ * Configure primary & secondary bus numbers for root port.
++ * Let sub-ordinate bus number be maximum bus number initially.
++ */
++ *(uint8_t *)(config->global_config_base +
++ PCIE_PRIMARY_BUS_NUM_OFFSET) = pri_bnum - 1;
++ *(uint8_t *)(config->global_config_base +
++ PCIE_SECONDARY_BUS_NUM_OFFSET) = pri_bnum;
++ *(uint8_t *)(config->global_config_base +
++ PCIE_SUBORDINATE_BUS_NUM_OFFSET) = PCIE_BUS_NUM_MAX;
++
++ sub_bnum = pcie_bus_scan(ecam_base_addr, pri_bnum, sec_bnum);
++
++ /*
++ * Update subordinate bus number with maximum bus number identified
++ * from bus scan for this bus hierarchy.
++ */
++ *(uint8_t *)(config->global_config_base +
++ PCIE_SUBORDINATE_BUS_NUM_OFFSET) = sub_bnum;
++ return_from_exception = false;
++
++ /*
++ * Make table entries to be even count by adding a dummy entry
++ * for 64-bit alignment
++ */
++ if (bdf_count & 0x1) {
++ *bdf_table_ptr++ = 0xFFFFFFFF;
++ bdf_count++;
++ }
++
++ table->bdf_count = bdf_count;
++
++ return FWK_SUCCESS;
++}
+--
+2.17.1
+