X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=EdkModulePkg%2FLibrary%2FEdkPciIncompatibleDeviceSupportLib%2FEdkPciIncompatibleDeviceSupportLib.c;fp=EdkModulePkg%2FLibrary%2FEdkPciIncompatibleDeviceSupportLib%2FEdkPciIncompatibleDeviceSupportLib.c;h=f6638c160706eef64cb21fca38a89666f7d57b21;hp=0000000000000000000000000000000000000000;hb=98419ef4b972aade5ff5201ff6dd99561872e52c;hpb=0eaa1933bc16010889cb39a8b91cbd0a48d985b2 diff --git a/EdkModulePkg/Library/EdkPciIncompatibleDeviceSupportLib/EdkPciIncompatibleDeviceSupportLib.c b/EdkModulePkg/Library/EdkPciIncompatibleDeviceSupportLib/EdkPciIncompatibleDeviceSupportLib.c new file mode 100644 index 0000000000..f6638c1607 --- /dev/null +++ b/EdkModulePkg/Library/EdkPciIncompatibleDeviceSupportLib/EdkPciIncompatibleDeviceSupportLib.c @@ -0,0 +1,388 @@ +/** @file + The implementation of PCI incompatible device support libary. + +Copyright (c) 2007 Intel Corporation. All rights reserved.
+This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +**/ + +#include "IncompatiblePciDeviceList.h" + +/** + Check whether two PCI devices matched + + @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO. + @param Header A pointer to EFI_PCI_DEVICE_INFO. + + @retval returns EFI_SUCCESS if two PCI device matched. +**/ +STATIC +EFI_STATUS +DeviceCheck ( + IN EFI_PCI_DEVICE_INFO *PciDeviceInfo, + IN EFI_PCI_DEVICE_INFO *Header + ) +{ + // + // See if the Header matches the parameters passed in + // + if (Header->VendorID != DEVICE_ID_NOCARE) { + if (PciDeviceInfo->VendorID != Header->VendorID) { + return EFI_UNSUPPORTED; + } + } + + if (Header->DeviceID != DEVICE_ID_NOCARE) { + if (PciDeviceInfo->DeviceID != Header->DeviceID) { + return EFI_UNSUPPORTED; + } + } + + if (Header->RevisionID != DEVICE_ID_NOCARE) { + if (PciDeviceInfo->RevisionID != Header->RevisionID) { + return EFI_UNSUPPORTED; + } + } + + if (Header->SubsystemVendorID != DEVICE_ID_NOCARE) { + if (PciDeviceInfo->SubsystemVendorID != Header->SubsystemVendorID) { + return EFI_UNSUPPORTED; + } + } + + if (Header->SubsystemID != DEVICE_ID_NOCARE) { + if (PciDeviceInfo->SubsystemID != Header->SubsystemID) { + return EFI_UNSUPPORTED; + } + } + + return EFI_SUCCESS; +} + + +/** + Check the incompatible device list for ACPI resource update and return + the configuration + + This function searches the incompatible device list according to request + information. If the PCI device belongs to the devices list, corresponding + configuration informtion will be returned, in the meantime return EFI_SUCCESS. + + @param PciDeviceInfo A pointer to PCI device information. + @param Configuration Returned information. + + @retval returns EFI_SUCCESS if check incompatible device ok. + Otherwise return EFI_UNSUPPORTED. +**/ +RETURN_STATUS +EFIAPI +PciResourceUpdateCheck ( + IN EFI_PCI_DEVICE_INFO *PciDeviceInfo, + OUT VOID *Configuration + ) +{ + UINT64 Tag; + UINT64 *ListPtr; + UINT64 *TempListPtr; + EFI_PCI_DEVICE_INFO *Header; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AcpiPtr; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *OldAcpiPtr; + EFI_PCI_RESOUCE_DESCRIPTOR *Dsc; + EFI_ACPI_END_TAG_DESCRIPTOR *PtrEnd; + UINTN Index; + + ASSERT (PciDeviceInfo != NULL); + + // + // Initialize the return value to NULL + // + * (VOID **) Configuration = NULL; + + ListPtr = IncompatiblePciDeviceListForResource; + while (*ListPtr != LIST_END_TAG) { + + Tag = *ListPtr; + + switch (Tag) { + case DEVICE_INF_TAG: + Header = (EFI_PCI_DEVICE_INFO *) (ListPtr + 1); + ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_INFO) / sizeof (UINT64); + + if (DeviceCheck (PciDeviceInfo, Header) != EFI_SUCCESS) { + continue; + } + + // + // Matched an item, so construct the ACPI descriptor for the resource. + // + // + // Count the resource items so that to allocate space + // + for (Index = 0, TempListPtr = ListPtr; *TempListPtr == DEVICE_RES_TAG; Index++) { + TempListPtr = TempListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64)); + } + // + // If there is at least one type of resource request, + // allocate a acpi resource node + // + if (Index == 0) { + return EFI_ABORTED; + } + + AcpiPtr = AllocateZeroPool ( + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * Index + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) + ); + + OldAcpiPtr = AcpiPtr; + + // + // Fill the EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR structure + // according to the EFI_PCI_RESOUCE_DESCRIPTOR structure + // + for (; *ListPtr == DEVICE_RES_TAG;) { + + Dsc = (EFI_PCI_RESOUCE_DESCRIPTOR *) (ListPtr + 1); + + AcpiPtr->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; + AcpiPtr->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + AcpiPtr->ResType = (UINT8) Dsc->ResType; + AcpiPtr->GenFlag = (UINT8) Dsc->GenFlag; + AcpiPtr->SpecificFlag = (UINT8) Dsc->SpecificFlag; + AcpiPtr->AddrSpaceGranularity = Dsc->AddrSpaceGranularity;; + AcpiPtr->AddrRangeMin = Dsc->AddrRangeMin; + AcpiPtr->AddrRangeMax = Dsc->AddrRangeMax; + AcpiPtr->AddrTranslationOffset = Dsc->AddrTranslationOffset; + AcpiPtr->AddrLen = Dsc->AddrLen; + + ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64)); + AcpiPtr++; + } + // + // put the checksum + // + PtrEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *) (AcpiPtr); + PtrEnd->Desc = ACPI_END_TAG_DESCRIPTOR; + PtrEnd->Checksum = 0; + + *(VOID **) Configuration = OldAcpiPtr; + + return EFI_SUCCESS; + + case DEVICE_RES_TAG: + // + // Adjust the pointer to the next PCI resource descriptor item + // + ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_RESOUCE_DESCRIPTOR)) / sizeof (UINT64)); + break; + + default: + return EFI_UNSUPPORTED; + } + } + + return EFI_UNSUPPORTED; + +} + +/** + Check the incompatible device list and return configuraton register mask values. + + This function searches the incompatible device list according to request + information. If the PCI device belongs to the devices list, corresponding + configuration informtion will be returned, in the meantime return EFI_SUCCESS. + + @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO. + @param AccessType Access Type, READ or WRITE. + @param Offset The address within the PCI configuration space. + @param Configuration Returned information. + + @retval returns EFI_SUCCESS if check incompatible device ok. + Otherwise return EFI_UNSUPPORTED. +**/ +RETURN_STATUS +EFIAPI +PciRegisterUpdateCheck ( + IN EFI_PCI_DEVICE_INFO *PciDeviceInfo, + IN UINT64 AccessType, + IN UINT64 Offset, + OUT VOID *Configuration + ) +{ + EFI_PCI_DEVICE_INFO *Header; + UINT64 Tag; + UINT64 *ListPtr; + EFI_PCI_REGISTER_VALUE_DATA *RegisterPtr; + EFI_PCI_REGISTER_VALUE_DATA *Dsc; + + ASSERT (PciDeviceInfo != NULL); + + ListPtr = IncompatiblePciDeviceListForRegister; + + // + // Initialize the return value to NULL + // + * (VOID **) Configuration = NULL; + + while (*ListPtr != LIST_END_TAG) { + + Tag = *ListPtr; + + switch (Tag) { + case DEVICE_INF_TAG: + Header = (EFI_PCI_DEVICE_INFO *) (ListPtr + 1); + ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_INFO) / sizeof (UINT64); + + // + // Check whether the PCI device matches the device in the incompatible devices list? + // If not, ship next + // + if (DeviceCheck (PciDeviceInfo, Header) != EFI_SUCCESS) { + continue; + } + + // + // Matched an item, check whether access matches? + // + for (; *ListPtr == DEVICE_RES_TAG;) { + ListPtr ++; + if (((EFI_PCI_REGISTER_VALUE_DESCRIPTOR *)ListPtr)->Offset == (Offset & 0xfc)) { + if (((EFI_PCI_REGISTER_VALUE_DESCRIPTOR *)ListPtr)->AccessType == AccessType) { + + Dsc = (EFI_PCI_REGISTER_VALUE_DATA *) (ListPtr + 2); + RegisterPtr = AllocateZeroPool (sizeof (EFI_PCI_REGISTER_VALUE_DATA)); + + RegisterPtr->AndValue = Dsc->AndValue; + RegisterPtr->OrValue = Dsc->OrValue; + + *(VOID **) Configuration = RegisterPtr; + + return EFI_SUCCESS; + } + } + ListPtr += sizeof (EFI_PCI_REGISTER_VALUE_DESCRIPTOR) / (sizeof (UINT64)); + } + return EFI_UNSUPPORTED; + + case DEVICE_RES_TAG: + // + // Adjust the pointer to the next item + // + ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_REGISTER_VALUE_DESCRIPTOR)) / sizeof (UINT64)); + break; + + default: + return EFI_UNSUPPORTED; + } + } + + return EFI_UNSUPPORTED; +} + +/** + Check the incompatible device list for access width incompatibility and + return the configuration + + This function searches the incompatible device list for access width + incompatibility according to request information. If the PCI device + belongs to the devices list, corresponding configuration informtion + will be returned, in the meantime return EFI_SUCCESS. + + @param PciDeviceInfo A pointer to PCI device information. + @param AccessType Access type, READ or WRITE. + @param Offset The address within the PCI configuration space. + @param AccessWidth Access width needs to check incompatibility. + @param Configuration Returned information. + + @retval returns EFI_SUCCESS if check incompatible device ok. + Otherwise return EFI_UNSUPPORTED. +**/ +RETURN_STATUS +EFIAPI +PciRegisterAccessCheck ( + IN EFI_PCI_DEVICE_INFO *PciDeviceInfo, + IN UINT64 AccessType, + IN UINT64 Offset, + IN UINT64 AccessWidth, + OUT VOID *Configuration + ) +{ + EFI_PCI_DEVICE_INFO *Header; + UINT64 Tag; + UINT64 *ListPtr; + EFI_PCI_REGISTER_ACCESS_DATA *RegisterPtr; + EFI_PCI_REGISTER_ACCESS_DATA *Dsc; + + ASSERT (PciDeviceInfo != NULL); + + ListPtr = DeviceListForAccessWidth; + + // + // Initialize the return value to NULL + // + * (VOID **) Configuration = NULL; + + while (*ListPtr != LIST_END_TAG) { + + Tag = *ListPtr; + + switch (Tag) { + case DEVICE_INF_TAG: + Header = (EFI_PCI_DEVICE_INFO *) (ListPtr + 1); + ListPtr = ListPtr + 1 + sizeof (EFI_PCI_DEVICE_INFO) / sizeof (UINT64); + + // + // Check whether the PCI device matches the device in the incompatible devices list? + // If not, ship next + // + if (DeviceCheck (PciDeviceInfo, Header) != EFI_SUCCESS) { + continue; + } + + // + // Matched an item, check whether access matches? + // + for (; *ListPtr == DEVICE_RES_TAG;) { + ListPtr ++; + if (((EFI_PCI_REGISTER_ACCESS_DESCRIPTOR *) ListPtr)->AccessType == AccessType && + ((EFI_PCI_REGISTER_ACCESS_DESCRIPTOR *) ListPtr)->AccessWidth == AccessWidth ) { + + Dsc = (EFI_PCI_REGISTER_ACCESS_DATA *) (ListPtr + 2); + + if((Dsc->StartOffset <= Offset) && (Dsc->EndOffset > Offset)) { + + RegisterPtr = AllocateZeroPool (sizeof (EFI_PCI_REGISTER_ACCESS_DATA)); + + RegisterPtr->StartOffset = Dsc->StartOffset; + RegisterPtr->EndOffset = Dsc->EndOffset; + RegisterPtr->Width = Dsc->Width; + + *(VOID **) Configuration = RegisterPtr; + + return EFI_SUCCESS; + } + } + ListPtr += sizeof (EFI_PCI_REGISTER_ACCESS_DESCRIPTOR) / (sizeof (UINT64)); + } + return EFI_UNSUPPORTED; + + case DEVICE_RES_TAG: + // + // Adjust the pointer to the next item + // + ListPtr = ListPtr + 1 + ((sizeof (EFI_PCI_REGISTER_ACCESS_DESCRIPTOR)) / sizeof (UINT64)); + break; + + default: + return EFI_UNSUPPORTED; + } + } + + return EFI_UNSUPPORTED; +} +