-/**\r
-\r
- Copyright (c) 2006 - 2007, Intel Corporation\r
- All rights reserved. This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
+/** @file\r
+ This driver installs Single Segment Pci Configuration 2 PPI\r
+ to provide read, write and modify access to Pci configuration space in PEI phase.\r
+ To follow PI specification, these services also support access to the unaligned Pci address.\r
\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include <PiPei.h>\r
-\r
#include <Ppi/PciCfg2.h>\r
-\r
#include <Library/BaseLib.h>\r
#include <Library/DebugLib.h>\r
#include <Library/PciLib.h>\r
#include <Library/PeimEntryPoint.h>\r
-\r
+#include <Library/PeiServicesLib.h>\r
#include <IndustryStandard/Pci.h>\r
\r
/**\r
Convert EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS to PCI_LIB_ADDRESS.\r
\r
- @param Address PCI address with\r
- EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS format.\r
- \r
- @return The PCI address with PCI_LIB_ADDRESS format.\r
- \r
+ @param Address PCI address with EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS format.\r
+\r
+ @return PCI address with PCI_LIB_ADDRESS format.\r
+\r
**/\r
-STATIC\r
UINTN\r
PciCfgAddressConvert (\r
EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS *Address\r
Reads from a given location in the PCI configuration space.\r
\r
@param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.\r
-\r
@param This Pointer to local data for the interface.\r
-\r
@param Width The width of the access. Enumerated in bytes.\r
See EFI_PEI_PCI_CFG_PPI_WIDTH above.\r
-\r
@param Address The physical address of the access. The format of\r
the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.\r
-\r
- @param Buffer A pointer to the buffer of data..\r
-\r
+ @param Buffer A pointer to the buffer of data.\r
\r
@retval EFI_SUCCESS The function completed successfully.\r
-\r
- @retval EFI_DEVICE_ERROR There was a problem with the transaction.\r
-\r
- @retval EFI_DEVICE_NOT_READY The device is not capable of supporting the operation at this\r
- time.\r
+ @retval EFI_INVALID_PARAMETER The invalid access width.\r
\r
**/\r
EFI_STATUS\r
-EFIAPI \r
-PciCfg2Read (\r
- IN CONST EFI_PEI_SERVICES **PeiServices,\r
- IN CONST EFI_PEI_PCI_CFG2_PPI *This,\r
- IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,\r
- IN UINT64 Address,\r
- IN OUT VOID *Buffer\r
-);\r
-\r
-/**\r
- Write to a given location in the PCI configuration space.\r
-\r
- @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.\r
-\r
- @param This Pointer to local data for the interface.\r
-\r
- @param Width The width of the access. Enumerated in bytes.\r
- See EFI_PEI_PCI_CFG_PPI_WIDTH above.\r
-\r
- @param Address The physical address of the access. The format of\r
- the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.\r
-\r
- @param Buffer A pointer to the buffer of data..\r
-\r
-\r
- @retval EFI_SUCCESS The function completed successfully.\r
-\r
- @retval EFI_DEVICE_ERROR There was a problem with the transaction.\r
-\r
- @retval EFI_DEVICE_NOT_READY The device is not capable of supporting the operation at this\r
- time.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI \r
-PciCfg2Write (\r
- IN CONST EFI_PEI_SERVICES **PeiServices,\r
- IN CONST EFI_PEI_PCI_CFG2_PPI *This,\r
- IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,\r
- IN UINT64 Address,\r
- IN OUT VOID *Buffer\r
-);\r
-\r
-\r
-/**\r
- PCI read-modify-write operation.\r
-\r
- @param PeiServices An indirect pointer to the PEI Services Table\r
- published by the PEI Foundation.\r
-\r
- @param This Pointer to local data for the interface.\r
-\r
- @param Width The width of the access. Enumerated in bytes. Type\r
- EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().\r
-\r
- @param Address The physical address of the access.\r
-\r
- @param SetBits Points to value to bitwise-OR with the read configuration value.\r
-\r
- The size of the value is determined by Width.\r
-\r
- @param ClearBits Points to the value to negate and bitwise-AND with the read configuration value.\r
- The size of the value is determined by Width.\r
-\r
-\r
- @retval EFI_SUCCESS The function completed successfully.\r
-\r
- @retval EFI_DEVICE_ERROR There was a problem with the transaction.\r
-\r
- @retval EFI_DEVICE_NOT_READY The device is not capable of supporting\r
- the operation at this time.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI \r
-PciCfg2Modify (\r
- IN CONST EFI_PEI_SERVICES **PeiServices,\r
- IN CONST EFI_PEI_PCI_CFG2_PPI *This,\r
- IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,\r
- IN UINT64 Address,\r
- IN CONST VOID *SetBits,\r
- IN CONST VOID *ClearBits\r
-);\r
-\r
-\r
-\r
-/**\r
- @par Ppi Description:\r
- The EFI_PEI_PCI_CFG2_PPI interfaces are used to abstract\r
- accesses to PCI controllers behind a PCI root bridge\r
- controller.\r
-\r
- @param Read PCI read services. See the Read() function description.\r
-\r
- @param Write PCI write services. See the Write() function description.\r
-\r
- @param Modify PCI read-modify-write services. See the Modify() function description.\r
-\r
- @param Segment The PCI bus segment which the specified functions will access.\r
-\r
-**/\r
-GLOBAL_REMOVE_IF_UNREFERENCED\r
-EFI_PEI_PCI_CFG2_PPI gPciCfg2Ppi = {\r
- PciCfg2Read,\r
- PciCfg2Write,\r
- PciCfg2Modify\r
-};\r
-\r
-GLOBAL_REMOVE_IF_UNREFERENCED\r
-EFI_PEI_PPI_DESCRIPTOR gPciCfg2PpiList = {\r
- (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
- &gEfiPciCfg2PpiGuid,\r
- &gPciCfg2Ppi\r
-};\r
-\r
-/**\r
- Reads from a given location in the PCI configuration space.\r
-\r
- @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.\r
-\r
- @param This Pointer to local data for the interface.\r
-\r
- @param Width The width of the access. Enumerated in bytes.\r
- See EFI_PEI_PCI_CFG_PPI_WIDTH above.\r
-\r
- @param Address The physical address of the access. The format of\r
- the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.\r
-\r
- @param Buffer A pointer to the buffer of data..\r
-\r
-\r
- @retval EFI_SUCCESS The function completed successfully.\r
-\r
- @retval EFI_DEVICE_ERROR There was a problem with the transaction.\r
-\r
- @retval EFI_DEVICE_NOT_READY The device is not capable of supporting the operation at this\r
- time.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI \r
+EFIAPI\r
PciCfg2Read (\r
IN CONST EFI_PEI_SERVICES **PeiServices,\r
IN CONST EFI_PEI_PCI_CFG2_PPI *This,\r
IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,\r
IN UINT64 Address,\r
IN OUT VOID *Buffer\r
-)\r
+ )\r
{\r
UINTN PciLibAddress;\r
\r
if (Width == EfiPeiPciCfgWidthUint8) {\r
*((UINT8 *) Buffer) = PciRead8 (PciLibAddress);\r
} else if (Width == EfiPeiPciCfgWidthUint16) {\r
- *((UINT16 *) Buffer) = PciRead16 (PciLibAddress);\r
+ if ((PciLibAddress & 0x01) == 0) {\r
+ //\r
+ // Aligned Pci address access\r
+ //\r
+ WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress));\r
+ } else {\r
+ //\r
+ // Unaligned Pci address access, break up the request into byte by byte.\r
+ //\r
+ *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);\r
+ *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1);\r
+ }\r
} else if (Width == EfiPeiPciCfgWidthUint32) {\r
- *((UINT32 *) Buffer) = PciRead32 (PciLibAddress);\r
+ if ((PciLibAddress & 0x03) == 0) {\r
+ //\r
+ // Aligned Pci address access\r
+ //\r
+ WriteUnaligned32 (((UINT32 *) Buffer), PciRead32 (PciLibAddress));\r
+ } else if ((PciLibAddress & 0x01) == 0) {\r
+ //\r
+ // Unaligned Pci address access, break up the request into word by word.\r
+ //\r
+ WriteUnaligned16 (((UINT16 *) Buffer), PciRead16 (PciLibAddress));\r
+ WriteUnaligned16 (((UINT16 *) Buffer + 1), PciRead16 (PciLibAddress + 2));\r
+ } else {\r
+ //\r
+ // Unaligned Pci address access, break up the request into byte by byte.\r
+ //\r
+ *((UINT8 *) Buffer) = PciRead8 (PciLibAddress);\r
+ *((UINT8 *) Buffer + 1) = PciRead8 (PciLibAddress + 1);\r
+ *((UINT8 *) Buffer + 2) = PciRead8 (PciLibAddress + 2);\r
+ *((UINT8 *) Buffer + 3) = PciRead8 (PciLibAddress + 3);\r
+ }\r
} else {\r
return EFI_INVALID_PARAMETER;\r
}\r
Write to a given location in the PCI configuration space.\r
\r
@param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.\r
-\r
@param This Pointer to local data for the interface.\r
-\r
@param Width The width of the access. Enumerated in bytes.\r
See EFI_PEI_PCI_CFG_PPI_WIDTH above.\r
-\r
@param Address The physical address of the access. The format of\r
the address is described by EFI_PEI_PCI_CFG_PPI_PCI_ADDRESS.\r
-\r
- @param Buffer A pointer to the buffer of data..\r
-\r
+ @param Buffer A pointer to the buffer of data.\r
\r
@retval EFI_SUCCESS The function completed successfully.\r
-\r
- @retval EFI_DEVICE_ERROR There was a problem with the transaction.\r
-\r
- @retval EFI_DEVICE_NOT_READY The device is not capable of supporting the operation at this\r
- time.\r
+ @retval EFI_INVALID_PARAMETER The invalid access width.\r
\r
**/\r
EFI_STATUS\r
-EFIAPI \r
+EFIAPI\r
PciCfg2Write (\r
IN CONST EFI_PEI_SERVICES **PeiServices,\r
IN CONST EFI_PEI_PCI_CFG2_PPI *This,\r
IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,\r
IN UINT64 Address,\r
IN OUT VOID *Buffer\r
-)\r
+ )\r
{\r
UINTN PciLibAddress;\r
\r
if (Width == EfiPeiPciCfgWidthUint8) {\r
PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));\r
} else if (Width == EfiPeiPciCfgWidthUint16) {\r
- PciWrite16 (PciLibAddress, *((UINT16 *) Buffer));\r
+ if ((PciLibAddress & 0x01) == 0) {\r
+ //\r
+ // Aligned Pci address access\r
+ //\r
+ PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer));\r
+ } else {\r
+ //\r
+ // Unaligned Pci address access, break up the request into byte by byte.\r
+ //\r
+ PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));\r
+ PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1));\r
+ }\r
} else if (Width == EfiPeiPciCfgWidthUint32) {\r
- PciWrite32 (PciLibAddress, *((UINT32 *) Buffer));\r
+ if ((PciLibAddress & 0x03) == 0) {\r
+ //\r
+ // Aligned Pci address access\r
+ //\r
+ PciWrite32 (PciLibAddress, ReadUnaligned32 ((UINT32 *) Buffer));\r
+ } else if ((PciLibAddress & 0x01) == 0) {\r
+ //\r
+ // Unaligned Pci address access, break up the request into word by word.\r
+ //\r
+ PciWrite16 (PciLibAddress, ReadUnaligned16 ((UINT16 *) Buffer));\r
+ PciWrite16 (PciLibAddress + 2, ReadUnaligned16 ((UINT16 *) Buffer + 1));\r
+ } else {\r
+ //\r
+ // Unaligned Pci address access, break up the request into byte by byte.\r
+ //\r
+ PciWrite8 (PciLibAddress, *((UINT8 *) Buffer));\r
+ PciWrite8 (PciLibAddress + 1, *((UINT8 *) Buffer + 1));\r
+ PciWrite8 (PciLibAddress + 2, *((UINT8 *) Buffer + 2));\r
+ PciWrite8 (PciLibAddress + 3, *((UINT8 *) Buffer + 3));\r
+ }\r
} else {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
\r
/**\r
- PCI read-modify-write operation.\r
+ This function performs a read-modify-write operation on the contents from a given\r
+ location in the PCI configuration space.\r
\r
@param PeiServices An indirect pointer to the PEI Services Table\r
published by the PEI Foundation.\r
-\r
@param This Pointer to local data for the interface.\r
-\r
@param Width The width of the access. Enumerated in bytes. Type\r
EFI_PEI_PCI_CFG_PPI_WIDTH is defined in Read().\r
-\r
@param Address The physical address of the access.\r
-\r
@param SetBits Points to value to bitwise-OR with the read configuration value.\r
-\r
The size of the value is determined by Width.\r
-\r
@param ClearBits Points to the value to negate and bitwise-AND with the read configuration value.\r
The size of the value is determined by Width.\r
\r
-\r
@retval EFI_SUCCESS The function completed successfully.\r
-\r
- @retval EFI_DEVICE_ERROR There was a problem with the transaction.\r
-\r
- @retval EFI_DEVICE_NOT_READY The device is not capable of supporting\r
- the operation at this time.\r
+ @retval EFI_INVALID_PARAMETER The invalid access width.\r
\r
**/\r
EFI_STATUS\r
-EFIAPI \r
+EFIAPI\r
PciCfg2Modify (\r
IN CONST EFI_PEI_SERVICES **PeiServices,\r
IN CONST EFI_PEI_PCI_CFG2_PPI *This,\r
IN EFI_PEI_PCI_CFG_PPI_WIDTH Width,\r
IN UINT64 Address,\r
- IN CONST VOID *SetBits,\r
- IN CONST VOID *ClearBits\r
-)\r
+ IN VOID *SetBits,\r
+ IN VOID *ClearBits\r
+ )\r
{\r
UINTN PciLibAddress;\r
UINT16 ClearValue16;\r
if (Width == EfiPeiPciCfgWidthUint8) {\r
PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));\r
} else if (Width == EfiPeiPciCfgWidthUint16) {\r
- ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits));\r
- SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits);\r
- PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);\r
+ if ((PciLibAddress & 0x01) == 0) {\r
+ //\r
+ // Aligned Pci address access\r
+ //\r
+ ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits));\r
+ SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits);\r
+ PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);\r
+ } else {\r
+ //\r
+ // Unaligned Pci address access, break up the request into byte by byte.\r
+ //\r
+ PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));\r
+ PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1));\r
+ }\r
} else if (Width == EfiPeiPciCfgWidthUint32) {\r
- ClearValue32 = (UINT32) (~ReadUnaligned32 ((UINT32 *) ClearBits));\r
- SetValue32 = ReadUnaligned32 ((UINT32 *) SetBits);\r
- PciAndThenOr32 (PciLibAddress, ClearValue32, SetValue32);\r
+ if ((PciLibAddress & 0x03) == 0) {\r
+ //\r
+ // Aligned Pci address access\r
+ //\r
+ ClearValue32 = (UINT32) (~ReadUnaligned32 ((UINT32 *) ClearBits));\r
+ SetValue32 = ReadUnaligned32 ((UINT32 *) SetBits);\r
+ PciAndThenOr32 (PciLibAddress, ClearValue32, SetValue32);\r
+ } else if ((PciLibAddress & 0x01) == 0) {\r
+ //\r
+ // Unaligned Pci address access, break up the request into word by word.\r
+ //\r
+ ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits));\r
+ SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits);\r
+ PciAndThenOr16 (PciLibAddress, ClearValue16, SetValue16);\r
+\r
+ ClearValue16 = (UINT16) (~ReadUnaligned16 ((UINT16 *) ClearBits + 1));\r
+ SetValue16 = ReadUnaligned16 ((UINT16 *) SetBits + 1);\r
+ PciAndThenOr16 (PciLibAddress + 2, ClearValue16, SetValue16);\r
+ } else {\r
+ //\r
+ // Unaligned Pci address access, break up the request into byte by byte.\r
+ //\r
+ PciAndThenOr8 (PciLibAddress, (UINT8) (~(*(UINT8 *) ClearBits)), *((UINT8 *) SetBits));\r
+ PciAndThenOr8 (PciLibAddress + 1, (UINT8) (~(*((UINT8 *) ClearBits + 1))), *((UINT8 *) SetBits + 1));\r
+ PciAndThenOr8 (PciLibAddress + 2, (UINT8) (~(*((UINT8 *) ClearBits + 2))), *((UINT8 *) SetBits + 2));\r
+ PciAndThenOr8 (PciLibAddress + 3, (UINT8) (~(*((UINT8 *) ClearBits + 3))), *((UINT8 *) SetBits + 3));\r
+ }\r
} else {\r
return EFI_INVALID_PARAMETER;\r
}\r
+\r
return EFI_SUCCESS;\r
}\r
\r
+EFI_PEI_PCI_CFG2_PPI gPciCfg2Ppi = {\r
+ PciCfg2Read,\r
+ PciCfg2Write,\r
+ PciCfg2Modify,\r
+ 0\r
+};\r
+\r
+EFI_PEI_PPI_DESCRIPTOR gPciCfg2PpiList = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEfiPciCfg2PpiGuid,\r
+ &gPciCfg2Ppi\r
+};\r
\r
+/**\r
+ Module's entry function.\r
+ This routine will install EFI_PEI_PCI_CFG2_PPI.\r
+\r
+ @param FileHandle Handle of the file being invoked.\r
+ @param PeiServices Describes the list of possible PEI Services.\r
+\r
+ @return Whether success to install service.\r
+**/\r
EFI_STATUS\r
EFIAPI\r
PeimInitializePciCfg (\r
- IN EFI_FFS_FILE_HEADER *FfsHeader,\r
- IN EFI_PEI_SERVICES **PeiServices\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
)\r
{\r
EFI_STATUS Status;\r
\r
- ASSERT ((**PeiServices).Hdr.Revision >= PEI_SERVICES_REVISION);\r
-\r
- (**PeiServices).PciCfg = &gPciCfg2Ppi;\r
- Status = (**PeiServices).InstallPpi ((CONST EFI_PEI_SERVICES **)PeiServices, &gPciCfg2PpiList);\r
+ (**(EFI_PEI_SERVICES **)PeiServices).PciCfg = &gPciCfg2Ppi;\r
+ Status = PeiServicesInstallPpi (&gPciCfg2PpiList);\r
+ ASSERT_EFI_ERROR (Status);\r
\r
return Status;\r
}\r