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