| /*++ | |
| Copyright (c) 2005 - 2009, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| Module Name: | |
| PcatPciRootBridge.c | |
| Abstract: | |
| EFI PC-AT PCI Root Bridge Controller | |
| --*/ | |
| #include "PcatPciRootBridge.h" | |
| #include "DeviceIo.h" | |
| EFI_CPU_IO2_PROTOCOL *gCpuIo; | |
| EFI_STATUS | |
| EFIAPI | |
| InitializePcatPciRootBridge ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| /*++ | |
| Routine Description: | |
| Initializes the PCI Root Bridge Controller | |
| Arguments: | |
| ImageHandle - | |
| SystemTable - | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
| UINTN PciSegmentIndex; | |
| UINTN PciRootBridgeIndex; | |
| UINTN PrimaryBusIndex; | |
| UINTN NumberOfPciRootBridges; | |
| UINTN NumberOfPciDevices; | |
| UINTN Device; | |
| UINTN Function; | |
| UINT16 VendorId; | |
| PCI_TYPE01 PciConfigurationHeader; | |
| UINT64 Address; | |
| UINT64 Value; | |
| UINT64 Base; | |
| UINT64 Limit; | |
| // | |
| // Initialize gCpuIo now since the chipset init code requires it. | |
| // | |
| Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **)&gCpuIo); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Initialize variables required to search all PCI segments for PCI devices | |
| // | |
| PciSegmentIndex = 0; | |
| PciRootBridgeIndex = 0; | |
| NumberOfPciRootBridges = 0; | |
| PrimaryBusIndex = 0; | |
| while (PciSegmentIndex <= PCI_MAX_SEGMENT) { | |
| PrivateData = NULL; | |
| Status = gBS->AllocatePool( | |
| EfiBootServicesData, | |
| sizeof (PCAT_PCI_ROOT_BRIDGE_INSTANCE), | |
| (VOID **)&PrivateData | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| ZeroMem (PrivateData, sizeof (PCAT_PCI_ROOT_BRIDGE_INSTANCE)); | |
| // | |
| // Initialize the signature of the private data structure | |
| // | |
| PrivateData->Signature = PCAT_PCI_ROOT_BRIDGE_SIGNATURE; | |
| PrivateData->Handle = NULL; | |
| PrivateData->DevicePath = NULL; | |
| InitializeListHead (&PrivateData->MapInfo); | |
| // | |
| // Initialize the PCI root bridge number and the bus range for that root bridge | |
| // | |
| PrivateData->RootBridgeNumber = (UINT32)PciRootBridgeIndex; | |
| PrivateData->PrimaryBus = (UINT32)PrimaryBusIndex; | |
| PrivateData->SubordinateBus = (UINT32)PrimaryBusIndex; | |
| PrivateData->IoBase = 0xffffffff; | |
| PrivateData->MemBase = 0xffffffff; | |
| PrivateData->Mem32Base = 0xffffffffffffffffULL; | |
| PrivateData->Pmem32Base = 0xffffffffffffffffULL; | |
| PrivateData->Mem64Base = 0xffffffffffffffffULL; | |
| PrivateData->Pmem64Base = 0xffffffffffffffffULL; | |
| // | |
| // The default mechanism for performing PCI Configuration cycles is to | |
| // use the I/O ports at 0xCF8 and 0xCFC. This is only used for IA-32. | |
| // IPF uses SAL calls to perform PCI COnfiguration cycles | |
| // | |
| PrivateData->PciAddress = 0xCF8; | |
| PrivateData->PciData = 0xCFC; | |
| // | |
| // Get the physical I/O base for performing PCI I/O cycles | |
| // For IA-32, this is always 0, because IA-32 has IN and OUT instructions | |
| // For IPF, a SAL call is made to retrieve the base address for PCI I/O cycles | |
| // | |
| Status = PcatRootBridgeIoGetIoPortMapping ( | |
| &PrivateData->PhysicalIoBase, | |
| &PrivateData->PhysicalMemoryBase | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Get PCI Express Base Address | |
| // | |
| PrivateData->PciExpressBaseAddress = GetPciExpressBaseAddressForRootBridge (PciSegmentIndex, PciRootBridgeIndex); | |
| if (PrivateData->PciExpressBaseAddress != 0) { | |
| DEBUG ((EFI_D_ERROR, "PCIE Base - 0x%lx\n", PrivateData->PciExpressBaseAddress)); | |
| } | |
| // | |
| // Create a lock for performing PCI Configuration cycles | |
| // | |
| EfiInitializeLock (&PrivateData->PciLock, TPL_HIGH_LEVEL); | |
| // | |
| // Initialize the attributes for this PCI root bridge | |
| // | |
| PrivateData->Attributes = 0; | |
| // | |
| // Build the EFI Device Path Protocol instance for this PCI Root Bridge | |
| // | |
| Status = PcatRootBridgeDevicePathConstructor (&PrivateData->DevicePath, PciRootBridgeIndex, (BOOLEAN)((PrivateData->PciExpressBaseAddress != 0) ? TRUE : FALSE)); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Build the PCI Root Bridge I/O Protocol instance for this PCI Root Bridge | |
| // | |
| Status = PcatRootBridgeIoConstructor (&PrivateData->Io, PciSegmentIndex); | |
| if (EFI_ERROR (Status)) { | |
| goto Done; | |
| } | |
| // | |
| // Scan all the PCI devices on the primary bus of the PCI root bridge | |
| // | |
| for (Device = 0, NumberOfPciDevices = 0; Device <= PCI_MAX_DEVICE; Device++) { | |
| for (Function = 0; Function <= PCI_MAX_FUNC; Function++) { | |
| // | |
| // Compute the PCI configuration address of the PCI device to probe | |
| // | |
| Address = EFI_PCI_ADDRESS (PrimaryBusIndex, Device, Function, 0); | |
| // | |
| // Read the Vendor ID from the PCI Configuration Header | |
| // | |
| Status = PrivateData->Io.Pci.Read ( | |
| &PrivateData->Io, | |
| EfiPciWidthUint16, | |
| Address, | |
| sizeof (VendorId) / sizeof (UINT16), | |
| &VendorId | |
| ); | |
| if ((EFI_ERROR (Status)) || ((VendorId == 0xffff) && (Function == 0))) { | |
| // | |
| // If the PCI Configuration Read fails, or a PCI device does not exist, then | |
| // skip this entire PCI device | |
| // | |
| break; | |
| } | |
| if (VendorId == 0xffff) { | |
| // | |
| // If PCI function != 0, VendorId == 0xFFFF, we continue to search PCI function. | |
| // | |
| continue; | |
| } | |
| // | |
| // Read the entire PCI Configuration Header | |
| // | |
| Status = PrivateData->Io.Pci.Read ( | |
| &PrivateData->Io, | |
| EfiPciWidthUint16, | |
| Address, | |
| sizeof (PciConfigurationHeader) / sizeof (UINT16), | |
| &PciConfigurationHeader | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // If the entire PCI Configuration Header can not be read, then skip this entire PCI device | |
| // | |
| break; | |
| } | |
| // | |
| // Increment the number of PCI device found on the primary bus of the PCI root bridge | |
| // | |
| NumberOfPciDevices++; | |
| // | |
| // Look for devices with the VGA Palette Snoop enabled in the COMMAND register of the PCI Config Header | |
| // | |
| if (PciConfigurationHeader.Hdr.Command & 0x20) { | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; | |
| } | |
| // | |
| // If the device is a PCI-PCI Bridge, then look at the Subordinate Bus Number | |
| // | |
| if (IS_PCI_BRIDGE(&PciConfigurationHeader)) { | |
| // | |
| // Get the Bus range that the PPB is decoding | |
| // | |
| if (PciConfigurationHeader.Bridge.SubordinateBus > PrivateData->SubordinateBus) { | |
| // | |
| // If the suborinate bus number of the PCI-PCI bridge is greater than the PCI root bridge's | |
| // current subordinate bus number, then update the PCI root bridge's subordinate bus number | |
| // | |
| PrivateData->SubordinateBus = PciConfigurationHeader.Bridge.SubordinateBus; | |
| } | |
| // | |
| // Get the I/O range that the PPB is decoding | |
| // | |
| Value = PciConfigurationHeader.Bridge.IoBase & 0x0f; | |
| Base = ((UINT32)PciConfigurationHeader.Bridge.IoBase & 0xf0) << 8; | |
| Limit = (((UINT32)PciConfigurationHeader.Bridge.IoLimit & 0xf0) << 8) | 0x0fff; | |
| if (Value == 0x01) { | |
| Base |= ((UINT32)PciConfigurationHeader.Bridge.IoBaseUpper16 << 16); | |
| Limit |= ((UINT32)PciConfigurationHeader.Bridge.IoLimitUpper16 << 16); | |
| } | |
| if (Base < Limit) { | |
| if (PrivateData->IoBase > Base) { | |
| PrivateData->IoBase = Base; | |
| } | |
| if (PrivateData->IoLimit < Limit) { | |
| PrivateData->IoLimit = Limit; | |
| } | |
| } | |
| // | |
| // Get the Memory range that the PPB is decoding | |
| // | |
| Base = ((UINT32)PciConfigurationHeader.Bridge.MemoryBase & 0xfff0) << 16; | |
| Limit = (((UINT32)PciConfigurationHeader.Bridge.MemoryLimit & 0xfff0) << 16) | 0xfffff; | |
| if (Base < Limit) { | |
| if (PrivateData->MemBase > Base) { | |
| PrivateData->MemBase = Base; | |
| } | |
| if (PrivateData->MemLimit < Limit) { | |
| PrivateData->MemLimit = Limit; | |
| } | |
| if (PrivateData->Mem32Base > Base) { | |
| PrivateData->Mem32Base = Base; | |
| } | |
| if (PrivateData->Mem32Limit < Limit) { | |
| PrivateData->Mem32Limit = Limit; | |
| } | |
| } | |
| // | |
| // Get the Prefetchable Memory range that the PPB is decoding | |
| // | |
| Value = PciConfigurationHeader.Bridge.PrefetchableMemoryBase & 0x0f; | |
| Base = ((UINT32)PciConfigurationHeader.Bridge.PrefetchableMemoryBase & 0xfff0) << 16; | |
| Limit = (((UINT32)PciConfigurationHeader.Bridge.PrefetchableMemoryLimit & 0xfff0) << 16) | 0xffffff; | |
| if (Value == 0x01) { | |
| Base |= LShiftU64((UINT64)PciConfigurationHeader.Bridge.PrefetchableBaseUpper32,32); | |
| Limit |= LShiftU64((UINT64)PciConfigurationHeader.Bridge.PrefetchableLimitUpper32,32); | |
| } | |
| if (Base < Limit) { | |
| if (PrivateData->MemBase > Base) { | |
| PrivateData->MemBase = Base; | |
| } | |
| if (PrivateData->MemLimit < Limit) { | |
| PrivateData->MemLimit = Limit; | |
| } | |
| if (Value == 0x00) { | |
| if (PrivateData->Pmem32Base > Base) { | |
| PrivateData->Pmem32Base = Base; | |
| } | |
| if (PrivateData->Pmem32Limit < Limit) { | |
| PrivateData->Pmem32Limit = Limit; | |
| } | |
| } | |
| if (Value == 0x01) { | |
| if (PrivateData->Pmem64Base > Base) { | |
| PrivateData->Pmem64Base = Base; | |
| } | |
| if (PrivateData->Pmem64Limit < Limit) { | |
| PrivateData->Pmem64Limit = Limit; | |
| } | |
| } | |
| } | |
| // | |
| // Look at the PPB Configuration for legacy decoding attributes | |
| // | |
| if (PciConfigurationHeader.Bridge.BridgeControl & 0x04) { | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; | |
| } | |
| if (PciConfigurationHeader.Bridge.BridgeControl & 0x08) { | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; | |
| } | |
| } else { | |
| // | |
| // Parse the BARs of the PCI device to determine what I/O Ranges, | |
| // Memory Ranges, and Prefetchable Memory Ranges the device is decoding | |
| // | |
| if ((PciConfigurationHeader.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) { | |
| Status = PcatPciRootBridgeParseBars ( | |
| PrivateData, | |
| PciConfigurationHeader.Hdr.Command, | |
| PrimaryBusIndex, | |
| Device, | |
| Function | |
| ); | |
| } | |
| // | |
| // See if the PCI device is an IDE controller | |
| // | |
| if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x01 && | |
| PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ) { | |
| if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x80) { | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; | |
| } | |
| if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x01) { | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; | |
| } | |
| if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x04) { | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; | |
| } | |
| } | |
| // | |
| // See if the PCI device is a legacy VGA controller | |
| // | |
| if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x00 && | |
| PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ) { | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; | |
| } | |
| // | |
| // See if the PCI device is a standard VGA controller | |
| // | |
| if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x03 && | |
| PciConfigurationHeader.Hdr.ClassCode[1] == 0x00 ) { | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; | |
| } | |
| // | |
| // See if the PCI Device is a PCI - ISA or PCI - EISA | |
| // or ISA_POSITIVIE_DECODE Bridge device | |
| // | |
| if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x06) { | |
| if (PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 || | |
| PciConfigurationHeader.Hdr.ClassCode[1] == 0x02 || | |
| PciConfigurationHeader.Hdr.ClassCode[1] == 0x80 ) { | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; | |
| PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; | |
| if (PrivateData->MemBase > 0xa0000) { | |
| PrivateData->MemBase = 0xa0000; | |
| } | |
| if (PrivateData->MemLimit < 0xbffff) { | |
| PrivateData->MemLimit = 0xbffff; | |
| } | |
| } | |
| } | |
| } | |
| // | |
| // If this device is not a multi function device, then skip the rest of this PCI device | |
| // | |
| if (Function == 0 && !(PciConfigurationHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION)) { | |
| break; | |
| } | |
| } | |
| } | |
| // | |
| // After scanning all the PCI devices on the PCI root bridge's primary bus, update the | |
| // Primary Bus Number for the next PCI root bridge to be this PCI root bridge's subordinate | |
| // bus number + 1. | |
| // | |
| PrimaryBusIndex = PrivateData->SubordinateBus + 1; | |
| // | |
| // If at least one PCI device was found on the primary bus of this PCI root bridge, then the PCI root bridge | |
| // exists. | |
| // | |
| if (NumberOfPciDevices > 0) { | |
| // | |
| // Adjust the I/O range used for bounds checking for the legacy decoding attributed | |
| // | |
| if (PrivateData->Attributes & 0x7f) { | |
| PrivateData->IoBase = 0; | |
| if (PrivateData->IoLimit < 0xffff) { | |
| PrivateData->IoLimit = 0xffff; | |
| } | |
| } | |
| // | |
| // Adjust the Memory range used for bounds checking for the legacy decoding attributed | |
| // | |
| if (PrivateData->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) { | |
| if (PrivateData->MemBase > 0xa0000) { | |
| PrivateData->MemBase = 0xa0000; | |
| } | |
| if (PrivateData->MemLimit < 0xbffff) { | |
| PrivateData->MemLimit = 0xbffff; | |
| } | |
| } | |
| // | |
| // Build ACPI descriptors for the resources on the PCI Root Bridge | |
| // | |
| Status = ConstructConfiguration(PrivateData); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Create the handle for this PCI Root Bridge | |
| // | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| &PrivateData->Handle, | |
| &gEfiDevicePathProtocolGuid, | |
| PrivateData->DevicePath, | |
| &gEfiPciRootBridgeIoProtocolGuid, | |
| &PrivateData->Io, | |
| NULL | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Contruct DeviceIoProtocol | |
| // | |
| Status = DeviceIoConstructor ( | |
| PrivateData->Handle, | |
| &PrivateData->Io, | |
| PrivateData->DevicePath, | |
| (UINT16)PrivateData->PrimaryBus, | |
| (UINT16)PrivateData->SubordinateBus | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Scan this PCI Root Bridge for PCI Option ROMs and add them to the PCI Option ROM Table | |
| // | |
| Status = ScanPciRootBridgeForRoms(&PrivateData->Io); | |
| // | |
| // Increment the index for the next PCI Root Bridge | |
| // | |
| PciRootBridgeIndex++; | |
| } else { | |
| // | |
| // If no PCI Root Bridges were found on the current PCI segment, then exit | |
| // | |
| if (NumberOfPciRootBridges == 0) { | |
| Status = EFI_SUCCESS; | |
| goto Done; | |
| } | |
| } | |
| // | |
| // If the PrimaryBusIndex is greater than the maximum allowable PCI bus number, then | |
| // the PCI Segment Number is incremented, and the next segment is searched starting at Bus #0 | |
| // Otherwise, the search is continued on the next PCI Root Bridge | |
| // | |
| if (PrimaryBusIndex > PCI_MAX_BUS) { | |
| PciSegmentIndex++; | |
| NumberOfPciRootBridges = 0; | |
| PrimaryBusIndex = 0; | |
| } else { | |
| NumberOfPciRootBridges++; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| Done: | |
| // | |
| // Clean up memory allocated for the PCI Root Bridge that was searched but not created. | |
| // | |
| if (PrivateData) { | |
| if (PrivateData->DevicePath) { | |
| gBS->FreePool(PrivateData->DevicePath); | |
| } | |
| gBS->FreePool (PrivateData); | |
| } | |
| // | |
| // If no PCI Root Bridges were discovered, then return the error condition from scanning the | |
| // first PCI Root Bridge | |
| // | |
| if (PciRootBridgeIndex == 0) { | |
| return Status; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| ConstructConfiguration( | |
| IN OUT PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| UINT8 NumConfig; | |
| EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration; | |
| EFI_ACPI_END_TAG_DESCRIPTOR *ConfigurationEnd; | |
| NumConfig = 0; | |
| PrivateData->Configuration = NULL; | |
| if (PrivateData->SubordinateBus >= PrivateData->PrimaryBus) { | |
| NumConfig++; | |
| } | |
| if (PrivateData->IoLimit >= PrivateData->IoBase) { | |
| NumConfig++; | |
| } | |
| if (PrivateData->Mem32Limit >= PrivateData->Mem32Base) { | |
| NumConfig++; | |
| } | |
| if (PrivateData->Pmem32Limit >= PrivateData->Pmem32Base) { | |
| NumConfig++; | |
| } | |
| if (PrivateData->Mem64Limit >= PrivateData->Mem64Base) { | |
| NumConfig++; | |
| } | |
| if (PrivateData->Pmem64Limit >= PrivateData->Pmem64Base) { | |
| NumConfig++; | |
| } | |
| if ( NumConfig == 0 ) { | |
| // | |
| // If there is no resource request | |
| // | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR), | |
| (VOID **)&PrivateData->Configuration | |
| ); | |
| if (EFI_ERROR (Status )) { | |
| return Status; | |
| } | |
| Configuration = PrivateData->Configuration; | |
| ZeroMem ( | |
| Configuration, | |
| sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) | |
| ); | |
| Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); | |
| Configuration++; | |
| ConfigurationEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *)(Configuration); | |
| ConfigurationEnd->Desc = ACPI_END_TAG_DESCRIPTOR; | |
| ConfigurationEnd->Checksum = 0; | |
| } | |
| // | |
| // If there is at least one type of resource request, | |
| // allocate a acpi resource node | |
| // | |
| Status = gBS->AllocatePool ( | |
| EfiBootServicesData, | |
| sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR), | |
| (VOID **)&PrivateData->Configuration | |
| ); | |
| if (EFI_ERROR (Status )) { | |
| return Status; | |
| } | |
| Configuration = PrivateData->Configuration; | |
| ZeroMem ( | |
| Configuration, | |
| sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR) | |
| ); | |
| if (PrivateData->SubordinateBus >= PrivateData->PrimaryBus) { | |
| Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); | |
| Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS; | |
| Configuration->SpecificFlag = 0; | |
| Configuration->AddrRangeMin = PrivateData->PrimaryBus; | |
| Configuration->AddrRangeMax = PrivateData->SubordinateBus; | |
| Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1; | |
| Configuration++; | |
| } | |
| // | |
| // Deal with io aperture | |
| // | |
| if (PrivateData->IoLimit >= PrivateData->IoBase) { | |
| Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); | |
| Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_IO; | |
| Configuration->SpecificFlag = 1; //non ISA range | |
| Configuration->AddrRangeMin = PrivateData->IoBase; | |
| Configuration->AddrRangeMax = PrivateData->IoLimit; | |
| Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1; | |
| Configuration++; | |
| } | |
| // | |
| // Deal with mem32 aperture | |
| // | |
| if (PrivateData->Mem32Limit >= PrivateData->Mem32Base) { | |
| Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); | |
| Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; | |
| Configuration->SpecificFlag = 0; //Nonprefechable | |
| Configuration->AddrSpaceGranularity = 32; //32 bit | |
| Configuration->AddrRangeMin = PrivateData->Mem32Base; | |
| Configuration->AddrRangeMax = PrivateData->Mem32Limit; | |
| Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1; | |
| Configuration++; | |
| } | |
| // | |
| // Deal with Pmem32 aperture | |
| // | |
| if (PrivateData->Pmem32Limit >= PrivateData->Pmem32Base) { | |
| Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); | |
| Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; | |
| Configuration->SpecificFlag = 0x6; //prefechable | |
| Configuration->AddrSpaceGranularity = 32; //32 bit | |
| Configuration->AddrRangeMin = PrivateData->Pmem32Base; | |
| Configuration->AddrRangeMax = PrivateData->Pmem32Limit; | |
| Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1; | |
| Configuration++; | |
| } | |
| // | |
| // Deal with mem64 aperture | |
| // | |
| if (PrivateData->Mem64Limit >= PrivateData->Mem64Base) { | |
| Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); | |
| Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; | |
| Configuration->SpecificFlag = 0; //nonprefechable | |
| Configuration->AddrSpaceGranularity = 64; //32 bit | |
| Configuration->AddrRangeMin = PrivateData->Mem64Base; | |
| Configuration->AddrRangeMax = PrivateData->Mem64Limit; | |
| Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1; | |
| Configuration++; | |
| } | |
| // | |
| // Deal with Pmem64 aperture | |
| // | |
| if (PrivateData->Pmem64Limit >= PrivateData->Pmem64Base) { | |
| Configuration->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Configuration->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); | |
| Configuration->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; | |
| Configuration->SpecificFlag = 0x06; //prefechable | |
| Configuration->AddrSpaceGranularity = 64; //32 bit | |
| Configuration->AddrRangeMin = PrivateData->Pmem64Base; | |
| Configuration->AddrRangeMax = PrivateData->Pmem64Limit; | |
| Configuration->AddrLen = Configuration->AddrRangeMax - Configuration->AddrRangeMin + 1; | |
| Configuration++; | |
| } | |
| // | |
| // put the checksum | |
| // | |
| ConfigurationEnd = (EFI_ACPI_END_TAG_DESCRIPTOR *)(Configuration); | |
| ConfigurationEnd->Desc = ACPI_END_TAG_DESCRIPTOR; | |
| ConfigurationEnd->Checksum = 0; | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| PcatPciRootBridgeBarExisted ( | |
| IN PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData, | |
| IN UINT64 Address, | |
| OUT UINT32 *OriginalValue, | |
| OUT UINT32 *Value | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| UINT32 AllOnes; | |
| EFI_TPL OldTpl; | |
| // | |
| // Preserve the original value | |
| // | |
| Status = PrivateData->Io.Pci.Read ( | |
| &PrivateData->Io, | |
| EfiPciWidthUint32, | |
| Address, | |
| 1, | |
| OriginalValue | |
| ); | |
| // | |
| // Raise TPL to high level to disable timer interrupt while the BAR is probed | |
| // | |
| OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); | |
| AllOnes = 0xffffffff; | |
| Status = PrivateData->Io.Pci.Write ( | |
| &PrivateData->Io, | |
| EfiPciWidthUint32, | |
| Address, | |
| 1, | |
| &AllOnes | |
| ); | |
| Status = PrivateData->Io.Pci.Read ( | |
| &PrivateData->Io, | |
| EfiPciWidthUint32, | |
| Address, | |
| 1, | |
| Value | |
| ); | |
| // | |
| //Write back the original value | |
| // | |
| Status = PrivateData->Io.Pci.Write ( | |
| &PrivateData->Io, | |
| EfiPciWidthUint32, | |
| Address, | |
| 1, | |
| OriginalValue | |
| ); | |
| // | |
| // Restore TPL to its original level | |
| // | |
| gBS->RestoreTPL (OldTpl); | |
| if ( *Value == 0 ) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| return Status; | |
| } | |
| EFI_STATUS | |
| PcatPciRootBridgeParseBars ( | |
| IN PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData, | |
| IN UINT16 Command, | |
| IN UINTN Bus, | |
| IN UINTN Device, | |
| IN UINTN Function | |
| ) | |
| /*++ | |
| Routine Description: | |
| Arguments: | |
| Returns: | |
| None | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| UINT64 Address; | |
| UINT32 OriginalValue; | |
| UINT32 Value; | |
| UINT32 OriginalUpperValue; | |
| UINT32 UpperValue; | |
| UINT64 Mask; | |
| UINTN Offset; | |
| UINT64 Base; | |
| UINT64 Length; | |
| UINT64 Limit; | |
| for (Offset = 0x10; Offset < 0x28; Offset += 4) { | |
| Address = EFI_PCI_ADDRESS (Bus, Device, Function, Offset); | |
| Status = PcatPciRootBridgeBarExisted ( | |
| PrivateData, | |
| Address, | |
| &OriginalValue, | |
| &Value | |
| ); | |
| if (!EFI_ERROR (Status )) { | |
| if ( Value & 0x01 ) { | |
| if (Command & 0x0001) { | |
| // | |
| //Device I/Os | |
| // | |
| Mask = 0xfffffffc; | |
| Base = OriginalValue & Mask; | |
| Length = ((~(Value & Mask)) & Mask) + 0x04; | |
| if (!(Value & 0xFFFF0000)){ | |
| Length &= 0x0000FFFF; | |
| } | |
| Limit = Base + Length - 1; | |
| if (Base < Limit) { | |
| if (PrivateData->IoBase > Base) { | |
| PrivateData->IoBase = (UINT32)Base; | |
| } | |
| if (PrivateData->IoLimit < Limit) { | |
| PrivateData->IoLimit = (UINT32)Limit; | |
| } | |
| } | |
| } | |
| } else { | |
| if (Command & 0x0002) { | |
| Mask = 0xfffffff0; | |
| Base = OriginalValue & Mask; | |
| Length = Value & Mask; | |
| if ((Value & 0x07) != 0x04) { | |
| Length = ((~Length) + 1) & 0xffffffff; | |
| } else { | |
| Offset += 4; | |
| Address = EFI_PCI_ADDRESS (Bus, Device, Function, Offset); | |
| Status = PcatPciRootBridgeBarExisted ( | |
| PrivateData, | |
| Address, | |
| &OriginalUpperValue, | |
| &UpperValue | |
| ); | |
| Base = Base | LShiftU64((UINT64)OriginalUpperValue,32); | |
| Length = Length | LShiftU64((UINT64)UpperValue,32); | |
| Length = (~Length) + 1; | |
| } | |
| Limit = Base + Length - 1; | |
| if (Base < Limit) { | |
| if (PrivateData->MemBase > Base) { | |
| PrivateData->MemBase = Base; | |
| } | |
| if (PrivateData->MemLimit < Limit) { | |
| PrivateData->MemLimit = Limit; | |
| } | |
| switch (Value &0x07) { | |
| case 0x00: ////memory space; anywhere in 32 bit address space | |
| if (Value & 0x08) { | |
| if (PrivateData->Pmem32Base > Base) { | |
| PrivateData->Pmem32Base = Base; | |
| } | |
| if (PrivateData->Pmem32Limit < Limit) { | |
| PrivateData->Pmem32Limit = Limit; | |
| } | |
| } else { | |
| if (PrivateData->Mem32Base > Base) { | |
| PrivateData->Mem32Base = Base; | |
| } | |
| if (PrivateData->Mem32Limit < Limit) { | |
| PrivateData->Mem32Limit = Limit; | |
| } | |
| } | |
| break; | |
| case 0x04: //memory space; anywhere in 64 bit address space | |
| if (Value & 0x08) { | |
| if (PrivateData->Pmem64Base > Base) { | |
| PrivateData->Pmem64Base = Base; | |
| } | |
| if (PrivateData->Pmem64Limit < Limit) { | |
| PrivateData->Pmem64Limit = Limit; | |
| } | |
| } else { | |
| if (PrivateData->Mem64Base > Base) { | |
| PrivateData->Mem64Base = Base; | |
| } | |
| if (PrivateData->Mem64Limit < Limit) { | |
| PrivateData->Mem64Limit = Limit; | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| UINT64 | |
| GetPciExpressBaseAddressForRootBridge ( | |
| IN UINTN HostBridgeNumber, | |
| IN UINTN RootBridgeNumber | |
| ) | |
| /*++ | |
| Routine Description: | |
| This routine is to get PciExpress Base Address for this RootBridge | |
| Arguments: | |
| HostBridgeNumber - The number of HostBridge | |
| RootBridgeNumber - The number of RootBridge | |
| Returns: | |
| UINT64 - PciExpressBaseAddress for this HostBridge and RootBridge | |
| --*/ | |
| { | |
| EFI_PCI_EXPRESS_BASE_ADDRESS_INFORMATION *PciExpressBaseAddressInfo; | |
| UINTN BufferSize; | |
| UINT32 Index; | |
| UINT32 Number; | |
| EFI_PEI_HOB_POINTERS GuidHob; | |
| // | |
| // Get PciExpressAddressInfo Hob | |
| // | |
| PciExpressBaseAddressInfo = NULL; | |
| BufferSize = 0; | |
| GuidHob.Raw = GetFirstGuidHob (&gEfiPciExpressBaseAddressGuid); | |
| if (GuidHob.Raw != NULL) { | |
| PciExpressBaseAddressInfo = GET_GUID_HOB_DATA (GuidHob.Guid); | |
| BufferSize = GET_GUID_HOB_DATA_SIZE (GuidHob.Guid); | |
| } else { | |
| return 0; | |
| } | |
| // | |
| // Search the PciExpress Base Address in the Hob for current RootBridge | |
| // | |
| Number = (UINT32)(BufferSize / sizeof(EFI_PCI_EXPRESS_BASE_ADDRESS_INFORMATION)); | |
| for (Index = 0; Index < Number; Index++) { | |
| if ((PciExpressBaseAddressInfo[Index].HostBridgeNumber == HostBridgeNumber) && | |
| (PciExpressBaseAddressInfo[Index].RootBridgeNumber == RootBridgeNumber)) { | |
| return PciExpressBaseAddressInfo[Index].PciExpressBaseAddress; | |
| } | |
| } | |
| // | |
| // Do not find the PciExpress Base Address in the Hob | |
| // | |
| return 0; | |
| } | |