/*++\r
\r
-Copyright (c) 2006, 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
- \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 - 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
+\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
\r
Module Name:\r
\r
- PciLib.c \r
- \r
+ PciLib.c\r
+\r
Abstract:\r
\r
PCI Bus Driver Lib file\r
- It abstracts some functions that can be different \r
+ It abstracts some functions that can be different\r
between light PCI bus driver and full PCI bus driver\r
\r
Revision History\r
if (!gFullEnumeration) {\r
\r
Address = 0;\r
- PciIoDevice->PciIo.Pci.Read (\r
+ PciIoRead (\r
&(PciIoDevice->PciIo),\r
EfiPciIoWidthUint32,\r
0x1c,\r
(PciIoDevice->PciBar)[P2C_MEM_1].BarType = PciBarTypeMem32;\r
\r
Address = 0;\r
- PciIoDevice->PciIo.Pci.Read (\r
+ PciIoRead (\r
&(PciIoDevice->PciIo),\r
EfiPciIoWidthUint32,\r
0x20,\r
(PciIoDevice->PciBar)[P2C_MEM_2].BarType = PciBarTypePMem32;\r
\r
Address = 0;\r
- PciIoDevice->PciIo.Pci.Read (\r
+ PciIoRead (\r
&(PciIoDevice->PciIo),\r
EfiPciIoWidthUint32,\r
0x2c,\r
(PciIoDevice->PciBar)[P2C_IO_1].BarType = PciBarTypeIo16;\r
\r
Address = 0;\r
- PciIoDevice->PciIo.Pci.Read (\r
+ PciIoRead (\r
&(PciIoDevice->PciIo),\r
EfiPciIoWidthUint32,\r
0x34,\r
// Skip rejection for all PPBs, while detect rejection for others\r
//\r
if (IsPciDeviceRejected (Temp)) {\r
- \r
+\r
//\r
// For P2C, remove all devices on it\r
//\r
- \r
+\r
if (!IsListEmpty (&Temp->ChildList)) {\r
RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);\r
}\r
- \r
+\r
//\r
// Finally remove itself\r
//\r
- \r
+\r
LastLink = CurrentLink->BackLink;\r
RemoveEntryList (CurrentLink);\r
FreePciDevice (Temp);\r
return PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (\r
PciResAlloc\r
);\r
- } \r
+ }\r
}\r
\r
\r
//\r
// Initialize resource pool\r
//\r
- \r
+\r
InitializeResourcePool (&IoPool, PciBarTypeIo16);\r
InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);\r
InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);\r
Mem32Bridge->Alignment = MaxOptionRomSize - 1;\r
}\r
}\r
- \r
+\r
//\r
// Based on the all the resource tree, contruct ACPI resource node to\r
// submit the resource aperture to pci host bridge protocol\r
//\r
// Free acpi resource node\r
//\r
- if (AcpiConfig) {\r
- gBS->FreePool (AcpiConfig);\r
+ if (AcpiConfig != NULL) {\r
+ FreePool (AcpiConfig);\r
}\r
\r
if (EFI_ERROR (Status)) {\r
if (RootBridgeDev == NULL) {\r
return EFI_NOT_FOUND;\r
}\r
- \r
+\r
//\r
// Get acpi resource node for all the resource types\r
//\r
);\r
\r
if (AcpiConfig != NULL) {\r
- gBS->FreePool (AcpiConfig);\r
+ FreePool (AcpiConfig);\r
}\r
}\r
\r
\r
//\r
// Initialize resource pool\r
- // \r
+ //\r
InitializeResourcePool (&IoPool, PciBarTypeIo16);\r
InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);\r
InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);\r
Mem32Bridge->Alignment = MaxOptionRomSize - 1;\r
}\r
}\r
- } \r
- \r
+ }\r
+\r
//\r
// Based on the all the resource tree, contruct ACPI resource node to\r
// submit the resource aperture to pci host bridge protocol\r
// Free acpi resource node\r
//\r
if (AcpiConfig != NULL) {\r
- gBS->FreePool (AcpiConfig);\r
+ FreePool (AcpiConfig);\r
}\r
\r
if (EFI_ERROR (Status)) {\r
//\r
// Notify pci bus driver starts to program the resource\r
//\r
- \r
+\r
Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);\r
\r
if (!EFI_ERROR (Status)) {\r
//\r
break;\r
}\r
- \r
+\r
//\r
// If the resource allocation is unsuccessful, free resources on bridge\r
//\r
- \r
+\r
RootBridgeDev = NULL;\r
RootBridgeHandle = 0;\r
\r
if (RootBridgeDev == NULL) {\r
return EFI_NOT_FOUND;\r
}\r
- \r
+\r
//\r
// Get host bridge handle for status report\r
//\r
&Mem64ResStatus,\r
&PMem64ResStatus\r
);\r
- gBS->FreePool (AcpiConfig);\r
+ FreePool (AcpiConfig);\r
}\r
}\r
//\r
if (RootBridgeDev == NULL) {\r
return EFI_NOT_FOUND;\r
}\r
- \r
+\r
//\r
// Get acpi resource node for all the resource types\r
//\r
{\r
if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
return PciScanBus_WithHotPlugDeviceSupport (\r
- Bridge, \r
- StartBusNumber, \r
- SubBusNumber, \r
+ Bridge,\r
+ StartBusNumber,\r
+ SubBusNumber,\r
PaddedBusRange\r
);\r
} else {\r
return PciScanBus_WithoutHotPlugDeviceSupport (\r
- Bridge, \r
- StartBusNumber, \r
- SubBusNumber, \r
+ Bridge,\r
+ StartBusNumber,\r
+ SubBusNumber,\r
PaddedBusRange\r
);\r
}\r
Func\r
);\r
\r
- if (!EFI_ERROR (Status) && \r
+ if (!EFI_ERROR (Status) &&\r
(IS_PCI_BRIDGE (&Pci) ||\r
IS_CARDBUS_BRIDGE (&Pci))) {\r
\r
\r
Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
\r
- Status = PciRootBridgeIo->Pci.Write (\r
+ Status = PciRootBridgeIoWrite (\r
PciRootBridgeIo,\r
+ &Pci,\r
EfiPciWidthUint16,\r
Address,\r
1,\r
// Initialize SubBusNumber to SecondBus\r
//\r
Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
- Status = PciRootBridgeIo->Pci.Write (\r
+ Status = PciRootBridgeIoWrite (\r
PciRootBridgeIo,\r
+ &Pci,\r
EfiPciWidthUint8,\r
Address,\r
1,\r
//\r
Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
Register = 0xFF;\r
- Status = PciRootBridgeIo->Pci.Write (\r
+ Status = PciRootBridgeIoWrite (\r
PciRootBridgeIo,\r
+ &Pci,\r
EfiPciWidthUint8,\r
Address,\r
1,\r
\r
Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
\r
- Status = PciRootBridgeIo->Pci.Write (\r
+ Status = PciRootBridgeIoWrite (\r
PciRootBridgeIo,\r
+ &Pci,\r
EfiPciWidthUint8,\r
Address,\r
1,\r
\r
continue;\r
}\r
- \r
+\r
//\r
// Get the PCI device information\r
//\r
EfiPciBeforeChildBusEnumeration\r
);\r
}\r
- \r
+\r
//\r
// For Pci Hotplug controller devcie only\r
//\r
Event,\r
&State\r
);\r
- \r
+\r
PreprocessController (\r
PciDevice,\r
PciDevice->BusNumber,\r
PciDevice->DeviceNumber,\r
PciDevice->FunctionNumber,\r
EfiPciBeforeChildBusEnumeration\r
- ); \r
+ );\r
continue;\r
}\r
}\r
if (gPciHotPlugInit != NULL) {\r
\r
if (IsRootPciHotPlugBus (PciDevice->DevicePath, &HpIndex)) {\r
- \r
+\r
//\r
// If it is initialized, get the padded bus range\r
//\r
Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);\r
Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
\r
- Status = PciRootBridgeIo->Pci.Write (\r
+ Status = PciRootBridgeIoWrite (\r
PciRootBridgeIo,\r
+ &Pci,\r
EfiPciWidthUint16,\r
Address,\r
1,\r
// If it is PPB, resursively search down this bridge\r
//\r
if (IS_PCI_BRIDGE (&Pci)) {\r
- \r
+\r
//\r
// Initialize SubBusNumber to Maximum bus number\r
//\r
Register = 0xFF;\r
Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
- Status = PciRootBridgeIo->Pci.Write (\r
+ Status = PciRootBridgeIoWrite (\r
PciRootBridgeIo,\r
+ &Pci,\r
EfiPciWidthUint8,\r
Address,\r
1,\r
//\r
Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
\r
- Status = PciRootBridgeIo->Pci.Write (\r
+ Status = PciRootBridgeIoWrite (\r
PciRootBridgeIo,\r
+ &Pci,\r
EfiPciWidthUint8,\r
Address,\r
1,\r
/*++\r
\r
Routine Description:\r
- \r
+\r
Process Option Rom on this host bridge\r
\r
Arguments:\r
if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {\r
\r
if (gPciHotPlugInit && Temp->Allocated) {\r
- \r
+\r
//\r
// Raise the EFI_IOB_PCI_HPC_INIT status code\r
//\r
/*++\r
\r
Routine Description:\r
- \r
+\r
Arguments:\r
\r
Returns:\r
\r
Routine Description:\r
\r
- This function is used to enumerate the entire host bridge \r
+ This function is used to enumerate the entire host bridge\r
in a given platform\r
\r
Arguments:\r
\r
if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
\r
- // \r
+ //\r
// Notify the bus allocation phase is finished for the first time\r
- // \r
+ //\r
NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);\r
- \r
- \r
+\r
+\r
if (gPciHotPlugInit != NULL) {\r
//\r
// Wait for all HPC initialized\r
// Notify the bus allocation phase is about to start for the 2nd time\r
//\r
NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);\r
- \r
+\r
RootBridgeHandle = NULL;\r
while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
\r
return Status;\r
}\r
}\r
- \r
+\r
//\r
// Notify the bus allocation phase is to end\r
//\r
\r
return EFI_SUCCESS;\r
}\r
+\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