**/\r
\r
#include <IndustryStandard/Acpi10.h>\r
+#include <IndustryStandard/Q35MchIch9.h>\r
#include <IndustryStandard/QemuPciBridgeCapabilities.h>\r
\r
#include <Library/BaseLib.h>\r
#include <Library/DebugLib.h>\r
#include <Library/DevicePathLib.h>\r
#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PciCapLib.h>\r
+#include <Library/PciCapPciSegmentLib.h>\r
#include <Library/PciLib.h>\r
#include <Library/UefiBootServicesTableLib.h>\r
\r
#include <Protocol/PciHotPlugInit.h>\r
#include <Protocol/PciRootBridgeIo.h>\r
\r
+//\r
+// TRUE if the PCI platform supports extended config space, FALSE otherwise.\r
+//\r
+STATIC BOOLEAN mPciExtConfSpaceSupported;\r
+\r
+\r
//\r
// The protocol interface this driver produces.\r
//\r
}\r
\r
\r
-/**\r
- Read a slice from conventional PCI config space at the given offset, then\r
- advance the offset.\r
-\r
- @param[in] PciAddress The address of the PCI Device -- Bus, Device, Function\r
- -- in UEFI (not PciLib) encoding.\r
-\r
- @param[in,out] Offset On input, the offset in conventional PCI config space\r
- to start reading from. On output, the offset of the\r
- first byte that was not read.\r
-\r
- @param[in] Size The number of bytes to read.\r
-\r
- @param[out] Buffer On output, the bytes read from PCI config space are\r
- stored in this object.\r
-**/\r
-STATIC\r
-VOID\r
-ReadConfigSpace (\r
- IN CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *PciAddress,\r
- IN OUT UINT8 *Offset,\r
- IN UINT8 Size,\r
- OUT VOID *Buffer\r
- )\r
-{\r
- PciReadBuffer (\r
- PCI_LIB_ADDRESS (\r
- PciAddress->Bus,\r
- PciAddress->Device,\r
- PciAddress->Function,\r
- *Offset\r
- ),\r
- Size,\r
- Buffer\r
- );\r
- *Offset += Size;\r
-}\r
-\r
-\r
-/**\r
- Convenience wrapper macro for ReadConfigSpace().\r
-\r
- Given the following conditions:\r
-\r
- - HeaderField is the first field in the structure pointed-to by Struct,\r
-\r
- - Struct->HeaderField has been populated from the conventional PCI config\r
- space of the PCI device identified by PciAddress,\r
-\r
- - *Offset points one past HeaderField in the conventional PCI config space of\r
- the PCI device identified by PciAddress,\r
-\r
- populate the rest of *Struct from conventional PCI config space, starting at\r
- *Offset. Finally, increment *Offset so that it point one past *Struct.\r
-\r
- @param[in] PciAddress The address of the PCI Device -- Bus, Device, Function\r
- -- in UEFI (not PciLib) encoding. Type: pointer to\r
- CONST EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS.\r
-\r
- @param[in,out] Offset On input, the offset in conventional PCI config space\r
- to start reading from; one past Struct->HeaderField.\r
- On output, the offset of the first byte that was not\r
- read; one past *Struct. Type: pointer to UINT8.\r
-\r
- @param[out] Struct The structure to complete. Type: pointer to structure\r
- object.\r
-\r
- @param[in] HeaderField The name of the first field in *Struct, after which\r
- *Struct should be populated. Type: structure member\r
- identifier.\r
-**/\r
-#define COMPLETE_CONFIG_SPACE_STRUCT(PciAddress, Offset, Struct, HeaderField) \\r
- ReadConfigSpace ( \\r
- (PciAddress), \\r
- (Offset), \\r
- (UINT8)(sizeof *(Struct) - sizeof ((Struct)->HeaderField)), \\r
- &((Struct)->HeaderField) + 1 \\r
- )\r
-\r
-\r
/**\r
Look up the QEMU-specific Resource Reservation capability in the conventional\r
config space of a Hotplug Controller (that is, PCI Bridge).\r
\r
- This function performs as few config space reads as possible.\r
+ On error, the contents of ReservationHint are indeterminate.\r
\r
@param[in] HpcPciAddress The address of the PCI Bridge -- Bus, Device,\r
Function -- in UEFI (not PciLib) encoding.\r
@retval EFI_SUCCESS The capability has been found, ReservationHint has\r
been populated.\r
\r
- @retval EFI_NOT_FOUND The capability is missing. The contents of\r
- ReservationHint are now indeterminate.\r
+ @retval EFI_NOT_FOUND The capability is missing.\r
+\r
+ @return Error codes from PciCapPciSegmentLib and PciCapLib.\r
**/\r
STATIC\r
EFI_STATUS\r
OUT QEMU_PCI_BRIDGE_CAPABILITY_RESOURCE_RESERVATION *ReservationHint\r
)\r
{\r
- UINT16 PciVendorId;\r
- UINT16 PciStatus;\r
- UINT8 PciCapPtr;\r
- UINT8 Offset;\r
+ UINT16 PciVendorId;\r
+ EFI_STATUS Status;\r
+ PCI_CAP_DEV *PciDevice;\r
+ PCI_CAP_LIST *CapList;\r
+ UINT16 VendorInstance;\r
+ PCI_CAP *VendorCap;\r
\r
//\r
// Check the vendor identifier.\r
}\r
\r
//\r
- // Check the Capabilities List bit in the PCI Status Register.\r
+ // Parse the capabilities lists.\r
//\r
- PciStatus = PciRead16 (\r
- PCI_LIB_ADDRESS (\r
- HpcPciAddress->Bus,\r
- HpcPciAddress->Device,\r
- HpcPciAddress->Function,\r
- PCI_PRIMARY_STATUS_OFFSET\r
- )\r
- );\r
- if ((PciStatus & EFI_PCI_STATUS_CAPABILITY) == 0) {\r
- return EFI_NOT_FOUND;\r
+ Status = PciCapPciSegmentDeviceInit (\r
+ mPciExtConfSpaceSupported ? PciCapExtended : PciCapNormal,\r
+ 0, // Segment\r
+ HpcPciAddress->Bus,\r
+ HpcPciAddress->Device,\r
+ HpcPciAddress->Function,\r
+ &PciDevice\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ Status = PciCapListInit (PciDevice, &CapList);\r
+ if (EFI_ERROR (Status)) {\r
+ goto UninitPciDevice;\r
}\r
\r
//\r
- // Fetch the start of the Capabilities List.\r
- //\r
- PciCapPtr = PciRead8 (\r
- PCI_LIB_ADDRESS (\r
- HpcPciAddress->Bus,\r
- HpcPciAddress->Device,\r
- HpcPciAddress->Function,\r
- PCI_CAPBILITY_POINTER_OFFSET\r
- )\r
- );\r
-\r
- //\r
- // Scan the Capabilities List until we find the terminator element, or the\r
- // Resource Reservation capability.\r
+ // Scan the vendor capability instances for the Resource Reservation\r
+ // capability.\r
//\r
- for (Offset = PciCapPtr & 0xFC;\r
- Offset > 0;\r
- Offset = ReservationHint->BridgeHdr.VendorHdr.Hdr.NextItemPtr & 0xFC) {\r
- BOOLEAN EnoughRoom;\r
-\r
- //\r
- // Check if the Resource Reservation capability would fit into config space\r
- // at this offset.\r
- //\r
- EnoughRoom = (BOOLEAN)(\r
- Offset <= PCI_MAX_CONFIG_OFFSET - sizeof *ReservationHint\r
- );\r
-\r
- //\r
- // Read the standard capability header so we can check the capability ID\r
- // (if necessary) and advance to the next capability.\r
- //\r
- ReadConfigSpace (\r
- HpcPciAddress,\r
- &Offset,\r
- (UINT8)sizeof ReservationHint->BridgeHdr.VendorHdr.Hdr,\r
- &ReservationHint->BridgeHdr.VendorHdr.Hdr\r
- );\r
- if (!EnoughRoom ||\r
- (ReservationHint->BridgeHdr.VendorHdr.Hdr.CapabilityID !=\r
- EFI_PCI_CAPABILITY_ID_VENDOR)) {\r
- continue;\r
+ VendorInstance = 0;\r
+ for (;;) {\r
+ UINT8 VendorLength;\r
+ UINT8 BridgeCapType;\r
+\r
+ Status = PciCapListFindCap (\r
+ CapList,\r
+ PciCapNormal,\r
+ EFI_PCI_CAPABILITY_ID_VENDOR,\r
+ VendorInstance++,\r
+ &VendorCap\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto UninitCapList;\r
}\r
\r
//\r
- // Read the rest of the vendor capability header so we can check the\r
- // capability length.\r
+ // Check the vendor capability length.\r
//\r
- COMPLETE_CONFIG_SPACE_STRUCT (\r
- HpcPciAddress,\r
- &Offset,\r
- &ReservationHint->BridgeHdr.VendorHdr,\r
- Hdr\r
- );\r
- if (ReservationHint->BridgeHdr.VendorHdr.Length !=\r
- sizeof *ReservationHint) {\r
+ Status = PciCapRead (\r
+ PciDevice,\r
+ VendorCap,\r
+ OFFSET_OF (EFI_PCI_CAPABILITY_VENDOR_HDR, Length),\r
+ &VendorLength,\r
+ sizeof VendorLength\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto UninitCapList;\r
+ }\r
+ if (VendorLength != sizeof *ReservationHint) {\r
continue;\r
}\r
\r
//\r
- // Read the rest of the QEMU bridge capability header so we can check the\r
- // capability type.\r
+ // Check the vendor bridge capability type.\r
//\r
- COMPLETE_CONFIG_SPACE_STRUCT (\r
- HpcPciAddress,\r
- &Offset,\r
- &ReservationHint->BridgeHdr,\r
- VendorHdr\r
- );\r
- if (ReservationHint->BridgeHdr.Type !=\r
+ Status = PciCapRead (\r
+ PciDevice,\r
+ VendorCap,\r
+ OFFSET_OF (QEMU_PCI_BRIDGE_CAPABILITY_HDR, Type),\r
+ &BridgeCapType,\r
+ sizeof BridgeCapType\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto UninitCapList;\r
+ }\r
+ if (BridgeCapType ==\r
QEMU_PCI_BRIDGE_CAPABILITY_TYPE_RESOURCE_RESERVATION) {\r
- continue;\r
+ //\r
+ // We have a match.\r
+ //\r
+ break;\r
}\r
-\r
- //\r
- // Read the body of the reservation hint.\r
- //\r
- COMPLETE_CONFIG_SPACE_STRUCT (\r
- HpcPciAddress,\r
- &Offset,\r
- ReservationHint,\r
- BridgeHdr\r
- );\r
- return EFI_SUCCESS;\r
}\r
\r
- return EFI_NOT_FOUND;\r
+ //\r
+ // Populate ReservationHint.\r
+ //\r
+ Status = PciCapRead (\r
+ PciDevice,\r
+ VendorCap,\r
+ 0, // SourceOffsetInCap\r
+ ReservationHint,\r
+ sizeof *ReservationHint\r
+ );\r
+\r
+UninitCapList:\r
+ PciCapListUninit (CapList);\r
+\r
+UninitPciDevice:\r
+ PciCapPciSegmentDeviceUninit (PciDevice);\r
+\r
+ return Status;\r
}\r
\r
\r
{\r
EFI_STATUS Status;\r
\r
+ mPciExtConfSpaceSupported = (PcdGet16 (PcdOvmfHostBridgePciDevId) ==\r
+ INTEL_Q35_MCH_DEVICE_ID);\r
mPciHotPlugInit.GetRootHpcList = GetRootHpcList;\r
mPciHotPlugInit.InitializeRootHpc = InitializeRootHpc;\r
mPciHotPlugInit.GetResourcePadding = GetResourcePadding;\r