/** @file Copyright (c) 2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #include #pragma pack(1) // // Data region after PCI configuration header(for cardbus bridge) // typedef struct { UINT16 SubVendorId; // Subsystem Vendor ID UINT16 SubSystemId; // Subsystem ID UINT32 LegacyBase; // Optional 16-Bit PC Card Legacy // Mode Base Address // UINT32 Data[46]; } PCI_CARDBUS_DATA; typedef union { PCI_DEVICE_HEADER_TYPE_REGION Device; PCI_BRIDGE_CONTROL_REGISTER Bridge; PCI_CARDBUS_CONTROL_REGISTER CardBus; } NON_COMMON_UNION; typedef struct { PCI_DEVICE_INDEPENDENT_REGION Common; NON_COMMON_UNION NonCommon; UINT32 Data[48]; } PCI_CONFIG_SPACE; #pragma pack() VOID DumpPciDevice ( IN UINT8 Bus, IN UINT8 Device, IN UINT8 Function, IN PCI_TYPE00 *PciData ) { //DEBUG ((DEBUG_INFO, " 00/00/00 : [0000][0000] [00|00|00] 00000000 00000000 00000000 00000000 00000000 00000000 0000\n")); DEBUG ((DEBUG_INFO, " %02x/%02x/%02x :", Bus, Device, Function )); DEBUG ((DEBUG_INFO, " [%04x][%04x]", PciData->Hdr.VendorId, PciData->Hdr.DeviceId )); DEBUG ((DEBUG_INFO, " [%02x|%02x|%02x]", PciData->Hdr.ClassCode[2], PciData->Hdr.ClassCode[1], PciData->Hdr.ClassCode[0] )); DEBUG ((DEBUG_INFO, " %08x %08x %08x %08x %08x %08x", PciData->Device.Bar[0], PciData->Device.Bar[1], PciData->Device.Bar[2], PciData->Device.Bar[3], PciData->Device.Bar[4], PciData->Device.Bar[6] )); DEBUG ((DEBUG_INFO, " %04x\n", PciData->Hdr.Command )); } VOID DumpPciBridge ( IN UINT8 Bus, IN UINT8 Device, IN UINT8 Function, IN PCI_TYPE01 *PciData ) { //DEBUG ((DEBUG_INFO, " 00/00/00*: [0000][0000] [00|00|00] 00000000 00000000 [00|00|00] [00:00] [0000:0000] [0000:0000] [00000000:00000000] [0000:0000] 0000 0000\n")); DEBUG ((DEBUG_INFO, " %02x/%02x/%02x*:", Bus, Device, Function )); DEBUG ((DEBUG_INFO, " [%04x][%04x]", PciData->Hdr.VendorId, PciData->Hdr.DeviceId )); DEBUG ((DEBUG_INFO, " [%02x|%02x|%02x]", PciData->Hdr.ClassCode[2], PciData->Hdr.ClassCode[1], PciData->Hdr.ClassCode[0] )); DEBUG ((DEBUG_INFO, " %08x %08x", PciData->Bridge.Bar[0], PciData->Bridge.Bar[1] )); DEBUG ((DEBUG_INFO, " [%02x|%02x|%02x]", PciData->Bridge.PrimaryBus, PciData->Bridge.SecondaryBus, PciData->Bridge.SubordinateBus )); DEBUG ((DEBUG_INFO, " [00:00] [0000:0000] [0000:0000]", PciData->Bridge.IoBase, PciData->Bridge.IoLimit, PciData->Bridge.MemoryBase, PciData->Bridge.MemoryLimit, PciData->Bridge.PrefetchableMemoryBase, PciData->Bridge.PrefetchableMemoryLimit )); DEBUG ((DEBUG_INFO, " [00000000:00000000] [0000:0000]", PciData->Bridge.PrefetchableBaseUpper32, PciData->Bridge.PrefetchableLimitUpper32, PciData->Bridge.IoBaseUpper16, PciData->Bridge.IoLimitUpper16 )); DEBUG ((DEBUG_INFO, " %04x ", PciData->Bridge.BridgeControl )); DEBUG ((DEBUG_INFO, " %04x\n", PciData->Hdr.Command )); } /** This function gets the protocol interface from the given handle, and obtains its address space descriptors. @param[in] Handle The PCI_ROOT_BRIDIGE_IO_PROTOCOL handle. @param[out] IoDev Handle used to access configuration space of PCI device. @param[out] Descriptors Points to the address space descriptors. @retval EFI_SUCCESS The command completed successfully **/ EFI_STATUS PciGetProtocolAndResource ( IN EFI_HANDLE Handle, OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **IoDev, OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors ) { EFI_STATUS Status; // // Get inferface from protocol // Status = gBS->HandleProtocol ( Handle, &gEfiPciRootBridgeIoProtocolGuid, (VOID**)IoDev ); if (EFI_ERROR (Status)) { return Status; } // // Call Configuration() to get address space descriptors // Status = (*IoDev)->Configuration (*IoDev, (VOID**)Descriptors); if (Status == EFI_UNSUPPORTED) { *Descriptors = NULL; return EFI_SUCCESS; } else { return Status; } } /** This function get the next bus range of given address space descriptors. It also moves the pointer backward a node, to get prepared to be called again. @param[in, out] Descriptors Points to current position of a serial of address space descriptors. @param[out] MinBus The lower range of bus number. @param[out] MaxBus The upper range of bus number. @param[out] IsEnd Meet end of the serial of descriptors. @retval EFI_SUCCESS The command completed successfully. **/ EFI_STATUS PciGetNextBusRange ( IN OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors, OUT UINT16 *MinBus, OUT UINT16 *MaxBus, OUT BOOLEAN *IsEnd ) { *IsEnd = FALSE; // // When *Descriptors is NULL, Configuration() is not implemented, so assume // range is 0~PCI_MAX_BUS // if ((*Descriptors) == NULL) { *MinBus = 0; *MaxBus = PCI_MAX_BUS; return EFI_SUCCESS; } // // *Descriptors points to one or more address space descriptors, which // ends with a end tagged descriptor. Examine each of the descriptors, // if a bus typed one is found and its bus range covers bus, this handle // is the handle we are looking for. // while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) { if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { *MinBus = (UINT16) (*Descriptors)->AddrRangeMin; *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax; (*Descriptors)++; return (EFI_SUCCESS); } (*Descriptors)++; } if ((*Descriptors)->Desc == ACPI_END_TAG_DESCRIPTOR) { *IsEnd = TRUE; } return EFI_SUCCESS; } EFI_STATUS TestPointCheckPciResource ( VOID ) { UINT16 Bus; UINT16 Device; UINT16 Func; UINT64 Address; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev; EFI_STATUS Status; PCI_TYPE00 PciData; UINTN Index; EFI_HANDLE *HandleBuf; UINTN HandleCount; EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; UINT16 MinBus; UINT16 MaxBus; BOOLEAN IsEnd; DEBUG ((DEBUG_INFO, "==== TestPointCheckPciResource - Enter\n")); HandleBuf = NULL; Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiPciRootBridgeIoProtocolGuid, NULL, &HandleCount, &HandleBuf ); if (EFI_ERROR (Status)) { goto Done ; } DEBUG ((DEBUG_INFO, " B D F* VID DID Class[CSP] Bar0 Bar1 Bus[PSS] Io[BL] Memory[BL]")); DEBUG ((DEBUG_INFO, " PMemory[BL] PMemoryU[BL] IoU[BL] BriCtl Command\n")); DEBUG ((DEBUG_INFO, " B D F VID DID Class[CSP] Bar0 Bar1 Bar2 Bar3 Bar4 Bar5 Command\n")); for (Index = 0; Index < HandleCount; Index++) { Status = PciGetProtocolAndResource ( HandleBuf[Index], &IoDev, &Descriptors ); while (TRUE) { Status = PciGetNextBusRange (&Descriptors, &MinBus, &MaxBus, &IsEnd); if (EFI_ERROR (Status)) { goto Done; } if (IsEnd) { break; } for (Bus = MinBus; Bus <= MaxBus; Bus++) { // // For each devices, enumerate all functions it contains // for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) { // // For each function, read its configuration space and print summary // for (Func = 0; Func <= PCI_MAX_FUNC; Func++) { Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); IoDev->Pci.Read ( IoDev, EfiPciWidthUint16, Address, 1, &PciData.Hdr.VendorId ); // // If VendorId = 0xffff, there does not exist a device at this // location. For each device, if there is any function on it, // there must be 1 function at Function 0. So if Func = 0, there // will be no more functions in the same device, so we can break // loop to deal with the next device. // if (PciData.Hdr.VendorId == 0xffff && Func == 0) { break; } if (PciData.Hdr.VendorId != 0xffff) { IoDev->Pci.Read ( IoDev, EfiPciWidthUint32, Address, sizeof (PciData) / sizeof (UINT32), &PciData ); if (IS_PCI_BRIDGE(&PciData)) { // Bridge DumpPciBridge ((UINT8)Bus, (UINT8)Device, (UINT8)Func, (PCI_TYPE01 *)&PciData); } else if (IS_CARDBUS_BRIDGE(&PciData)) { // CardBus Bridge } else { // Device DumpPciDevice ((UINT8)Bus, (UINT8)Device, (UINT8)Func, &PciData); } // // If this is not a multi-function device, we can leave the loop // to deal with the next device. // if (Func == 0 && ((PciData.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00)) { break; } } } } } // // If Descriptor is NULL, Configuration() returns EFI_UNSUPPRORED, // we assume the bus range is 0~PCI_MAX_BUS. After enumerated all // devices on all bus, we can leave loop. // if (Descriptors == NULL) { break; } } } Done: if (HandleBuf != NULL) { FreePool (HandleBuf); } DEBUG ((DEBUG_INFO, "==== TestPointCheckPciResource - Exit\n")); if (EFI_ERROR(Status)) { TestPointLibAppendErrorString ( PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV, NULL, TEST_POINT_BYTE3_PCI_ENUMERATION_DONE_RESOURCE_ALLOCATED_ERROR_CODE \ TEST_POINT_PCI_ENUMERATION_DONE \ TEST_POINT_BYTE3_PCI_ENUMERATION_DONE_RESOURCE_ALLOCATED_ERROR_STRING ); } return Status; } EFI_STATUS TestPointCheckPciBusMaster ( VOID ) { UINTN Segment; UINTN SegmentCount; UINTN Bus; UINTN Device; UINTN Function; UINT16 VendorId; UINT16 Command; UINT8 HeaderType; EFI_STATUS Status; PCI_SEGMENT_INFO *PciSegmentInfo; PciSegmentInfo = GetPciSegmentInfo (&SegmentCount); if (PciSegmentInfo == NULL) { return EFI_OUT_OF_RESOURCES; } Status = EFI_SUCCESS; for (Segment = 0; Segment < SegmentCount; Segment++) { for (Bus = PciSegmentInfo[Segment].StartBusNumber; Bus <= PciSegmentInfo[Segment].EndBusNumber; Bus++) { for (Device = 0; Device <= 0x1F; Device++) { for (Function = 0; Function <= 0x7; Function++) { VendorId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(PciSegmentInfo[Segment].SegmentNumber, Bus, Device, Function, PCI_VENDOR_ID_OFFSET)); // // If VendorId = 0xffff, there does not exist a device at this // location. For each device, if there is any function on it, // there must be 1 function at Function 0. So if Func = 0, there // will be no more functions in the same device, so we can break // loop to deal with the next device. // if (VendorId == 0xffff && Function == 0) { break; } if (VendorId != 0xffff) { Command = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_COMMAND_OFFSET)); if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) { DEBUG ((DEBUG_INFO, "PCI BME enabled (S%04x.B%02x.D%02x.F%x - %04x)\n", Segment, Bus, Device, Function, Command)); TestPointLibAppendErrorString ( PLATFORM_TEST_POINT_ROLE_PLATFORM_IBV, NULL, TEST_POINT_BYTE3_PCI_ENUMERATION_DONE_BUS_MASTER_DISABLED_ERROR_CODE \ TEST_POINT_PCI_ENUMERATION_DONE \ TEST_POINT_BYTE3_PCI_ENUMERATION_DONE_BUS_MASTER_DISABLED_ERROR_STRING ); Status = EFI_INVALID_PARAMETER; } // // If this is not a multi-function device, we can leave the loop // to deal with the next device. // HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_HEADER_TYPE_OFFSET)); if (Function == 0 && ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00)) { break; } } } } } } return Status; }