+\r
+/**\r
+ Read PCI device configuration register by specified address.\r
+\r
+ This function check the incompatiblilites on PCI device. Return the register\r
+ value.\r
+\r
+ @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+ @param PciIo A pointer to EFI_PCI_PROTOCOL.\r
+ @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.\r
+ @param Width Signifies the width of the memory operations.\r
+ @Param Address The address within the PCI configuration space for the PCI controller.\r
+ @param Buffer For read operations, the destination buffer to store the results. For\r
+ write operations, the source buffer to write data from.\r
+\r
+ @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+ReadConfigData (\r
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL\r
+ IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,\r
+ IN UINT64 Width,\r
+ IN UINT64 Address,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 AccessWidth;\r
+ EFI_PCI_REGISTER_ACCESS_DATA *PciRegisterAccessData;\r
+ UINT64 AccessAddress;\r
+ UINTN Stride;\r
+ UINT64 TempBuffer;\r
+ UINT8 *Pointer;\r
+\r
+ ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
+\r
+ if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) {\r
+ //\r
+ // check access compatibility at first time\r
+ //\r
+ Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, Address & 0xff, Width, &PciRegisterAccessData);\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // there exist incompatibility on this operation\r
+ //\r
+ AccessWidth = Width;\r
+\r
+ if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
+ AccessWidth = PciRegisterAccessData->Width;\r
+ }\r
+\r
+ AccessAddress = Address & ~((1 << AccessWidth) - 1);\r
+\r
+ TempBuffer = 0;\r
+ Stride = 0;\r
+ Pointer = (UINT8 *) &TempBuffer;\r
+\r
+ while (1) {\r
+\r
+ if (PciRootBridgeIo != NULL) {\r
+ Status = PciRootBridgeIo->Pci.Read (\r
+ PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,\r
+ AccessAddress,\r
+ 1,\r
+ Pointer\r
+ );\r
+ } else if (PciIo != NULL) {\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,\r
+ (UINT32) AccessAddress,\r
+ 1,\r
+ Pointer\r
+ );\r
+ }\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+\r
+ Stride = 1 << AccessWidth;\r
+ AccessAddress += Stride;\r
+ if (AccessAddress >= (Address + (1 << Width))) {\r
+ //\r
+ // if all datas have been read, exist\r
+ //\r
+ break;\r
+ }\r
+\r
+ Pointer += Stride;\r
+\r
+ if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {\r
+ //\r
+ // if current offset doesn't reach the end\r
+ //\r
+ continue;\r
+ }\r
+\r
+ FreePool (PciRegisterAccessData);\r
+\r
+ //\r
+ // continue checking access incompatibility\r
+ //\r
+ Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);\r
+ if (Status == EFI_SUCCESS) {\r
+ if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
+ AccessWidth = PciRegisterAccessData->Width;\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool (PciRegisterAccessData);\r
+\r
+ switch (Width) {\r
+ case EfiPciWidthUint8:\r
+ * (UINT8 *) Buffer = (UINT8) TempBuffer;\r
+ break;\r
+ case EfiPciWidthUint16:\r
+ * (UINT16 *) Buffer = (UINT16) TempBuffer;\r
+ break;\r
+ case EfiPciWidthUint32:\r
+ * (UINT32 *) Buffer = (UINT32) TempBuffer;\r
+ break;\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ return Status;\r
+ }\r
+ }\r
+ //\r
+ // AccessWidth incompatible check not supportted\r
+ // or, there doesn't exist incompatibility on this operation\r
+ //\r
+ if (PciRootBridgeIo != NULL) {\r
+ Status = PciRootBridgeIo->Pci.Read (\r
+ PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
+ Address,\r
+ 1,\r
+ Buffer\r
+ );\r
+\r
+ } else {\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
+ (UINT32) Address,\r
+ 1,\r
+ Buffer\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Update register value by checking PCI device incompatibility.\r
+\r
+ This function check register value incompatibilites on PCI device. Return the register\r
+ value.\r
+\r
+ @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.\r
+ @param AccessType Access type, READ or WRITE.\r
+ @Param Address The address within the PCI configuration space.\r
+ @param Buffer Store the register data.\r
+\r
+ @retval EFI_SUCCESS The data has been updated.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UpdateConfigData (\r
+ IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,\r
+ IN UINT64 AccessType,\r
+ IN UINT64 Width,\r
+ IN UINT64 Address,\r
+ IN OUT VOID *Buffer\r
+)\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_REGISTER_VALUE_DATA *PciRegisterData;\r
+ UINT64 AndValue;\r
+ UINT64 OrValue;\r
+ UINT32 TempValue;\r
+\r
+ //\r
+ // check register value incompatibility\r
+ //\r
+ Status = PciRegisterUpdateCheck (PciDeviceInfo, AccessType, Address & 0xff, &PciRegisterData);\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+\r
+ AndValue = (PciRegisterData->AndValue) >> ((Address & 0x3) * 8);\r
+ OrValue = (PciRegisterData->OrValue) >> ((Address & 0x3) * 8);\r
+\r
+ TempValue = * (UINT32 *) Buffer;\r
+\r
+ if (PciRegisterData->AndValue != VALUE_NOCARE) {\r
+ TempValue &= (UINT32) AndValue;\r
+ }\r
+ if (PciRegisterData->OrValue != VALUE_NOCARE) {\r
+ TempValue |= (UINT32) OrValue;\r
+ }\r
+\r
+ switch (Width) {\r
+ case EfiPciWidthUint8:\r
+ *(UINT32 *)Buffer = *(UINT32 *)Buffer & 0xffffff00 + (UINT8)TempValue;\r
+ break;\r
+\r
+ case EfiPciWidthUint16:\r
+ *(UINT32 *)Buffer = *(UINT32 *)Buffer & 0xffff0000 + (UINT16)TempValue;\r
+ break;\r
+ case EfiPciWidthUint32:\r
+ *(UINT32 *)Buffer = TempValue;\r
+ break;\r
+\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ FreePool (PciRegisterData);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write PCI device configuration register by specified address.\r
+\r
+ This function check the incompatiblilites on PCI device, and write date\r
+ into register.\r
+\r
+ @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+ @param PciIo A pointer to EFI_PCI_PROTOCOL.\r
+ @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.\r
+ @param Width Signifies the width of the memory operations.\r
+ @Param Address The address within the PCI configuration space for the PCI controller.\r
+ @param Buffer For read operations, the destination buffer to store the results. For\r
+ write operations, the source buffer to write data from.\r
+\r
+ @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+WriteConfigData (\r
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL\r
+ IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,\r
+ IN UINT64 Width,\r
+ IN UINT64 Address,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 AccessWidth;\r
+ EFI_PCI_REGISTER_ACCESS_DATA *PciRegisterAccessData;\r
+ UINT64 AccessAddress;\r
+ UINTN Stride;\r
+ UINT8 *Pointer;\r
+ UINT64 Data;\r
+ UINTN Shift;\r
+\r
+ ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
+\r
+ if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) {\r
+ //\r
+ // check access compatibility at first time\r
+ //\r
+ Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, Address & 0xff, Width, &PciRegisterAccessData);\r
+\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // there exist incompatibility on this operation\r
+ //\r
+ AccessWidth = Width;\r
+\r
+ if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
+ AccessWidth = PciRegisterAccessData->Width;\r
+ }\r
+\r
+ AccessAddress = Address & ~((1 << AccessWidth) - 1);\r
+\r
+ Stride = 0;\r
+ Pointer = (UINT8 *) &Buffer;\r
+ Data = * (UINT64 *) Buffer;\r
+\r
+ while (1) {\r
+\r
+ if (AccessWidth > Width) {\r
+ //\r
+ // if actual access width is larger than orignal one, additional data need to be read back firstly\r
+ //\r
+ Status = ReadConfigData (PciRootBridgeIo, PciIo, PciDeviceInfo, AccessWidth, AccessAddress, &Data);\r
+ if (Status != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // check data read incompatibility\r
+ //\r
+ UpdateConfigData (PciDeviceInfo, PCI_REGISTER_READ, AccessWidth, AccessAddress & 0xff, &Data);\r
+\r
+ Shift = (Address - AccessAddress) * 8;\r
+ switch (Width) {\r
+ case EfiPciWidthUint8:\r
+ Data = (* (UINT8 *) Buffer) << Shift | (Data & ~(0xff << Shift));\r
+ break;\r
+\r
+ case EfiPciWidthUint16:\r
+ Data = (* (UINT16 *) Buffer) << Shift | (Data & ~(0xffff << Shift));\r
+ break;\r
+ }\r
+\r
+ //\r
+ // check data write incompatibility\r
+ //\r
+ UpdateConfigData (PciDeviceInfo, PCI_REGISTER_WRITE, AccessWidth, AccessAddress * 0xff, &Data);\r
+ }\r
+\r
+ if (PciRootBridgeIo != NULL) {\r
+ Status = PciRootBridgeIo->Pci.Write (\r
+ PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,\r
+ AccessAddress,\r
+ 1,\r
+ &Data\r
+ );\r
+ } else {\r
+ Status = PciIo->Pci.Write (\r
+ PciIo,\r
+ (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,\r
+ (UINT32) AccessAddress,\r
+ 1,\r
+ &Data\r
+ );\r
+ }\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+\r
+ Data = Data >> ((1 << AccessWidth) * 8);\r
+\r
+ Stride = 1 << AccessWidth;\r
+ AccessAddress += Stride;\r
+ if (AccessAddress >= (Address + (1 << Width))) {\r
+ //\r
+ // if all datas have been written, exist\r
+ //\r
+ break;\r
+ }\r
+\r
+ Pointer += Stride;\r
+\r
+ if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {\r
+ //\r
+ // if current offset doesn't reach the end\r
+ //\r
+ continue;\r
+ }\r
+\r
+ FreePool (PciRegisterAccessData);\r
+\r
+ //\r
+ // continue checking access incompatibility\r
+ //\r
+ Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);\r
+ if (Status == EFI_SUCCESS) {\r
+ if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
+ AccessWidth = PciRegisterAccessData->Width;\r
+ }\r
+ }\r
+ };\r
+\r
+ FreePool (PciRegisterAccessData);\r
+\r
+ return Status;\r
+ }\r
+\r
+ }\r
+ //\r
+ // AccessWidth incompatible check not supportted\r
+ // or, there doesn't exist incompatibility on this operation\r
+ //\r
+ if (PciRootBridgeIo != NULL) {\r
+ Status = PciRootBridgeIo->Pci.Write (\r
+ PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
+ Address,\r
+ 1,\r
+ Buffer\r
+ );\r
+ } else {\r
+ Status = PciIo->Pci.Write (\r
+ PciIo,\r
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
+ (UINT32) Address,\r
+ 1,\r
+ Buffer\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Abstract PCI device device information.\r
+\r
+ @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+ @param PciIo A pointer to EFI_PCI_PROTOCOL.\r
+ @param Pci A pointer to PCI_TYPE00.\r
+ @Param Address The address within the PCI configuration space for the PCI controller.\r
+ @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.\r
+\r
+ @retval EFI_SUCCESS Pci device device information has been abstracted.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+GetPciDeviceDeviceInfo (\r
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL\r
+ IN PCI_TYPE00 *Pci, OPTIONAL\r
+ IN UINT64 Address, OPTIONAL\r
+ OUT EFI_PCI_DEVICE_INFO *PciDeviceInfo\r
+)\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 PciAddress;\r
+ UINT32 PciConfigData;\r
+ PCI_IO_DEVICE *PciIoDevice;\r
+\r
+ ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
+\r
+ if (PciIo != NULL) {\r
+ PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
+\r
+ //\r
+ // get pointer to PCI_TYPE00 from PciIoDevice\r
+ //\r
+ Pci = &PciIoDevice->Pci;\r
+ }\r
+\r
+ if (Pci == NULL) {\r
+ //\r
+ // while PCI_TYPE00 hasn't been gotten, read PCI device device information directly\r
+ //\r
+ PciAddress = Address & 0xffffffffffffff00ULL;\r
+ Status = PciRootBridgeIo->Pci.Read (\r
+ PciRootBridgeIo,\r
+ EfiPciWidthUint32,\r
+ PciAddress,\r
+ 1,\r
+ &PciConfigData\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((PciConfigData & 0xffff) == 0xffff) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ PciDeviceInfo->VendorID = PciConfigData & 0xffff;\r
+ PciDeviceInfo->DeviceID = PciConfigData >> 16;\r
+\r
+ Status = PciRootBridgeIo->Pci.Read (\r
+ PciRootBridgeIo,\r
+ EfiPciWidthUint32,\r
+ PciAddress + 8,\r
+ 1,\r
+ &PciConfigData\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PciDeviceInfo->RevisionID = PciConfigData & 0xf;\r
+\r
+ Status = PciRootBridgeIo->Pci.Read (\r
+ PciRootBridgeIo,\r
+ EfiPciWidthUint32,\r
+ PciAddress + 0x2c,\r
+ 1,\r
+ &PciConfigData\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PciDeviceInfo->SubsystemVendorID = PciConfigData & 0xffff;\r
+ PciDeviceInfo->SubsystemID = PciConfigData >> 16;\r
+\r
+ } else {\r
+ PciDeviceInfo->VendorID = Pci->Hdr.VendorId;\r
+ PciDeviceInfo->DeviceID = Pci->Hdr.DeviceId;\r
+ PciDeviceInfo->RevisionID = Pci->Hdr.RevisionID;\r
+ PciDeviceInfo->SubsystemVendorID = Pci->Device.SubsystemVendorID;\r
+ PciDeviceInfo->SubsystemID = Pci->Device.SubsystemID;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read PCI configuration space with incompatibility check.\r
+\r
+ @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+ @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.\r
+ @param Pci A pointer to PCI_TYPE00.\r
+ @param Width Signifies the width of the memory operations.\r
+ @Param Address The address within the PCI configuration space for the PCI controller.\r
+ @param Buffer For read operations, the destination buffer to store the results. For\r
+ write operations, the source buffer to write data from.\r
+\r
+ @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+PciIncompatibilityCheckRead (\r
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL\r
+ IN PCI_TYPE00 *Pci, OPTIONAL\r
+ IN UINTN Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+)\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_DEVICE_INFO PciDeviceInfo;\r
+ UINT32 Stride;\r
+\r
+ ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
+\r
+ //\r
+ // get PCI device device information\r
+ //\r
+ Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo);\r
+ if (Status != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+\r
+ Stride = 1 << Width;\r
+\r
+ for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *)Buffer + Stride) {\r
+\r
+ //\r
+ // read configuration register\r
+ //\r
+ Status = ReadConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, (UINT64) Width, Address, Buffer);\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // update the data read from configuration register\r
+ //\r
+ if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) {\r
+ UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_READ, Width, Address & 0xff, Buffer);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Write PCI configuration space with incompatibility check.\r
+\r
+ @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+ @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.\r
+ @param Pci A pointer to PCI_TYPE00.\r
+ @param Width Signifies the width of the memory operations.\r
+ @Param Address The address within the PCI configuration space for the PCI controller.\r
+ @param Buffer For read operations, the destination buffer to store the results. For\r
+ write operations, the source buffer to write data from.\r
+\r
+ @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+PciIncompatibilityCheckWrite (\r
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL\r
+ IN PCI_TYPE00 *Pci, OPTIONAL\r
+ IN UINTN Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+)\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_DEVICE_INFO PciDeviceInfo;\r
+ UINT32 Stride;\r
+ UINT64 Data;\r
+\r
+ ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
+\r
+ //\r
+ // get PCI device device information\r
+ //\r
+ Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo);\r
+ if (Status != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+\r
+ Stride = 1 << Width;\r
+\r
+ for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *) Buffer + Stride) {\r
+\r
+ Data = 0;\r
+\r
+ switch (Width) {\r
+ case EfiPciWidthUint8:\r
+ Data = * (UINT8 *) Buffer;\r
+ break;\r
+ case EfiPciWidthUint16:\r
+ Data = * (UINT16 *) Buffer;\r
+ break;\r
+\r
+ case EfiPciWidthUint32:\r
+ Data = * (UINT32 *) Buffer;\r
+ break;\r
+\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // update the data writen into configuration register\r
+ //\r
+ if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) {\r
+ UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_WRITE, Width, Address & 0xff, &Data);\r
+ }\r
+\r
+ //\r
+ // write configuration register\r
+ //\r
+ Status = WriteConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, Width, Address, &Data);\r
+\r
+ if (Status != EFI_SUCCESS) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+\r
+ @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+ @param Pci A pointer to PCI_TYPE00.\r
+ @param Width Signifies the width of the memory operations.\r
+ @Param Address The address within the PCI configuration space for the PCI controller.\r
+ @param Buffer For read operations, the destination buffer to store the results. For\r
+ write operations, the source buffer to write data from.\r
+\r
+ @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+PciRootBridgeIoRead (\r
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
+ IN PCI_TYPE00 *Pci, OPTIONAL\r
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) {\r
+ //\r
+ // if PCI incompatibility check enabled\r
+ //\r
+ return PciIncompatibilityCheckRead (\r
+ PciRootBridgeIo,\r
+ NULL,\r
+ Pci,\r
+ (UINTN) Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+ } else {\r
+ return PciRootBridgeIo->Pci.Read (\r
+ PciRootBridgeIo,\r
+ Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+ }\r
+}\r
+\r
+/**\r
+ Write PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+\r
+ @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+ @param Pci A pointer to PCI_TYPE00.\r
+ @param Width Signifies the width of the memory operations.\r
+ @Param Address The address within the PCI configuration space for the PCI controller.\r
+ @param Buffer For read operations, the destination buffer to store the results. For\r
+ write operations, the source buffer to write data from.\r
+\r
+ @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+PciRootBridgeIoWrite (\r
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
+ IN PCI_TYPE00 *Pci,\r
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) {\r
+ //\r
+ // if PCI incompatibility check enabled\r
+ //\r
+ return PciIncompatibilityCheckWrite (\r
+ PciRootBridgeIo,\r
+ NULL,\r
+ Pci,\r
+ Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+\r
+ } else {\r
+ return PciRootBridgeIo->Pci.Write (\r
+ PciRootBridgeIo,\r
+ Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+ }\r
+}\r
+\r
+/**\r
+ Read PCI configuration space through EFI_PCI_IO_PROTOCOL.\r
+\r
+ @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.\r
+ @param Width Signifies the width of the memory operations.\r
+ @Param Address The address within the PCI configuration space for the PCI controller.\r
+ @param Buffer For read operations, the destination buffer to store the results. For\r
+ write operations, the source buffer to write data from.\r
+\r
+ @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+PciIoRead (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT32 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) {\r
+ //\r
+ // if PCI incompatibility check enabled\r
+ //\r
+ return PciIncompatibilityCheckRead (\r
+ NULL,\r
+ PciIo,\r
+ NULL,\r
+ (UINTN) Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+ } else {\r
+ return PciIo->Pci.Read (\r
+ PciIo,\r
+ Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+ }\r
+}\r
+\r
+/**\r
+ Write PCI configuration space through EFI_PCI_IO_PROTOCOL.\r
+\r
+ @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.\r
+ @param Width Signifies the width of the memory operations.\r
+ @Param Address The address within the PCI configuration space for the PCI controller.\r
+ @param Buffer For read operations, the destination buffer to store the results. For\r
+ write operations, the source buffer to write data from.\r
+\r
+ @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+PciIoWrite (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
+ IN UINT32 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) {\r
+\r
+ //\r
+ // if PCI incompatibility check enabled\r
+ //\r
+ return PciIncompatibilityCheckWrite (\r
+ NULL,\r
+ PciIo,\r
+ NULL,\r
+ Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+\r
+ } else {\r
+ return PciIo->Pci.Write (\r
+ PciIo,\r
+ Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+ }\r
+}\r