]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkModulePkg/Library/EdkPciIncompatibleDeviceSupportLib/EdkPciIncompatibleDeviceSupportLib.c
1. Added EdkPciIncompatibleDeviceSupportLib in EdkModulePkg, this library is used...
[mirror_edk2.git] / EdkModulePkg / Library / EdkPciIncompatibleDeviceSupportLib / EdkPciIncompatibleDeviceSupportLib.c
diff --git a/EdkModulePkg/Library/EdkPciIncompatibleDeviceSupportLib/EdkPciIncompatibleDeviceSupportLib.c b/EdkModulePkg/Library/EdkPciIncompatibleDeviceSupportLib/EdkPciIncompatibleDeviceSupportLib.c
new file mode 100644 (file)
index 0000000..f6638c1
--- /dev/null
@@ -0,0 +1,388 @@
+/** @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